code wiki / _hdl_build / nx_opaque_rfc_kat.nx
nx_opaque_rfc_kat.nx source
↩ module page · 327 lines · 17294 B
1// nx_opaque_rfc_kat.nx -- ENGINEER gate: OPAQUE-3DH (RFC 9807) vs the RFC's OWN P-256 vectors.
2//
3// Drives the deterministic cores with the fixed randomness from RFC 9807 Appendix
4// C.1.5 (default identities) + C.1.6 (explicit identities "alice"/"bob") and asserts
5// BYTE-EXACT equality on every output message: registration_request, registration_
6// response, registration_upload, export_key, KE1, KE2, KE3, session_key. One green
7// run validates the ENTIRE stack: VOPRF blind/evaluate/finalize, HashToScalar,
8// DeriveKeyPair, envelope Store/Recover, masking, preamble, 3DH, HKDF key schedule,
9// transcript MACs -- against the standard, not against ourselves.
10//
11// Negative KATs: wrong password => ENVELOPE_AUTH_FAIL; tampered server_mac =>
12// SERVER_AUTH_FAIL; tampered KE3 => CLIENT_AUTH_FAIL. Production-randomness round
13// trip: register+login via the CSPRNG wrappers => client/server session keys agree,
14// register/login export keys agree.
15//
16// Vectors staged: knowledge/specs/2026-06-10-rfc9807-opaque-p256-vectors.ref
17// license_tier: ORIGINAL
18import "hub/nx_opaque_pake.nx"
19import "nx_syscalls.nx"
20
21func ok_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
22func ok_nib(c: i64) -> i64 {
23 if c >= 48 { if c <= 57 { return c - 48 } }
24 if c >= 97 { if c <= 102 { return c - 87 } }
25 return 0
26}
27func ok_hex(hexs: *u8, out: *u8) -> i64 {
28 var i: i64 = 0
29 while hexs[i*2] != (0 as u8) {
30 out[i] = ((ok_nib(hexs[i*2] as i64) << 4) | ok_nib(hexs[i*2+1] as i64)) as u8
31 i = i + 1
32 }
33 return i
34}
35func ok_eq(a: *u8, b: *u8, n: i64) -> i64 {
36 var i: i64 = 0
37 while i < n { if (a[i] as i64) != (b[i] as i64) { return 0 } i = i + 1 }
38 return 1
39}
40func ok_dump(label: *u8, b: *u8, n: i64) -> i64 {
41 ok_w(label)
42 let hx: *u8 = "0123456789abcdef" as *u8
43 let line: *u8 = sys_mmap(2*n + 2)
44 var i: i64 = 0
45 while i < n {
46 line[i*2] = hx[((b[i] as i64) >> 4) & 15]
47 line[i*2+1] = hx[(b[i] as i64) & 15]
48 i = i + 1
49 }
50 line[2*n] = 10 as u8
51 sys_write(1, line, 2*n + 1)
52 return 0
53}
54
55// shared fixed inputs (identical across C.1.5 and C.1.6)
56struct OkVec {
57 oprf_seed: *u8
58 cred_id: *u8 // "1234"
59 password: *u8 // 25 bytes
60 password_n: i64
61 envelope_nonce: *u8
62 masking_nonce: *u8
63 server_priv: *u8
64 server_pub: *u8
65 server_nonce: *u8
66 client_nonce: *u8
67 client_ks_seed: *u8
68 server_ks_seed: *u8
69 blind_reg: *u8
70 blind_login: *u8
71 context: *u8 // "OPAQUE-POC" (10)
72}
73
74func ok_load_inputs(v: *OkVec) -> i64 {
75 v.oprf_seed = sys_mmap(32)
76 ok_hex("62f60b286d20ce4fd1d64809b0021dad6ed5d52a2c8cf27ae6582543a0a8dce2" as *u8, v.oprf_seed)
77 v.cred_id = "1234" as *u8
78 v.password = sys_mmap(32)
79 v.password_n = ok_hex("436f7272656374486f72736542617474657279537461706c65" as *u8, v.password)
80 v.envelope_nonce = sys_mmap(32)
81 ok_hex("a921f2a014513bd8a90e477a629794e89fec12d12206dde662ebdcf65670e51f" as *u8, v.envelope_nonce)
82 v.masking_nonce = sys_mmap(32)
83 ok_hex("38fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80f612fdfc6d" as *u8, v.masking_nonce)
84 v.server_priv = sys_mmap(32)
85 ok_hex("c36139381df63bfc91c850db0b9cfbec7a62e86d80040a41aa7725bf0e79d5e5" as *u8, v.server_priv)
86 v.server_pub = sys_mmap(33)
87 ok_hex("035f40ff9cf88aa1f5cd4fe5fd3da9ea65a4923a5594f84fd9f2092d6067784874" as *u8, v.server_pub)
88 v.server_nonce = sys_mmap(32)
89 ok_hex("71cd9960ecef2fe0d0f7494986fa3d8b2bb01963537e60efb13981e138e3d4a1" as *u8, v.server_nonce)
90 v.client_nonce = sys_mmap(32)
91 ok_hex("ab3d33bde0e93eda72392346a7a73051110674bbf6b1b7ffab8be4f91fdaeeb1" as *u8, v.client_nonce)
92 v.client_ks_seed = sys_mmap(32)
93 ok_hex("633b875d74d1556d2a2789309972b06db21dfcc4f5ad51d7e74d783b7cfab8dc" as *u8, v.client_ks_seed)
94 v.server_ks_seed = sys_mmap(32)
95 ok_hex("05a4f54206eef1ba2f615bc0aa285cb22f26d1153b5b40a1e85ff80da12f982f" as *u8, v.server_ks_seed)
96 v.blind_reg = sys_mmap(32)
97 ok_hex("411bf1a62d119afe30df682b91a0a33d777972d4f2daa4b34ca527d597078153" as *u8, v.blind_reg)
98 v.blind_login = sys_mmap(32)
99 ok_hex("c497fddf6056d241e6cf9fb7ac37c384f49b357a221eb0a802c989b9942256c1" as *u8, v.blind_login)
100 v.context = sys_mmap(16)
101 ok_hex("4f50415155452d504f43" as *u8, v.context)
102 return 0
103}
104
105func ok_mk_ccfg(v: *OkVec, client_id: *u8, client_id_n: i64, server_id: *u8, server_id_n: i64) -> *NxOpqClientCfg {
106 let c: *NxOpqClientCfg = sys_mmap(80) as *NxOpqClientCfg
107 c.server_id = server_id
108 c.server_id_n = server_id_n
109 c.client_id = client_id
110 c.client_id_n = client_id_n
111 c.context = v.context
112 c.context_n = 10
113 c.ksf_mode = NX_OPQ_KSF_IDENTITY
114 c.ksf_m_kib = 0
115 c.ksf_t = 0
116 return c
117}
118
119func ok_mk_scfg(v: *OkVec, server_id: *u8, server_id_n: i64) -> *NxOpqServerCfg {
120 let s: *NxOpqServerCfg = sys_mmap(64) as *NxOpqServerCfg
121 s.server_priv_32 = v.server_priv
122 s.server_pub_33 = v.server_pub
123 s.oprf_seed_32 = v.oprf_seed
124 s.server_id = server_id
125 s.server_id_n = server_id_n
126 s.context = v.context
127 s.context_n = 10
128 return s
129}
130
131// run one full vector (registration + login). wants are the expected outputs.
132// returns number of failures; prints a FAIL line per mismatch tagged `tag`.
133func ok_run_vector(
134 v: *OkVec,
135 ccfg: *NxOpqClientCfg, scfg: *NxOpqServerCfg,
136 client_id: *u8, client_id_n: i64,
137 want_upload_129: *u8, want_ke2_259: *u8, want_ke3_32: *u8,
138 want_export_32: *u8, want_session_32: *u8,
139 tag: *u8
140) -> i64 {
141 var bad: i64 = 0
142
143 // --- registration ---
144 let req: *u8 = sys_mmap(33)
145 if nx_opaque_create_registration_request_det(v.password, v.password_n, v.blind_reg, req) != NX_OPQ_OK {
146 ok_w("FAIL reg_request rc " as *u8); ok_w(tag); ok_w("\n" as *u8); return 1
147 }
148 let want_req: *u8 = sys_mmap(33)
149 ok_hex("029e949a29cfa0bf7c1287333d2fb3dc586c41aa652f5070d26a5315a1b50229f8" as *u8, want_req)
150 if ok_eq(req, want_req, 33) == 0 { bad = bad + 1; ok_w("FAIL reg_request bytes " as *u8); ok_w(tag); ok_w("\n" as *u8); ok_dump(" got=" as *u8, req, 33) }
151
152 let resp: *u8 = sys_mmap(66)
153 if nx_opaque_create_registration_response(req, v.server_pub, v.cred_id, 4, v.oprf_seed, resp) != NX_OPQ_OK {
154 ok_w("FAIL reg_response rc " as *u8); ok_w(tag); ok_w("\n" as *u8); return bad + 1
155 }
156 let want_resp: *u8 = sys_mmap(66)
157 ok_hex("0350d3694c00978f00a5ce7cd08a00547e4ab5fb5fc2b2f6717cdaa6c89136efef035f40ff9cf88aa1f5cd4fe5fd3da9ea65a4923a5594f84fd9f2092d6067784874" as *u8, want_resp)
158 if ok_eq(resp, want_resp, 66) == 0 { bad = bad + 1; ok_w("FAIL reg_response bytes " as *u8); ok_w(tag); ok_w("\n" as *u8); ok_dump(" got=" as *u8, resp, 66) }
159
160 let record: *u8 = sys_mmap(129)
161 let export1: *u8 = sys_mmap(32)
162 if nx_opaque_finalize_registration_det(ccfg, v.password, v.password_n, v.blind_reg, resp, v.envelope_nonce, record, export1) != NX_OPQ_OK {
163 ok_w("FAIL finalize_reg rc " as *u8); ok_w(tag); ok_w("\n" as *u8); return bad + 1
164 }
165 if ok_eq(record, want_upload_129, 129) == 0 { bad = bad + 1; ok_w("FAIL registration_upload " as *u8); ok_w(tag); ok_w("\n" as *u8); ok_dump(" got=" as *u8, record, 129) }
166 if ok_eq(export1, want_export_32, 32) == 0 { bad = bad + 1; ok_w("FAIL export_key(reg) " as *u8); ok_w(tag); ok_w("\n" as *u8) }
167
168 // --- login ---
169 let ke1: *u8 = sys_mmap(98)
170 let client_secret: *u8 = sys_mmap(32)
171 if nx_opaque_generate_ke1_det(v.password, v.password_n, v.blind_login, v.client_nonce, v.client_ks_seed, ke1, client_secret) != NX_OPQ_OK {
172 ok_w("FAIL ke1 rc " as *u8); ok_w(tag); ok_w("\n" as *u8); return bad + 1
173 }
174 let want_ke1: *u8 = sys_mmap(98)
175 ok_hex("037342f0bcb3ecea754c1e67576c86aa90c1de3875f390ad599a26686cdfee6e07ab3d33bde0e93eda72392346a7a73051110674bbf6b1b7ffab8be4f91fdaeeb1022ed3f32f318f81bab80da321fecab3cd9b6eea11a95666dfa6beeaab321280b6" as *u8, want_ke1)
176 if ok_eq(ke1, want_ke1, 98) == 0 { bad = bad + 1; ok_w("FAIL KE1 bytes " as *u8); ok_w(tag); ok_w("\n" as *u8); ok_dump(" got=" as *u8, ke1, 98) }
177
178 let ke2: *u8 = sys_mmap(259)
179 let expected_cmac: *u8 = sys_mmap(32)
180 let session_s: *u8 = sys_mmap(32)
181 if nx_opaque_generate_ke2_det(scfg, record, v.cred_id, 4, client_id, client_id_n, ke1, v.masking_nonce, v.server_nonce, v.server_ks_seed, ke2, expected_cmac, session_s) != NX_OPQ_OK {
182 ok_w("FAIL ke2 rc " as *u8); ok_w(tag); ok_w("\n" as *u8); return bad + 1
183 }
184 if ok_eq(ke2, want_ke2_259, 259) == 0 { bad = bad + 1; ok_w("FAIL KE2 bytes " as *u8); ok_w(tag); ok_w("\n" as *u8); ok_dump(" got=" as *u8, ke2, 259) }
185 if ok_eq(session_s, want_session_32, 32) == 0 { bad = bad + 1; ok_w("FAIL session_key(server) " as *u8); ok_w(tag); ok_w("\n" as *u8) }
186
187 let ke3: *u8 = sys_mmap(32)
188 let session_c: *u8 = sys_mmap(32)
189 let export2: *u8 = sys_mmap(32)
190 if nx_opaque_generate_ke3(ccfg, v.password, v.password_n, v.blind_login, client_secret, ke1, ke2, ke3, session_c, export2) != NX_OPQ_OK {
191 ok_w("FAIL ke3 rc " as *u8); ok_w(tag); ok_w("\n" as *u8); return bad + 1
192 }
193 if ok_eq(ke3, want_ke3_32, 32) == 0 { bad = bad + 1; ok_w("FAIL KE3 bytes " as *u8); ok_w(tag); ok_w("\n" as *u8); ok_dump(" got=" as *u8, ke3, 32) }
194 if ok_eq(session_c, want_session_32, 32) == 0 { bad = bad + 1; ok_w("FAIL session_key(client) " as *u8); ok_w(tag); ok_w("\n" as *u8) }
195 if ok_eq(export2, want_export_32, 32) == 0 { bad = bad + 1; ok_w("FAIL export_key(login) " as *u8); ok_w(tag); ok_w("\n" as *u8) }
196 if nx_opaque_server_finish(ke3, expected_cmac) != NX_OPQ_OK {
197 bad = bad + 1; ok_w("FAIL server_finish " as *u8); ok_w(tag); ok_w("\n" as *u8)
198 }
199
200 // --- negative: wrong password fails at envelope recovery ---
201 let wrong_pw: *u8 = sys_mmap(32)
202 var wp: i64 = 0
203 while wp < v.password_n { wrong_pw[wp] = v.password[wp]; wp = wp + 1 }
204 wrong_pw[0] = ((wrong_pw[0] as i64) ^ 1) as u8
205 let ke1w: *u8 = sys_mmap(98)
206 let csw: *u8 = sys_mmap(32)
207 nx_opaque_generate_ke1_det(wrong_pw, v.password_n, v.blind_login, v.client_nonce, v.client_ks_seed, ke1w, csw)
208 let ke2w: *u8 = sys_mmap(259)
209 let ecmw: *u8 = sys_mmap(32)
210 let ssw: *u8 = sys_mmap(32)
211 nx_opaque_generate_ke2_det(scfg, record, v.cred_id, 4, client_id, client_id_n, ke1w, v.masking_nonce, v.server_nonce, v.server_ks_seed, ke2w, ecmw, ssw)
212 let ke3w: *u8 = sys_mmap(32)
213 let scw: *u8 = sys_mmap(32)
214 let exw: *u8 = sys_mmap(32)
215 let rc_wrong: i64 = nx_opaque_generate_ke3(ccfg, wrong_pw, v.password_n, v.blind_login, csw, ke1w, ke2w, ke3w, scw, exw)
216 if rc_wrong != (0 - NX_OPQ_ENVELOPE_AUTH_FAIL) {
217 bad = bad + 1; ok_w("FAIL wrong-password not rejected " as *u8); ok_w(tag); ok_w("\n" as *u8)
218 }
219
220 // --- negative: tampered server_mac rejected by client ---
221 let ke2t: *u8 = sys_mmap(259)
222 var t: i64 = 0
223 while t < 259 { ke2t[t] = ke2[t]; t = t + 1 }
224 ke2t[227] = ((ke2t[227] as i64) ^ 1) as u8
225 let ke3t: *u8 = sys_mmap(32)
226 let sct: *u8 = sys_mmap(32)
227 let ext: *u8 = sys_mmap(32)
228 let rc_smac: i64 = nx_opaque_generate_ke3(ccfg, v.password, v.password_n, v.blind_login, client_secret, ke1, ke2t, ke3t, sct, ext)
229 if rc_smac != (0 - NX_OPQ_SERVER_AUTH_FAIL) {
230 bad = bad + 1; ok_w("FAIL tampered server_mac not rejected " as *u8); ok_w(tag); ok_w("\n" as *u8)
231 }
232
233 // --- negative: tampered client_mac rejected by server ---
234 let ke3x: *u8 = sys_mmap(32)
235 var x: i64 = 0
236 while x < 32 { ke3x[x] = ke3[x]; x = x + 1 }
237 ke3x[0] = ((ke3x[0] as i64) ^ 1) as u8
238 if nx_opaque_server_finish(ke3x, expected_cmac) != (0 - NX_OPQ_CLIENT_AUTH_FAIL) {
239 bad = bad + 1; ok_w("FAIL tampered KE3 not rejected " as *u8); ok_w(tag); ok_w("\n" as *u8)
240 }
241
242 return bad
243}
244
245// production-randomness round trip: CSPRNG wrappers end to end, fresh keys.
246func ok_run_random_roundtrip(v: *OkVec) -> i64 {
247 var bad: i64 = 0
248 let ccfg: *NxOpqClientCfg = ok_mk_ccfg(v, 0 as *u8, 0, 0 as *u8, 0)
249 let scfg: *NxOpqServerCfg = ok_mk_scfg(v, 0 as *u8, 0)
250
251 let blind_r: *u8 = sys_mmap(32)
252 let req: *u8 = sys_mmap(33)
253 if nx_opaque_create_registration_request(v.password, v.password_n, blind_r, req) != NX_OPQ_OK { return 1 }
254 let resp: *u8 = sys_mmap(66)
255 if nx_opaque_create_registration_response(req, v.server_pub, v.cred_id, 4, v.oprf_seed, resp) != NX_OPQ_OK { return 1 }
256 let record: *u8 = sys_mmap(129)
257 let export1: *u8 = sys_mmap(32)
258 if nx_opaque_finalize_registration(ccfg, v.password, v.password_n, blind_r, resp, record, export1) != NX_OPQ_OK { return 1 }
259
260 let blind_l: *u8 = sys_mmap(32)
261 let ke1: *u8 = sys_mmap(98)
262 let cs: *u8 = sys_mmap(32)
263 if nx_opaque_generate_ke1(v.password, v.password_n, blind_l, ke1, cs) != NX_OPQ_OK { return 1 }
264 let ke2: *u8 = sys_mmap(259)
265 let ecm: *u8 = sys_mmap(32)
266 let ss: *u8 = sys_mmap(32)
267 if nx_opaque_generate_ke2(scfg, record, v.cred_id, 4, 0 as *u8, 0, ke1, ke2, ecm, ss) != NX_OPQ_OK { return 1 }
268 let ke3: *u8 = sys_mmap(32)
269 let sc: *u8 = sys_mmap(32)
270 let export2: *u8 = sys_mmap(32)
271 if nx_opaque_generate_ke3(ccfg, v.password, v.password_n, blind_l, cs, ke1, ke2, ke3, sc, export2) != NX_OPQ_OK { return 1 }
272 if nx_opaque_server_finish(ke3, ecm) != NX_OPQ_OK { bad = bad + 1; ok_w("FAIL rnd server_finish\n" as *u8) }
273 if ok_eq(sc, ss, 32) == 0 { bad = bad + 1; ok_w("FAIL rnd session keys differ\n" as *u8) }
274 if ok_eq(export1, export2, 32) == 0 { bad = bad + 1; ok_w("FAIL rnd export keys differ\n" as *u8) }
275 return bad
276}
277
278func main() -> i64 {
279 let v: *OkVec = sys_mmap(160) as *OkVec
280 ok_load_inputs(v)
281 var bad: i64 = 0
282
283 // ===== Vector C.1.5: default identities =====
284 let up5: *u8 = sys_mmap(129)
285 ok_hex("03b218507d978c3db570ca994aaf36695a731ddb2db272c817f79746fc37ae52147f0ed53532d3ae8e505ecc70d42d2b814b6b0e48156def71ea029148b2803aafa921f2a014513bd8a90e477a629794e89fec12d12206dde662ebdcf65670e51fad30bbcfc1f8eda0211553ab9aaf26345ad59a128e80188f035fe4924fad67b8" as *u8, up5)
286 let ke2_5: *u8 = sys_mmap(259)
287 ok_hex("0246da9fe4d41d5ba69faa6c509a1d5bafd49a48615a47a8dd4b0823cc1476481138fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80f612fdfc6d2f0c547f70deaeca54d878c14c1aa5e1ab405dec833777132eea905c2fbb12504a67dcbe0e66740c76b62c13b04a38a77926e19072953319ec65e41f9bfd2ae26837b6ce688bf9af2542f04eec9ab96a1b9328812dc2f5c89182ed47fead61f09f71cd9960ecef2fe0d0f7494986fa3d8b2bb01963537e60efb13981e138e3d4a103c1701353219b53acf337bf6456a83cefed8f563f1040b65afbf3b65d3bc9a19b50a73b145bc87a157e8c58c0342e2047ee22ae37b63db17e0a82a30fcc4ecf7b" as *u8, ke2_5)
288 let ke3_5: *u8 = sys_mmap(32)
289 ok_hex("e97cab4433aa39d598e76f13e768bba61c682947bdcf9936035e8a3a3ebfb66e" as *u8, ke3_5)
290 let ex5: *u8 = sys_mmap(32)
291 ok_hex("c3c9a1b0e33ac84dd83d0b7e8af6794e17e7a3caadff289fbd9dc769a853c64b" as *u8, ex5)
292 let ses5: *u8 = sys_mmap(32)
293 ok_hex("484ad345715ccce138ca49e4ea362c6183f0949aaaa1125dc3bc3f80876e7cd1" as *u8, ses5)
294 let ccfg5: *NxOpqClientCfg = ok_mk_ccfg(v, 0 as *u8, 0, 0 as *u8, 0)
295 let scfg5: *NxOpqServerCfg = ok_mk_scfg(v, 0 as *u8, 0)
296 bad = bad + ok_run_vector(v, ccfg5, scfg5, 0 as *u8, 0, up5, ke2_5, ke3_5, ex5, ses5, "[C.1.5]" as *u8)
297
298 // ===== Vector C.1.6: identities alice/bob =====
299 let alice: *u8 = "alice" as *u8
300 let bob: *u8 = "bob" as *u8
301 let up6: *u8 = sys_mmap(129)
302 ok_hex("03b218507d978c3db570ca994aaf36695a731ddb2db272c817f79746fc37ae52147f0ed53532d3ae8e505ecc70d42d2b814b6b0e48156def71ea029148b2803aafa921f2a014513bd8a90e477a629794e89fec12d12206dde662ebdcf65670e51f4d7773a36a208a866301dbb2858e40dc5638017527cf91aef32d3848eebe0971" as *u8, up6)
303 let ke2_6: *u8 = sys_mmap(259)
304 ok_hex("0246da9fe4d41d5ba69faa6c509a1d5bafd49a48615a47a8dd4b0823cc1476481138fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80f612fdfc6d2f0c547f70deaeca54d878c14c1aa5e1ab405dec833777132eea905c2fbb12504a67dcbe0e66740c76b62c13b04a38a77926e19072953319ec65e41f9bfd2ae268d7f106042021c80300e4c6f585980cf39fc51a4a6bba41b0729f9b240c729e5671cd9960ecef2fe0d0f7494986fa3d8b2bb01963537e60efb13981e138e3d4a103c1701353219b53acf337bf6456a83cefed8f563f1040b65afbf3b65d3bc9a19b84922c7e5d074838a8f278592c53f61fb59f031e85ad480c0c71086b871e1b24" as *u8, ke2_6)
305 let ke3_6: *u8 = sys_mmap(32)
306 ok_hex("46833578cee137775f6be3f01b80748daac5a694101ad0e9e7025480552da56a" as *u8, ke3_6)
307 let ses6: *u8 = sys_mmap(32)
308 ok_hex("27766fabd8dd88ff37fbd0ef1a491e601d10d9f016c2b28c4bd1b0fb7511a3c3" as *u8, ses6)
309 let ccfg6: *NxOpqClientCfg = ok_mk_ccfg(v, alice, 5, bob, 3)
310 let scfg6: *NxOpqServerCfg = ok_mk_scfg(v, bob, 3)
311 bad = bad + ok_run_vector(v, ccfg6, scfg6, alice, 5, up6, ke2_6, ke3_6, ex5, ses6, "[C.1.6]" as *u8)
312
313 // ===== production-randomness round trip =====
314 bad = bad + ok_run_random_roundtrip(v)
315
316 if bad == 0 {
317 ok_w("OPAQUE RFC9807 KAT GREEN (C.1.5 + C.1.6 byte-exact: reg/KE1/KE2/KE3/export/session; wrong-pw + 2 tamper rejections; random round trip)\n" as *u8)
318 sys_exit(0)
319 }
320 ok_w("OPAQUE KAT FAILED bad=" as *u8)
321 let d: *u8 = sys_mmap(4)
322 d[0] = (48 + (bad % 10)) as u8
323 d[1] = 10 as u8
324 sys_write(1, d, 2)
325 sys_exit(1)
326 return 1
327}