Right-to-erasure for compressed archives
AT-1 makes a compressed archive selectively erasable: each data subject's records are encrypted under their own key, so a GDPR/CCPA erasure request is satisfied by destroying one key — leaving the archive bytes unchanged and every other subject intact, with a signed certificate as proof. See the product overview for the why.
1. Build an erasable archive
Group rows by data subject and encrypt each group under a unique AES-256-GCM key.
# records.json: a JSON array of rows, each with a subject field (e.g. user_id) at1 erase build records.json --subject-field user_id --out archive/ # -> archive/archive.json (per-subject AES-256-GCM encrypted blocks) # archive.vault.json (the key store — OUTSIDE the archive, on purpose) # The keys never live inside the archive they protect. If they did, any tarball, bucket sync or # snapshot would capture them, and restoring that backup would silently reverse every erasure. # Use --vault to put the key store somewhere else entirely; a path inside the archive is refused. # Archives built before 0.2.32 keep working and warn: at1 erase migrate-vault archive/
2. Create a signing identity
Erasure certificates are Ed25519-signed so an auditor can verify them with your public key.
at1 erase keygen --out issuer.key # Ed25519 keypair -> issuer.key + issuer.key.pub # the issuer key signs erasure certificates; the .pub verifies them
3. Read and erase
Erasure destroys the subject's key and writes a certificate. The encrypted block stays physically in the archive but is unrecoverable. Destroying the key is O(1) in archive size — no re-encryption, no rewriting, no data movement, which is the property that matters for a deadline-bound DSAR. Issuing the certificate is linear, because the certificate carries the archive content hash and computing that reads the archive.
at1 erase read archive/ 1337 # the subject's records, across tables at1 erase erase archive/ 1337 --signing-key issuer.key --out-cert cert.json at1 erase read archive/ 1337 # -> exits non-zero: ERASED at1 erase read archive/ 1338 # -> still intact # key-only (above) leaves the archive byte-identical, and is the ONLY mode possible on WORM or # object-lock storage. On mutable storage, redact also removes the record and its label, so a # vault holder cannot even test whether the person was ever present: at1 erase erase archive/ 1337 --signing-key issuer.key --out-cert cert.json --mode redact # -> the archive hash CHANGES (a record was removed) and the certificate carries a survivor root # proving no other subject moved. A certificate claiming "unchanged" here would be false.
4. Verify the certificate
at1 erase verify cert.json issuer.key.pub # certificate signature: VALID (subject 1337, erased 2026-06-19T19:19:06Z, archive-unchanged=True)
The certificate is a self-contained JSON artifact:
{
"subject_id": "1337",
"erased_at": "2026-06-19T19:19:06Z",
"record_groups_erased": 1,
"archive_hash_before": "d5b75e94…",
"archive_hash_after": "d5b75e94…", // identical -> archive was not modified
"key_destruction_proof": "242b2484…", // commitment to the destroyed key
"issuer": "AT-1 DPO service", // set with --issuer
"payload_hash": "8627d736…", // OPTIONAL external commitment bound at build (see step 5)
"signature": "dd141c4a…" // Ed25519 over the above (payload_hash included when present)
}5. Bind an external commitment & set the issuer (optional)
For attestation and ledger integrations, bind a caller-supplied hash — e.g. an upstream H(payload) that some other receipt already committed to — with --hash-field. The certificate then proves “the payload that hashed to X was erased”, not merely “subject S was erased”. It is a hash, not PII: stored in cleartext, folded into the archive integrity hash (tamper-evident), and echoed into the signed certificate. Set your own issuer label with --issuer at the same time — trust comes from your signing key, the label is yours.
# each record carries a field (e.g. payload_hash) with the external commitment at1 erase build records.json --subject-field user_id --hash-field payload_hash --out archive/ at1 erase erase archive/ 1337 --signing-key issuer.key --issuer "Acme DPO" --out-cert cert.json # -> the certificate now carries "payload_hash" (bound into the signature) and "issuer": "Acme DPO"
Certificates verify independently of AT-1: the reference verifier is public Ed25519 + SHA-256 with no engine internals, so an auditor or a downstream ledger (e.g. an attestation witness) can adopt it directly and re-verify byte-for-byte. Forging payload_hash in a signed certificate invalidates the signature.
How it works
- Per-subject record-groups. All rows for one subject (across tables) are encrypted under one key, with the subject id bound as authenticated associated data (AAD).
- The archive identifies nobody. Blocks are keyed by HMAC-SHA256(index_key, subject_id), and the index key lives in the vault — outside the archive. A copy, backup or snapshot of an archive is therefore unlinkable to people on its own. A plain hash would not do this: with a known date of birth, sha256 of an SA ID number reverses in about a third of a second. It is the key the archive does not contain that makes the labels unlinkable, not the hashing.
- Erasure = key destruction. The key is zeroed in place and removed from the vault; a tombstone records that it was destroyed (so the system can prove the key is gone, not merely missing). The tombstone records the label, not the person, so the vault is not a register of who exercised Article 17.
- Two erasure modes. key-only (the default) destroys the key and leaves the archive byte-identical. The label stays — that is what keeps the bytes unchanged — so a party holding the vault can still test whether a given person was ever present by computing their label and looking for it. This is the only mode possible on WORM or object-lock storage, where by definition nothing can be removed; there, the residual is a property of the medium, not of the design. --mode redact also deletes the block and the label, so nothing about the person remains. The archive hash then changes, and the certificate proves nobody else moved with a survivor root — a hash over every block except the erased one, which an auditor can recompute from the archive as it stands, without ever having seen it before the erasure.
- Archive immutability. The certificate carries the archive content hash before and after — they are equal, proving the erasure modified no other data.
- Verifiability. The certificate is Ed25519-signed; any party with the issuer public key can verify it, and any tampering invalidates the signature.
- External commitment (optional). A caller-supplied payload_hash is folded into the archive integrity hash and included in the signed certificate — binding the deletion to a specific upstream commitment (e.g. a receipt's H(payload)) so it can seal back into another ledger.
Production notes
- Back the key vault with a KMS/HSM — the file vault (<archive>.vault.json) is for evaluation. Erasure then means a KMS key-version destroy.
- Keep keys out of the archive's backup scope. The vault is written outside the archive directory by default, and a --vault path inside the archive is refused. This is not cosmetic: a key captured by a snapshot is not destroyed, so restoring that snapshot would reverse the erasure. Point --vault at storage with its own retention policy, and exclude it from archive replication.
- Propagate erasure to replicas/derived archives by replicating only the tombstone.
- Anchor certificates to your existing tamper-evident integrity ledger for independent timestamping.
Honest scope
This uses cryptographic erasure (crypto-shredding), a method EU regulators recognise (EDPB Guidelines 5/2019, ICO, CNIL). We make no novel-patent claim — the value is the turnkey integration with a compressed, queryable AT-1 archive, per-subject grouping across tables, and the productised DPO workflow.