code wiki / (root) / nx_crc32_kat.nx

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}