const POLY: u32 = 0xedb8_8320;
const fn make_table() -> [u32; 256] {
let mut table = [0u32; 256];
let mut i = 0;
while i < 256 {
let mut crc = i as u32;
let mut bit = 0;
while bit < 8 {
if crc & 1 != 0 {
crc = (crc >> 1) ^ POLY;
} else {
crc >>= 1;
}
bit += 1;
}
table[i] = crc;
i += 1;
}
table
}
const TABLE: [u32; 256] = make_table();
#[inline]
#[allow(dead_code)] pub(crate) fn crc32(data: &[u8]) -> u32 {
crc32_append(0, data)
}
#[inline]
pub(crate) fn crc32_append(crc: u32, data: &[u8]) -> u32 {
let mut crc = !crc;
for &b in data {
let idx = ((crc as u8) ^ b) as usize;
crc = TABLE[idx] ^ (crc >> 8);
}
!crc
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn matches_java_ieee_check_vector() {
assert_eq!(crc32(b"123456789"), 0xcbf4_3926);
assert_eq!(crc32(b""), 0);
let incremental = crc32_append(crc32(b"12345"), b"6789");
assert_eq!(incremental, 0xcbf4_3926);
assert_ne!(crc32(b"123456789"), 0xe306_9283);
}
#[test]
fn multi_block_e2e_payload_golden() {
let block = 64 * 1024;
let payload: Vec<u8> = (0..block * 3 + 123).map(|i| (i % 251) as u8).collect();
assert_eq!(crc32(&payload), 0x9c20_a08f);
}
}