crc/
crc128.rs

1use crate::util::crc128;
2use crc_catalog::Algorithm;
3
4mod bytewise;
5mod nolookup;
6mod slice16;
7
8const fn init(algorithm: &Algorithm<u128>, initial: u128) -> u128 {
9    if algorithm.refin {
10        initial.reverse_bits() >> (128u8 - algorithm.width)
11    } else {
12        initial << (128u8 - algorithm.width)
13    }
14}
15
16const fn finalize(algorithm: &Algorithm<u128>, mut crc: u128) -> u128 {
17    if algorithm.refin ^ algorithm.refout {
18        crc = crc.reverse_bits();
19    }
20    if !algorithm.refout {
21        crc >>= 128u8 - algorithm.width;
22    }
23    crc ^ algorithm.xorout
24}
25
26const fn update_nolookup(mut crc: u128, algorithm: &Algorithm<u128>, bytes: &[u8]) -> u128 {
27    let poly = if algorithm.refin {
28        let poly = algorithm.poly.reverse_bits();
29        poly >> (128u8 - algorithm.width)
30    } else {
31        algorithm.poly << (128u8 - algorithm.width)
32    };
33
34    let mut i = 0;
35    if algorithm.refin {
36        while i < bytes.len() {
37            let to_crc = (crc ^ bytes[i] as u128) & 0xFF;
38            crc = crc128(poly, algorithm.refin, to_crc) ^ (crc >> 8);
39            i += 1;
40        }
41    } else {
42        while i < bytes.len() {
43            let to_crc = ((crc >> 120) ^ bytes[i] as u128) & 0xFF;
44            crc = crc128(poly, algorithm.refin, to_crc) ^ (crc << 8);
45            i += 1;
46        }
47    }
48    crc
49}
50
51const fn update_bytewise(mut crc: u128, reflect: bool, table: &[u128; 256], bytes: &[u8]) -> u128 {
52    let mut i = 0;
53    if reflect {
54        while i < bytes.len() {
55            let table_index = ((crc ^ bytes[i] as u128) & 0xFF) as usize;
56            crc = table[table_index] ^ (crc >> 8);
57            i += 1;
58        }
59    } else {
60        while i < bytes.len() {
61            let table_index = (((crc >> 120) ^ bytes[i] as u128) & 0xFF) as usize;
62            crc = table[table_index] ^ (crc << 8);
63            i += 1;
64        }
65    }
66    crc
67}
68
69const fn update_slice16(
70    mut crc: u128,
71    reflect: bool,
72    table: &[[u128; 256]; 16],
73    bytes: &[u8],
74) -> u128 {
75    let mut i = 0;
76    let len = bytes.len();
77    if reflect {
78        while i + 16 <= len {
79            let current0 = bytes[i] ^ crc as u8;
80            let current1 = bytes[i + 1] ^ (crc >> 8) as u8;
81            let current2 = bytes[i + 2] ^ (crc >> 16) as u8;
82            let current3 = bytes[i + 3] ^ (crc >> 24) as u8;
83            let current4 = bytes[i + 4] ^ (crc >> 32) as u8;
84            let current5 = bytes[i + 5] ^ (crc >> 40) as u8;
85            let current6 = bytes[i + 6] ^ (crc >> 48) as u8;
86            let current7 = bytes[i + 7] ^ (crc >> 56) as u8;
87            let current8 = bytes[i + 8] ^ (crc >> 64) as u8;
88            let current9 = bytes[i + 9] ^ (crc >> 72) as u8;
89            let current10 = bytes[i + 10] ^ (crc >> 80) as u8;
90            let current11 = bytes[i + 11] ^ (crc >> 88) as u8;
91            let current12 = bytes[i + 12] ^ (crc >> 96) as u8;
92            let current13 = bytes[i + 13] ^ (crc >> 104) as u8;
93            let current14 = bytes[i + 14] ^ (crc >> 112) as u8;
94            let current15 = bytes[i + 15] ^ (crc >> 120) as u8;
95
96            crc = table[15][current0 as usize]
97                ^ table[14][current1 as usize]
98                ^ table[13][current2 as usize]
99                ^ table[12][current3 as usize]
100                ^ table[11][current4 as usize]
101                ^ table[10][current5 as usize]
102                ^ table[9][current6 as usize]
103                ^ table[8][current7 as usize]
104                ^ table[7][current8 as usize]
105                ^ table[6][current9 as usize]
106                ^ table[5][current10 as usize]
107                ^ table[4][current11 as usize]
108                ^ table[3][current12 as usize]
109                ^ table[2][current13 as usize]
110                ^ table[1][current14 as usize]
111                ^ table[0][current15 as usize];
112
113            i += 16;
114        }
115
116        while i < len {
117            let table_index = ((crc ^ bytes[i] as u128) & 0xFF) as usize;
118            crc = table[0][table_index] ^ (crc >> 8);
119            i += 1;
120        }
121    } else {
122        while i + 16 <= len {
123            let current0 = bytes[i] ^ (crc >> 120) as u8;
124            let current1 = bytes[i + 1] ^ (crc >> 112) as u8;
125            let current2 = bytes[i + 2] ^ (crc >> 104) as u8;
126            let current3 = bytes[i + 3] ^ (crc >> 96) as u8;
127            let current4 = bytes[i + 4] ^ (crc >> 88) as u8;
128            let current5 = bytes[i + 5] ^ (crc >> 80) as u8;
129            let current6 = bytes[i + 6] ^ (crc >> 72) as u8;
130            let current7 = bytes[i + 7] ^ (crc >> 64) as u8;
131            let current8 = bytes[i + 8] ^ (crc >> 56) as u8;
132            let current9 = bytes[i + 9] ^ (crc >> 48) as u8;
133            let current10 = bytes[i + 10] ^ (crc >> 40) as u8;
134            let current11 = bytes[i + 11] ^ (crc >> 32) as u8;
135            let current12 = bytes[i + 12] ^ (crc >> 24) as u8;
136            let current13 = bytes[i + 13] ^ (crc >> 16) as u8;
137            let current14 = bytes[i + 14] ^ (crc >> 8) as u8;
138            let current15 = bytes[i + 15] ^ crc as u8;
139
140            crc = table[15][current0 as usize]
141                ^ table[14][current1 as usize]
142                ^ table[13][current2 as usize]
143                ^ table[12][current3 as usize]
144                ^ table[11][current4 as usize]
145                ^ table[10][current5 as usize]
146                ^ table[9][current6 as usize]
147                ^ table[8][current7 as usize]
148                ^ table[7][current8 as usize]
149                ^ table[6][current9 as usize]
150                ^ table[5][current10 as usize]
151                ^ table[4][current11 as usize]
152                ^ table[3][current12 as usize]
153                ^ table[2][current13 as usize]
154                ^ table[1][current14 as usize]
155                ^ table[0][current15 as usize];
156
157            i += 16;
158        }
159
160        while i < len {
161            let table_index = (((crc >> 120) ^ bytes[i] as u128) & 0xFF) as usize;
162            crc = table[0][table_index] ^ (crc << 8);
163            i += 1;
164        }
165    }
166    crc
167}
168
169#[cfg(test)]
170mod test {
171    use crate::*;
172    use crc_catalog::{Algorithm, CRC_82_DARC};
173
174    /// Test this optimized version against the well known implementation to ensure correctness
175    #[test]
176    fn correctness() {
177        let data: &[&str] = &[
178        "",
179        "1",
180        "1234",
181        "123456789",
182        "0123456789ABCDE",
183        "01234567890ABCDEFGHIJK",
184        "01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK",
185    ];
186
187        pub const CRC_82_DARC_NONREFLEX: Algorithm<u128> = Algorithm {
188            width: 82,
189            poly: 0x0308c0111011401440411,
190            init: 0x000000000000000000000,
191            refin: false,
192            refout: true,
193            xorout: 0x000000000000000000000,
194            check: 0x09ea83f625023801fd612,
195            residue: 0x000000000000000000000,
196        };
197
198        let algs_to_test = [&CRC_82_DARC, &CRC_82_DARC_NONREFLEX];
199
200        for alg in algs_to_test {
201            for data in data {
202                let crc_slice16 = Crc::<u128, Table<16>>::new(alg);
203                let crc_nolookup = Crc::<u128, NoTable>::new(alg);
204                let expected = Crc::<u128, Table<1>>::new(alg).checksum(data.as_bytes());
205
206                // Check that doing all at once works as expected
207                assert_eq!(crc_slice16.checksum(data.as_bytes()), expected);
208                assert_eq!(crc_nolookup.checksum(data.as_bytes()), expected);
209
210                let mut digest = crc_slice16.digest();
211                digest.update(data.as_bytes());
212                assert_eq!(digest.finalize(), expected);
213
214                let mut digest = crc_nolookup.digest();
215                digest.update(data.as_bytes());
216                assert_eq!(digest.finalize(), expected);
217
218                // Check that we didn't break updating from multiple sources
219                if data.len() > 2 {
220                    let data = data.as_bytes();
221                    let data1 = &data[..data.len() / 2];
222                    let data2 = &data[data.len() / 2..];
223                    let mut digest = crc_slice16.digest();
224                    digest.update(data1);
225                    digest.update(data2);
226                    assert_eq!(digest.finalize(), expected);
227                    let mut digest = crc_nolookup.digest();
228                    digest.update(data1);
229                    digest.update(data2);
230                    assert_eq!(digest.finalize(), expected);
231                }
232            }
233        }
234    }
235}