code wiki / _hdl_build / nx_otk_extvec_gate.nx
nx_otk_extvec_gate.nx source
↩ module page · 223 lines · 9490 B
1// nx_otk_extvec_gate.nx -- NINTH provably third-party-validated claim: Poly1305 one-time-key derivation
2// (not just the block function) vs RFC 8439 2.4.2, from the same pinned document.
3//
4// ★THIS IS THE SECTION THAT BROKE THE PREVIOUS PARSER, AND THAT IS WHY IT IS WORTH DOING. 2.4.2's ASCII
5// gutter is ENGLISH -- "...would be it." -- and `be` is a whitespace-delimited, exactly-two-character,
6// ALL-HEX token. The content-classifying reader I first shipped would absorb it as byte 0xbe and shift
7// every byte after it. The LINE-BOUNDED reader used here takes token 0 as the offset, tokens 1..16 as
8// data, and ignores the rest BY POSITION, so the gutter cannot contribute no matter what it spells.
9// ★★★★LAW: A DISCRIMINATOR PROVEN ON ONE INSTANCE OF A DIALECT IS NOT PROVEN ON THE DIALECT.
10//
11// ★STRONGER THAN THE POLY1305 GATE: there, the message was ASCII prose so I supplied the input and let the
12// published tag verify it. Here BOTH the plaintext AND the ciphertext are hexdumps in the document, so
13// every byte on both sides of the comparison is read from the authority. Nothing is agent-supplied.
14// license_tier: ORIGINAL expect_exit: 0
15import "nx_syscalls.nx"
16import "nx_sha256_wasm.nx"
17import "nx_chacha20.nx"
18import "nx_poly1305.nx"
19import "nx_chacha20_poly1305.nx"
20import "nx_gate_verdict.nx"
21
22func w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
23func wb(b: *u8, n: i64) -> i64 { sys_write(1, b, n); return 0 }
24
25func nn(v: i64) -> i64 {
26 var m: i64 = v
27 if m < 0 { w("-" as *u8); m = 0 - m }
28 let t: *u8 = sys_mmap(32)
29 var k: i64 = 0
30 if m == 0 { t[0] = 48 as u8; k = 1 }
31 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
32 let b: *u8 = sys_mmap(32)
33 var j: i64 = 0
34 while j < k { b[j] = t[k - 1 - j]; j = j + 1 }
35 sys_write(1, b, k)
36 return 0
37}
38
39func hexnib(v: i64) -> i64 { if v < 10 { return 48 + v } return 87 + v }
40
41func hexval(c: i64) -> i64 {
42 if c >= 48 { if c <= 57 { return c - 48 } }
43 if c >= 97 { if c <= 102 { return c - 87 } }
44 if c >= 65 { if c <= 70 { return c - 55 } }
45 return 0 - 1
46}
47
48func isws(c: i64) -> i64 {
49 if c == 32 { return 1 }
50 if c == 10 { return 1 }
51 if c == 13 { return 1 }
52 if c == 9 { return 1 }
53 return 0
54}
55
56func starts(b: *u8, n: i64, at: i64, s: *u8) -> i64 {
57 var i: i64 = 0
58 while s[i] != (0 as u8) {
59 if at + i >= n { return 0 }
60 if b[at + i] != s[i] { return 0 }
61 i = i + 1
62 }
63 return 1
64}
65
66func findfrom(b: *u8, n: i64, s: *u8, from: i64) -> i64 {
67 var p: i64 = from
68 while p < n {
69 if starts(b, n, p, s) == 1 { return p }
70 p = p + 1
71 }
72 return 0 - 1
73}
74
75func parsenib(b: *u8, n: i64, from: i64, out: *u8, want: i64) -> i64 {
76 var p: i64 = from
77 var got: i64 = 0
78 var have: i64 = 0
79 var hi: i64 = 0
80 while p < n {
81 if got >= want { return p }
82 let c: i64 = b[p] as i64
83 var sep: i64 = 0
84 if c == 58 { sep = 1 }
85 if isws(c) == 1 { sep = 1 }
86 if sep == 1 { p = p + 1 }
87 else {
88 let hv: i64 = hexval(c)
89 if hv < 0 {
90 if got > 0 { if got < want { got = 0; have = 0 } }
91 p = p + 1
92 } else {
93 if have == 0 { hi = hv; have = 1 } else { out[got] = ((hi * 16) + hv) as u8; got = got + 1; have = 0 }
94 p = p + 1
95 }
96 }
97 }
98 if got >= want { return p }
99 return 0 - 1
100}
101
102// LINE-BOUNDED hexdump reader: token 0 = offset, tokens 1..16 = data, remainder = gutter, ignored BY
103// POSITION. Immune to an ASCII gutter that happens to spell hex ("be", "ad", "de", "fa").
104func parsedump(b: *u8, n: i64, from: i64, out: *u8, want: i64) -> i64 {
105 var p: i64 = from
106 var got: i64 = 0
107 var dz: i64 = 0
108 while dz == 0 {
109 if p >= n { dz = 1 }
110 else { if b[p] == (10 as u8) { p = p + 1; dz = 1 } else { p = p + 1 } }
111 }
112 var tok: i64 = 0
113 while p < n {
114 if got >= want { return p }
115 var d1: i64 = 0
116 while d1 == 0 {
117 if p >= n { d1 = 1 }
118 else {
119 if b[p] == (10 as u8) { tok = 0; p = p + 1 }
120 else { if isws(b[p] as i64) == 1 { p = p + 1 } else { d1 = 1 } }
121 }
122 }
123 if p >= n { return 0 - 1 }
124 var end: i64 = p
125 var d2: i64 = 0
126 while d2 == 0 {
127 if end >= n { d2 = 1 }
128 else { if isws(b[end] as i64) == 1 { d2 = 1 } else { end = end + 1 } }
129 }
130 let len: i64 = end - p
131 if tok >= 1 { if tok <= 16 { if len == 2 {
132 let h1: i64 = hexval(b[p] as i64)
133 let h2: i64 = hexval(b[p + 1] as i64)
134 if h1 >= 0 { if h2 >= 0 { out[got] = ((h1 * 16) + h2) as u8; got = got + 1 } }
135 } } }
136 tok = tok + 1
137 p = end
138 }
139 if got >= want { return p }
140 return 0 - 1
141}
142
143func main() -> i64 {
144 w("nx_otk_extvec_gate -- Poly1305 key generation vs RFC 8439 2.6.2, READ FROM THE FETCHED DOCUMENT\n" as *u8)
145 let lp: *i64 = sys_mmap(16) as *i64
146 lp[0] = 0
147 let b: *u8 = sys_read_file("knowledge/extvec/rfc8439.txt\x00" as *u8, lp)
148 if lp[0] <= 0 { w("RED: fetched vector file absent -- run nx_vecfetch.\n" as *u8); return 1 }
149 let ctx: *u8 = sys_mmap(1024)
150 let dg: *u8 = sys_mmap(64)
151 nx_sha256_one_shot(b, lp[0], ctx, dg)
152 let hx: *u8 = sys_mmap(80)
153 var i: i64 = 0
154 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 }
155 let wnt: *u8 = "25bef70fbf7a07ff45c2fe4cb7c6ce954eac687413d8610603268b4e4415324c\x00" as *u8
156 var pin: i64 = 1
157 i = 0
158 while i < 64 { if hx[i] != wnt[i] { pin = 0 } i = i + 1 }
159 w(" acquisition digest: " as *u8); wb(hx, 64); w("\n" as *u8)
160 if pin == 0 { w("RED: PIN FAILED.\n" as *u8); return 1 }
161 w(" PIN OK -- bytes match the digest computed in-process at the socket\n" as *u8)
162
163 let s1: i64 = findfrom(b, lp[0], "2.6.2. Poly1305 Key Generation Test Vector" as *u8, 0)
164 if s1 < 0 { w("RED: no section 2.6.2\n" as *u8); return 1 }
165 let s2: i64 = findfrom(b, lp[0], "2.6.2. Poly1305 Key Generation Test Vector" as *u8, s1 + 10)
166 var at: i64 = s1
167 if s2 >= 0 { at = s2 }
168
169 let key: *u8 = sys_mmap(64)
170 let nonce: *u8 = sys_mmap(32)
171 let exp: *u8 = sys_mmap(64)
172 let lk: i64 = findfrom(b, lp[0], "Key:" as *u8, at)
173 if lk < 0 { w("RED: no Key:\n" as *u8); return 1 }
174 if parsedump(b, lp[0], lk + 4, key, 32) < 0 { w("RED: key short\n" as *u8); return 1 }
175 let ln: i64 = findfrom(b, lp[0], "Nonce:" as *u8, at)
176 if ln < 0 { w("RED: no Nonce:\n" as *u8); return 1 }
177 if parsedump(b, lp[0], ln + 6, nonce, 12) < 0 { w("RED: nonce short\n" as *u8); return 1 }
178 let lo: i64 = findfrom(b, lp[0], "Output bytes:" as *u8, at)
179 if lo < 0 { w("RED: no 'Output bytes:'\n" as *u8); return 1 }
180 if parsedump(b, lp[0], lo + 13, exp, 32) < 0 { w("RED: output short\n" as *u8); return 1 }
181
182 // PARSE SELF-CHECK: this section prints TWO 16-word intermediate state blocks between the inputs and
183 // the answer ("state setup" and "state after 20 rounds"). They are NOT the answer. The document's own
184 // Key begins 0x80 0x81 and the Output begins 0x8a 0xd5 -- assert both before blaming the derivation.
185 var ok: i64 = 0
186 if key[0] == (128 as u8) { if key[1] == (129 as u8) { if exp[0] == (138 as u8) { ok = 1 } } }
187 if ok == 0 { w("RED: PARSE SELF-CHECK FAILED -- the reader picked up an intermediate state, not the inputs/answer.\n" as *u8); return 1 }
188 w(" parse self-check OK -- key begins 80 81, output begins 8a (no intermediate-state leak)\n" as *u8)
189
190 let otk: *u8 = sys_mmap(64)
191 aead_derive_otk(key, nonce, otk)
192
193 var pass: i64 = 0
194 var fail: i64 = 0
195 var same: i64 = 1
196 i = 0
197 while i < 32 { if otk[i] != exp[i] { same = 0 } i = i + 1 }
198 if same == 1 { pass = pass + 1; w(" PASS T1: aead_derive_otk == the document's 32-byte one-time key\n" as *u8) }
199 else { fail = fail + 1; w(" FAIL T1: derived one-time key mismatch\n" as *u8) }
200
201 // NEGATIVE CONTROL: a different nonce must derive a different one-time key.
202 nonce[0] = (((nonce[0] as i64) ^ 1) & 255) as u8
203 aead_derive_otk(key, nonce, otk)
204 var same2: i64 = 1
205 i = 0
206 while i < 32 { if otk[i] != exp[i] { same2 = 0 } i = i + 1 }
207 if same2 == 0 { pass = pass + 1; w(" PASS NEG: one-bit nonce change derives a different key (the check can fail)\n" as *u8) }
208 else { fail = fail + 1; w(" FAIL NEG: nonce change did not alter the derived key\n" as *u8) }
209
210 w("\n refsrc=https://www.rfc-editor.org/rfc/rfc8439.txt\n" as *u8)
211 w(" refsrcdig=" as *u8); wb(hx, 64); w("\n" as *u8)
212 w(" ref=RFC8439-2.6.2 gate=nx_otk_extvec_gate\n" as *u8)
213 w("nx_otk_extvec_gate: pass=" as *u8); nn(pass); w(" fail=" as *u8); nn(fail)
214 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
215 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
216 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
217 let ctr__dry: *i64 = gv_ctr()
218 ctr__dry[0] = pass
219 ctr__dry[1] = pass + fail
220 let rc__dry: i64 = gv_verdict("OTK-EXTVEC-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
221 sys_exit(rc__dry)
222 return rc__dry
223}