|
1 | | -const GF2_DIM: usize = 32; |
| 1 | +const POLY: u32 = 0xedb88320; |
2 | 2 |
|
3 | | -fn gf2_matrix_times(mat: &[u32; GF2_DIM], vec: u32) -> u32 { |
4 | | - let mut sum = 0; |
| 3 | +static X2N_TABLE: [u32; 32] = [ |
| 4 | + 0x00800000, 0x00008000, 0xedb88320, 0xb1e6b092, 0xa06a2517, 0xed627dae, 0x88d14467, 0xd7bbfe6a, |
| 5 | + 0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0, 0x09fe548f, 0x83852d0f, 0x30362f1a, 0x7b5a9cc3, |
| 6 | + 0x31fec169, 0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e, 0xbad90e37, 0x2e4e5eef, 0x4eaba214, |
| 7 | + 0xa8a472c0, 0x429a969e, 0x148d302a, 0xc40ba6d0, 0xc4e22c3c, 0x40000000, 0x20000000, 0x08000000, |
| 8 | +]; |
5 | 9 |
|
6 | | - for (i, m) in mat.iter().enumerate() { |
7 | | - if vec >> i & 1 == 1 { |
8 | | - sum ^= *m; |
9 | | - } |
10 | | - } |
11 | | - |
12 | | - sum |
13 | | -} |
| 10 | +// Calculates a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, |
| 11 | +// reflected. For speed, this requires that a not be zero. |
| 12 | +fn multiply(a: u32, mut b: u32) -> u32 { |
| 13 | + let mut m = 1u32 << 31; |
| 14 | + let mut p = 0u32; |
14 | 15 |
|
15 | | -fn gf2_matrix_square(square: &mut [u32; GF2_DIM], mat: &[u32; GF2_DIM]) { |
16 | | - for n in 0..GF2_DIM { |
17 | | - square[n] = gf2_matrix_times(mat, mat[n]); |
18 | | - } |
19 | | -} |
20 | | - |
21 | | -pub(crate) fn combine(mut crc1: u32, crc2: u32, mut len2: u64) -> u32 { |
22 | | - let mut even = [0u32; GF2_DIM]; // even-power-of-two zeros operator |
23 | | - let mut odd = [0u32; GF2_DIM]; // odd-power-of-two zeros operator |
24 | | - |
25 | | - // degenerate case (also disallow negative lengths) |
26 | | - if len2 == 0 { |
27 | | - return crc1; |
28 | | - } |
29 | | - |
30 | | - // put operator for one zero bit in odd |
31 | | - odd[0] = 0xedb88320; // CRC-32 polynomial |
32 | | - for (i, r) in odd[1..].iter_mut().enumerate() { |
33 | | - *r = 1 << i; |
34 | | - } |
35 | | - |
36 | | - // put operator for two zero bits in even |
37 | | - gf2_matrix_square(&mut even, &odd); |
38 | | - |
39 | | - // put operator for four zero bits in odd |
40 | | - gf2_matrix_square(&mut odd, &even); |
41 | | - |
42 | | - // apply len2 zeros to crc1 (first square will put the operator for one |
43 | | - // zero byte, eight zero bits, in even) |
44 | 16 | loop { |
45 | | - // apply zeros operator for this bit of len2 |
46 | | - gf2_matrix_square(&mut even, &odd); |
47 | | - if len2 & 1 == 1 { |
48 | | - crc1 = gf2_matrix_times(&even, crc1); |
| 17 | + if (a & m) != 0 { |
| 18 | + p ^= b; |
| 19 | + if (a & (m - 1)) == 0 { |
| 20 | + break; |
| 21 | + } |
49 | 22 | } |
50 | | - len2 >>= 1; |
51 | | - |
52 | | - // if no more bits set, then done |
53 | | - if len2 == 0 { |
54 | | - break; |
| 23 | + m >>= 1; |
| 24 | + if b & 1 != 0 { |
| 25 | + b = (b >> 1) ^ POLY; |
| 26 | + } else { |
| 27 | + b >>= 1; |
55 | 28 | } |
| 29 | + } |
56 | 30 |
|
57 | | - // another iteration of the loop with odd and even swapped |
58 | | - gf2_matrix_square(&mut odd, &even); |
59 | | - if len2 & 1 == 1 { |
60 | | - crc1 = gf2_matrix_times(&odd, crc1); |
61 | | - } |
62 | | - len2 >>= 1; |
| 31 | + p |
| 32 | +} |
| 33 | + |
| 34 | +pub(crate) fn combine(crc1: u32, crc2: u32, len2: u64) -> u32 { |
| 35 | + let mut p = 1u32 << 31; // x^0 == 1 |
| 36 | + let n = 64 - len2.leading_zeros(); |
63 | 37 |
|
64 | | - // if no more bits set, then done |
65 | | - if len2 == 0 { |
66 | | - break; |
| 38 | + for i in 0..n { |
| 39 | + if (len2 >> i & 1) != 0 { |
| 40 | + p = multiply(X2N_TABLE[(i & 0x1F) as usize], p); |
67 | 41 | } |
68 | 42 | } |
69 | 43 |
|
70 | | - // return combined crc |
71 | | - crc1 ^ crc2 |
| 44 | + multiply(p, crc1) ^ crc2 |
| 45 | +} |
| 46 | + |
| 47 | +#[test] |
| 48 | +fn golden() { |
| 49 | + assert_eq!( |
| 50 | + combine(0xB8AD0532, 0x804754D9, 0x19B77C403D9D90EE), |
| 51 | + 940758956 |
| 52 | + ); |
| 53 | + assert_eq!( |
| 54 | + combine(0xF310DC54, 0x8B65DF79, 0x2F0327F1309076FF), |
| 55 | + 3454617599 |
| 56 | + ); |
72 | 57 | } |
0 commit comments