Coverage Report

Created: 2026-11-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/crc32fast-1.5.5/src/combine.rs
Line
Count
Source
1
const POLY: u32 = 0xedb88320;
2
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
];
9
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
0
const fn multiply(a: u32, mut b: u32) -> u32 {
13
0
    let mut p = 0u32;
14
15
0
    let mut i = 0;
16
0
    while i < 32 {
17
0
        p ^= b & ((a >> (31 - i)) & 1).wrapping_neg();
18
0
        b = (b >> 1) ^ ((b & 1).wrapping_neg() & POLY);
19
0
        i += 1;
20
0
    }
21
22
0
    p
23
0
}
24
25
/// Returns x^(8 * len) modulo p(x), reflected. Multiplying a CRC state by it appends `len` zero
26
/// bytes.
27
0
const fn x8n(len: u64) -> u32 {
28
0
    let mut p = 0x8000_0000; // x^0
29
0
    let mut sq = 0x0080_0000; // x^8
30
0
    let mut n = len;
31
0
    while n != 0 {
32
0
        if n & 1 != 0 {
33
0
            p = multiply(sq, p);
34
0
        }
35
0
        sq = multiply(sq, sq);
36
0
        n >>= 1;
37
    }
38
0
    p
39
0
}
40
41
/// The constants that fold a 128-bit accumulator forward by `bits` bits with two carry-less
42
/// multiplies: `(x^(bits + 32), x^(bits - 32))` modulo p(x), reflected, as 33-bit values (the
43
/// `K1`..`K4` of `specialized/pclmulqdq.rs`, which a test checks).
44
#[cfg_attr(
45
    not(all(stable_arm_crc32_intrinsics, target_arch = "aarch64")),
46
    allow(dead_code)
47
)]
48
0
pub(crate) const fn fold_keys(bits: u64) -> [u64; 2] {
49
0
    [
50
0
        (x8n((bits + 32) / 8) as u64) << 1,
51
0
        (x8n((bits - 32) / 8) as u64) << 1,
52
0
    ]
53
0
}
54
55
/// Builds tables that append `len` zero bytes to a CRC state a byte at a time: the new state is
56
/// the XOR of `table[k][(state >> (8 * k)) & 0xFF]` for `k` in `0..4`.
57
#[cfg_attr(
58
    not(all(stable_arm_crc32_intrinsics, target_arch = "aarch64")),
59
    allow(dead_code)
60
)]
61
0
pub(crate) const fn shift_table(len: u64) -> [[u32; 256]; 4] {
62
0
    let x = x8n(len);
63
0
    let mut table = [[0u32; 256]; 4];
64
0
    let mut k = 0;
65
0
    while k < 4 {
66
0
        let mut v = 0;
67
0
        while v < 256 {
68
0
            table[k][v] = multiply(x, (v as u32) << (8 * k));
69
0
            v += 1;
70
0
        }
71
0
        k += 1;
72
    }
73
0
    table
74
0
}
75
76
/// Appends the zero bytes `table` was built for to the CRC state `state`.
77
#[cfg_attr(
78
    not(all(stable_arm_crc32_intrinsics, target_arch = "aarch64")),
79
    allow(dead_code)
80
)]
81
#[inline(always)]
82
0
pub(crate) fn shift(table: &[[u32; 256]; 4], state: u32) -> u32 {
83
0
    table[0][(state & 0xFF) as usize]
84
0
        ^ table[1][((state >> 8) & 0xFF) as usize]
85
0
        ^ table[2][((state >> 16) & 0xFF) as usize]
86
0
        ^ table[3][(state >> 24) as usize]
87
0
}
88
89
0
pub(crate) fn combine(crc1: u32, crc2: u32, len2: u64) -> u32 {
90
    // Special case: If the length of the second chunk is zero, return the hash
91
    // of the first chunk.
92
0
    if len2 == 0 {
93
0
        return crc1;
94
0
    }
95
96
    // We are padding the first checksum with len2-amount of zeroes. For efficiency,
97
    // this is done in powers-of-two via a lookup table rather than one by one.
98
0
    let mut p = crc1;
99
0
    let n = 64 - len2.leading_zeros();
100
0
    for i in 0..n {
101
0
        if (len2 >> i & 1) != 0 {
102
0
            p = multiply(X2N_TABLE[(i & 0x1F) as usize], p);
103
0
        }
104
    }
105
106
0
    p ^ crc2
107
0
}
108
109
#[test]
110
fn fold_keys_match_the_x86_constants() {
111
    assert_eq!(fold_keys(128), [0x1751997d0, 0x0ccaa009e]);
112
    assert_eq!(fold_keys(512), [0x154442bd4, 0x1c6e41596]);
113
    assert_eq!(fold_keys(1024), [0x1e88ef372, 0x14a7fe880]);
114
    assert_eq!(fold_keys(2048), [0x11542778a, 0x1322d1430]);
115
}
116
117
#[test]
118
fn shift_table_appends_zeros() {
119
    for &len in &[1u64, 7, 512, 32768] {
120
        let table = shift_table(len);
121
        let zeros = vec![0u8; len as usize];
122
        for &state in &[0u32, 1, 0x8000_0000, 0xDEAD_BEEF, 0xFFFF_FFFF, 0x1234_5678] {
123
            // `update_slow` takes and returns finalized CRCs, which are the inverted state.
124
            let expected = !crate::baseline::update_slow(!state, &zeros);
125
            assert_eq!(
126
                shift(&table, state),
127
                expected,
128
                "len={len} state={state:#010x}"
129
            );
130
        }
131
    }
132
}
133
134
#[test]
135
fn golden() {
136
    assert_eq!(combine(0x0, 0x1, 0x0), 0x0);
137
    assert_eq!(combine(0xc401f8c9, 0x00000000, 0x0), 0xc401f8c9);
138
    assert_eq!(combine(0x7cba3d5e, 0xe7466d39, 0xb), 0x76365c4f);
139
    assert_eq!(combine(0x576c62d6, 0x123256e1, 0x47), 0x579a636);
140
    assert_eq!(combine(0x4f626f9a, 0x9e5ccbf5, 0xa59d), 0x98d43168);
141
    assert_eq!(combine(0xa09b8a88, 0x815b0f48, 0x40f39511), 0xd7a5f79);
142
    assert_eq!(
143
        combine(0x7f6a4306, 0xbc929646, 0x828cde72b3e25301),
144
        0xef922dda
145
    );
146
}