rustlavel_http/compression/checksum.rs
1//! The two checksums the compressed formats carry.
2//!
3//! gzip (RFC 1952 §2.3.1) ends a member with a CRC-32 of the uncompressed
4//! data; zlib (RFC 1950 §2.2) ends its stream with an Adler-32. Neither is a
5//! cryptographic hash — they exist to catch a truncated or corrupted stream
6//! before a caller trusts the bytes that came out of the inflater — so the
7//! "no cryptography from scratch" exception does not apply and both are
8//! written here.
9//!
10//! Both come in an incremental form (`Crc32::new().update(..).finish()`) for
11//! callers that see the data in pieces, and a one-shot function for the
12//! common case.
13
14/// The reflected form of the IEEE 802.3 polynomial 0x04C11DB7. Reflecting it
15/// lets the byte-at-a-time loop shift right and read the input least
16/// significant bit first, which is the bit order gzip, zip and PNG all agree
17/// on.
18const CRC32_POLYNOMIAL: u32 = 0xEDB8_8320;
19
20/// One entry per byte value: the CRC of that byte alone. Built at compile
21/// time, so it costs nothing at start-up and lives in read-only memory.
22const CRC32_TABLE: [u32; 256] = build_crc32_table();
23
24const fn build_crc32_table() -> [u32; 256] {
25 let mut table = [0u32; 256];
26 let mut byte = 0;
27 while byte < 256 {
28 let mut crc = byte as u32;
29 let mut bit = 0;
30 while bit < 8 {
31 crc = if crc & 1 != 0 { CRC32_POLYNOMIAL ^ (crc >> 1) } else { crc >> 1 };
32 bit += 1;
33 }
34 table[byte] = crc;
35 byte += 1;
36 }
37 table
38}
39
40/// The CRC-32 gzip uses (IEEE 802.3, reflected, initial value and final XOR
41/// both all-ones). `crc32(b"123456789")` is `0xCBF43926`, the check value
42/// every CRC catalogue lists for this variant.
43pub fn crc32(bytes: &[u8]) -> u32 {
44 let mut crc = Crc32::new();
45 crc.update(bytes);
46 crc.finish()
47}
48
49/// An incremental CRC-32.
50#[derive(Debug, Clone)]
51pub struct Crc32 {
52 /// The running register, kept inverted so that `update` is a plain table
53 /// loop and the initial value / final XOR of the standard fall out of
54 /// `new` and `finish`.
55 state: u32,
56}
57
58impl Default for Crc32 {
59 fn default() -> Self {
60 Self::new()
61 }
62}
63
64impl Crc32 {
65 pub fn new() -> Self {
66 Self { state: 0xFFFF_FFFF }
67 }
68
69 pub fn update(&mut self, bytes: &[u8]) {
70 let mut crc = self.state;
71 for &byte in bytes {
72 crc = CRC32_TABLE[((crc ^ u32::from(byte)) & 0xFF) as usize] ^ (crc >> 8);
73 }
74 self.state = crc;
75 }
76
77 pub fn finish(&self) -> u32 {
78 !self.state
79 }
80}
81
82/// The largest prime below 2^16, which is what makes Adler-32 slightly better
83/// at catching errors than a plain 16-bit sum (RFC 1950 §8.2).
84const ADLER_MODULUS: u32 = 65_521;
85
86/// How many bytes can be added to the running sums before either of them can
87/// overflow a `u32`, so the modulo only needs taking once per chunk rather
88/// than once per byte. The bound is the one zlib derives: the largest `n`
89/// with `255n(n+1)/2 + (n+1)(65520) < 2^32`.
90const ADLER_CHUNK: usize = 5552;
91
92/// Adler-32, the zlib trailer checksum. `adler32(b"Wikipedia")` is
93/// `0x11E60398`.
94pub fn adler32(bytes: &[u8]) -> u32 {
95 let mut adler = Adler32::new();
96 adler.update(bytes);
97 adler.finish()
98}
99
100/// An incremental Adler-32.
101#[derive(Debug, Clone)]
102pub struct Adler32 {
103 /// The sum of every byte seen so far, starting from one — the "a" of the
104 /// RFC — and the sum of every intermediate value of `a` — the "b".
105 a: u32,
106 b: u32,
107}
108
109impl Default for Adler32 {
110 fn default() -> Self {
111 Self::new()
112 }
113}
114
115impl Adler32 {
116 pub fn new() -> Self {
117 Self { a: 1, b: 0 }
118 }
119
120 pub fn update(&mut self, bytes: &[u8]) {
121 for chunk in bytes.chunks(ADLER_CHUNK) {
122 for &byte in chunk {
123 self.a += u32::from(byte);
124 self.b += self.a;
125 }
126 self.a %= ADLER_MODULUS;
127 self.b %= ADLER_MODULUS;
128 }
129 }
130
131 pub fn finish(&self) -> u32 {
132 (self.b << 16) | self.a
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn crc32_check_value() {
142 // The reference check value for CRC-32/ISO-HDLC, the variant gzip uses.
143 assert_eq!(crc32(b"123456789"), 0xCBF4_3926);
144 }
145
146 #[test]
147 fn crc32_of_nothing_is_zero() {
148 assert_eq!(crc32(b""), 0);
149 }
150
151 #[test]
152 fn crc32_incremental_matches_one_shot() {
153 let data: Vec<u8> = (0..10_000u32).map(|i| (i * 7 % 251) as u8).collect();
154 let mut crc = Crc32::new();
155 for piece in data.chunks(333) {
156 crc.update(piece);
157 }
158 assert_eq!(crc.finish(), crc32(&data));
159 }
160
161 #[test]
162 fn adler32_check_value() {
163 // The worked example from the Wikipedia article on Adler-32.
164 assert_eq!(adler32(b"Wikipedia"), 0x11E6_0398);
165 }
166
167 #[test]
168 fn adler32_of_nothing_is_one() {
169 // RFC 1950 §8.2: "a" starts at one, so the empty checksum is 1, not 0.
170 assert_eq!(adler32(b""), 1);
171 }
172
173 #[test]
174 fn adler32_incremental_matches_one_shot_across_chunk_boundary() {
175 // Long enough that the deferred modulo has to be taken several times,
176 // and split at odd sizes so chunk boundaries do not line up with it.
177 let data: Vec<u8> = (0..30_000u32).map(|i| (i.wrapping_mul(2654435761) >> 24) as u8).collect();
178 let mut adler = Adler32::new();
179 for piece in data.chunks(1234) {
180 adler.update(piece);
181 }
182 assert_eq!(adler.finish(), adler32(&data));
183 // And a high-valued input, where the sums grow fastest.
184 let ones = vec![0xFFu8; 3 * ADLER_CHUNK + 17];
185 let mut adler = Adler32::new();
186 adler.update(&ones[..100]);
187 adler.update(&ones[100..]);
188 assert_eq!(adler.finish(), adler32(&ones));
189 }
190}