nx_crc32c.nx source
↩ module page · 78 lines · 2907 B
1// nx_crc32c.nx -- fast TABLE-driven CRC-32C (Castagnoli) for per-PDU
2// integrity: critical-grade table-stakes (BPv7 Type-2 CRC, RIST/SRT
3// integrity, FEC-block validation). Generalizes the shipped bit-by-bit
4// nx_crc32_v1.nx (CLAUDE.md 15 / review-existing-functionality) to the
5// 256-entry byte-table lookup it flagged as future work -- the table is
6// BUILT AT RUNTIME from the polynomial (sidesteps the const-array-literal
7// gap), so it stays pure NishiLang, integer-only, zero deps.
8//
9// CRC-32C: reflected polynomial 0x82F63B78, init/xorout 0xFFFFFFFF,
10// refin/refout true. Canonical check: crc32c("123456789") = 0xE3069283.
11//
12// license_tier: ORIGINAL
13
14import "nx_syscalls.nx"
15
16const CRC32C_POLY: i64 = 0x82F63B78
17const CRC_U32: i64 = 0xFFFFFFFF
18
19// Build the 256-entry lookup table from the polynomial (call once).
20func crc32c_build_table() -> *i64 {
21 let t: *i64 = sys_mmap(256 * 8) as *i64
22 var b: i64 = 0
23 while b < 256 {
24 var c: i64 = b
25 var k: i64 = 0
26 while k < 8 {
27 if (c & 1) != 0 { c = (c >> 1) ^ CRC32C_POLY } else { c = c >> 1 }
28 k = k + 1
29 }
30 t[b] = c & CRC_U32
31 b = b + 1
32 }
33 return t
34}
35
36// One-shot CRC-32C over `n` bytes using table `t`. Includes the standard
37// init (0xFFFFFFFF) and final xor (0xFFFFFFFF).
38func crc32c_table(t: *i64, bytes: *u8, n: i64) -> i64 {
39 var crc: i64 = CRC_U32
40 var i: i64 = 0
41 while i < n {
42 let idx: i64 = (crc ^ ((bytes[i] as i64) & 0xff)) & 0xff
43 crc = ((crc >> 8) ^ t[idx]) & CRC_U32
44 i = i + 1
45 }
46 return crc ^ CRC_U32
47}
48
49// Streaming: feed chunks. `state` is the RAW running value (NOT final-
50// xored). Start with crc32c_begin(); feed with crc32c_update(); finish
51// with crc32c_final(). Lets a PDU be CRC'd across scattered buffers.
52func crc32c_begin() -> i64 { return CRC_U32 }
53func crc32c_update(t: *i64, state: i64, bytes: *u8, n: i64) -> i64 {
54 var crc: i64 = state
55 var i: i64 = 0
56 while i < n {
57 let idx: i64 = (crc ^ ((bytes[i] as i64) & 0xff)) & 0xff
58 crc = ((crc >> 8) ^ t[idx]) & CRC_U32
59 i = i + 1
60 }
61 return crc
62}
63func crc32c_final(state: i64) -> i64 { return state ^ CRC_U32 }
64
65// Verify a PDU: append the 4-byte CRC (BE) after the payload, then
66// crc32c over (payload+crc) yields the well-known residue 0 when intact.
67// Returns 1 if intact, 0 if corrupted.
68func crc32c_pdu_check(t: *i64, pdu: *u8, total_len: i64) -> i64 {
69 // crc over payload, compare to the trailing 4 bytes (BE).
70 if total_len < 4 { return 0 }
71 let plen: i64 = total_len - 4
72 let want: i64 = crc32c_table(t, pdu, plen)
73 let base: i64 = pdu as i64
74 let got: i64 = (((pdu[plen] as i64) & 0xff) << 24) | (((pdu[plen+1] as i64) & 0xff) << 16)
75 | (((pdu[plen+2] as i64) & 0xff) << 8) | ((pdu[plen+3] as i64) & 0xff)
76 if got == want { return 1 }
77 return 0
78}