nx_crc32_kat.nx source
↩ module page · 105 lines · 4620 B
1// nx_crc32_kat.nx -- functional KAT for the hardware CRC-32C intrinsic
2// __crc32_u64 (x86 SSE4.2 crc32q). Two independent checks:
3//
4// (A) STANDARD CHECK VALUE: a software CRC-32C oracle (reflected poly
5// 0x82F63B78, init 0xFFFFFFFF, final XOR 0xFFFFFFFF) over the ASCII
6// string "123456789" must equal 0xE3069283 -- the world-standard
7// CRC-32C/iSCSI (Castagnoli) validation constant. This proves the
8// oracle's math is the real CRC-32C.
9//
10// (B) HARDWARE == ORACLE: the hardware __crc32_u64(crc, data) must match
11// a bit-identical software model of x86 crc32q (the same reflected
12// step, 64 bits LSB-first, NO init/final -- those are the software
13// convention) over a spread of (crc, data) inputs. Since (A) proves
14// the oracle IS CRC-32C and (B) proves hardware == oracle, the
15// hardware instruction is transitively validated against the standard.
16//
17// exit 0 = all cases correct.
18// license_tier: ORIGINAL
19
20const CRC32C_REFL_POLY: i64 = 0x82F63B78 // reflected CRC-32C polynomial
21
22// Software model of ONE x86 `crc32q` step: fold a 64-bit data word into the
23// 32-bit crc, reflected, 64 iterations LSB-first. No init, no final XOR --
24// exactly what the crc32q instruction computes.
25func sw_crc32q(crc_in: i64, data: i64) -> i64 {
26 var crc: i64 = crc_in & 0xFFFFFFFF
27 var i: i64 = 0
28 while i < 64 {
29 let dbit: i64 = (data >> i) & 1
30 let mix: i64 = (crc ^ dbit) & 1
31 crc = (crc >> 1) & 0x7FFFFFFF // 32-bit logical shift right
32 if mix == 1 { crc = crc ^ CRC32C_REFL_POLY }
33 i = i + 1
34 }
35 return crc & 0xFFFFFFFF
36}
37
38// Software model of ONE x86 `crc32b` step (fold a single byte): 8 iterations.
39// Used only to build the standard byte-wise check value in (A).
40func sw_crc32b(crc_in: i64, byte: i64) -> i64 {
41 var crc: i64 = crc_in & 0xFFFFFFFF
42 var i: i64 = 0
43 while i < 8 {
44 let dbit: i64 = (byte >> i) & 1
45 let mix: i64 = (crc ^ dbit) & 1
46 crc = (crc >> 1) & 0x7FFFFFFF
47 if mix == 1 { crc = crc ^ CRC32C_REFL_POLY }
48 i = i + 1
49 }
50 return crc & 0xFFFFFFFF
51}
52
53func main() -> i64 {
54 // ---- (A) STANDARD CHECK VALUE over "123456789" ----
55 // CRC-32C convention: init = 0xFFFFFFFF, fold each byte, final XOR 0xFFFFFFFF.
56 var c: i64 = 0xFFFFFFFF
57 c = sw_crc32b(c, 0x31) // '1'
58 c = sw_crc32b(c, 0x32) // '2'
59 c = sw_crc32b(c, 0x33) // '3'
60 c = sw_crc32b(c, 0x34) // '4'
61 c = sw_crc32b(c, 0x35) // '5'
62 c = sw_crc32b(c, 0x36) // '6'
63 c = sw_crc32b(c, 0x37) // '7'
64 c = sw_crc32b(c, 0x38) // '8'
65 c = sw_crc32b(c, 0x39) // '9'
66 let check: i64 = c ^ 0xFFFFFFFF
67 if check != 0xE3069283 { return 1 } // oracle math is genuine CRC-32C
68
69 // ---- (B) HARDWARE __crc32_u64 == software crc32q model ----
70 // Case b1: crc=0, data=0 -> both must be 0 (CRC of all-zero into 0 accumulator).
71 if __crc32_u64(0, 0) != sw_crc32q(0, 0) { return 2 }
72
73 // Case b2: crc=0xFFFFFFFF (standard init), data = the 8 bytes "12345678".
74 // "12345678" little-endian as a u64 = 0x3837363534333231.
75 let d8: i64 = 0x3837363534333231
76 if __crc32_u64(0xFFFFFFFF, d8) != sw_crc32q(0xFFFFFFFF, d8) { return 3 }
77
78 // Case b3: a spread of fixed vectors.
79 if __crc32_u64(0, 1) != sw_crc32q(0, 1) { return 4 }
80 if __crc32_u64(0x12345678, 0x9ABCDEF0) != sw_crc32q(0x12345678, 0x9ABCDEF0) { return 5 }
81 let allone: i64 = 0 - 1 // 0xFFFFFFFFFFFFFFFF
82 if __crc32_u64(0xFFFFFFFF, allone) != sw_crc32q(0xFFFFFFFF, allone) { return 6 }
83
84 // Case b4: 256 pseudo-random inputs via a simple LCG -- broad agreement.
85 var seed: i64 = 0x2545F4914F6CDD1D
86 var n: i64 = 0
87 while n < 256 {
88 seed = (seed * 6364136223846793005 + 1442695040888963407)
89 let crc: i64 = seed & 0xFFFFFFFF
90 seed = (seed * 6364136223846793005 + 1442695040888963407)
91 let data: i64 = seed
92 if __crc32_u64(crc, data) != sw_crc32q(crc, data) { return 7 }
93 n = n + 1
94 }
95
96 // Case b5: CHAINING -- fold "12345678" (8 bytes) then the trailing '9'
97 // byte-wise, apply init+final, and confirm we recover the SAME standard
98 // check value 0xE3069283 -- now through the HARDWARE crc32q for the 8-byte
99 // block. (init already folded by feeding 0xFFFFFFFF as the seed accumulator.)
100 let h1: i64 = __crc32_u64(0xFFFFFFFF, d8) // hardware: 8 bytes at once
101 let h2: i64 = sw_crc32b(h1, 0x39) // '9' (software byte step; no crc32b intrinsic)
102 if (h2 ^ 0xFFFFFFFF) != 0xE3069283 { return 8 }
103
104 return 0
105}