Commitment payload formats — decision & shelved designs
Status: one format shipped (payload/commitment.py). This records why, and preserves the
short-codeword alternatives for a future revisit.
Shipped: bound-ordinal commitment @ 64-bit
tag = HMAC(k_epoch, ctx || email || 0x00 || day_be32 || n_be32 [|| 0x00 doc_id])[:5] # 40-bit tag
codeword = RS(8,5)(tag) # 64-bit
- Traceability, DB-free. Attribution needs only the epoch key + the recipient roster. It survives
a full database nuke, deleted issuance rows, or a deleted document row. Key and roster live outside
the app DB by construction (vault/HSM; HR/IdP). n= per-(email, day) issuance ordinal, bound into the tag, not carried. This gives
per-issuance resolution (which of several copies to the same person that day) for free: with a live
ledger you recompute over its rows and match instantly; with the DB gone you enumerate
email × day × n(n is 0..255) and the 40-bit tag still pins the exact issuance. "Bind, don't
embed," one level deeper than the identity.- Floor: decodes a ~one-paragraph excerpt (~9–11 lines / ~64–73 gaps). Below that a paragraph has
fewer inter-word gaps than the 64-bit codeword needs — an information wall, not a decoder weakness. - False-match (DB-gone worst case):
roster × days × n / 2^40. For 100 × 1000 × 256 ≈ 2.6e7,
that is ~2e-5. The forensic search is a rare offline operation; the 256× from enumeratingnis
irrelevant to that.
Shelved: short codewords (Hybrid @48 / @32)
To attribute a sub-one-paragraph excerpt you must shrink the codeword, which shrinks the tag:
| format | codeword | min lines (real doc) | payload split | DB-free fallback |
|---|---|---|---|---|
| commitment @64 (shipped) | 64-bit | ~9 | 40-bit tag | yes (~2e-5 false) |
| Hybrid @48 | 48-bit | ~6 | ~12b seq + ~12b tag | no — 12-bit tag → ~24 false matches over 1e5 candidates |
| Hybrid @32 | 32-bit | ~4 | ~16b seq+tag | no |
The short formats reach smaller excerpts (measured 9 → 6 → 4 lines) but only because a ledger
resolves the identity and the tiny tag merely confirms the one name it supplies (a 12-bit tag
confirming a single candidate is wrong 1-in-4096 — fine). With the DB gone there is no name to
confirm, and the tag is far too short to identify anyone against a roster. The short mark dies with
the DB — inverting the survivability premise this whole design exists for.
Why not ship them alongside as an option
- A format is a permanent decode obligation. Marks sit in leaked documents for years; every
format ever shipped must be decoded forever. - A weak format weakens the whole decoder. A leaked excerpt does not announce its format, so
the decoder must try them all. Adding a 16-bit-tag format means every decode of every artifact
also runs a weak-tag search — importing that false-match risk system-wide, onto documents that were
marked with the strong format.
That cost is real and permanent; the gain is ~3 lines. Not worth it by default.
When to revisit / better alternative
If genuine sub-9-line attribution is ever needed, prefer a second carrier axis (more bits per
line without shrinking the tag) — e.g. combine the word-gap carrier with a sub-line baseline channel —
over a short codeword. If a short format is truly required, scope it as an explicit
per-classification setting clearly labelled as trading away DB-free recovery, composable with any
mode — never as the default and never as a fourth mode.