Audit chain + TSA anchoring
Every action in a session — joins, snapshots, whiteboards, recording starts, ends — lands in a per-session SHA-256 hash chain. The chain head is anchored at multiple independent timestamp authorities the moment the session closes. Tampering is detectable; the proof survives without trusting us.
How it works
Each audit event carries the SHA-256 hash of the prior event plus its own canonical payload. A Postgres advisory lock serialises writes so two concurrent capture events can't race the chain. Reorder a single event later and every downstream hash mismatches — verification fails on the first divergent row.
| Field | Purpose |
|---|---|
| sequence | Monotonic per-session counter. Append-only at the Postgres trigger level. |
| prev_hash | SHA-256 of the previous event row's canonical hash. First event has the all-zero prefix. |
| payload_jsonb | Canonical-JSON event data. Sorted keys, no whitespace — so the hash is reproducible. |
| hash | SHA-256 over (sequence ‖ prev_hash ‖ kind ‖ canonical payload ‖ occurred_at). |
| occurred_at | Stamped on the server. Client clocks don't drive ordering. |
Multi-backend anchoring
On session end, the chain head is submitted to two independent timestamp authorities in parallel. One outage doesn't break the proof — the verifier accepts any token whose backend cross-check passes.
Public-ledger anchor
Chain head is committed to a smart contract on Tezos. Finality lands in 15–20 minutes; the receipt carries the block hash + depth. Anyone with the session's chain head can verify against the public ledger without our cooperation.
Qualified time-stamp
Synchronous timestamp request to a qualified TSA — DataSure (ANSSI-qualified, eIDAS Art. 42) on managed deployments, or FreeTSA for self-host pilots. The TSR is a signed ASN.1 token that any RFC 3161 verifier can validate offline.
The backend interface is swappable — Sectigo, DigiCert, OpenTimestamps and other qualified TSPs drop in with a config change. Customers on managed deployments inherit DataSure; self-host operators pick their own.
What verification looks like
Every session ships with a public verify URL (HMAC-pinned, expires in 90 days). The auditor opens it, sees the chain head, the TSA receipts, and a chain-integrity check — no login, no API key, no special tooling. The verifier re-hashes every event row and cross-checks the TSA witnesses; both must pass.
| Check | What it proves |
|---|---|
| chain_integrity.ok | Every row's hash matches the re-computed hash. No middle row was edited. |
| tokens[].ok | Each TSA receipt cross-checks against the chain head it claims to anchor. |
| event_count | Compared to the count the operator saw at close — detects truncation. |
| issuing_org_name | Identity of the org that ran the session — for the auditor's case file. |
Why this matters in court
eIDAS Art. 42 establishes legal presumption for qualified electronic timestamps in EU courts — a court must accept the timestamp as genuine unless the opposing party proves otherwise. Pair that with an immutable hash chain over the session events and the burden of proof flips: instead of "we recorded this, take our word for it," you have a cryptographic witness that's independent of us, independent of you, and verifiable years later without trusting either side.
See a chain you can poke at
The demo seeder mints a real session with a real audit chain anchored at real TSAs. Get a public verify URL, change a byte in the event log, watch the proof break.