code wiki / _hdl_build / nx_evattest_gate.nx
nx_evattest_gate.nx source
↩ module page · 221 lines · 11691 B
1// nx_evattest_gate.nx -- proves the signed-attestation layer accepts a genuine operator sign-off and
2// REFUSES every way of faking one. The clause it defends (`require_human`) is the single thing standing
3// between "an agent certified its own work" and a PROVEN verdict, so every refusal path here is
4// negative-controlled: a gate that only ever demonstrates acceptance has proven nothing.
5// license_tier: ORIGINAL expect_exit: 0
6import "nx_syscalls.nx"
7import "nx_evattest.nx"
8
9func w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
10func wn(v: i64) -> i64 { let t: *u8=sys_mmap(28); var m: i64=v; var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} let b: *u8=sys_mmap(28); var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 }
11func ck(pass: i64, label: *u8, fails: *i64) -> i64 {
12 w(" " as *u8); w(label); w(": " as *u8)
13 if pass==1 { w("PASS\n" as *u8) } else { w("FAIL\n" as *u8); fails[0]=fails[0]+1 }
14 return 0
15}
16func hexout(src: *u8, n: i64, dst: *u8, off: i64) -> i64 {
17 let hexd: *u8 = "0123456789abcdef"
18 var o: i64 = off
19 var i: i64 = 0
20 while i < n {
21 let b: i64 = src[i] as i64
22 dst[o] = hexd[(b >> 4) & 15]; o = o + 1
23 dst[o] = hexd[b & 15]; o = o + 1
24 i = i + 1
25 }
26 return o
27}
28func cat(dst: *u8, off: i64, s: *u8) -> i64 {
29 var o: i64 = off
30 var i: i64 = 0
31 while s[i] != (0 as u8) { dst[o] = s[i]; o = o + 1; i = i + 1 }
32 return o
33}
34
35func main() -> i64 {
36 let fails: *i64 = sys_mmap(16) as *i64
37 fails[0]=0
38 w("=== nx_evattest_gate -- a genuine operator sign-off passes; every forgery is refused ===\n" as *u8)
39
40 // Two deterministic test keys. HUMAN = the operator's; MACHINE = one the automation might hold.
41 let hpriv: *u8 = sys_mmap(32)
42 let mpriv: *u8 = sys_mmap(32)
43 var i: i64 = 0
44 while i < 32 { hpriv[i] = (i + 11) as u8; mpriv[i] = (i + 200) as u8; i = i + 1 }
45 let hpub: *u8 = sys_mmap(32)
46 let mpub: *u8 = sys_mmap(32)
47 ed25519_pub_from_priv(hpriv, hpub)
48 ed25519_pub_from_priv(mpriv, mpub)
49
50 // Key registry: the human key is role=human, the machine key role=machine. A third key is left
51 // deliberately unregistered so "valid signature from a stranger" can be tested.
52 let conf: *u8 = sys_mmap(4096)
53 var c: i64 = 0
54 c = cat(conf, c, "# test registry\nrole=human pub=" as *u8)
55 c = hexout(hpub, 32, conf, c)
56 c = cat(conf, c, " name=operator\nrole=machine pub=" as *u8)
57 c = hexout(mpub, 32, conf, c)
58 c = cat(conf, c, " name=automation\n" as *u8)
59
60 // ---- build a genuine human attestation ----
61 let row: *u8 = sys_mmap(4096)
62 var r: i64 = 0
63 r = cat(row, r, "class=human verdict=pass scope=reviewed-9-warden-axes-against-source signer=operator epoch=1785400000" as *u8)
64 let sig: *u8 = sys_mmap(64)
65 ed25519_sign_full(hpriv, row, r, sig)
66 var rf: i64 = cat(row, r, " pub=" as *u8)
67 rf = hexout(hpub, 32, row, rf)
68 rf = cat(row, rf, " sig=" as *u8)
69 rf = hexout(sig, 64, row, rf)
70
71 // T1: the genuine operator attestation is ACCEPTED (the layer is usable, not merely strict)
72 var t1: i64=0
73 if at_verify_row(row, 0, rf, AT_CLASS_HUMAN, conf, c)==AT_OK { t1=1 }
74 ck(t1, "T1 genuine operator-signed human row -> OK (accepts real sign-off)" as *u8, fails)
75
76 // T2: THE ATTACK THIS EXISTS TO STOP -- the automation signs a human-class row with ITS OWN key.
77 // Cryptographically valid, registered key, and still REFUSED on role.
78 let row2: *u8 = sys_mmap(4096)
79 var r2: i64 = 0
80 r2 = cat(row2, r2, "class=human verdict=pass scope=I-checked-my-own-work signer=automation epoch=1785400000" as *u8)
81 let sig2: *u8 = sys_mmap(64)
82 ed25519_sign_full(mpriv, row2, r2, sig2)
83 var rf2: i64 = cat(row2, r2, " pub=" as *u8)
84 rf2 = hexout(mpub, 32, row2, rf2)
85 rf2 = cat(row2, rf2, " sig=" as *u8)
86 rf2 = hexout(sig2, 64, row2, rf2)
87 var t2: i64=0
88 if at_verify_row(row2, 0, rf2, AT_CLASS_HUMAN, conf, c)==AT_ERR_ROLE { t2=1 }
89 ck(t2, "T2 MACHINE key signs a human row (valid sig, registered) -> REFUSED on role" as *u8, fails)
90
91 // T3: the same machine key IS accepted for a machine-class claim -- role separation is a boundary,
92 // not a blanket refusal of the automation.
93 var t3: i64=0
94 if at_verify_row(row2, 0, rf2, AT_CLASS_MECH, conf, c)==AT_OK { t3=1 }
95 ck(t3, "T3 same machine key for a MECH claim -> OK (separation, not blanket refusal)" as *u8, fails)
96
97 // T4: TAMPER -- flip one byte of the signed scope. Signature must fail.
98 let row3: *u8 = sys_mmap(4096)
99 var q: i64 = 0
100 while q < rf { row3[q] = row[q]; q = q + 1 }
101 row3[30] = (row3[30] as i64 + 1) as u8
102 var t4: i64=0
103 if at_verify_row(row3, 0, rf, AT_CLASS_HUMAN, conf, c)==AT_ERR_BADSIG { t4=1 }
104 ck(t4, "T4 one byte of the signed scope altered -> BAD-SIGNATURE (tamper-evident)" as *u8, fails)
105
106 // T5: an UNSIGNED row -- the pre-seq1367 format -- must not be honoured at all.
107 let row4: *u8 = sys_mmap(1024)
108 let r4: i64 = cat(row4, 0, "class=human verdict=pass scope=trust-me signer=whoever epoch=1785400000" as *u8)
109 var t5: i64=0
110 if at_verify_row(row4, 0, r4, AT_CLASS_HUMAN, conf, c)==AT_ERR_NOSIG { t5=1 }
111 ck(t5, "T5 legacy UNSIGNED row -> UNSIGNED (fails closed, not grandfathered)" as *u8, fails)
112
113 // T6: a VALID signature from an UNREGISTERED key is still refused -- a signature from a stranger is
114 // not an authorisation.
115 let upriv: *u8 = sys_mmap(32)
116 i = 0
117 while i < 32 { upriv[i] = (i + 77) as u8; i = i + 1 }
118 let upub: *u8 = sys_mmap(32)
119 ed25519_pub_from_priv(upriv, upub)
120 let row5: *u8 = sys_mmap(4096)
121 var r5: i64 = 0
122 r5 = cat(row5, r5, "class=human verdict=pass scope=stranger-signed signer=nobody epoch=1785400000" as *u8)
123 let sig5: *u8 = sys_mmap(64)
124 ed25519_sign_full(upriv, row5, r5, sig5)
125 var rf5: i64 = cat(row5, r5, " pub=" as *u8)
126 rf5 = hexout(upub, 32, row5, rf5)
127 rf5 = cat(row5, rf5, " sig=" as *u8)
128 rf5 = hexout(sig5, 64, row5, rf5)
129 var t6: i64=0
130 if at_verify_row(row5, 0, rf5, AT_CLASS_HUMAN, conf, c)==AT_ERR_UNKNOWNKEY { t6=1 }
131 ck(t6, "T6 valid signature from an UNREGISTERED key -> refused (a signature is not an authorisation)" as *u8, fails)
132
133 // T7: SIGNATURE-SWAP -- take the genuine human signature and paste it onto a different claim.
134 // The canonical message covers class/verdict/scope/epoch, so a lifted signature cannot be re-pointed.
135 let row6: *u8 = sys_mmap(4096)
136 var r6: i64 = 0
137 r6 = cat(row6, r6, "class=human verdict=pass scope=SOMETHING-ELSE-ENTIRELY signer=operator epoch=1785400000" as *u8)
138 var rf6: i64 = cat(row6, r6, " pub=" as *u8)
139 rf6 = hexout(hpub, 32, row6, rf6)
140 rf6 = cat(row6, rf6, " sig=" as *u8)
141 rf6 = hexout(sig, 64, row6, rf6)
142 var t7: i64=0
143 if at_verify_row(row6, 0, rf6, AT_CLASS_HUMAN, conf, c)==AT_ERR_BADSIG { t7=1 }
144 ck(t7, "T7 genuine signature lifted onto a DIFFERENT claim -> BAD-SIGNATURE (cannot be re-pointed)" as *u8, fails)
145
146 // ---- T8..T12: THE ORACLE CLASS -- DERIVED, NEVER DECLARED (added 2026-07-31 with AT_CLASS_ORACLE) ----
147 // Before this, EV_CLASS_ORACLE(8) reached at_verify_row and matched NO rule, so it was authorised by
148 // fall-through and no tooth here could tell. A clause with no negative control has not been shown to
149 // measure anything -- so each of the three required fields gets its own failing case.
150 // The signature is REAL and the key is REGISTERED in every one of these rows: the only thing under test
151 // is whether the CLAIM carries its own re-derivation recipe. That isolation is the point -- it proves
152 // the refusal is about verifiability, not about the signer.
153 let ro: *u8 = sys_mmap(4096)
154 var q0: i64 = 0
155 q0 = cat(ro, q0, "class=oracle verdict=pass scope=sha256-native ref=FIPS 180-4 refdig=d719137726632612 gate=nx_sha256_native_kat_gate signer=automation epoch=1785400000" as *u8)
156 let sigo: *u8 = sys_mmap(64)
157 ed25519_sign_full(mpriv, ro, q0, sigo)
158 var rfo: i64 = cat(ro, q0, " pub=" as *u8)
159 rfo = hexout(mpub, 32, ro, rfo)
160 rfo = cat(ro, rfo, " sig=" as *u8)
161 rfo = hexout(sigo, 64, ro, rfo)
162 var t8: i64=0
163 if at_verify_row(ro, 0, rfo, AT_CLASS_ORACLE, conf, c)==AT_OK { t8=1 }
164 ck(t8, "T8 complete oracle row, MACHINE key -> OK (independence is in the REFERENCE, not the signer)" as *u8, fails)
165
166 // T9 NEG: drop refdig=. This is the field that makes the class ungameable -- prose can claim FIPS 180-4,
167 // only a digest commits to the bytes that were actually compared.
168 let r9: *u8 = sys_mmap(4096)
169 var q9: i64 = 0
170 q9 = cat(r9, q9, "class=oracle verdict=pass scope=sha256-native ref=FIPS 180-4 gate=nx_sha256_native_kat_gate signer=automation epoch=1785400000" as *u8)
171 let sig9: *u8 = sys_mmap(64)
172 ed25519_sign_full(mpriv, r9, q9, sig9)
173 var rf9: i64 = cat(r9, q9, " pub=" as *u8)
174 rf9 = hexout(mpub, 32, r9, rf9)
175 rf9 = cat(r9, rf9, " sig=" as *u8)
176 rf9 = hexout(sig9, 64, r9, rf9)
177 var t9: i64=0
178 if at_verify_row(r9, 0, rf9, AT_CLASS_ORACLE, conf, c)==AT_ERR_NOTDERIVED { t9=1 }
179 ck(t9, "T9 NEG oracle row without refdig= -> NOT-DERIVED (a claim that commits to no bytes)" as *u8, fails)
180
181 // T10 NEG: drop gate=. Without the recipe the reader cannot re-run the comparison, and re-runnability
182 // is the whole reason this class does not need to be trusted.
183 let r10: *u8 = sys_mmap(4096)
184 var q10: i64 = 0
185 q10 = cat(r10, q10, "class=oracle verdict=pass scope=sha256-native ref=FIPS 180-4 refdig=d719137726632612 signer=automation epoch=1785400000" as *u8)
186 let sig10: *u8 = sys_mmap(64)
187 ed25519_sign_full(mpriv, r10, q10, sig10)
188 var rf10: i64 = cat(r10, q10, " pub=" as *u8)
189 rf10 = hexout(mpub, 32, r10, rf10)
190 rf10 = cat(r10, rf10, " sig=" as *u8)
191 rf10 = hexout(sig10, 64, r10, rf10)
192 var t10: i64=0
193 if at_verify_row(r10, 0, rf10, AT_CLASS_ORACLE, conf, c)==AT_ERR_NOTDERIVED { t10=1 }
194 ck(t10, "T10 NEG oracle row without gate= -> NOT-DERIVED (no re-derivation recipe)" as *u8, fails)
195
196 // T11 NEG: THE PROSE FORGERY. Drop ref= -- an oracle that will not say what it matched.
197 let r11: *u8 = sys_mmap(4096)
198 var q11: i64 = 0
199 q11 = cat(r11, q11, "class=oracle verdict=pass scope=sha256-native refdig=d719137726632612 gate=nx_sha256_native_kat_gate signer=automation epoch=1785400000" as *u8)
200 let sig11: *u8 = sys_mmap(64)
201 ed25519_sign_full(mpriv, r11, q11, sig11)
202 var rf11: i64 = cat(r11, q11, " pub=" as *u8)
203 rf11 = hexout(mpub, 32, r11, rf11)
204 rf11 = cat(r11, rf11, " sig=" as *u8)
205 rf11 = hexout(sig11, 64, r11, rf11)
206 var t11: i64=0
207 if at_verify_row(r11, 0, rf11, AT_CLASS_ORACLE, conf, c)==AT_ERR_NOTDERIVED { t11=1 }
208 ck(t11, "T11 NEG oracle row without ref= -> NOT-DERIVED (it matched WHAT?)" as *u8, fails)
209
210 // T12: the derived contract binds ONLY the oracle class. The same recipe-less row is fine as a MECH
211 // claim -- so the new clause raised the bar for one class without silently tightening the others.
212 var t12: i64=0
213 if at_verify_row(r11, 0, rf11, AT_CLASS_MECH, conf, c)==AT_OK { t12=1 }
214 ck(t12, "T12 same recipe-less row as a MECH claim -> OK (the clause is scoped, not a blanket)" as *u8, fails)
215
216 w(" fails=" as *u8); wn(fails[0]); w("\n" as *u8)
217 if fails[0]==0 { w("VERDICT: verdict=GREEN (signed attestations: real sign-off accepted; machine-signed human rows, tampering, lifting, strangers and legacy unsigned rows all refused)\n" as *u8); sys_exit(0) }
218 w("VERDICT: verdict=RED\n" as *u8)
219 sys_exit(1)
220 return 1
221}