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}