1const CRC_TABLE:[u32; 256] = crc32_lookup_table();
2const INITIAL_REGISTER_REFLECTED:u32= 0xFFFFFFFF;
3const XOR_OUT_REFLECTED:u32= 0xFFFFFFFF;
4
5#[inline]
49fn crc_division_reflected_optimized(message: &[u8]) -> u32 {
50 let mut register = INITIAL_REGISTER_REFLECTED;
51 let data = message;
52 let len = data.len();
53
54 for i in 0..len {
56 register = CRC_TABLE[(register ^ data[i] as u32) as usize & 0xff] ^ (register >> 8);
57 }
58
59 register ^ XOR_OUT_REFLECTED
60}
61
62const fn build_lookup_table(poly:u32, reflect:bool) -> [u32; 256] {
63 let mut table = [0u32; 256];
64 let top_bit = 0x80000000;
65 let mut i = 1usize;
66 while i < 256 {
67 let mut r:u32 = if reflect { (i as u8).reverse_bits() as u32 } else { i as u32};
68 r <<= 24;
69 let mut j = 0usize;
70 while j < 8 {
71 r = if r & top_bit > 0 {
72 (r << 1) ^ poly
73 }
74 else {
75 r << 1
76 };
77 j += 1;
78 }
79 table[i] = if reflect { r.reverse_bits()} else { r };
80 i += 1;
81 }
82 table
83}
84
85#[inline]
108pub fn crc32(message: &[u8]) -> u32 {
109 crc_division_reflected_optimized(message)
110}
111
112
113const fn crc32_lookup_table() -> [u32; 256] {
114 build_lookup_table(0x04C11DB7, true)
115}
116
117
118
119#[cfg(test)]
121fn crc_division_straightforward(message: &[u8], divisor: u32, initial: u32, xor_out: u32, reflect: bool) -> u32 {
122 let mut register = initial;
123 let top_bit = 0x80000000;
124 let mut length = message.len();
125 while length > 0 {
126 let uch: u32 = if reflect {
127 message[message.len() - length].reverse_bits() as u32
128 }
129 else {
130 message[message.len() - length] as u32
131 };
132 register ^= uch << 24;
133 for _ in 0usize..8 {
134 register = if register & top_bit > 0 {
135 (register << 1) ^ divisor
136 } else {
137 register << 1
138 };
139 }
140 length -= 1;
141 }
142 if reflect {
143 register = register.reverse_bits();
144 }
145
146 register ^ xor_out
147}
148
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[test]
155 fn test_build_lookup_table(){
156 let table:&[u32] = &build_lookup_table(0x04C11DB7, true);
157 let expected:&[u32] = &[
158 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
159 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
160 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
161 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
162 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
163 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
164 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
165 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
166 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
167 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
168 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
169 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
170 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
171 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
172 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
173 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
174 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
175 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
176 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
177 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
178 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
179 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
180 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
181 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
182 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
183 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
184 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
185 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
186 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
187 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
188 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
189 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
190 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
191 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
192 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
193 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
194 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
195 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
196 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
197 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
198 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
199 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
200 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
201 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
202 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
203 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
204 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
205 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
206 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
207 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
208 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
209 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
210 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
211 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
212 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
213 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
214 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
215 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
216 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
217 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
218 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
219 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
220 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
221 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D];
222 assert_eq!(&table, &expected);
223 }
224
225
226 #[test]
227 fn test_crc_division_straightforward() {
228 let result = crc_division_straightforward("123456789".as_bytes(), 0x04C11DB7,
229 0xFFFFFFFF, 0xFFFFFFFF, true);
230 assert_eq!(result, 0xcbf43926);
231
232 let result = crc_division_straightforward("123456789".as_bytes(), 0x04C11DB7,
233 0, 0, false);
234 assert_eq!(result, 0x89a1897f);
235
236 let message = [0x00u8, 0x01, 0x00, 0x4c, 0x21, 0x12, 0xa4, 0x42, 0x5a, 0x84, 0x33, 0x57, 0xaa, 0xbd, 0x48, 0xab, 0x43, 0x83, 0xef, 0x44, 0x00, 0x06, 0x00, 0x11, 0x39, 0x66, 0x64, 0x38, 0x33, 0x36, 0x66, 0x61, 0x3a, 0x38, 0x66, 0x66, 0x65, 0x31, 0x35, 0x34, 0x65, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x04, 0x6e, 0x7f, 0x00, 0xff, 0x80, 0x29, 0x00, 0x08, 0x94, 0xb7, 0xef, 0x1f, 0xb0, 0xc6, 0x79, 0x36, 0x00, 0x08, 0x00, 0x14, 0x03, 0xa9, 0x68, 0xe5, 0x68, 0x7f, 0xae, 0xd6, 0x8e, 0x91, 0x4b, 0x11, 0x6d, 0xa2, 0x9f, 0x79, 0x61, 0xef, 0xf6, 0x0a];
237 let result = crc_division_straightforward(&message, 0x04C11DB7,
238 0xFFFFFFFF, 0xFFFFFFFF, true);
239 eprintln!("result {:02x}", result);
240 assert_eq!(result, 0x10a4b112);
241
242 }
243
244 #[test]
245 fn test_crc32(){
246 let message = [0x00u8, 0x01, 0x00, 0x4c, 0x21, 0x12, 0xa4, 0x42, 0x5a, 0x84, 0x33, 0x57, 0xaa, 0xbd, 0x48, 0xab, 0x43, 0x83, 0xef, 0x44, 0x00, 0x06, 0x00, 0x11, 0x39, 0x66, 0x64, 0x38, 0x33, 0x36, 0x66, 0x61, 0x3a, 0x38, 0x66, 0x66, 0x65, 0x31, 0x35, 0x34, 0x65, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x04, 0x6e, 0x7f, 0x00, 0xff, 0x80, 0x29, 0x00, 0x08, 0x94, 0xb7, 0xef, 0x1f, 0xb0, 0xc6, 0x79, 0x36, 0x00, 0x08, 0x00, 0x14, 0x03, 0xa9, 0x68, 0xe5, 0x68, 0x7f, 0xae, 0xd6, 0x8e, 0x91, 0x4b, 0x11, 0x6d, 0xa2, 0x9f, 0x79, 0x61, 0xef, 0xf6, 0x0a];
247 let result = crc32(&message);
248 assert_eq!(result, 0x10a4b112);
249 }
250}