Skip to content

Validation

How ad1-core/ad1-forensic correctness is established, graded by who confirms it (most-trustworthy first).

Summary

Aspect Tier Status
zlib chunk decompression + logical addressing 2 ✅ recomputed MD5/SHA1 match independent (flate2 + RustCrypto) ground truth
Structural offsets (headers, item, metadata, chunk table) 1 ✅ confirmed against FTK-written hashes across all 299,729 files of a real AD1
Robustness / panic-freedom on malformed input 2 ✅ malformed-input suite + two cargo-fuzz targets (3 real bugs found & fixed)
End-to-end vs FTK Imager stored hashes on userbss.ad1 1 ✅ 299,729/299,729 files — MD5 + SHA1 both match, 0 mismatches

Tier 2 — independent oracle on crafted data

The test fixtures are built by an encoder that follows the al3ks1s/AD1-tools layout, but the file data is compressed by flate2 and the stored hashes are computed by RustCrypto md-5/sha1 — libraries independent of ad1-core. So when the reader decompresses a file and its recomputed MD5 equals the stored MD5, the chunk table walk, cross-segment logical addressing, and zlib inflate are confirmed against ground truth the reader did not produce (read_at_whole_file_matches_data_and_stored_hash, reads_file_data_spanning_multiple_segments).

The residual tier-3 risk: the encoder and decoder share the structural offsets (both take them from the same C reference). A systematic offset error would pass these tests. That is exactly what the tier-1 step below closes.

Tier 2 — fuzzing

Two cargo-fuzz targets (fuzz_reader, fuzz_forensic) drive arbitrary bytes through open → entries → read_at and audit. They found and fixed three real defects: a 72 GB allocation from an attacker-controlled segment_count, a count + 1 overflow on a u64::MAX chunk count, and a cur - chunk_base underflow on a short non-last chunk. Each has a deterministic regression test.

Tier 1 — real-world data (confirmed)

The authoritative check: reconcile ad1-core's decompression + recomputed hashes against FTK Imager's stored per-file hashes in a real AD1 — userbss.ad1 from the 2025 Magnet Virtual Summit CTF (Hexordia / Kevin Pagano). FTK is a fully independent implementation, so agreement confirms the structural offsets the crafted fixtures could not (both sides of a fixture share those offsets; FTK does not).

  • Image: userbss.ad1, 51,678,663,221 bytes (48 GiB), single segment, MD5 0b6b53e3475b97ae8b3bd3c1e7cec2d9.
  • Parsed: version 4, 64 KiB chunks, 316,682 tree entries.
  • Result (full image): for all 299,729 files, ad1-core's recomputed MD5 and SHA1 (RustCrypto, over its own zlib decompression + logical addressing) match FTK's stored values — 299,729/299,729 MD5, 299,729/299,729 SHA1, 0 mismatches, 0 short decompressions (~600k independent comparisons, 10m49s).

Reproduce (the image is gitignored — see tests/data/README.md):

AD1_USERBSS=/path/to/userbss.ad1 \
  cargo test -p ad1-core --test tier1_real --release -- --nocapture
# AD1_USERBSS_LIMIT=N caps the file count for a quick smoke run.

The test (core/tests/tier1_real.rs) is env-gated: it skips cleanly when AD1_USERBSS is unset, so CI stays green without the 48 GiB artifact.