const fn build_crc8_table() -> [u8; 256] {
let mut table = [0u8; 256];
let mut i = 0;
while i < 256 {
let mut crc = i as u8;
let mut bit = 0;
while bit < 8 {
crc = if crc & 0x80 != 0 {
(crc << 1) ^ 0x07
} else {
crc << 1
};
bit += 1;
}
table[i] = crc;
i += 1;
}
table
}
const fn build_crc16_table() -> [u16; 256] {
let mut table = [0u16; 256];
let mut i = 0;
while i < 256 {
let mut crc = (i as u16) << 8;
let mut bit = 0;
while bit < 8 {
crc = if crc & 0x8000 != 0 {
(crc << 1) ^ 0x8005
} else {
crc << 1
};
bit += 1;
}
table[i] = crc;
i += 1;
}
table
}
const CRC8_TABLE: [u8; 256] = build_crc8_table();
const CRC16_TABLE: [u16; 256] = build_crc16_table();
pub fn crc8(data: &[u8]) -> u8 {
let mut crc = 0u8;
for &b in data {
crc = CRC8_TABLE[(crc ^ b) as usize];
}
crc
}
pub fn crc16(data: &[u8]) -> u16 {
let mut crc = 0u16;
for &b in data {
crc = (crc << 8) ^ CRC16_TABLE[((crc >> 8) ^ b as u16) as usize];
}
crc
}
#[cfg(test)]
mod tests {
use super::*;
fn crc8_ref(data: &[u8]) -> u8 {
let mut crc = 0u8;
for &b in data {
crc ^= b;
for _ in 0..8 {
crc = if crc & 0x80 != 0 {
(crc << 1) ^ 0x07
} else {
crc << 1
};
}
}
crc
}
fn crc16_ref(data: &[u8]) -> u16 {
let mut crc = 0u16;
for &b in data {
crc ^= (b as u16) << 8;
for _ in 0..8 {
crc = if crc & 0x8000 != 0 {
(crc << 1) ^ 0x8005
} else {
crc << 1
};
}
}
crc
}
#[test]
fn tables_match_bitwise_reference() {
let data: Vec<u8> = (0..4096u32).map(|i| (i * 31 + 7) as u8).collect();
for len in [0, 1, 2, 63, 64, 65, 4096] {
assert_eq!(crc8(&data[..len]), crc8_ref(&data[..len]), "crc8 len={len}");
assert_eq!(
crc16(&data[..len]),
crc16_ref(&data[..len]),
"crc16 len={len}"
);
}
}
}