nx_shani_block_probe.nx source
↩ module page · 122 lines · 4423 B
1// nx_shani_block_probe.nx -- BLOCK-LEVEL oracle probe for the SHA-NI intrinsic.
2//
3// Validates __sha256_ni_block (hardware SHA extension) against the software
4// sha256_compress on the SAME single 64-byte block, for several blocks. This is the
5// bit-exact correctness gate that must pass BEFORE the mainline sha256_compress is
6// routed through the intrinsic. Software path is the ORACLE.
7//
8// exit 0 = every block's NI result matches the software result word-for-word.
9// nonzero = first mismatch (encodes which block / which word).
10//
11// expect_exit: 0
12// license_tier: ORIGINAL
13
14import "nx_syscalls.nx"
15import "nx_sha256.nx"
16const K_MAGIC_1103515245: i64 = 1103515245
17const K_MAGIC_12345: i64 = 12345
18
19// 32-bit words are stored as i32 (4 bytes); SHA-256 word bit-patterns are sign-agnostic,
20// and the hardware loads/stores raw 128-bit lanes regardless of signedness.
21
22// Run ONE software block compression: seed a ctx with the SHA-256 IV, load the 64-byte
23// block, call sha256_compress, write the 8 resulting words (as u32 values) to out8.
24func sw_block(block: *u8, out8: *i64) -> i64 {
25 let ctx_raw: *u8 = sys_mmap(256)
26 let c: *Sha256 = ctx_raw as *Sha256
27 sha256_init(c) // sets IV + allocates bufptr/kptr/wptr
28 let bp: *u8 = c.bufptr as *u8
29 var i: i64 = 0
30 while i < 64 { bp[i] = block[i]; i = i + 1 }
31 sha256_compress(c)
32 out8[0] = c.h0; out8[1] = c.h1; out8[2] = c.h2; out8[3] = c.h3
33 out8[4] = c.h4; out8[5] = c.h5; out8[6] = c.h6; out8[7] = c.h7
34 return 0
35}
36
37// Build a 64-word (256-byte) K table as CONTIGUOUS i32, from sha256_k().
38func build_k32(k32: *i32) -> i64 {
39 var i: i64 = 0
40 while i < 64 { k32[i] = (sha256_k(i) & 0xFFFFFFFF) as i32; i = i + 1 }
41 return 0
42}
43
44// Run ONE hardware-SHA-NI block: state8 seeded to the IV, call __sha256_ni_block, read back.
45func ni_block(block: *u8, k32: *i32, out8: *i64) -> i64 {
46 let st_raw: *u8 = sys_mmap(64)
47 let st: *i32 = st_raw as *i32
48 // SHA-256 IV (FIPS 180-4 5.3.3), as 8 contiguous i32 h0..h7.
49 st[0] = 0x6a09e667 as i32; st[1] = 0xbb67ae85 as i32
50 st[2] = 0x3c6ef372 as i32; st[3] = 0xa54ff53a as i32
51 st[4] = 0x510e527f as i32; st[5] = 0x9b05688c as i32
52 st[6] = 0x1f83d9ab as i32; st[7] = 0x5be0cd19 as i32
53 let _r: i64 = __sha256_ni_block(st_raw, block, k32 as *u8)
54 var i: i64 = 0
55 while i < 8 { out8[i] = (st[i] as i64) & 0xFFFFFFFF; i = i + 1 }
56 return 0
57}
58
59// Compare one block; return 0 if match, else (block_tag*10 + word_index + 1).
60func check_block(block: *u8, k32: *i32, tag: i64) -> i64 {
61 let sw: *i64 = sys_mmap(64) as *i64
62 let ni: *i64 = sys_mmap(64) as *i64
63 sw_block(block, sw)
64 ni_block(block, k32, ni)
65 var i: i64 = 0
66 while i < 8 {
67 if (sw[i] & 0xFFFFFFFF) != (ni[i] & 0xFFFFFFFF) {
68 return tag * 10 + i + 1
69 }
70 i = i + 1
71 }
72 return 0
73}
74
75func main() -> i64 {
76 let k32: *i32 = sys_mmap(256) as *i32
77 build_k32(k32)
78
79 // Block A: the "abc" padded block -- 'a''b''c' 0x80 then zeros, length=24 bits at the end.
80 let a: *u8 = sys_mmap(64)
81 var i: i64 = 0
82 while i < 64 { a[i] = 0 as u8; i = i + 1 }
83 a[0] = 0x61 as u8; a[1] = 0x62 as u8; a[2] = 0x63 as u8; a[3] = 0x80 as u8
84 a[63] = 0x18 as u8 // bit length = 24
85 let ra: i64 = check_block(a, k32, 1)
86 if ra != 0 { return ra }
87
88 // Block B: all zero bytes.
89 let b: *u8 = sys_mmap(64)
90 i = 0
91 while i < 64 { b[i] = 0 as u8; i = i + 1 }
92 let rb: i64 = check_block(b, k32, 2)
93 if rb != 0 { return rb }
94
95 // Block C: 0x00,0x01,...,0x3f (every byte distinct) -- exercises all message lanes.
96 let cc: *u8 = sys_mmap(64)
97 i = 0
98 while i < 64 { cc[i] = (i & 0xff) as u8; i = i + 1 }
99 let rc: i64 = check_block(cc, k32, 3)
100 if rc != 0 { return rc }
101
102 // Block D: 0xff everywhere -- high-bit / carry stress.
103 let d: *u8 = sys_mmap(64)
104 i = 0
105 while i < 64 { d[i] = 0xff as u8; i = i + 1 }
106 let rd: i64 = check_block(d, k32, 4)
107 if rd != 0 { return rd }
108
109 // Block E: a pseudo-random-ish pattern (LCG) -- broad coverage.
110 let e: *u8 = sys_mmap(64)
111 var x: i64 = 0x12345678
112 i = 0
113 while i < 64 {
114 x = (x * K_MAGIC_1103515245 + K_MAGIC_12345) & 0xFFFFFFFF
115 e[i] = ((x >> 16) & 0xff) as u8
116 i = i + 1
117 }
118 let re: i64 = check_block(e, k32, 5)
119 if re != 0 { return re }
120
121 return 0
122}