Selective disclosure — at1 reveal

Hand someone a file with parts withheld, which can still prove it is the original. See /reveal for working examples you can verify in a browser.

Why a Merkle root and not a hash

A single hash over a whole file answers one question: is this bit-for-bit what was sealed? Redact anything and the answer becomes no, which is indistinguishable from tampering. A Merkle root over the parts answers a better question. When a part is withheld, its original commitmentis kept in the certificate — a hash reveals nothing about the content, and is exactly what the tree needs to close. The recipient rebuilds the original root from the parts they can see plus the commitments of the parts they cannot, and compares.

container root = merkle( part_leaf[0..N] )      # frames or rows
container root = merkle( frame_root[0..N] )    # tiles: frame_root = merkle( tile_leaf[0..T] )

Usage

# seal your own data — the input type is detected
at1 reveal seal dashcam.mp4 --fps 2            # video   -> frames
at1 reveal seal ./frames                       # images  -> frames
at1 reveal seal transactions.csv               # CSV     -> rows
at1 reveal seal dashcam.mp4 --tiles            # video   -> tiles (region redaction)

# withhold parts, keeping them provable
at1 reveal redact sealed.at1bb --frames 176,178,180 \
    --reason "bystanders identifiable" --by "custodian" -o court.at1bb
at1 reveal redact sealed.at1t --auto --reason "faces" -o court.at1t
at1 reveal redact sealed.at1s --rows salary --reason "rental application" -o rental.at1s

# check a withheld copy against the ORIGINAL seal
at1 reveal prove court.at1bb

# give the recipient something they can run
at1 reveal verifier -o verify_reveal.py
PROVED against the ORIGINAL seal
  235 surviving frames are byte-identical to the original
  5 frame(s) removed — 'third parties identifiable at intersection (POPIA s.11)'
  rebuilt root b5d00c6d5cb4ba6a… == original

Three granularities

  • Frames (.at1bb) — withhold whole moments. Each frame also carries a measured motion figure, so “where is the moment” is answered from the index without decoding any footage.
  • Tiles (.at1t) — withhold a region inside a frame. A frame is stored as independently encoded tiles because you cannot blur part of a JPEG and keep the rest byte-identical.
  • Rows (.at1s) — withhold transactions in a document, while an issuer-signed summary keeps the totals honest.

The recipient

at1 reveal verifierwrites a single Python file with no dependencies beyond the standard library — no install, no account, no network. There is also a browser verifier at /reveal/verify.htmlwhich checks the file with WebCrypto on the recipient’s own device. A proof only the issuer can run is not a proof.

Limits worth reading before you rely on it

  • It does not judge the redaction. The seal is emphatic about integrity and silent about whether the right things were withheld. Automated detection needs a human in the loop or a published recall figure.
  • Anchor the original root. A custodian controlling both the file and the claimed original root can produce a consistent lie. Write the root to an append-only log at the moment of sealing.
  • It proves presence, not absence. Withholding is indistinguishable from absence. For absence proofs see training-data attestation.
  • Row commitments use a fixed canonical form, not canonical JSON — Python renders 38500.0 and JavaScript renders 38500, so a JSON-canonicalised leaf verifies in one and fails in the other.