code wiki / _hdl_build / nx_coe_witness.nx
nx_coe_witness.nx source
↩ module page · 221 lines · 7410 B
1// nx_coe_witness.nx -- CHAIN-OF-EVIDENCE TRANSPARENCY-LOG WITNESS (F713, Rekor-class)
2// Builds a SHA-256 Merkle tree over the frame-hash leaves of the signed evidence chain
3// (knowledge/status/coe_signed.log), computes the tree ROOT (a signed-tree-head), emits an
4// INCLUSION PROOF (audit path) for the latest leaf, and VERIFIES it deny-by-default (the audit
5// path must recompute the exact root). Each run appends the root to coe_witness.log = the STH
6// sequence (the substrate for consistency proofs). This is the transparency-log property Sigstore
7// /Rekor provide; sovereign (our own sha256), append-only, never deletes.
8// Composes proven libs only: nx_str/nx_syscalls/nx_sha256. x86-lane. license_tier: ORIGINAL
9import "nx_str.nx"
10import "nx_syscalls.nx"
11import "nx_sha256.nx"
12
13const CW_CAP: i64 = 1048576
14const CW_MAXLEAF: i64 = 4096
15
16func cw_puts(s: *u8) -> i64 { sys_write(1, s, nx_str_len(s)); return 0 }
17
18func cw_pi(v: i64) -> i64 {
19 let t: *u8 = sys_mmap(32)
20 var m: i64 = v
21 var k: i64 = 0
22 if m == 0 { t[0] = 48 as u8; k = 1 }
23 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
24 let o: *u8 = sys_mmap(32)
25 var i: i64 = 0
26 while i < k { o[i] = t[k-1-i]; i = i + 1 }
27 sys_write(1, o, k)
28 return 0
29}
30
31func cw_hexn(d: *u8, n: i64, out: *u8) -> i64 {
32 let hx: *u8 = "0123456789abcdef" as *u8
33 var i: i64 = 0
34 while i < n {
35 let b: i64 = d[i] as i64
36 out[i*2] = hx[(b >> 4) & 15]
37 out[i*2+1] = hx[b & 15]
38 i = i + 1
39 }
40 out[n*2] = 0 as u8
41 return n*2
42}
43
44func cw_nib(c: i64) -> i64 {
45 if c >= 97 { return c - 87 }
46 return c - 48
47}
48
49func cw_cat(dst: *u8, off: i64, s: *u8) -> i64 {
50 var i: i64 = 0
51 while s[i] != (0 as u8) { dst[off+i] = s[i]; i = i + 1 }
52 return off + i
53}
54func cw_catn(dst: *u8, off: i64, v: i64) -> i64 {
55 let t: *u8 = sys_mmap(32)
56 var m: i64 = v
57 var k: i64 = 0
58 if m == 0 { t[0] = 48 as u8; k = 1 }
59 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
60 var i: i64 = 0
61 while i < k { dst[off+i] = t[k-1-i]; i = i + 1 }
62 return off + k
63}
64
65func cw_line_end(b: *u8, i0: i64, n: i64) -> i64 {
66 var e: i64 = i0
67 while e < n { if b[e] == (10 as u8) { return e } e = e + 1 }
68 return n
69}
70func cw_find_tab(b: *u8, i0: i64, e: i64) -> i64 {
71 var j: i64 = i0
72 while j < e { if b[j] == (9 as u8) { return j } j = j + 1 }
73 return e
74}
75
76// copy 32 bytes
77func cw_cp32(dst: *u8, src: *u8) -> i64 { var i: i64 = 0; while i < 32 { dst[i] = src[i]; i = i + 1 } return 0 }
78// 1 if equal 32 bytes else 0
79func cw_eq32(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while i < 32 { if a[i] != b[i] { return 0 } i = i + 1 } return 1 }
80// out = sha256(left32 || right32)
81func cw_pair(l: *u8, r: *u8, out: *u8) -> i64 {
82 let b: *u8 = sys_mmap(64)
83 var i: i64 = 0
84 while i < 32 { b[i] = l[i]; i = i + 1 }
85 i = 0
86 while i < 32 { b[32+i] = r[i]; i = i + 1 }
87 sha256_digest(b, 64, out)
88 return 0
89}
90// decode 64 hex chars at src[off..] into out[0..32)
91func cw_unhex32(src: *u8, off: i64, out: *u8) -> i64 {
92 var i: i64 = 0
93 while i < 32 {
94 let hi: i64 = cw_nib(src[off + i*2] as i64)
95 let lo: i64 = cw_nib(src[off + i*2 + 1] as i64)
96 out[i] = ((hi * 16) + lo) as u8
97 i = i + 1
98 }
99 return 0
100}
101
102func main() -> i64 {
103 cw_puts("=== COE-WITNESS (F713): Merkle transparency-log over the signed chain ===\n" as *u8)
104 let plane: *u8 = "knowledge/status/coe_signed.log" as *u8
105
106 let lenp: *i64 = sys_mmap(16) as *i64
107 lenp[0] = 0
108 let vb: *u8 = sys_read_file(plane, lenp)
109 var vn: i64 = lenp[0]
110 if vn < 0 { vn = 0 }
111 if vn > CW_CAP { vn = CW_CAP }
112
113 // parse leaves = field0 (frame-hash hex, 64 chars) of each row -> 32 raw bytes
114 let leaves: *u8 = sys_mmap(CW_MAXLEAF * 32 + 16)
115 var n: i64 = 0
116 var i: i64 = 0
117 while i < vn {
118 let e: i64 = cw_line_end(vb, i, vn)
119 if e > i {
120 if n < CW_MAXLEAF {
121 let t: i64 = cw_find_tab(vb, i, e)
122 if (t - i) >= 64 {
123 cw_unhex32(vb, i, ((leaves as i64) + n*32) as *u8)
124 n = n + 1
125 }
126 }
127 }
128 i = e + 1
129 }
130
131 if n == 0 { cw_puts("COE-WITNESS RED reason=no-leaves\n" as *u8); sys_exit(1); return 1 }
132
133 // build the tree bottom-up; record the audit path for the LAST leaf (tk = n-1)
134 let lvl: *u8 = sys_mmap(CW_MAXLEAF * 32 + 16)
135 let nxt: *u8 = sys_mmap(CW_MAXLEAF * 32 + 16)
136 var c: i64 = 0
137 while c < n*32 { lvl[c] = leaves[c]; c = c + 1 }
138
139 let pathh: *u8 = sys_mmap(64 * 32 + 16)
140 let paths: *u8 = sys_mmap(80)
141 var pl: i64 = 0
142 var curn: i64 = n
143 var tk: i64 = n - 1
144
145 while curn > 1 {
146 // sibling of tk at this level
147 var si: i64 = tk + 1
148 if (tk & 1) == 1 { si = tk - 1 }
149 if si >= curn {
150 cw_cp32(((pathh as i64) + pl*32) as *u8, ((lvl as i64) + tk*32) as *u8)
151 paths[pl] = 1 as u8
152 } else {
153 cw_cp32(((pathh as i64) + pl*32) as *u8, ((lvl as i64) + si*32) as *u8)
154 if (tk & 1) == 0 { paths[pl] = 1 as u8 } else { paths[pl] = 0 as u8 }
155 }
156 pl = pl + 1
157
158 // build next level
159 var nn: i64 = 0
160 var j: i64 = 0
161 while j < curn {
162 let leftp: *u8 = ((lvl as i64) + j*32) as *u8
163 var rightp: *u8 = ((lvl as i64) + j*32) as *u8
164 if (j + 1) < curn { rightp = ((lvl as i64) + (j+1)*32) as *u8 }
165 cw_pair(leftp, rightp, ((nxt as i64) + nn*32) as *u8)
166 nn = nn + 1
167 j = j + 2
168 }
169 c = 0
170 while c < nn*32 { lvl[c] = nxt[c]; c = c + 1 }
171 curn = nn
172 tk = tk / 2
173 }
174
175 // root = lvl[0..32)
176 let roothex: *u8 = sys_mmap(80)
177 cw_hexn(lvl, 32, roothex)
178
179 // verify the inclusion proof: recompute root from leaf[n-1] + audit path
180 let h: *u8 = sys_mmap(32)
181 cw_cp32(h, ((leaves as i64) + (n-1)*32) as *u8)
182 let tmp: *u8 = sys_mmap(32)
183 var p: i64 = 0
184 while p < pl {
185 if (paths[p] as i64) == 1 {
186 cw_pair(h, ((pathh as i64) + p*32) as *u8, tmp)
187 } else {
188 cw_pair(((pathh as i64) + p*32) as *u8, h, tmp)
189 }
190 cw_cp32(h, tmp)
191 p = p + 1
192 }
193 var ok: i64 = cw_eq32(h, lvl)
194
195 // append the root to the STH witness log (transparency-log head sequence)
196 let now: i64 = sys_now_realtime_sec()
197 let wl: *u8 = sys_mmap(256)
198 var wo: i64 = 0
199 wo = cw_cat(wl, wo, roothex)
200 wl[wo] = 9 as u8; wo = wo + 1
201 wo = cw_cat(wl, wo, "leaves=" as *u8)
202 wo = cw_catn(wl, wo, n)
203 wl[wo] = 9 as u8; wo = wo + 1
204 wo = cw_catn(wl, wo, now)
205 wl[wo] = 10 as u8; wo = wo + 1
206 let fd: i64 = sys_openat_append("knowledge/status/coe_witness.log" as *u8, 0x1a4)
207 if fd >= 0 { sys_write(fd, wl, wo); sys_close(fd) }
208
209 cw_puts(" root=" as *u8); cw_puts(roothex)
210 cw_puts(" leaves=" as *u8); cw_pi(n)
211 cw_puts(" proof-depth=" as *u8); cw_pi(pl); cw_puts("\n" as *u8)
212 if ok == 1 {
213 cw_puts("COE-WITNESS GREEN merkle-root=OK inclusion-proof=OK leaves=" as *u8); cw_pi(n)
214 cw_puts(" envelope=cap:" as *u8); cw_pi(CW_CAP)
215 cw_puts("/maxleaf:" as *u8); cw_pi(CW_MAXLEAF); cw_puts("\n" as *u8)
216 return 0
217 }
218 cw_puts("COE-WITNESS RED reason=inclusion-proof-mismatch\n" as *u8)
219 sys_exit(1)
220 return 1
221}