code wiki / (root) / nx_ghash_clmul_gate.nx

nx_ghash_clmul_gate.nx source

↩ module page · 92 lines · 3771 B

1// nx_ghash_clmul_gate.nx -- KAT-equality gate: the PCLMULQDQ GHASH backend 2// (nx_ghash_mul_clmul) must be BYTE-IDENTICAL to the canonical bit-by-bit reference 3// (nx_ghash_mul) on the NIST vector, edge cases, and many pseudo-random inputs. 4// The bit-by-bit reference is the trusted oracle. Any mismatch fails LOUD with a code. 5// 6// expect_exit: 0 7// license_tier: ORIGINAL 8 9import "nx_syscalls.nx" 10import "nx_ghash.nx" 11import "nx_ghash_clmul.nx" 12 13func g_ps(s: *u8, n: i64) -> i64 { sys_write(1, s, n); return 0 } 14func g_pn(v: i64) -> i64 { 15 let b: *u8 = sys_mmap(24); var x: i64 = v 16 if x < 0 { x = 0 - x } 17 var i: i64 = 22 18 if x == 0 { b[i] = 0x30 as u8; i = i - 1 } 19 else { while x > 0 { b[i] = (0x30 + (x - (x/10)*10)) as u8; x = x/10; i = i - 1 } } 20 sys_write(1, ((b as i64) + i + 1) as *u8, 22 - i); return 0 21} 22 23// compare two 16-byte buffers: 0 = equal, else (1 + first differing index) 24func eq16(a: *u8, b: *u8) -> i64 { 25 var i: i64 = 0 26 while i < 16 { if (a[i] & 0xff) != (b[i] & 0xff) { return 1 + i } i = i + 1 } 27 return 0 28} 29 30// one mul both ways; return 0 if identical, else nonzero. 31// Oracle = the bit-by-bit reference (nx_ghash_mul now delegates to clmul, so we must 32// call the _bitwise reference directly or the comparison would be clmul-vs-clmul). 33func check(x: *u8, h: *u8, zr: *u8, zc: *u8) -> i64 { 34 nx_ghash_mul_bitwise(x, h, zr) 35 nx_ghash_mul_clmul(x, h, zc) 36 return eq16(zr, zc) 37} 38 39func main() -> i64 { 40 let x: *u8 = sys_mmap(16) 41 let h: *u8 = sys_mmap(16) 42 let zr: *u8 = sys_mmap(16) 43 let zc: *u8 = sys_mmap(16) 44 var i: i64 = 0 45 46 // --- edge: x = 0 -> product 0 --- 47 i = 0; while i < 16 { x[i] = 0; h[i] = (i * 7 + 3) as u8; i = i + 1 } 48 if check(x, h, zr, zc) != 0 { g_ps("FAIL x=0\n" as *u8, 8); sys_exit(1); return 1 } 49 50 // --- edge: h = 0 -> product 0 --- 51 i = 0; while i < 16 { x[i] = (i * 5 + 1) as u8; h[i] = 0; i = i + 1 } 52 if check(x, h, zr, zc) != 0 { g_ps("FAIL h=0\n" as *u8, 8); sys_exit(2); return 2 } 53 54 // --- edge: all-ones (exercises the reduction overflow path) --- 55 i = 0; while i < 16 { x[i] = 0xff as u8; h[i] = 0xff as u8; i = i + 1 } 56 if check(x, h, zr, zc) != 0 { g_ps("FAIL all-ones\n" as *u8, 13); sys_exit(3); return 3 } 57 58 // --- NIST SP 800-38D Test Case 2: H and C --- 59 h[0]=0x66; h[1]=0xe9; h[2]=0x4b; h[3]=0xd4; h[4]=0xef; h[5]=0x8a; h[6]=0x2c; h[7]=0x3b 60 h[8]=0x88; h[9]=0x4c; h[10]=0xfa; h[11]=0x59; h[12]=0xca; h[13]=0x34; h[14]=0x2b; h[15]=0x2e 61 x[0]=0x03; x[1]=0x88; x[2]=0xda; x[3]=0xce; x[4]=0x60; x[5]=0xb6; x[6]=0xa3; x[7]=0x92 62 x[8]=0xf3; x[9]=0x28; x[10]=0xc2; x[11]=0xb9; x[12]=0x71; x[13]=0xb2; x[14]=0xfe; x[15]=0x78 63 if check(x, h, zr, zc) != 0 { g_ps("FAIL NIST-vec\n" as *u8, 13); sys_exit(4); return 4 } 64 65 // --- many pseudo-random pairs (LCG, deterministic) --- 66 var st: i64 = 0x123456789abcdef 67 var n: i64 = 0 68 let N: i64 = 2000 69 while n < N { 70 i = 0 71 while i < 16 { 72 st = st * 6364136223846793005 + 1442695040888963407 73 x[i] = (gh_byte_from(st, 0)) as u8 74 st = st * 6364136223846793005 + 1442695040888963407 75 h[i] = (gh_byte_from(st, 1)) as u8 76 i = i + 1 77 } 78 let r: i64 = check(x, h, zr, zc) 79 if r != 0 { g_ps("FAIL rand n=" as *u8, 11); g_pn(n); g_ps(" idx=" as *u8, 5); g_pn(r - 1); g_ps("\n" as *u8, 1); sys_exit(5); return 5 } 80 n = n + 1 81 } 82 83 g_ps("ghash-clmul == reference: " as *u8, 26); g_pn(N + 4); g_ps(" vectors OK\n" as *u8, 12) 84 sys_exit(0) 85 return 0 86} 87 88// extract a byte from LCG state (different slices for x vs h to decorrelate) 89func gh_byte_from(st: i64, which: i64) -> i64 { 90 if which == 0 { return (st >> 40) & 0xff } 91 return (st >> 24) & 0xff 92}