ltmarx / core /crc.ts
harelcain's picture
Upload 37 files
f2f99a3 verified
/**
* CRC computation for payload integrity verification
* Supports CRC-4, CRC-8, and CRC-16
*/
// CRC-4 polynomial: x^4 + x + 1 (0x13, used bits: 0x03)
const CRC4_POLY = 0x03;
// CRC-8 polynomial: x^8 + x^2 + x + 1 (CRC-8-CCITT)
const CRC8_POLY = 0x07;
// CRC-16 polynomial: x^16 + x^15 + x^2 + 1 (CRC-16-IBM)
const CRC16_POLY = 0x8005;
/**
* Compute CRC over a bit array
* Uses non-zero initial value to prevent all-zeros from having CRC=0
*/
function computeCrc(bits: Uint8Array, poly: number, crcBits: number): number {
const mask = (1 << crcBits) - 1;
let crc = mask; // Non-zero init: all 1s (0xF for CRC-4, 0xFF for CRC-8, 0xFFFF for CRC-16)
for (let i = 0; i < bits.length; i++) {
crc ^= (bits[i] & 1) << (crcBits - 1);
if (crc & (1 << (crcBits - 1))) {
crc = ((crc << 1) ^ poly) & mask;
} else {
crc = (crc << 1) & mask;
}
}
return crc;
}
/**
* Compute CRC and append to bit array
*/
export function crcAppend(bits: Uint8Array, crcBits: 4 | 8 | 16): Uint8Array {
const poly = crcBits === 4 ? CRC4_POLY : crcBits === 8 ? CRC8_POLY : CRC16_POLY;
const crc = computeCrc(bits, poly, crcBits);
const result = new Uint8Array(bits.length + crcBits);
result.set(bits);
// Append CRC bits (MSB first)
for (let i = 0; i < crcBits; i++) {
result[bits.length + i] = (crc >> (crcBits - 1 - i)) & 1;
}
return result;
}
/**
* Verify CRC on a bit array (last crcBits bits are the CRC)
* Returns the payload bits (without CRC) if valid, null otherwise
*/
export function crcVerify(bits: Uint8Array, crcBits: 4 | 8 | 16): Uint8Array | null {
if (bits.length <= crcBits) return null;
const payload = bits.subarray(0, bits.length - crcBits);
const poly = crcBits === 4 ? CRC4_POLY : crcBits === 8 ? CRC8_POLY : CRC16_POLY;
const computed = computeCrc(payload, poly, crcBits);
// Extract received CRC
let received = 0;
for (let i = 0; i < crcBits; i++) {
received |= (bits[bits.length - crcBits + i] & 1) << (crcBits - 1 - i);
}
if (computed === received) {
return new Uint8Array(payload);
}
return null;
}