| use super::braid::CRC32_LSB_POLY; |
| |
| pub const fn crc32_combine(crc1: u32, crc2: u32, len2: u64) -> u32 { |
| crc32_combine_op(crc1, crc2, crc32_combine_gen(len2)) |
| } |
| |
| #[inline(always)] |
| const fn crc32_combine_gen(len2: u64) -> u32 { |
| x2nmodp(len2, 3) |
| } |
| |
| #[inline(always)] |
| const fn crc32_combine_op(crc1: u32, crc2: u32, op: u32) -> u32 { |
| multmodp(op, crc1) ^ crc2 |
| } |
| |
| const X2N_TABLE: [u32; 32] = [ |
| 0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000, 0xedb88320, 0xb1e6b092, 0xa06a2517, |
| 0xed627dae, 0x88d14467, 0xd7bbfe6a, 0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0, 0x09fe548f, |
| 0x83852d0f, 0x30362f1a, 0x7b5a9cc3, 0x31fec169, 0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e, |
| 0xbad90e37, 0x2e4e5eef, 0x4eaba214, 0xa8a472c0, 0x429a969e, 0x148d302a, 0xc40ba6d0, 0xc4e22c3c, |
| ]; |
| |
| // Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, |
| // reflected. For speed, this requires that a not be zero. |
| const fn multmodp(a: u32, mut b: u32) -> u32 { |
| let mut m = 1 << 31; |
| let mut p = 0; |
| |
| loop { |
| if (a & m) != 0 { |
| p ^= b; |
| if (a & (m - 1)) == 0 { |
| break; |
| } |
| } |
| m >>= 1; |
| b = if (b & 1) != 0 { |
| (b >> 1) ^ CRC32_LSB_POLY as u32 |
| } else { |
| b >> 1 |
| }; |
| } |
| |
| p |
| } |
| |
| // Return x^(n * 2^k) modulo p(x). |
| const fn x2nmodp(mut n: u64, mut k: u32) -> u32 { |
| let mut p: u32 = 1 << 31; /* x^0 == 1 */ |
| |
| while n > 0 { |
| if (n & 1) != 0 { |
| p = multmodp(X2N_TABLE[k as usize & 31], p); |
| } |
| n >>= 1; |
| k += 1; |
| } |
| |
| p |
| } |
| |
| #[cfg(test)] |
| mod test { |
| use super::*; |
| |
| use crate::crc32; |
| |
| #[test] |
| fn test_crc32_combine() { |
| ::quickcheck::quickcheck(test as fn(_) -> _); |
| |
| fn test(data: Vec<u8>) -> bool { |
| let Some(buf_len) = data.first().copied() else { |
| return true; |
| }; |
| |
| let buf_size = Ord::max(buf_len, 1) as usize; |
| |
| let crc0 = 0; |
| let mut crc1 = crc0; |
| let mut crc2 = crc0; |
| |
| /* CRC32 */ |
| for chunk in data.chunks(buf_size) { |
| let crc3 = crc32(crc0, chunk); |
| let op = crc32_combine_gen(chunk.len() as _); |
| let crc4 = crc32_combine_op(crc1, crc3, op); |
| crc1 = crc32(crc1, chunk); |
| |
| assert_eq!(crc1, crc4); |
| } |
| |
| crc2 = crc32(crc2, &data); |
| |
| assert_eq!(crc1, crc2); |
| |
| let combine1 = crc32_combine(crc1, crc2, data.len() as _); |
| let combine2 = crc32_combine(crc1, crc1, data.len() as _); |
| assert_eq!(combine1, combine2); |
| |
| // Fast CRC32 combine. |
| let op = crc32_combine_gen(data.len() as _); |
| let combine1 = crc32_combine_op(crc1, crc2, op); |
| let combine2 = crc32_combine_op(crc2, crc1, op); |
| assert_eq!(combine1, combine2); |
| |
| let combine1 = crc32_combine(crc1, crc2, data.len() as _); |
| let combine2 = crc32_combine_op(crc2, crc1, op); |
| assert_eq!(combine1, combine2); |
| |
| true |
| } |
| } |
| } |