code wiki / _hdl_build / nx_base32hex_extvec_gate.nx
nx_base32hex_extvec_gate.nx source
↩ module page · 186 lines · 8228 B
1// nx_base32hex_extvec_gate.nx -- validates the NEW base32hex_encode against RFC 4648 section 10 (7 vectors).
2// The capability did not exist in this tree until 2026-08-01; the authority's vectors did. Implemented
3// by alphabet translation over the already-GREEN base32_encode, so this gate also re-proves that the
4// translation preserved the bit-packing. * A NEW CAPABILITY SHOULD ARRIVE WITH ITS AUTHORITY ALREADY
5// ATTACHED -- writing the encoder and its published-vector gate in one step leaves no window in which
6// an unvalidated encoder is available to callers.
7//
8// nx_base32hex_extvec_gate.nx -- EIGHTH provably third-party-validated claim, and the first OUTSIDE
9// cryptography: Base64 vs RFC 4648 section 10.
10//
11// ★A FIFTH VECTOR DIALECT. The previous seven gates read hex in four different layouts; RFC 4648 states
12// its vectors as QUOTED ASCII:
13// BASE64("") = ""
14// BASE64("f") = "Zg=="
15// BASE64("foobar") = "Zm9vYmFy"
16// No hex reader touches this. ★The recurring lesson of this session, once more: there is no general
17// parser, only one proven against the section in front of you.
18//
19// Construction unchanged from the other seven: nothing expected appears in this source, the document is
20// pinned to a digest nx_vecfetch computed IN-PROCESS AT THE SOCKET, and every input AND output below is
21// read out of that pinned document at run time.
22// ★THE EMPTY-STRING VECTOR IS KEPT DELIBERATELY. BASE64("") = "" is the case an encoder is most likely to
23// get wrong (a stray pad, a spurious byte) and the one a hand-written test is most likely to omit. The
24// authority published it; we do not get to skip it.
25// license_tier: ORIGINAL expect_exit: 0
26import "nx_syscalls.nx"
27import "nx_sha256_wasm.nx"
28import "nx_base32.nx"
29import "nx_gate_verdict.nx"
30
31func w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
32func wb(b: *u8, n: i64) -> i64 { sys_write(1, b, n); return 0 }
33
34func nn(v: i64) -> i64 {
35 var m: i64 = v
36 if m < 0 { w("-" as *u8); m = 0 - m }
37 let t: *u8 = sys_mmap(32)
38 var k: i64 = 0
39 if m == 0 { t[0] = 48 as u8; k = 1 }
40 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
41 let b: *u8 = sys_mmap(32)
42 var j: i64 = 0
43 while j < k { b[j] = t[k - 1 - j]; j = j + 1 }
44 sys_write(1, b, k)
45 return 0
46}
47
48func hexnib(v: i64) -> i64 { if v < 10 { return 48 + v } return 87 + v }
49
50func starts(b: *u8, n: i64, at: i64, s: *u8) -> i64 {
51 var i: i64 = 0
52 while s[i] != (0 as u8) {
53 if at + i >= n { return 0 }
54 if b[at + i] != s[i] { return 0 }
55 i = i + 1
56 }
57 return 1
58}
59
60func findfrom(b: *u8, n: i64, s: *u8, from: i64) -> i64 {
61 var p: i64 = from
62 while p < n {
63 if starts(b, n, p, s) == 1 { return p }
64 p = p + 1
65 }
66 return 0 - 1
67}
68
69// Copy the run of bytes from `from` up to (not including) the next double-quote. Returns the length, or -1
70// if no closing quote appears. Empty is a VALID result -- BASE64("") = "" is a real published vector, so a
71// zero length must never be treated as a parse failure.
72func parseq(b: *u8, n: i64, from: i64, out: *u8, cap: i64, endout: *i64) -> i64 {
73 var p: i64 = from
74 var k: i64 = 0
75 while p < n {
76 if b[p] == (34 as u8) { endout[0] = p; return k }
77 if k >= cap { return 0 - 1 }
78 out[k] = b[p]
79 k = k + 1
80 p = p + 1
81 }
82 return 0 - 1
83}
84
85func main() -> i64 {
86 w("nx_base32hex_extvec_gate -- Base64 vs RFC 4648 section 10, READ FROM THE FETCHED DOCUMENT\n" as *u8)
87
88 let lp: *i64 = sys_mmap(16) as *i64
89 lp[0] = 0
90 let b: *u8 = sys_read_file("knowledge/extvec/rfc4648.txt\x00" as *u8, lp)
91 if lp[0] <= 0 { w("RED: fetched vector file absent -- run nx_vecfetch.\n" as *u8); return 1 }
92
93 let ctx: *u8 = sys_mmap(1024)
94 let dg: *u8 = sys_mmap(64)
95 nx_sha256_one_shot(b, lp[0], ctx, dg)
96 let hx: *u8 = sys_mmap(80)
97 var i: i64 = 0
98 while i < 32 { hx[i*2] = hexnib(((dg[i] as i64)/16)&15) as u8; hx[i*2+1] = hexnib((dg[i] as i64)&15) as u8; i = i + 1 }
99 let wnt: *u8 = "84e14418f795d503be5f34bf23ce4ebaa119e9ec7c9f667d8caeb111385b178f\x00" as *u8
100 var pin: i64 = 1
101 i = 0
102 while i < 64 { if hx[i] != wnt[i] { pin = 0 } i = i + 1 }
103 w(" acquisition digest: " as *u8); wb(hx, 64); w("\n" as *u8)
104 if pin == 0 { w("RED: PIN FAILED -- not the file nx_vecfetch acquired.\n" as *u8); return 1 }
105 w(" PIN OK -- bytes match the digest computed in-process at the socket\n" as *u8)
106
107 // Anchor on the SECTION BODY, not the contents line: "10. Test Vectors" (two spaces) appears in the
108 // body; the TOC line reads "10. Test Vectors ....". Take the last occurrence to be safe.
109 var at: i64 = 0
110 var scan: i64 = 0
111 var dsec: i64 = 0
112 while dsec == 0 {
113 let h: i64 = findfrom(b, lp[0], "BASE32-HEX(\"" as *u8, scan)
114 if h < 0 { dsec = 1 } else { if at == 0 { at = h } scan = h + 12 }
115 }
116 if at == 0 { w("RED: no BASE64(\") vectors found\n" as *u8); return 1 }
117
118 let inb: *u8 = sys_mmap(64)
119 let exp: *u8 = sys_mmap(64)
120 let got: *u8 = sys_mmap(128)
121 let ep: *i64 = sys_mmap(16) as *i64
122
123 var pass: i64 = 0
124 var fail: i64 = 0
125 var seen: i64 = 0
126 var cur: i64 = at
127 var done: i64 = 0
128 while done == 0 {
129 let h: i64 = findfrom(b, lp[0], "BASE32-HEX(\"" as *u8, cur)
130 if h < 0 { done = 1 }
131 else {
132 ep[0] = 0
133 let inlen: i64 = parseq(b, lp[0], h + 12, inb, 60, ep)
134 if inlen < 0 { done = 1 }
135 else {
136 let q: i64 = findfrom(b, lp[0], "= \"" as *u8, ep[0])
137 if q < 0 { done = 1 }
138 else {
139 ep[0] = 0
140 let elen: i64 = parseq(b, lp[0], q + 3, exp, 60, ep)
141 if elen < 0 { done = 1 }
142 else {
143 let glen: i64 = base32hex_encode(inb, inlen, got)
144 var same: i64 = 1
145 if glen != elen { same = 0 }
146 else { i = 0; while i < elen { if got[i] != exp[i] { same = 0 } i = i + 1 } }
147 seen = seen + 1
148 if same == 1 {
149 pass = pass + 1
150 w(" PASS BASE32-HEX(\"" as *u8); wb(inb, inlen); w("\") == \"" as *u8); wb(exp, elen); w("\"\n" as *u8)
151 } else {
152 fail = fail + 1
153 w(" FAIL BASE32-HEX(\"" as *u8); wb(inb, inlen); w("\") expected \"" as *u8); wb(exp, elen)
154 w("\" got \"" as *u8); wb(got, glen); w("\"\n" as *u8)
155 }
156 cur = ep[0]
157 }
158 }
159 }
160 }
161 }
162
163 // The authority publishes SEVEN Base64 vectors in section 10 (empty through "foobar"). Finding fewer
164 // means the reader lost some -- and a gate that silently grades 3 of 7 while printing GREEN is exactly
165 // the coverage-gaming this workstream exists to stop.
166 if seen < 7 {
167 w(" RED: only " as *u8); nn(seen); w(" vectors parsed; RFC 4648 section 10 publishes 7.\n" as *u8)
168 w(" Refusing to report GREEN on a partial read of the authority.\n" as *u8)
169 fail = fail + 1
170 }
171
172 w("\n refsrc=https://www.rfc-editor.org/rfc/rfc4648.txt\n" as *u8)
173 w(" refsrcdig=" as *u8); wb(hx, 64); w("\n" as *u8)
174 w(" ref=RFC4648-10-BASE32HEX gate=nx_base32hex_extvec_gate\n" as *u8)
175 w("nx_base32hex_extvec_gate: vectors=" as *u8); nn(seen)
176 w(" pass=" as *u8); nn(pass); w(" fail=" as *u8); nn(fail)
177 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
178 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
179 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
180 let ctr__dry: *i64 = gv_ctr()
181 ctr__dry[0] = pass
182 ctr__dry[1] = pass + fail
183 let rc__dry: i64 = gv_verdict("BASE64-EXTVEC-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
184 sys_exit(rc__dry)
185 return rc__dry
186}