code wiki / _hdl_build / nx_opaque_rfc_kat.nx

nx_opaque_rfc_kat.nx source

↩ module page · 335 lines · 18144 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" 20import "nx_gate_verdict.nx" 21 22func 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 } 23func ok_nib(c: i64) -> i64 { 24 if c >= 48 { if c <= 57 { return c - 48 } } 25 if c >= 97 { if c <= 102 { return c - 87 } } 26 return 0 27} 28func ok_hex(hexs: *u8, out: *u8) -> i64 { 29 var i: i64 = 0 30 while hexs[i*2] != (0 as u8) { 31 out[i] = ((ok_nib(hexs[i*2] as i64) << 4) | ok_nib(hexs[i*2+1] as i64)) as u8 32 i = i + 1 33 } 34 return i 35} 36func ok_eq(a: *u8, b: *u8, n: i64) -> i64 { 37 var i: i64 = 0 38 while i < n { if (a[i] as i64) != (b[i] as i64) { return 0 } i = i + 1 } 39 return 1 40} 41func ok_dump(label: *u8, b: *u8, n: i64) -> i64 { 42 ok_w(label) 43 let hx: *u8 = "0123456789abcdef" as *u8 44 let line: *u8 = sys_mmap(2*n + 2) 45 var i: i64 = 0 46 while i < n { 47 line[i*2] = hx[((b[i] as i64) >> 4) & 15] 48 line[i*2+1] = hx[(b[i] as i64) & 15] 49 i = i + 1 50 } 51 line[2*n] = 10 as u8 52 sys_write(1, line, 2*n + 1) 53 return 0 54} 55 56// shared fixed inputs (identical across C.1.5 and C.1.6) 57struct OkVec { 58 oprf_seed: *u8 59 cred_id: *u8 // "1234" 60 password: *u8 // 25 bytes 61 password_n: i64 62 envelope_nonce: *u8 63 masking_nonce: *u8 64 server_priv: *u8 65 server_pub: *u8 66 server_nonce: *u8 67 client_nonce: *u8 68 client_ks_seed: *u8 69 server_ks_seed: *u8 70 blind_reg: *u8 71 blind_login: *u8 72 context: *u8 // "OPAQUE-POC" (10) 73} 74 75func ok_load_inputs(v: *OkVec) -> i64 { 76 v.oprf_seed = sys_mmap(32) 77 ok_hex("62f60b286d20ce4fd1d64809b0021dad6ed5d52a2c8cf27ae6582543a0a8dce2" as *u8, v.oprf_seed) 78 v.cred_id = "1234" as *u8 79 v.password = sys_mmap(32) 80 v.password_n = ok_hex("436f7272656374486f72736542617474657279537461706c65" as *u8, v.password) 81 v.envelope_nonce = sys_mmap(32) 82 ok_hex("a921f2a014513bd8a90e477a629794e89fec12d12206dde662ebdcf65670e51f" as *u8, v.envelope_nonce) 83 v.masking_nonce = sys_mmap(32) 84 ok_hex("38fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80f612fdfc6d" as *u8, v.masking_nonce) 85 v.server_priv = sys_mmap(32) 86 ok_hex("c36139381df63bfc91c850db0b9cfbec7a62e86d80040a41aa7725bf0e79d5e5" as *u8, v.server_priv) 87 v.server_pub = sys_mmap(33) 88 ok_hex("035f40ff9cf88aa1f5cd4fe5fd3da9ea65a4923a5594f84fd9f2092d6067784874" as *u8, v.server_pub) 89 v.server_nonce = sys_mmap(32) 90 ok_hex("71cd9960ecef2fe0d0f7494986fa3d8b2bb01963537e60efb13981e138e3d4a1" as *u8, v.server_nonce) 91 v.client_nonce = sys_mmap(32) 92 ok_hex("ab3d33bde0e93eda72392346a7a73051110674bbf6b1b7ffab8be4f91fdaeeb1" as *u8, v.client_nonce) 93 v.client_ks_seed = sys_mmap(32) 94 ok_hex("633b875d74d1556d2a2789309972b06db21dfcc4f5ad51d7e74d783b7cfab8dc" as *u8, v.client_ks_seed) 95 v.server_ks_seed = sys_mmap(32) 96 ok_hex("05a4f54206eef1ba2f615bc0aa285cb22f26d1153b5b40a1e85ff80da12f982f" as *u8, v.server_ks_seed) 97 v.blind_reg = sys_mmap(32) 98 ok_hex("411bf1a62d119afe30df682b91a0a33d777972d4f2daa4b34ca527d597078153" as *u8, v.blind_reg) 99 v.blind_login = sys_mmap(32) 100 ok_hex("c497fddf6056d241e6cf9fb7ac37c384f49b357a221eb0a802c989b9942256c1" as *u8, v.blind_login) 101 v.context = sys_mmap(16) 102 ok_hex("4f50415155452d504f43" as *u8, v.context) 103 return 0 104} 105 106func ok_mk_ccfg(v: *OkVec, client_id: *u8, client_id_n: i64, server_id: *u8, server_id_n: i64) -> *NxOpqClientCfg { 107 let c: *NxOpqClientCfg = sys_mmap(80) as *NxOpqClientCfg 108 c.server_id = server_id 109 c.server_id_n = server_id_n 110 c.client_id = client_id 111 c.client_id_n = client_id_n 112 c.context = v.context 113 c.context_n = 10 114 c.ksf_mode = NX_OPQ_KSF_IDENTITY 115 c.ksf_m_kib = 0 116 c.ksf_t = 0 117 return c 118} 119 120func ok_mk_scfg(v: *OkVec, server_id: *u8, server_id_n: i64) -> *NxOpqServerCfg { 121 let s: *NxOpqServerCfg = sys_mmap(64) as *NxOpqServerCfg 122 s.server_priv_32 = v.server_priv 123 s.server_pub_33 = v.server_pub 124 s.oprf_seed_32 = v.oprf_seed 125 s.server_id = server_id 126 s.server_id_n = server_id_n 127 s.context = v.context 128 s.context_n = 10 129 return s 130} 131 132// run one full vector (registration + login). wants are the expected outputs. 133// returns number of failures; prints a FAIL line per mismatch tagged `tag`. 134func ok_run_vector( 135 v: *OkVec, 136 ccfg: *NxOpqClientCfg, scfg: *NxOpqServerCfg, 137 client_id: *u8, client_id_n: i64, 138 want_upload_129: *u8, want_ke2_259: *u8, want_ke3_32: *u8, 139 want_export_32: *u8, want_session_32: *u8, 140 tag: *u8 141) -> i64 { 142 var bad: i64 = 0 143 144 // --- registration --- 145 let req: *u8 = sys_mmap(33) 146 if nx_opaque_create_registration_request_det(v.password, v.password_n, v.blind_reg, req) != NX_OPQ_OK { 147 ok_w("FAIL reg_request rc " as *u8); ok_w(tag); ok_w("\n" as *u8); return 1 148 } 149 let want_req: *u8 = sys_mmap(33) 150 ok_hex("029e949a29cfa0bf7c1287333d2fb3dc586c41aa652f5070d26a5315a1b50229f8" as *u8, want_req) 151 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) } 152 153 let resp: *u8 = sys_mmap(66) 154 if nx_opaque_create_registration_response(req, v.server_pub, v.cred_id, 4, v.oprf_seed, resp) != NX_OPQ_OK { 155 ok_w("FAIL reg_response rc " as *u8); ok_w(tag); ok_w("\n" as *u8); return bad + 1 156 } 157 let want_resp: *u8 = sys_mmap(66) 158 ok_hex("0350d3694c00978f00a5ce7cd08a00547e4ab5fb5fc2b2f6717cdaa6c89136efef035f40ff9cf88aa1f5cd4fe5fd3da9ea65a4923a5594f84fd9f2092d6067784874" as *u8, want_resp) 159 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) } 160 161 let record: *u8 = sys_mmap(129) 162 let export1: *u8 = sys_mmap(32) 163 if nx_opaque_finalize_registration_det(ccfg, v.password, v.password_n, v.blind_reg, resp, v.envelope_nonce, record, export1) != NX_OPQ_OK { 164 ok_w("FAIL finalize_reg rc " as *u8); ok_w(tag); ok_w("\n" as *u8); return bad + 1 165 } 166 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) } 167 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) } 168 169 // --- login --- 170 let ke1: *u8 = sys_mmap(98) 171 let client_secret: *u8 = sys_mmap(32) 172 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 { 173 ok_w("FAIL ke1 rc " as *u8); ok_w(tag); ok_w("\n" as *u8); return bad + 1 174 } 175 let want_ke1: *u8 = sys_mmap(98) 176 ok_hex("037342f0bcb3ecea754c1e67576c86aa90c1de3875f390ad599a26686cdfee6e07ab3d33bde0e93eda72392346a7a73051110674bbf6b1b7ffab8be4f91fdaeeb1022ed3f32f318f81bab80da321fecab3cd9b6eea11a95666dfa6beeaab321280b6" as *u8, want_ke1) 177 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) } 178 179 let ke2: *u8 = sys_mmap(259) 180 let expected_cmac: *u8 = sys_mmap(32) 181 let session_s: *u8 = sys_mmap(32) 182 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 { 183 ok_w("FAIL ke2 rc " as *u8); ok_w(tag); ok_w("\n" as *u8); return bad + 1 184 } 185 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) } 186 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) } 187 188 let ke3: *u8 = sys_mmap(32) 189 let session_c: *u8 = sys_mmap(32) 190 let export2: *u8 = sys_mmap(32) 191 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 { 192 ok_w("FAIL ke3 rc " as *u8); ok_w(tag); ok_w("\n" as *u8); return bad + 1 193 } 194 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) } 195 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) } 196 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) } 197 if nx_opaque_server_finish(ke3, expected_cmac) != NX_OPQ_OK { 198 bad = bad + 1; ok_w("FAIL server_finish " as *u8); ok_w(tag); ok_w("\n" as *u8) 199 } 200 201 // --- negative: wrong password fails at envelope recovery --- 202 let wrong_pw: *u8 = sys_mmap(32) 203 var wp: i64 = 0 204 while wp < v.password_n { wrong_pw[wp] = v.password[wp]; wp = wp + 1 } 205 wrong_pw[0] = ((wrong_pw[0] as i64) ^ 1) as u8 206 let ke1w: *u8 = sys_mmap(98) 207 let csw: *u8 = sys_mmap(32) 208 nx_opaque_generate_ke1_det(wrong_pw, v.password_n, v.blind_login, v.client_nonce, v.client_ks_seed, ke1w, csw) 209 let ke2w: *u8 = sys_mmap(259) 210 let ecmw: *u8 = sys_mmap(32) 211 let ssw: *u8 = sys_mmap(32) 212 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) 213 let ke3w: *u8 = sys_mmap(32) 214 let scw: *u8 = sys_mmap(32) 215 let exw: *u8 = sys_mmap(32) 216 let rc_wrong: i64 = nx_opaque_generate_ke3(ccfg, wrong_pw, v.password_n, v.blind_login, csw, ke1w, ke2w, ke3w, scw, exw) 217 if rc_wrong != (0 - NX_OPQ_ENVELOPE_AUTH_FAIL) { 218 bad = bad + 1; ok_w("FAIL wrong-password not rejected " as *u8); ok_w(tag); ok_w("\n" as *u8) 219 } 220 221 // --- negative: tampered server_mac rejected by client --- 222 let ke2t: *u8 = sys_mmap(259) 223 var t: i64 = 0 224 while t < 259 { ke2t[t] = ke2[t]; t = t + 1 } 225 ke2t[227] = ((ke2t[227] as i64) ^ 1) as u8 226 let ke3t: *u8 = sys_mmap(32) 227 let sct: *u8 = sys_mmap(32) 228 let ext: *u8 = sys_mmap(32) 229 let rc_smac: i64 = nx_opaque_generate_ke3(ccfg, v.password, v.password_n, v.blind_login, client_secret, ke1, ke2t, ke3t, sct, ext) 230 if rc_smac != (0 - NX_OPQ_SERVER_AUTH_FAIL) { 231 bad = bad + 1; ok_w("FAIL tampered server_mac not rejected " as *u8); ok_w(tag); ok_w("\n" as *u8) 232 } 233 234 // --- negative: tampered client_mac rejected by server --- 235 let ke3x: *u8 = sys_mmap(32) 236 var x: i64 = 0 237 while x < 32 { ke3x[x] = ke3[x]; x = x + 1 } 238 ke3x[0] = ((ke3x[0] as i64) ^ 1) as u8 239 if nx_opaque_server_finish(ke3x, expected_cmac) != (0 - NX_OPQ_CLIENT_AUTH_FAIL) { 240 bad = bad + 1; ok_w("FAIL tampered KE3 not rejected " as *u8); ok_w(tag); ok_w("\n" as *u8) 241 } 242 243 return bad 244} 245 246// production-randomness round trip: CSPRNG wrappers end to end, fresh keys. 247func ok_run_random_roundtrip(v: *OkVec) -> i64 { 248 var bad: i64 = 0 249 let ccfg: *NxOpqClientCfg = ok_mk_ccfg(v, 0 as *u8, 0, 0 as *u8, 0) 250 let scfg: *NxOpqServerCfg = ok_mk_scfg(v, 0 as *u8, 0) 251 252 let blind_r: *u8 = sys_mmap(32) 253 let req: *u8 = sys_mmap(33) 254 if nx_opaque_create_registration_request(v.password, v.password_n, blind_r, req) != NX_OPQ_OK { return 1 } 255 let resp: *u8 = sys_mmap(66) 256 if nx_opaque_create_registration_response(req, v.server_pub, v.cred_id, 4, v.oprf_seed, resp) != NX_OPQ_OK { return 1 } 257 let record: *u8 = sys_mmap(129) 258 let export1: *u8 = sys_mmap(32) 259 if nx_opaque_finalize_registration(ccfg, v.password, v.password_n, blind_r, resp, record, export1) != NX_OPQ_OK { return 1 } 260 261 let blind_l: *u8 = sys_mmap(32) 262 let ke1: *u8 = sys_mmap(98) 263 let cs: *u8 = sys_mmap(32) 264 if nx_opaque_generate_ke1(v.password, v.password_n, blind_l, ke1, cs) != NX_OPQ_OK { return 1 } 265 let ke2: *u8 = sys_mmap(259) 266 let ecm: *u8 = sys_mmap(32) 267 let ss: *u8 = sys_mmap(32) 268 if nx_opaque_generate_ke2(scfg, record, v.cred_id, 4, 0 as *u8, 0, ke1, ke2, ecm, ss) != NX_OPQ_OK { return 1 } 269 let ke3: *u8 = sys_mmap(32) 270 let sc: *u8 = sys_mmap(32) 271 let export2: *u8 = sys_mmap(32) 272 if nx_opaque_generate_ke3(ccfg, v.password, v.password_n, blind_l, cs, ke1, ke2, ke3, sc, export2) != NX_OPQ_OK { return 1 } 273 if nx_opaque_server_finish(ke3, ecm) != NX_OPQ_OK { bad = bad + 1; ok_w("FAIL rnd server_finish\n" as *u8) } 274 if ok_eq(sc, ss, 32) == 0 { bad = bad + 1; ok_w("FAIL rnd session keys differ\n" as *u8) } 275 if ok_eq(export1, export2, 32) == 0 { bad = bad + 1; ok_w("FAIL rnd export keys differ\n" as *u8) } 276 return bad 277} 278 279func main() -> i64 { 280 let v: *OkVec = sys_mmap(160) as *OkVec 281 ok_load_inputs(v) 282 var bad: i64 = 0 283 284 // ===== Vector C.1.5: default identities ===== 285 let up5: *u8 = sys_mmap(129) 286 ok_hex("03b218507d978c3db570ca994aaf36695a731ddb2db272c817f79746fc37ae52147f0ed53532d3ae8e505ecc70d42d2b814b6b0e48156def71ea029148b2803aafa921f2a014513bd8a90e477a629794e89fec12d12206dde662ebdcf65670e51fad30bbcfc1f8eda0211553ab9aaf26345ad59a128e80188f035fe4924fad67b8" as *u8, up5) 287 let ke2_5: *u8 = sys_mmap(259) 288 ok_hex("0246da9fe4d41d5ba69faa6c509a1d5bafd49a48615a47a8dd4b0823cc1476481138fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80f612fdfc6d2f0c547f70deaeca54d878c14c1aa5e1ab405dec833777132eea905c2fbb12504a67dcbe0e66740c76b62c13b04a38a77926e19072953319ec65e41f9bfd2ae26837b6ce688bf9af2542f04eec9ab96a1b9328812dc2f5c89182ed47fead61f09f71cd9960ecef2fe0d0f7494986fa3d8b2bb01963537e60efb13981e138e3d4a103c1701353219b53acf337bf6456a83cefed8f563f1040b65afbf3b65d3bc9a19b50a73b145bc87a157e8c58c0342e2047ee22ae37b63db17e0a82a30fcc4ecf7b" as *u8, ke2_5) 289 let ke3_5: *u8 = sys_mmap(32) 290 ok_hex("e97cab4433aa39d598e76f13e768bba61c682947bdcf9936035e8a3a3ebfb66e" as *u8, ke3_5) 291 let ex5: *u8 = sys_mmap(32) 292 ok_hex("c3c9a1b0e33ac84dd83d0b7e8af6794e17e7a3caadff289fbd9dc769a853c64b" as *u8, ex5) 293 let ses5: *u8 = sys_mmap(32) 294 ok_hex("484ad345715ccce138ca49e4ea362c6183f0949aaaa1125dc3bc3f80876e7cd1" as *u8, ses5) 295 let ccfg5: *NxOpqClientCfg = ok_mk_ccfg(v, 0 as *u8, 0, 0 as *u8, 0) 296 let scfg5: *NxOpqServerCfg = ok_mk_scfg(v, 0 as *u8, 0) 297 let b5: i64 = ok_run_vector(v, ccfg5, scfg5, 0 as *u8, 0, up5, ke2_5, ke3_5, ex5, ses5, "[C.1.5]" as *u8) 298 bad = bad + b5 299 300 // ===== Vector C.1.6: identities alice/bob ===== 301 let alice: *u8 = "alice" as *u8 302 let bob: *u8 = "bob" as *u8 303 let up6: *u8 = sys_mmap(129) 304 ok_hex("03b218507d978c3db570ca994aaf36695a731ddb2db272c817f79746fc37ae52147f0ed53532d3ae8e505ecc70d42d2b814b6b0e48156def71ea029148b2803aafa921f2a014513bd8a90e477a629794e89fec12d12206dde662ebdcf65670e51f4d7773a36a208a866301dbb2858e40dc5638017527cf91aef32d3848eebe0971" as *u8, up6) 305 let ke2_6: *u8 = sys_mmap(259) 306 ok_hex("0246da9fe4d41d5ba69faa6c509a1d5bafd49a48615a47a8dd4b0823cc1476481138fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80f612fdfc6d2f0c547f70deaeca54d878c14c1aa5e1ab405dec833777132eea905c2fbb12504a67dcbe0e66740c76b62c13b04a38a77926e19072953319ec65e41f9bfd2ae268d7f106042021c80300e4c6f585980cf39fc51a4a6bba41b0729f9b240c729e5671cd9960ecef2fe0d0f7494986fa3d8b2bb01963537e60efb13981e138e3d4a103c1701353219b53acf337bf6456a83cefed8f563f1040b65afbf3b65d3bc9a19b84922c7e5d074838a8f278592c53f61fb59f031e85ad480c0c71086b871e1b24" as *u8, ke2_6) 307 let ke3_6: *u8 = sys_mmap(32) 308 ok_hex("46833578cee137775f6be3f01b80748daac5a694101ad0e9e7025480552da56a" as *u8, ke3_6) 309 let ses6: *u8 = sys_mmap(32) 310 ok_hex("27766fabd8dd88ff37fbd0ef1a491e601d10d9f016c2b28c4bd1b0fb7511a3c3" as *u8, ses6) 311 let ccfg6: *NxOpqClientCfg = ok_mk_ccfg(v, alice, 5, bob, 3) 312 let scfg6: *NxOpqServerCfg = ok_mk_scfg(v, bob, 3) 313 let b6: i64 = ok_run_vector(v, ccfg6, scfg6, alice, 5, up6, ke2_6, ke3_6, ex5, ses6, "[C.1.6]" as *u8) 314 bad = bad + b6 315 316 // ===== production-randomness round trip ===== 317 let br: i64 = ok_run_random_roundtrip(v) 318 bad = bad + br 319 320 // gate base class: every vector is a named tooth, the exit code carries the verdict, the 321 // canonical 'passed N/M verdict=' line is LAST (gv_last_line anchors by position). The old 322 // hand-rolled GREEN/FAILED lines printed no canonical verdict, so the compare referee read 323 // this KAT as VACUOUS (pass=0/0) and the deploy board could never prove its OPAQUE claim. 324 let ctr: *i64 = gv_ctr() 325 var t5: i64 = 0 326 if b5 == 0 { t5 = 1 } 327 gv_check("T1 RFC 9807 C.1.5 default identities: registration/KE1/KE2/KE3/export/session byte-exact + wrong-password + 2 tamper rejections (the RFC's own vectors, not ours)" as *u8, t5, ctr) 328 var t6: i64 = 0 329 if b6 == 0 { t6 = 1 } 330 gv_check("T2 RFC 9807 C.1.6 explicit identities alice/bob: byte-exact + wrong-password + 2 tamper rejections" as *u8, t6, ctr) 331 var t7: i64 = 0 332 if br == 0 { t7 = 1 } 333 gv_check("T3 production-randomness round trip: client and server session keys agree, register and login export keys agree" as *u8, t7, ctr) 334 return gv_verdict("OPAQUE-RFC9807-KAT" as *u8, ctr, "exit carries the verdict; each tooth names its RFC vector" as *u8) 335}