Skip to main content

git_zero_core/pack/
crc.rs

1/// Standard reflected IEEE CRC-32 used by Git pack indexes (initial/final XOR).
2pub fn crc32(bytes: &[u8]) -> u32 {
3    let mut crc = Crc32::new();
4    crc.update(bytes);
5    crc.value()
6}
7
8/// Incremental wire checksum shared by pack readers and index writers.
9pub(super) struct Crc32(u32);
10
11impl Crc32 {
12    pub(super) const fn new() -> Self {
13        Self(u32::MAX)
14    }
15    pub(super) fn value(&self) -> u32 {
16        !self.0
17    }
18    pub(super) fn update(&mut self, bytes: &[u8]) {
19        const TABLE: [[u32; 256]; 8] = crc_tables();
20        let mut crc = self.0;
21        let mut chunks = bytes.chunks_exact(8);
22        for chunk in &mut chunks {
23            let low = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]) ^ crc;
24            crc = TABLE[7][usize::from(low as u8)]
25                ^ TABLE[6][usize::from((low >> 8) as u8)]
26                ^ TABLE[5][usize::from((low >> 16) as u8)]
27                ^ TABLE[4][(low >> 24) as usize]
28                ^ TABLE[3][usize::from(chunk[4])]
29                ^ TABLE[2][usize::from(chunk[5])]
30                ^ TABLE[1][usize::from(chunk[6])]
31                ^ TABLE[0][usize::from(chunk[7])];
32        }
33        for &byte in chunks.remainder() {
34            crc = (crc >> 8) ^ TABLE[0][usize::from(crc as u8 ^ byte)];
35        }
36        self.0 = crc;
37    }
38}
39
40const fn crc_tables() -> [[u32; 256]; 8] {
41    let mut table = [[0; 256]; 8];
42    let mut index = 0;
43    while index < 256 {
44        let mut value = index as u32;
45        let mut bit = 0;
46        while bit < 8 {
47            value = (value >> 1) ^ if value & 1 != 0 { 0xedb8_8320 } else { 0 };
48            bit += 1;
49        }
50        table[0][index] = value;
51        index += 1;
52    }
53    let mut slice = 1;
54    while slice < 8 {
55        index = 0;
56        while index < 256 {
57            let previous = table[slice - 1][index];
58            table[slice][index] = (previous >> 8) ^ table[0][(previous & 255) as usize];
59            index += 1;
60        }
61        slice += 1;
62    }
63    table
64}