What the pattern checks — and why you need both
Two independent verifications on every record restored from the server:- AES-256-GCM authentication tag.
decryptJsonverifies the ciphertext bytes are exactly what was written — any bit flip, truncation, or extension causes it to throw. - Re-derived hash comparison. Re-run
sha256(canonicalize(payload))on the decrypted result and compare it toreceipt.client_payload_hash, the anchor the client computed at write time over the full payload object (which itself includesagent_id,sequence_number,parent_snapshot,policy_hash,active_context, andtimestamp). This catches what the auth tag alone cannot: a malicious server returning a different record you wrote earlier — one that decrypts perfectly but belongs to the wrong point in your lineage.
The auth tag proves the bytes weren’t altered. It does not prove those bytes are the record you asked for. A server could swap in an older, still-validly-encrypted snapshot and the tag would pass. The hash comparison is what catches that — because
client_payload_hash is computed over the entire payload, including parent_snapshot, so a substituted record’s re-derived hash will not match the one issued at its original write.The checks, end to end
Attack and caught-by table
Implementing the check
client.restore() directly and trusting the result.
Where this applies
Limits — what this does not protect against
This is a network-layer defense. It cannot protect you from the following, which need separate mitigations:
- Compromised device. If your AES-256 key is exfiltrated, the checks still pass — an attacker with the key can forge valid records. Protect key material via the OS keychain and restrict physical access.
- Weak or guessable passphrase. Key derivation is only as strong as the secret it derives from.
- Freshness. This confirms a record is exactly what was written — it does not confirm it is the most recent write for that agent. Use
sequence_numberand lineage walking for freshness guarantees. - Denial of service. A malicious server can simply refuse to return your records. The check doesn’t prevent that; it only ensures that if you do get records back, they are authentic.
Operational guidance
Next steps
Zero-Knowledge Guarantees
The broader cryptographic contract this pattern operates inside, including the formal threat model.
Deterministic Lineage
Why parent-pointers make substitution structurally detectable.
Cryptographic Trust Center
Consolidated threat model, key custody boundaries, and honest compliance posture.
AES-256-GCM
Primitive-level detail on the authentication tag and nonce generation.