code wiki / (root) / nx_bit_provenance.nx

nx_bit_provenance.nx source

↩ module page · 182 lines · 6155 B

1// nx_bit_provenance.nx -- bit-provenance ledger (silicon-to-death tracking). 2// 3// Cardinal: feedback-no-skips-bit-provenance-silicon-to-death. 4// 5// Every output bit the substrate produces carries an ID and an upstream 6// chain. Every consumer (the bit's "death") joins its observation to 7// the chain. Auditable end-to-end: query the ledger for orphans 8// (consumed-without-producer) and zombies (produced-without-consumer) 9// to find substrate honesty bugs. 10// 11// API surface (V0): 12// 13// let id: i64 = nx_bprov_alloc() 14// nx_bprov_emit(id, src_a_id, src_b_id, layer_tag, primitive_tag) 15// nx_bprov_emit3(id, src_a_id, src_b_id, src_c_id, layer_tag, primitive_tag) 16// nx_bprov_join(in_bit_id, layer_tag, primitive_tag) 17// nx_bprov_audit_zombies() -> i64 -- 0 = clean 18// nx_bprov_lookup_join(id) -> i64 -- the consumer layer, -1 if unjoined 19// nx_bprov_n_records() -> i64 20// 21// Layer tags (sealed enum matching SMOKE_SCHEMA.md + CAR_DIAGRAM.md): 22 23import "syscalls.nx" 24const NX_MAGIC_12345: i64 = 12345 25const NX_MAGIC_67890: i64 = 67890 26const NX_MAGIC_11111: i64 = 11111 27const NX_MAGIC_22222: i64 = 22222 28const NX_MAGIC_33333: i64 = 33333 29const NX_MAGIC_44444: i64 = 44444 30const NX_MAGIC_99999: i64 = 99999 31 32const NX_BPROV_L_NEG_1: i64 = -1 33const NX_BPROV_L_0: i64 = 0 34const NX_BPROV_L_1: i64 = 1 35const NX_BPROV_L_1S: i64 = 2 36const NX_BPROV_L_2: i64 = 3 37const NX_BPROV_L_3: i64 = 4 38const NX_BPROV_L_35: i64 = 5 39const NX_BPROV_L_36: i64 = 6 40const NX_BPROV_L_37: i64 = 7 41const NX_BPROV_L_4: i64 = 8 42const NX_BPROV_L_5: i64 = 9 43const NX_BPROV_L_6: i64 = 10 44const NX_BPROV_L_7: i64 = 11 45const NX_BPROV_L_IMG: i64 = 12 46const NX_BPROV_L_RC: i64 = 13 47 48const NX_BPROV_REC_SIZE: i64 = 64 // 8 i64 fields 49const NX_BPROV_CHUNK_BYTES: i64 = 262144 // 4096 records 50 51static NX_BPROV_LEDGER_PTR: i64 52static NX_BPROV_NEXT_ID: i64 53static NX_BPROV_N_RECORDS: i64 54static NX_BPROV_CAPACITY: i64 55 56func nx_bprov_init() -> i64 { 57 if NX_BPROV_LEDGER_PTR != 0 { return 0 } 58 let raw: *u8 = sys_mmap(NX_BPROV_CHUNK_BYTES) 59 if (raw as i64) == 0 { return 1 } 60 if (raw as i64) == 0 - 1 { return 2 } 61 NX_BPROV_LEDGER_PTR = raw as i64 62 NX_BPROV_NEXT_ID = 1 63 NX_BPROV_N_RECORDS = 0 64 NX_BPROV_CAPACITY = NX_BPROV_CHUNK_BYTES / NX_BPROV_REC_SIZE 65 return 0 66} 67 68func nx_bprov_alloc() -> i64 { 69 nx_bprov_init() 70 let id: i64 = NX_BPROV_NEXT_ID 71 NX_BPROV_NEXT_ID = id + 1 72 return id 73} 74 75func _nx_bprov_write(id: i64, src_a: i64, src_b: i64, src_c: i64, 76 layer: i64, primitive: i64) -> i64 { 77 nx_bprov_init() 78 if NX_BPROV_N_RECORDS >= NX_BPROV_CAPACITY { return 3 } 79 let base: i64 = NX_BPROV_LEDGER_PTR + (NX_BPROV_N_RECORDS * NX_BPROV_REC_SIZE) 80 let rec: *i64 = base as *i64 81 rec[0] = id 82 rec[1] = src_a 83 rec[2] = src_b 84 rec[3] = src_c 85 rec[4] = layer 86 rec[5] = primitive 87 rec[6] = 0 // join_layer (only valid when rec[7] == 1) 88 rec[7] = 0 // joined_flag: 0 = zombie, 1 = joined 89 NX_BPROV_N_RECORDS = NX_BPROV_N_RECORDS + 1 90 return 0 91} 92 93func nx_bprov_emit(id: i64, src_a: i64, src_b: i64, 94 layer: i64, primitive: i64) -> i64 { 95 return _nx_bprov_write(id, src_a, src_b, 0, layer, primitive) 96} 97 98func nx_bprov_emit3(id: i64, src_a: i64, src_b: i64, src_c: i64, 99 layer: i64, primitive: i64) -> i64 { 100 return _nx_bprov_write(id, src_a, src_b, src_c, layer, primitive) 101} 102 103func nx_bprov_join(in_bit_id: i64, layer: i64, primitive: i64) -> i64 { 104 nx_bprov_init() 105 var i: i64 = 0 106 while i < NX_BPROV_N_RECORDS { 107 let base: i64 = NX_BPROV_LEDGER_PTR + (i * NX_BPROV_REC_SIZE) 108 let rec: *i64 = base as *i64 109 if rec[0] == in_bit_id { 110 rec[6] = layer 111 // primitive tag stored in slot 8 via a separate alloc; 112 // V0: we keep just layer + joined_flag, primitive is 113 // logged in trace. Could extend rec to 9 fields later. 114 rec[7] = 1 // joined 115 return 0 116 } 117 i = i + 1 118 } 119 return 1 120} 121 122func nx_bprov_audit_zombies() -> i64 { 123 nx_bprov_init() 124 var n: i64 = 0 125 var i: i64 = 0 126 while i < NX_BPROV_N_RECORDS { 127 let base: i64 = NX_BPROV_LEDGER_PTR + (i * NX_BPROV_REC_SIZE) 128 let rec: *i64 = base as *i64 129 if rec[7] == 0 { n = n + 1 } // joined_flag=0 -> zombie 130 i = i + 1 131 } 132 return n 133} 134 135func nx_bprov_lookup_join(in_bit_id: i64) -> i64 { 136 nx_bprov_init() 137 var i: i64 = 0 138 while i < NX_BPROV_N_RECORDS { 139 let base: i64 = NX_BPROV_LEDGER_PTR + (i * NX_BPROV_REC_SIZE) 140 let rec: *i64 = base as *i64 141 if rec[0] == in_bit_id { 142 if rec[7] == 0 { return 0 - 2 } // unjoined sentinel 143 return rec[6] // joined layer 144 } 145 i = i + 1 146 } 147 return 0 - 1 // record not found 148} 149 150func nx_bprov_n_records() -> i64 { 151 nx_bprov_init() 152 return NX_BPROV_N_RECORDS 153} 154 155// ---- self-test --------------------------------------------------- 156// expect_exit: 0 157 158func main() -> i64 { 159 if nx_bprov_init() != 0 { return 1 } 160 let id_a: i64 = nx_bprov_alloc() 161 if id_a != 1 { return 2 } 162 let id_b: i64 = nx_bprov_alloc() 163 if id_b != 2 { return 3 } 164 if nx_bprov_emit(id_b, id_a, 0, NX_BPROV_L_3, NX_MAGIC_12345) != 0 { return 4 } 165 if nx_bprov_join(id_b, NX_BPROV_L_7, NX_MAGIC_67890) != 0 { return 5 } 166 if nx_bprov_lookup_join(id_b) != NX_BPROV_L_7 { return 6 } 167 168 let id_c: i64 = nx_bprov_alloc() 169 if nx_bprov_emit(id_c, id_a, id_b, NX_BPROV_L_4, NX_MAGIC_11111) != 0 { return 7 } 170 if nx_bprov_audit_zombies() != 1 { return 8 } 171 if nx_bprov_join(id_c, NX_BPROV_L_IMG, NX_MAGIC_22222) != 0 { return 9 } 172 if nx_bprov_audit_zombies() != 0 { return 10 } 173 174 let id_d: i64 = nx_bprov_alloc() 175 if nx_bprov_emit3(id_d, id_a, id_b, id_c, NX_BPROV_L_35, NX_MAGIC_33333) != 0 { return 11 } 176 if nx_bprov_join(id_d, NX_BPROV_L_4, NX_MAGIC_44444) != 0 { return 12 } 177 178 if nx_bprov_lookup_join(NX_MAGIC_99999) != 0 - 1 { return 13 } 179 if nx_bprov_n_records() != 3 { return 14 } 180 181 return 0 182}