Proof format
hash_v1: the audit-trail hash format
Every event in a Fohrkast audit trail carries two SHA-256 hashes in this format. The format is frozen: rows already hashed never change format, and any successor would be named hash_v2 and apply to new rows only. The checker shipped in every evidence pack, verify.mjs, recomputes both hashes offline.
Byte layout
Each input is a UTF-8 string of the fields below joined with a single | (0x7C). An empty value contributes zero bytes. Output is lowercase hexadecimal.
payload_sha256 = SHA-256( actor | subject_id | thread | body_text | sealed_hex | retention_class ) hash = SHA-256( prev_hash | tenant_id | seq | type | at | recorded_at | payload_sha256 )
A chain is intact when, for each event in sequence order, seq is the previous seq plus 1, prev_hash equals the previous event's hash, and both hashes recompute; the stored chain head equals the last hash. An event emptied at the end of its retention period keeps seq, prev_hash and hash only, and is checked as a link.
Fields
- prev_hash
- The previous event's hash; for the first event, 64 characters 0.
- tenant_id
- The organisation's UUID, lowercase, with hyphens.
- seq
- The event's sequence number in decimal, from 1, without gaps.
- type
- The event type, for example case.opened.
- at, recorded_at
- UTC, YYYY-MM-DDTHH:MM:SS.ffffffZ, always six fractional digits.
- actor
- The actor identifier, or empty.
- subject_id, thread
- UUID, lowercase, with hyphens, or empty.
- body_text
- The event body as PostgreSQL prints jsonb: keys ordered by byte length, then bytewise; ": " after each key; ", " between members. Exported verbatim in every evidence pack.
- sealed_hex
- The sealed note's ciphertext bytes in lowercase hex, or empty.
- retention_class
- consent_proof, case_record, processing_log or tenant_life.
Example
Payload input bytes:
u-example||7c9e6679-7425-40de-944b-e07fc1f90ae7|{"channel": "web", "case_type": "incident"}||case_recordpayload_sha256 = cdd03a9454f5617e3d59cbae6caccf48a44e5a86881313423253788bb438fae8
Hash input bytes:
0000000000000000000000000000000000000000000000000000000000000000|3f1c2a9e-5b7d-4e2a-9c1b-0d8e7f6a5b4c|1|case.opened|2026-10-19T08:30:00.000000Z|2026-10-19T08:30:00.123456Z|cdd03a9454f5617e3d59cbae6caccf48a44e5a86881313423253788bb438fae8
hash = 5a494e6d3975ad8227ccc0c921ab7c32f85a8b48e00e85ca3fe403c1d95cc04d