/ 01The hash-chained log
Atrium's audit log is append-only and hash-chained. Every entry's hash field covers the previous entry's hash plus the canonical JSON of the current entry's payload. Removing or modifying any entry breaks the chain from that point onward, detectable in O(n) by walking the entries.
impl ChainEntry { pub fn link(prev: &ChainEntry, payload: Value) -> Self { let canonical = canonical_json(&payload); // RFC 8785 let mut hasher = Sha256::new(); hasher.update(&prev.hash); hasher.update(canonical.as_bytes()); let hash: [u8; 32] = hasher.finalize().into(); Self { id: new_id(), payload, prev_hash: prev.hash, hash } } }
/ 02RFC 8785 canonicalisation
JSON has many equivalent serialisations: {"a":1,"b":2} and {"b": 2, "a": 1} are the same object. Hashing raw JSON would give different chains for equivalent payloads — useless for verification.
RFC 8785 (JSON Canonicalization Scheme) defines a single serialisation: sorted keys, no whitespace, normalised numbers, normalised strings. Rust, Python, and the in-browser WASM verifier all produce byte-identical canonical JSON from identical payloads, hence identical hashes.
/ 03RFC 3161 timestamps
Internal hash-chaining proves this log has not been modified since hash X was computed. It does not prove X existed at time T. For that, we anchor.
Every N entries (configurable; default 1,000 or every hour, whichever first), Atrium computes the chain head and submits it to one or more RFC 3161 Time-Stamp Authorities. The TSA signs (hash, time, TSA identity) and returns a TimeStampToken stored alongside the log.
Default TSAs:
- FreeTSA (EU-hosted) — public, free
- DigiCert TSA — commercial, reciprocal
- Customer-supplied — for sovereign deployments
/ 04Customer-controlled witness
Above TSA anchoring, customers can configure a private witness service. Atrium pushes chain heads to the witness on every anchor tick; the witness signs and stores them in a customer-controlled audit silo.
The witness sits outside the platform's trust boundary. Compromising Atrium and the TSA together still cannot rewrite history — the witness has independent timestamps.
/ 05The WASM verifier
The verifier is the load-bearing piece. It is a single Rust crate (atrium-verifier) compiled to WebAssembly and packaged as a standalone HTML app. It runs entirely client-side; no network calls.
What it does
- Load an audit export (JSON or signed envelope)
- Walk every entry; verify the hash chain
- For each anchor point, verify the RFC 3161 token signature and timestamp
- If a witness signature is present, verify it against the witness's published public key
- Render the result — verified entry count, anchor points, any tamper detected
Source is published. An auditor can rebuild the WASM blob from source and confirm it byte-matches the binary shipped with the platform. The crate is small enough to read end-to-end.
/ 06Court-ready exports
Audit exports come in two shapes:
- Live JSON — array of entries, with embedded anchor records; for piping into SIEM or ad-hoc analysis
- Sealed bundle — JSON + WASM verifier + index.html + README, all in a ZIP; opens locally in any browser, verifies offline
The sealed bundle is what regulators and courts receive. Defence is "open this; press verify; the verifier is open source and re-buildable from the linked repo." The platform is not in the trust path.
