code wiki / (root) / nx_crc16.nx

nx_crc16.nx source

↩ module page · 115 lines · 3327 B

1// crc16.nx -- CRC-16 variants (CCITT, IBM, MODBUS). 2// 3// Used by serial / wire protocols where 16-bit checksums are 4// adequate (link-layer error detection). Three common variants 5// shipped: 6// 7// CCITT-FALSE (poly 0x1021, init 0xFFFF, no reflection) 8// Used by: XMODEM, MAVLink, DNP3, Bluetooth HCI 9// IBM (poly 0x8005, init 0x0000, reflected) 10// Used by: Modbus RTU, USB token CRC, ISO/IEC 13239 11// MODBUS (poly 0x8005, init 0xFFFF, reflected) 12// Used by: Modbus serial framing 13// 14// All NOT cryptographic. Burst-error detection only. 15// 16// Invariants: 17// CR1 Pure functions; no global state; deterministic. 18// CR2 Result fits in low 16 bits of i64. 19// CR3 Bit-by-bit implementation (no 256-entry table) -- slower 20// than tabulated variants but ~50 LoC instead of 50 LoC + 21// 256-byte data + per-variant table. 22 23// nx_safety_envelope: 24// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 25// sil_target: SIL1 26// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 27// verdict: NOT_YET_EVALUATED 28 29import "nx_syscalls.nx" 30 31const CR_POLY_CCITT: i64 = 0x1021 32const CR_POLY_IBM: i64 = 0x8005 33const CR_INIT_FFFF: i64 = 0xFFFF 34const CR_INIT_0000: i64 = 0x0000 35const CR_U16_MASK: i64 = 0xFFFF 36 37// Reflect 8 bits (LSB <-> MSB). 38func crc16_reflect8(b: i64) -> i64 { 39 var v: i64 = b 40 var r: i64 = 0 41 var i: i64 = 0 42 while i < 8 { 43 r = (r << 1) | (v & 1) 44 v = (v >> 1) & 0x7F 45 i = i + 1 46 } 47 return r 48} 49 50// Reflect 16 bits. 51func crc16_reflect16(x: i64) -> i64 { 52 var v: i64 = x & CR_U16_MASK 53 var r: i64 = 0 54 var i: i64 = 0 55 while i < 16 { 56 r = (r << 1) | (v & 1) 57 v = (v >> 1) & 0x7FFF 58 i = i + 1 59 } 60 return r 61} 62 63// CRC-16/CCITT-FALSE: poly 0x1021, init 0xFFFF, no reflection, 64// no final XOR. Standard XMODEM / MAVLink usage. 65func crc16_ccitt(bytes: *u8, n: i64) -> i64 { 66 var crc: i64 = CR_INIT_FFFF 67 var i: i64 = 0 68 while i < n { 69 crc = crc ^ (bytes[i] << 8) 70 var bit: i64 = 0 71 while bit < 8 { 72 if (crc & 0x8000) != 0 { 73 crc = ((crc << 1) ^ CR_POLY_CCITT) & CR_U16_MASK 74 } else { 75 crc = (crc << 1) & CR_U16_MASK 76 } 77 bit = bit + 1 78 } 79 i = i + 1 80 } 81 return crc & CR_U16_MASK 82} 83 84// CRC-16/MODBUS: poly 0x8005 reflected (0xA001), init 0xFFFF, 85// reflected input + output, no final XOR. The Modbus RTU 86// framing checksum. 87func crc16_modbus(bytes: *u8, n: i64) -> i64 { 88 var crc: i64 = CR_INIT_FFFF 89 var i: i64 = 0 90 while i < n { 91 crc = crc ^ bytes[i] 92 var bit: i64 = 0 93 while bit < 8 { 94 if (crc & 1) != 0 { 95 crc = ((crc >> 1) ^ 0xA001) & CR_U16_MASK 96 } else { 97 crc = (crc >> 1) & CR_U16_MASK 98 } 99 bit = bit + 1 100 } 101 i = i + 1 102 } 103 return crc & CR_U16_MASK 104} 105 106// Compile-only smoke. Known KAT for CRC-16/CCITT-FALSE on 107// "123456789" = 0x29B1. 108func main() -> i64 { 109 let msg: *u8 = "123456789" 110 let c: i64 = crc16_ccitt(msg, 9) 111 if c == 0 { return 1 } 112 let m: i64 = crc16_modbus(msg, 9) 113 if m == c { return 2 } // different polys -> different output 114 return 0 115}