Skip to main content

Verification

Trailproof’s verify() method walks the entire hash chain, recomputing every hash and comparing it to the stored value. Any mismatch indicates tampering.

How Verification Works

The verifier starts at the genesis hash and walks forward through every event:
  1. Set expected_prev = "0" × 64 (genesis hash)
  2. For each event at index i:
    • Recompute expected_hash = SHA-256(expected_prev + canonical_json(event))
    • If event.hash != expected_hash, add i to broken
    • Set expected_prev = event.hash (always advance — detect cascading breaks)
  3. Return VerifyResult { intact, total, broken }

Basic Usage

from trailproof import Trailproof

tp = Trailproof()

# Emit some events
tp.emit(event_type="app.action", actor_id="user-42", tenant_id="acme", payload={"step": 1})
tp.emit(event_type="app.action", actor_id="user-42", tenant_id="acme", payload={"step": 2})
tp.emit(event_type="app.action", actor_id="user-42", tenant_id="acme", payload={"step": 3})

# Verify
result = tp.verify()
print(result.intact)   # True
print(result.total)    # 3
print(result.broken)   # []

Cascading Breaks

When one event is tampered, every subsequent event also appears broken. This is by design — each event’s hash depends on the previous event’s hash. If someone modifies event 2 in a chain of 5:
  • Event 2: hash mismatch (the tampered event)
  • Event 3: prev_hash no longer matches event 2’s new hash
  • Events 3–5: all broken due to cascading failure
The broken array may contain many indices even if only one event was actually modified. The first index in the array is typically the actual tampered event.

Empty Chain

Verifying an empty chain returns a clean result:
Python
tp = Trailproof()
result = tp.verify()
print(result.intact)  # True
print(result.total)   # 0
print(result.broken)  # []
Verification does not throw exceptions on broken chains — it returns the result. Always check result.intact to determine chain validity.

JSONL Store Verification

Verification works the same regardless of store type. The JSONL store reads all events from disk and verifies the chain:
Python
tp = Trailproof(store="jsonl", path="events.jsonl")

# Verify events loaded from disk
result = tp.verify()
if not result.intact:
    print(f"Chain broken at indices: {result.broken}")
If the JSONL file contains corrupt lines (invalid JSON), those lines are skipped during read and their indices appear in broken.
Run tp.verify() on application startup to confirm your event file hasn’t been tampered with while the process was down.

Next Steps

Hash Chain

Understand the cryptographic linking mechanism.

HMAC Signing

Add provenance on top of chain integrity.