code wiki / (root) / nx_provenance_chain.nx

nx_provenance_chain.nx source

↩ module page · 251 lines · 9537 B

1// nx_provenance_chain.nx -- typed transform chain (bit-traceability). 2// 3// Per [[feedback-end-to-end-bit-traceability-architecture]]: 4// "Every transformation of any signal emits a (prev_hash, transform_id, 5// params, output_hash, timestamp) ProvenanceLink to a local trace log 6// so any bit's journey reconstructable end-to-end." 7// 8// THIS IS THE BIT-TRACE FOUNDATION. Every transform in the substrate 9// (capture, preprocess, encode, packetize, encrypt, NIC send, NIC 10// recv, decrypt, decode, render) creates a ProvenanceLink that chains 11// to the prior link by prev_hash. The full chain is a Merkle DAG of 12// what happened to a bit from generation to endpoint. 13// 14// Per user 2026-05-17: "id love for our system to be so sss class 15// world class whatever that the bit is followed from generated signal 16// to endpoint so we can see degradation both on silicon across the 17// world so that its the circuitboard is the whole system itself." 18// 19// Composes: 20// nx_methyl -- each link methyl-marked so chain authenticity 21// survives even when some links are sent across 22// cells / hosts / wire 23// nx_xenocell -- signed observations are provenance links too 24// nx_evict_journal -- significant events surface as journal entries 25// while detail lives in the trace chain 26// nx_pollinate -- federated trace fragments (peer-mesh of chains) 27// 28// V1 ships: 29// - struct NxProvenanceLink with prev_hash, transform_id, params_hash, 30// output_hash, timestamp, originator_id 31// - struct NxProvenanceChain as ordered ring of links 32// - append(): new link references the previous chain head 33// - verify_continuity(): walk chain and check each prev_hash 34// matches the prior link's output_hash 35// - find_by_output_hash(): locate any link by its output hash 36// (forensic query: "what produced this byte?") 37// 38// Gap list (V1 honest perf verdict): 39// - links are in-memory ring; on-disk JSONL persistence is queued 40// - merkle-tree summary of chain not built (V2: nx_trace_merkle) 41// - per-call consent for cross-device federation not built 42// (V2: nx_trace_consent) 43// - no rebuild from-disk after process restart 44// - signatures externally supplied via nx_methyl (V2 inline crypto) 45// 46// genealogy_id: cardinal_2026-05-17_end_to_end_bit_traceability + 47// content_addressed_provenance + merkle_chain 48// lineage_id: substrate_provenance_chain_v1 49// 50// nx_safety_envelope: 51// intended_use: "Append-only typed transform chain for end- 52// to-end bit traceability; every substrate 53// transform emits a link" 54// sil_target: SIL3 55// evidence: [append_only_invariant, 56// content_addressed_links, 57// continuity_verifiable] 58// verdict: NOT_YET_EVALUATED 59 60import "nx_syscalls.nx" 61import "nx_tier.nx" 62import "nx_methyl.nx" 63 64// ===== Sealed enum: NxTransformKind =============================== 65// 66// V1 ships the canonical chain points from the cardinal. Caller can 67// extend via opaque integer kinds (any value above NX_TX_N_KINDS is 68// caller-defined and won't be validated by us). 69 70const NX_TX_NONE: nx_int = 0 71const NX_TX_CAPTURE: nx_int = 1 72const NX_TX_PREPROCESS: nx_int = 2 73const NX_TX_ENCODE: nx_int = 3 74const NX_TX_PACKETIZE: nx_int = 4 75const NX_TX_ENCRYPT: nx_int = 5 76const NX_TX_NIC_SEND: nx_int = 6 77const NX_TX_NIC_RECV: nx_int = 7 78const NX_TX_DECRYPT: nx_int = 8 79const NX_TX_JITTER: nx_int = 9 80const NX_TX_DECODE: nx_int = 10 81const NX_TX_RENDER: nx_int = 11 82const NX_TX_DAC: nx_int = 12 // future-silicon DAC 83const NX_TX_N_KINDS: nx_int = 13 84 85// ===== Sealed enum: NxProvenanceVerdict =========================== 86 87const NX_PV_OK: nx_int = 0 88const NX_PV_ERR_CHAIN_FULL: nx_int = 1 89const NX_PV_ERR_BROKEN: nx_int = 2 // continuity check failed 90const NX_PV_ERR_BAD_LINK: nx_int = 3 91const NX_PV_ERR_NOT_FOUND: nx_int = 4 92 93// ===== Struct: NxProvenanceLink =================================== 94// 95// One transform step. prev_hash references the chain's prior link's 96// output_hash. params_hash hashes the transform parameters (so the 97// same input + same params reproduce the same output by content 98// addressing). output_hash is BLAKE3 of the produced output bytes. 99 100struct NxProvenanceLink { 101 prev_hash: nx_size, 102 transform_id: nx_int, 103 params_hash: nx_size, 104 output_hash: nx_size, 105 ts_us: nx_size, 106 originator_id: nx_int, 107 mark: *NxMethylMark, 108} 109 110// ===== Struct: NxProvenanceChain ================================== 111 112struct NxProvenanceChain { 113 links: *NxProvenanceLink, 114 capacity: nx_size, 115 head: nx_size, 116 count: nx_size, 117 last_hash: nx_size, // cached output_hash of the most recent link 118} 119 120const NX_PV_LINK_BYTES: nx_size = 56 121 122// ===== nx_tx_is_canonical ========================================= 123// 124// Predicate: is this transform_id one of the canonical V1 kinds? 125// Caller-defined kinds (>= NX_TX_N_KINDS) are allowed but not 126// canonical (won't appear in canonical-chain reports). 127 128func nx_tx_is_canonical(t: nx_int) -> nx_int { 129 if t <= 0 { return 0 } 130 if t >= NX_TX_N_KINDS { return 0 } 131 return 1 132} 133 134// ===== nx_provenance_chain_new ==================================== 135 136func nx_provenance_chain_new(capacity: nx_size) -> *NxProvenanceChain { 137 let c: *NxProvenanceChain = (sys_mmap(40)) as *NxProvenanceChain 138 let bytes: nx_size = capacity * NX_PV_LINK_BYTES 139 c.links = (sys_mmap(bytes)) as *NxProvenanceLink 140 c.capacity = capacity 141 c.head = 0 142 c.count = 0 143 c.last_hash = 0 144 return c 145} 146 147// ===== _pv_at ===================================================== 148 149func _pv_at(c: *NxProvenanceChain, idx: nx_size) -> *NxProvenanceLink { 150 return (c.links as i64 + (idx as i64) * NX_PV_LINK_BYTES) as *NxProvenanceLink 151} 152 153// ===== nx_provenance_append ======================================= 154// 155// Append a new link. prev_hash is automatically set to the chain's 156// current last_hash (the prior link's output_hash). Returns OK on 157// success, BAD_LINK if mark is missing. 158 159func nx_provenance_append(c: *NxProvenanceChain, 160 transform_id: nx_int, 161 params_hash: nx_size, 162 output_hash: nx_size, 163 ts_us: nx_size, 164 originator_id: nx_int, 165 mark: *NxMethylMark) -> nx_int { 166 if (mark as i64) == 0 { return NX_PV_ERR_BAD_LINK } 167 let slot: *NxProvenanceLink = _pv_at(c, c.head) 168 slot.prev_hash = c.last_hash 169 slot.transform_id = transform_id 170 slot.params_hash = params_hash 171 slot.output_hash = output_hash 172 slot.ts_us = ts_us 173 slot.originator_id = originator_id 174 slot.mark = mark 175 c.head = c.head + 1 176 if c.head >= c.capacity { c.head = 0 } 177 c.count = c.count + 1 178 c.last_hash = output_hash 179 return NX_PV_OK 180} 181 182// ===== nx_provenance_link_at ====================================== 183// 184// Read the link at index. Returns NULL if index is out of range. 185 186func nx_provenance_link_at(c: *NxProvenanceChain, idx: nx_size) -> *NxProvenanceLink { 187 if idx >= c.capacity { return (0 as i64) as *NxProvenanceLink } 188 return _pv_at(c, idx) 189} 190 191// ===== nx_provenance_verify_continuity ============================ 192// 193// Walk the live links in order and check each prev_hash equals the 194// prior link's output_hash. Returns OK if continuous, BROKEN at the 195// index where continuity broke. First link has prev_hash 0 by 196// convention. 197 198func nx_provenance_verify_continuity(c: *NxProvenanceChain) -> nx_int { 199 var live: nx_size = c.count 200 if live > c.capacity { live = c.capacity } 201 if live == 0 { return NX_PV_OK } 202 var expected_prev: nx_size = 0 203 var i: nx_size = 0 204 while i < live { 205 let lnk: *NxProvenanceLink = _pv_at(c, i) 206 if lnk.prev_hash != expected_prev { return NX_PV_ERR_BROKEN } 207 expected_prev = lnk.output_hash 208 i = i + 1 209 } 210 return NX_PV_OK 211} 212 213// ===== nx_provenance_find_by_output_hash ========================= 214// 215// Forensic query: "which transform produced output_hash X?" Returns 216// the link index or -1 if not found. Used by audit / forensic UI. 217 218func nx_provenance_find_by_output_hash(c: *NxProvenanceChain, 219 output_hash: nx_size) -> nx_int { 220 var live: nx_size = c.count 221 if live > c.capacity { live = c.capacity } 222 var i: nx_size = 0 223 while i < live { 224 let lnk: *NxProvenanceLink = _pv_at(c, i) 225 if lnk.output_hash == output_hash { return i as i64 } 226 i = i + 1 227 } 228 return -1 229} 230 231// ===== nx_provenance_count_by_transform ========================== 232 233func nx_provenance_count_by_transform(c: *NxProvenanceChain, 234 transform_id: nx_int) -> nx_int { 235 var hits: nx_int = 0 236 var live: nx_size = c.count 237 if live > c.capacity { live = c.capacity } 238 var i: nx_size = 0 239 while i < live { 240 let lnk: *NxProvenanceLink = _pv_at(c, i) 241 if lnk.transform_id == transform_id { hits = hits + 1 } 242 i = i + 1 243 } 244 return hits 245} 246 247// ===== nx_provenance_last_hash ==================================== 248 249func nx_provenance_last_hash(c: *NxProvenanceChain) -> nx_size { 250 return c.last_hash 251}