nx_mlkem_kat_gate.nx source
↩ module page · 57 lines · 5066 B
1// nx_mlkem_kat_gate.nx -- FIPS-203 INTEROP KAT for the real ML-KEM-768 (nx_ml_kem_768_wasm.nx).
2// Unlike the round-trip gate (self-consistency only), this proves the impl matches the NIST ACVP
3// FIPS-203 ML-KEM-768 keyGen vector BYTE-EXACT: KeyGen(d||z) -> ek must equal NIST's expected ek.
4// Vector = NIST usnistgov/ACVP-Server ML-KEM-keyGen-FIPS203 tgId 2 (ML-KEM-768) tcId 26, fetched
5// sovereignly via nx_https_get_cli. This is F-sec-04.0 -- the interop gate that must pass before PQ
6// is wired into TLS. RED if the impl diverges from the standard (never a false-green). license_tier: ORIGINAL
7import "nx_syscalls.nx"
8import "nx_ml_kem_768_wasm.nx"
9
10func kw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
11func kn(v: i64) -> i64 {
12 if v==0 { sys_write(1,"0" as *u8,1); return 0 }
13 var m: i64=v; if m<0 { sys_write(1,"-" as *u8,1); m=0-m }
14 let t: *u8=sys_mmap(24); var k: i64=0
15 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
16 let o: *u8=sys_mmap(24); var w: i64=0; var q: i64=k-1
17 while q>=0 { o[w]=t[q]; w=w+1; q=q-1 }
18 sys_write(1,o,w); return 0
19}
20func hexnib(c: u8) -> i64 {
21 let v: i64=c as i64
22 if v>=48 { if v<=57 { return v-48 } }
23 if v>=65 { if v<=70 { return v-55 } }
24 if v>=97 { if v<=102 { return v-87 } }
25 return 0
26}
27func hexdec(hex: *u8, out: *u8, nbytes: i64) -> i64 {
28 var i: i64=0
29 while i<nbytes { out[i]=(((hexnib(hex[i*2]) << 4) | hexnib(hex[i*2+1]))) as u8; i=i+1 }
30 return 0
31}
32
33func main() -> i64 {
34 let seed: *u8 = sys_mmap(64)
35 let scratch: *u8 = sys_mmap(131072)
36 let ek: *u8 = sys_mmap(1184)
37 let dk: *u8 = sys_mmap(2400)
38 let exp: *u8 = sys_mmap(1184)
39 // tcId 26 seed = d || z (FIPS-203 KeyGen_internal inputs)
40 hexdec("E582B7D75E6C80B05AE392A1FC9F7153B12390FD99930368CC67A768BAEBC8A01CDACB8740C0B87C4A379575F187B367CBFA3B300BF591B109F79816E9CBE8F0" as *u8, seed, 64)
41 // tcId 26 expected encapsulation key (ek), 1184 bytes
42 hexdec("28C793778741B80B02B4339F2AA4347255B099F17264E1B8CC0A2C7C2A1A79F7997B907FD0496C6E6C8AD7714F5F339D75F11F625591A869BE1175AE47F05FD4313468232BA6957D7807B824F445AC99A0D568AB1AD54DCA8249D1482E61275F52248C77F61A4248753188CD1794CD0A465EC0DC4B025985C461B74E76286E4C37E77405695CC9FD0654374B427A20343AEC0FF1A187768273BFC4905472A1DA387F14559D6CE87313F6A5B6138434539F9A13684055B177E543F8B40F432ABD7CC49989A50A9084C660913F45A8593B17499BC4CF936C2BC1851421CB986808A0EF30AFE97AAB5B8B8EB3F0B3506A95B91563A0E57DB7231044987EF141BDAB3537C316AD16F17805A81F29329879A94E96157E4B7447F7D59603B21BD896CC47B7CD4E232322EB9C5D2215696BCFFCA3A04EFCC4C5D9CC39AC9A6E8700D38C244B0169E7FA1FE81B4B10365E74E6A1F7F756D11ACDC84043F81006D62995376C22535958FEB53F78117EE0F61C4C862640D06DC57A2B8BE62A41A642AF3BC63F6BAC98BBBBFF70570F37B8F8D9572F2735657A6C98F96CAF57A849868720B2640B8BB2732237A1F984C18872D10289CE43C952C9257E06529AEB76AFD127B17596FD25C5216C9CABD9B18EFC50E87BBB04568BB7D5C4E9288C006483AF5912E19108573700BD10CD77224B80659EA75AA74270B33AC4008B738BFEE271E78658C8742FF13C96AD0781A03C7576CA26DD58B52980BA58C0505E446AFA140CDCEA0490DB1F9B18815D4314B2459CACC562441C91F4084E5426C88E632CF7482E79907911D06473260835D7B85E7856A829AEA0381707B939CE86882CC09C4448C6AE94A9C303107C5667EEFB8DF7763CC21189A3C590C40AA51F491503A7935EC08F4FC300CBE607ED8C9100C29FBF45584B13C8D780069337AEC76C36CEB70373E2AB6E7B934B466F53FB32EAF040055496B8540E23A2A277E534468608D5EC0F8D38CEA5BBB806C1BF4F164F6AC826FE733F95461E29DCC11200C0AADA1B8332023EAB329718CE25CC0A09555903F3578BBC863B1752CA94365DA556DF54C3B7E05CBB7115FBC1B6C57A172C31B9906560C8FB54F3C563A2256CC073243B8179B4A28D60E086CF51082EE429272996F0AABE03BA0EAFD3C8E7D954BD0933E2F60ED0C32CEDE7B820A28E48F3CA3C40913CCCAE2337ABFC59843F08C9863325D65A4E9E15C1F46172B118B2B5EB0F1D5158A00134F27B085488C3A0621FE4E5678698250FB74EE5152E3E35A66544A05D279EA99131FBC15165060B90F88EEB7B20892A4DE4CB1683495BD7DA037966B47CC040F1764C5DEB06B5499D4267391CEBBB47F734D8539E39528436A1858182854BF20B1F93279AFB706464C65CCC5AE099B37CC03556C26ABF4C3F8B9BA3A936707211A49A59B268F5284F7970C77612719450377417428C4BA47C9CA115CF95304C4759C5D8859B44985C06A6C924689237BA320D610960D61C53E85431789E67A40113F167FF93429C264F6CABC95448C903437D39A6577BE0CF0012852AA476351A9046A110A1A625A3D74C910B78BCE9CFCA735E4F91B8A4C57DBE489E849446098AACF73070AEE638FCC8896473D3C159D3AFB4B687B40DFBF371A9C2644B605187B71A14BC4C8678FE8247" as *u8, exp, 1184)
43
44 let r: i64 = nx_mlkem_keygen(seed, scratch, ek, dk)
45 var diff: i64 = 0
46 var i: i64 = 0
47 while i < 1184 { if ek[i] != exp[i] { diff = diff + 1 } i = i + 1 }
48
49 kw("nx_mlkem_kat NIST ACVP FIPS-203 ML-KEM-768 keyGen tcId26: keygen_rc=" as *u8); kn(r)
50 kw(" ek_mismatch_bytes=" as *u8); kn(diff); kw("/1184\n" as *u8)
51 if r == 0 { if diff == 0 {
52 kw("GATE nx_mlkem_kat verdict=GREEN pass=1/1 (ek BYTE-EXACT vs NIST FIPS-203 vector -- interop-correct, not just round-trip)\n" as *u8)
53 sys_exit(0); return 0
54 } }
55 kw("GATE nx_mlkem_kat verdict=RED (impl output diverges from the NIST FIPS-203 standard vector)\n" as *u8)
56 sys_exit(1); return 1
57}