1The problem
A consent record that cannot be independently verified is a liability, not an asset. Most systems store audit trails in the same mutable database as everything else, and ask auditors to trust that nothing was changed. TrustNet's audit log is built so that trust is not required.
1.1 A log you have to take on trust
A conventional audit table can be edited or deleted by anyone with database access — accidentally, or on purpose. Nothing in the record itself reveals that it changed, so proving its integrity means proving a negative.
1.2 Consent that cannot be evidenced
Under GDPR Art. 7(1), you must be able to demonstrate that a data subject consented, and to what. If the trail is incomplete, or the consent wording and purpose it references are not versioned, "the user agreed" is an assertion, not evidence.
1.3 The audit trail as a second copy of PII
A log that records raw claim values turns the audit system into a second, unmanaged copy of personal data — a honeypot, and another breach surface. The trail should prove what was disclosed without becoming the disclosure.
1.4 Erasure versus accountability
GDPR Art. 17 (erasure) pulls against Art. 5(2), 7 and 30 (accountability). If the identifying data and the proof are the same bytes, honouring a deletion request destroys the evidence. TrustNet separates the two so erasure never edits a proof.
1.5 Tampering that is only noticed too late
Even a hash-chained log leaves one gap: the operator that holds the log can rewrite the chain and recompute the hashes. Without an external witness, a determined insider can rewrite history and make it self-consistent. This is threat T4 in TrustNet's threat model, and the reason for the daily external timestamp.
2What "tamper-proof" means
Tamper-proof here is a precise, testable property — not a claim of physical impossibility. Any retroactive insertion, deletion, reordering, or modification of the trail is detectable, by an outsider from the tree alone, and by TrustNet's own operator from an externally timestamped anchor.
2.1 Append-only, enforced
Audit and consent rows admit no UPDATE or
DELETE outside an audited erasure workflow. This is
enforced by a database trigger and by an
INSERT-only writer role — two independent layers, not a
convention.
2.2 A hash chain, not a promise
Every event is canonicalized and hashed into a Merkle log. Changing any leaf changes its hash, which changes every hash up to the root, which breaks the proofs that a verifier holds. A signed, externally timestamped tree head pins the whole tree to a point in time.
2.3 Two threats, two defences
- Tampering by an outsider — prevented from going unnoticed by Merkle inclusion and consistency proofs plus the signed tree head.
- Tampering by TrustNet itself — caught by the external RFC 3161 timestamp over the daily meta-root; rewriting the log cannot forge an external authority's timestamp, and past anchors are immutable history.
3How it works
3.1 From event to anchored leaf
There is one write primitive. Each event is canonicalized with JCS (RFC 8785) and hashed into a leaf; leaves are combined into a Merkle tree; the tree head is signed; and every tree head is rolled into a daily meta-root that is timestamped by an external authority.
flowchart LR
E["Event: consent, access, revocation"] --> C["Canonical JSON (JCS, RFC 8785)"]
C --> H["Leaf hash (SHA-256, RFC 6962)"]
H --> T["Per-RP Merkle tree"]
T --> S["Signed tree head (Ed25519, key in Vault)"]
S --> M["Daily meta-root over every tree"]
M --> A["External RFC 3161 timestamp"]
3.2 The Merkle tree and inclusion proofs
Each relying party (RP) gets its own tree, so an auditor's bundle is self-contained for that RP. An inclusion proof lets a verifier recompute the root from a single leaf and a handful of sibling hashes — without seeing the rest of the tree, and without the values behind any other leaf.
flowchart BT
L0["leaf 0: rp.registered"] --> P0["interior hash"]
L1["leaf 1: consent.granted"] --> P0
L2["leaf 2: disclosure.read_batch"] --> P1["interior hash"]
L3["leaf 3: consent.revoked"] --> P1
P0 --> Root["Root hash"]
P1 --> Root
Root --> STH["Signed tree head"]
3.3 Signed tree heads and external anchoring
A tree head is emitted on every change and at least daily, signed with a dedicated Ed25519 key held in a vault — separate from the OIDC and webhook keys, so its blast radius is independent. The anchor job builds one meta-tree over every tree's current head, timestamps the meta-root, and stores the per-tree inclusion proofs. The signature proves who; the external timestamp proves when.
3.4 What tampering breaks
There is no way to alter a recorded event and keep every proof consistent. The breakage is what a verifier checks: a proof that no longer verifies against a previously seen head is a finding, not a silent pass.
flowchart TB
X["A leaf is edited, removed, or reordered"] --> Y["Its hash changes"]
Y --> Z["Hashes up to the root change"]
Z --> C1["The inclusion proof for that leaf fails"]
Z --> C2["The consistency proof against the previous tree head fails"]
C2 --> C3["The root no longer matches the timestamped anchor"]
3.5 Verifying a bundle offline
An RP can export its own trail as a self-contained bundle — a signed manifest, the events, the proofs, the anchors and the public keys — and verify it with an offline CLI. No network call, no trust in a live TrustNet service.
sequenceDiagram
autonumber
participant RP as RP owner or auditor
participant V as trustnet-verify (offline)
participant B as Export bundle
RP->>V: trustnet-verify bundle.tar.gz
V->>B: read manifest JWS, events, proofs, anchors, keys
V->>V: recompute every leaf hash
V->>V: check inclusion and consistency proofs
V->>V: verify the Ed25519 tree-head signature
V->>V: check meta-tree inclusion and the RFC 3161 token
V-->>RP: VALID, or the exact findings
3.6 Privacy by construction
- Claim names, never values. The log records
which claims were approved or revoked —
email,country— never the values behind them. - Pseudonymous. Events carry pairwise subject and actor identifiers, unlinkable across trees; raw identifiers never enter the hashed record.
- Erasure-compatible. Correlation metadata lives in a separate, erasable sibling row. A GDPR Art. 17 erasure deletes that metadata; the PII-free hashed leaf — the proof — is never touched.
4Proving compliance
The trail is not an internal logging convenience; it is the evidence layer for accountability. Each governing requirement maps to a concrete mechanism.
4.1 Regulation mapping
| Requirement | What it demands | Mechanism |
|---|---|---|
| GDPR Art. 5(2) | Demonstrate compliance; records must be reliable | Append-only Merkle log + signed tree heads + external anchoring |
| GDPR Art. 7(1) | Prove consent was given, with the information shown | Versioned consent wording and purpose; consent.granted leaf |
| GDPR Art. 15 / 20 | Produce the subject's record on request | Per-user export (Art. 15/20 artifact) |
| GDPR Art. 17 | Erase identifying data without destroying the record | PII-free hashed leaf + erasable correlation sibling |
| GDPR Art. 30 | Maintain records of processing | Consent history + per-RP compliance export |
| eIDAS Art. 41 | Presumption of time accuracy | Daily RFC 3161 timestamp (qualified-TSA path) |
| RFC 9162 / 6962 | Verifiable log construction | Merkle tree, inclusion and consistency proofs |
| RFC 8785 | Canonical serialization before hashing | JCS leaf hashing |
4.2 A worked audit
- An RP (or its auditor) requests its trail export. The request itself is written back into the same tree, so an export is never invisible.
- The export returns a self-contained bundle: the events, the Merkle proofs, the signed tree heads, the daily anchors, and the public keys.
- The auditor runs the offline verifier. It recomputes leaf hashes, checks each inclusion and consistency proof, verifies the Ed25519 tree-head signature, and checks the meta-tree inclusion against the external timestamp.
- A missing consent, an edited record, or a reordered event does not merely fail a test — it cannot be made to reproduce the signed, externally timestamped root. The verifier reports the exact finding.
4.3 What each audience receives
| Audience | What they get |
|---|---|
| End user | Who has their data, what they shared, when, and how to revoke it |
| RP / its auditor | A self-contained, offline-verifiable bundle of every event in their tree |
| Regulator | A tamper-evident, externally timestamped trail that survives the RP's deletion and proves its own integrity |
5Honest limits
We state the boundaries as plainly as the guarantees, because a compliance claim is only as strong as its caveats.
- Completeness is scoped. Per-tree completeness is provable; completeness across trees is not claimed, and the verifier says so.
- The external timestamp is a trust you still make — but a narrow, independent one. Tamper-evidence by TrustNet's own operator rests on the timestamp authority, not on TrustNet. Production migrates from a public TSA to a qualified EU timestamp provider.
- Reads are corroborating. Post-consent access reads are batched and hash-committed; the disclosure of record is the consent decision itself.
- Erasure reduces detail, never the fact. An Art. 17 erasure removes the correlation metadata and leaves the PII-free leaf — the proof that a consent once existed — intact.
6Glossary
| Leaf | A single canonicalized, hashed audit event. |
| Tree head | The root hash of a tree at a point in time, signed with the audit key. |
| Inclusion proof | The sibling hashes needed to recompute the root from one leaf. |
| Consistency proof | Evidence that a newer tree head extends an older one — no history rewritten. |
| Anchor | A signed tree head timestamped by an external authority (RFC 3161). |
| JCS | JSON Canonicalization Scheme (RFC 8785), applied before hashing. |
7References
- RFC 9162 — Certificate Transparency v2.0
- RFC 6962 — Certificate Transparency (Merkle tree hashing)
- RFC 3161 — Time-Stamp Protocol
- RFC 8785 — JSON Canonicalization Scheme
- GDPR Articles 5(2), 7(1), 15, 17, 20, 30; eIDAS Art. 41
- TrustNet ADR-0012 (audit transparency-log backend), ADR-0013 (immutable leaf / erasable metadata)
This document is an indicative product description, not legal advice, and not final copy.