const CRC8_TABLE: [u8; 256] = {
let mut table = [0u8; 256];
let mut i = 0;
while i < 256 {
let mut crc = i as u8;
let mut j = 0;
while j < 8 {
crc = if crc & 1 != 0 {
(crc >> 1) ^ 0x81
} else {
crc >> 1
};
j += 1;
}
table[i] = crc;
i += 1;
}
table
};
const CRC16_TABLE: [u16; 256] = {
let mut table = [0u16; 256];
let mut i = 0;
while i < 256 {
let mut crc = i as u16;
let mut j = 0;
while j < 8 {
crc = if crc & 1 != 0 {
(crc >> 1) ^ 0x8408
} else {
crc >> 1
};
j += 1;
}
table[i] = crc;
i += 1;
}
table
};
#[must_use]
pub fn crc8(data: &[u8]) -> u8 {
let mut crc = 0xFF;
for &byte in data {
crc = CRC8_TABLE[(crc ^ byte) as usize];
}
!crc
}
#[must_use]
pub fn crc8_valid(data_with_crc: &[u8]) -> bool {
!data_with_crc.is_empty()
&& crc8(&data_with_crc[..data_with_crc.len() - 1]) == data_with_crc[data_with_crc.len() - 1]
}
#[must_use]
pub fn crc16(data: &[u8]) -> u16 {
let mut crc = 0xFFFF;
for &byte in data {
crc = (crc >> 8) ^ CRC16_TABLE[((crc ^ byte as u16) & 0xFF) as usize];
}
!crc
}
#[must_use]
pub fn crc16_valid(data_with_crc: &[u8]) -> bool {
if data_with_crc.len() < 3 {
return false;
}
let split = data_with_crc.len() - 2;
let stored = u16::from_le_bytes([data_with_crc[split], data_with_crc[split + 1]]);
crc16(&data_with_crc[..split]) == stored
}
const CRC32K_POLYNOMIAL: u32 = 0xEB31_D82E;
const fn crc32k_shift(mut crc: u32, bits: u32) -> u32 {
let mut bit = 0;
while bit < bits {
crc = if crc & 1 != 0 {
(crc >> 1) ^ CRC32K_POLYNOMIAL
} else {
crc >> 1
};
bit += 1;
}
crc
}
#[cfg(any(feature = "crc32k-table", test))]
const CRC32K_TABLE: [u32; 256] = {
let mut table = [0u32; 256];
let mut i = 0;
while i < 256 {
table[i] = crc32k_shift(i as u32, 8);
i += 1;
}
table
};
#[cfg(any(not(feature = "crc32k-table"), test))]
const CRC32K_NIBBLES: [u32; 16] = {
let mut table = [0u32; 16];
let mut i = 0;
while i < 16 {
table[i] = crc32k_shift(i as u32, 4);
i += 1;
}
table
};
#[cfg(any(feature = "crc32k-table", test))]
fn crc32k_octet_by_table(crc: u32, byte: u8) -> u32 {
(crc >> 8) ^ CRC32K_TABLE[((crc ^ u32::from(byte)) & 0xFF) as usize]
}
#[cfg(any(not(feature = "crc32k-table"), test))]
fn crc32k_octet_by_nibbles(crc: u32, byte: u8) -> u32 {
let crc = crc ^ u32::from(byte);
let crc = (crc >> 4) ^ CRC32K_NIBBLES[(crc & 0x0F) as usize];
(crc >> 4) ^ CRC32K_NIBBLES[(crc & 0x0F) as usize]
}
pub(crate) fn crc32k_update(crc: u32, data: &[u8]) -> u32 {
#[cfg(feature = "crc32k-table")]
let octet = crc32k_octet_by_table;
#[cfg(not(feature = "crc32k-table"))]
let octet = crc32k_octet_by_nibbles;
data.iter().fold(crc, |crc, &byte| octet(crc, byte))
}
#[must_use]
pub fn crc32k(data: &[u8]) -> u32 {
!crc32k_update(u32::MAX, data)
}
#[cfg(test)]
mod tests {
use super::{crc32k_octet_by_nibbles, crc32k_octet_by_table, crc32k_shift};
#[test]
fn both_crc32k_tables_match_the_bitwise_register() {
let registers = [
0,
u32::MAX,
1,
0x8000_0000,
0x0843_323B,
0x1234_5678,
0xEDCB_A987,
0x5555_AAAA,
];
for register in registers {
for byte in 0..=u8::MAX {
let bitwise = crc32k_shift(register ^ u32::from(byte), 8);
assert_eq!(crc32k_octet_by_table(register, byte), bitwise);
assert_eq!(crc32k_octet_by_nibbles(register, byte), bitwise);
}
}
}
}