crc32c/
combine.rs

1//! Implements the CRC32c "combine" function, which calculates the CRC32c of two byte streams
2//! concatenated together using their individual CRC32c values (plus the length of the second byte
3//! stream).
4//!
5//! This module is essentially a line-by-line translation of ZLIB's CRC "combine" function
6//! implementation from C to Rust, except for the CRC polynomial used (original uses the CRC32
7//! polynomial 0xedb88320UL, we use the CRC32c polynomial 0x82F63B78).
8//!
9//! Link to original implementation: https://github.com/madler/zlib/blob/master/crc32.c
10//!
11//! This file is based on the Zlib project, located at: https://github.com/madler/zlib,
12//! which includes the following notice:
13//!
14//! crc32.c -- compute the CRC-32 of a data stream
15//! Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler
16//! For conditions of distribution and use, see copyright notice in zlib.h
17//!
18//! Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
19//! CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
20//! tables for updating the shift register in one step with three exclusive-ors
21//! instead of four steps with four exclusive-ors.  This results in about a
22//! factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
23
24const GF2_DIM: usize = 32;
25
26fn gf2_matrix_times(mat: &[u32; GF2_DIM], mut vec: u32) -> u32 {
27    let mut sum = 0;
28    let mut idx = 0;
29    while vec > 0 {
30        if vec & 1 == 1 {
31            sum ^= mat[idx];
32        }
33        vec >>= 1;
34        idx += 1;
35    }
36    sum
37}
38
39fn gf2_matrix_square(square: &mut [u32; GF2_DIM], mat: &[u32; GF2_DIM]) {
40    for n in 0..GF2_DIM {
41        square[n] = gf2_matrix_times(mat, mat[n]);
42    }
43}
44
45pub(crate) fn crc32c_combine(mut crc1: u32, crc2: u32, mut len2: usize) -> u32 {
46    let mut row: u32 = 1;
47    let mut even = [0u32; GF2_DIM]; /* even-power-of-two zeros operator */
48    let mut odd = [0u32; GF2_DIM]; /* odd-power-of-two zeros operator */
49
50    /* degenerate case (also disallow negative lengths) */
51    if len2 == 0 {
52        return crc1;
53    }
54
55    /* put operator for one zero bit in odd */
56    odd[0] = 0x82F63B78; /* CRC-32c polynomial */
57    #[allow(clippy::needless_range_loop)]
58    for n in 1..GF2_DIM {
59        odd[n] = row;
60        row <<= 1;
61    }
62
63    /* put operator for two zero bits in even */
64    gf2_matrix_square(&mut even, &odd);
65
66    /* put operator for four zero bits in odd */
67    gf2_matrix_square(&mut odd, &even);
68
69    /* apply len2 zeros to crc1 (first square will put the operator for one
70    zero byte, eight zero bits, in even) */
71    loop {
72        /* apply zeros operator for this bit of len2 */
73        gf2_matrix_square(&mut even, &odd);
74        if len2 & 1 == 1 {
75            crc1 = gf2_matrix_times(&even, crc1);
76        }
77        len2 >>= 1;
78
79        /* if no more bits set, then done */
80        if len2 == 0 {
81            break;
82        }
83
84        /* another iteration of the loop with odd and even swapped */
85        gf2_matrix_square(&mut odd, &even);
86        if len2 & 1 == 1 {
87            crc1 = gf2_matrix_times(&odd, crc1);
88        }
89        len2 >>= 1;
90
91        /* if no more bits set, then done */
92        if len2 == 0 {
93            break;
94        }
95    }
96
97    /* return combined crc */
98    crc1 ^= crc2;
99    crc1
100}