Commit 7a4ccfd
prov: tamper-evident hash chain — V-L1-B1 + V-L2-N1 + V-L2-C1..C4 + V-L2-L1..L2 (#33)
Step 2 of the bottom-up plan. Brings the Provenance octad concern up to
the claim made in the README: tampering with any audit-relevant field
in a logged entry breaks `verify()`.
V-L1-B1 — docs/theory/provenance-threat-model.adoc:
Four-adversary model (R / SW / SR / SR+CK), per-adversary protection
matrix, the field-coverage and canonical-encoding requirements that
bind V-L2-C1 + V-L2-C2, the append-serialisation requirement that
binds V-L2-L1 + V-L2-L2, anchor/notary future work, open questions
(None vs Some(""), chain_id). Each Step 2 issue cites a section.
V-L2-N1 — deduplicate ProvenanceRecord vs ProvenanceEntry:
Delete src/tier1/provenance.rs::ProvenanceRecord (orphan duplicate
of abi::ProvenanceEntry with its own compute_hash that risked
drifting). tier1/provenance.rs now re-exports the canonical type;
the file is the future home of V-L1-C1's write-path helpers
(sqlite3_update_hook → append_provenance). TOPOLOGY.md updated.
V-L2-C1 — full-field, domain-separated hash:
compute_hash signature changes from (4 strs) to (5 strs + DateTime +
2 Options). New preimage = domain tag b"verisim-prov-v1\0" ||
length-prefixed (previous_hash, entity_id, operation, actor) ||
canonical timestamp (V-L2-C2) || length-prefixed (before_snapshot,
transformation). All seven fields participate. PROV_DOMAIN_TAG
versioning is reserved for a future SHA-256→? migration.
verify(), genesis(), chain() all pass the full field set.
V-L2-C2 — canonical timestamp:
Replace timestamp.to_rfc3339() (multiple valid forms per instant)
with i64_le(timestamp()) || u32_le(timestamp_subsec_nanos()), 12
bytes total. Round-trip unit test asserts two construction paths
that yield the same instant produce the same hash.
V-L2-C3 — positive tamper-detection tests:
Eight new unit tests in abi::tests covering each hash-covered
field (entity_id, actor, before_snapshot, transformation,
operation, previous_hash, timestamp) plus the canonical-encoding
property test plus a 4-entry chain mutation-matrix that asserts
every field mutation on every entry breaks verify(). 9 new test
cases (26 → 35 lib tests).
V-L2-C4 — flip the wontfix test:
tests/integration_test.rs::test_provenance_chain_integrity_multi_step
previously codified the bug ("Actor is not part of hash — tamper to
actor alone is invisible"). Replaced with assertions that
tampering with actor and with before_snapshot both break verify().
V-L2-L1 — chain_head table + write-path serialisation spec:
codegen/overlay.rs emits a new verisimdb_provenance_chain_head
(entity_id PK, head_hash, updated_at) alongside the provenance log.
The write-path lock (SELECT … FOR UPDATE / BEGIN IMMEDIATE on the
head row, INSERT into log, UPDATE head, COMMIT) is specified in
the threat-model doc and the table-generator docstring. The
library function that performs the transaction is V-L1-C1's job;
V-L2-L1 only lands the schema.
V-L2-L2 — UNIQUE INDEX makes forks unrepresentable:
CREATE UNIQUE INDEX IF NOT EXISTS ux_provenance_chain ON
verisimdb_provenance_log(entity_id, previous_hash). Genesis rows
all carry previous_hash='' so the same constraint enforces exactly
one genesis per entity. Two new DDL tests assert presence of both
the UNIQUE INDEX and the chain_head table.
Verified locally:
- cargo fmt --all -- --check clean
- cargo clippy --all-targets -- -D warnings clean
- cargo test reports 35 + 9 = 44 tests, 0 failed
Closes #25, #26, #27, #28, #29, #30, #31, #32
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>1 parent db7b7e9 commit 7a4ccfd
6 files changed
Lines changed: 450 additions & 76 deletions
File tree
- docs
- architecture
- theory
- src
- abi
- codegen
- tier1
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
| 15 | + | |
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
0 commit comments