Skip to main content

basalt/
crc.rs

1/// Hand-rolled CRC-32 (ISO-HDLC / IEEE 802.3, polynomial 0xEDB88320),
2/// table-driven. Used for WAL frame checksums.
3const CRC_TABLE: [u32; 256] = make_crc_table();
4
5const fn make_crc_table() -> [u32; 256] {
6    let mut table = [0u32; 256];
7    let mut i = 0usize;
8    while i < 256 {
9        let mut c = i as u32;
10        let mut k = 0;
11        while k < 8 {
12            c = if c & 1 != 0 {
13                0xEDB8_8320 ^ (c >> 1)
14            } else {
15                c >> 1
16            };
17            k += 1;
18        }
19        table[i] = c;
20        i += 1;
21    }
22    table
23}
24
25pub fn crc32(bytes: &[u8]) -> u32 {
26    let mut crc: u32 = 0xFFFF_FFFF;
27    for &b in bytes {
28        crc = CRC_TABLE[((crc ^ b as u32) & 0xFF) as usize] ^ (crc >> 8);
29    }
30    crc ^ 0xFFFF_FFFF
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36
37    #[test]
38    fn known_vectors() {
39        // Standard CRC-32 test vectors.
40        assert_eq!(crc32(b""), 0x0000_0000);
41        assert_eq!(crc32(b"123456789"), 0xCBF4_3926);
42    }
43
44    #[test]
45    fn detects_bit_flips() {
46        let a = crc32(b"the quick brown fox");
47        let mut mangled = b"the quick brown fox".to_vec();
48        mangled[5] ^= 0x40;
49        assert_ne!(a, crc32(&mangled));
50    }
51}