• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Fast, SIMD-accelerated CRC32 (IEEE) checksum computation.
2 //!
3 //! ## Usage
4 //!
5 //! ### Simple usage
6 //!
7 //! For simple use-cases, you can call the [`hash()`] convenience function to
8 //! directly compute the CRC32 checksum for a given byte slice:
9 //!
10 //! ```rust
11 //! let checksum = crc32fast::hash(b"foo bar baz");
12 //! ```
13 //!
14 //! ### Advanced usage
15 //!
16 //! For use-cases that require more flexibility or performance, for example when
17 //! processing large amounts of data, you can create and manipulate a [`Hasher`]:
18 //!
19 //! ```rust
20 //! use crc32fast::Hasher;
21 //!
22 //! let mut hasher = Hasher::new();
23 //! hasher.update(b"foo bar baz");
24 //! let checksum = hasher.finalize();
25 //! ```
26 //!
27 //! ## Performance
28 //!
29 //! This crate contains multiple CRC32 implementations:
30 //!
31 //! - A fast baseline implementation which processes up to 16 bytes per iteration
32 //! - An optimized implementation for modern `x86` using `sse` and `pclmulqdq` instructions
33 //!
34 //! Calling the [`Hasher::new`] constructor at runtime will perform a feature detection to select the most
35 //! optimal implementation for the current CPU feature set.
36 
37 #![cfg_attr(not(feature = "std"), no_std)]
38 #![cfg_attr(
39     all(feature = "nightly", target_arch = "aarch64"),
40     feature(stdsimd, aarch64_target_feature)
41 )]
42 
43 #[deny(missing_docs)]
44 #[cfg(test)]
45 #[macro_use]
46 extern crate quickcheck;
47 
48 #[macro_use]
49 extern crate cfg_if;
50 
51 #[cfg(feature = "std")]
52 use std as core;
53 
54 use core::fmt;
55 use core::hash;
56 
57 mod baseline;
58 mod combine;
59 mod specialized;
60 mod table;
61 
62 /// Computes the CRC32 hash of a byte slice.
63 ///
64 /// Check out [`Hasher`] for more advanced use-cases.
hash(buf: &[u8]) -> u3265 pub fn hash(buf: &[u8]) -> u32 {
66     let mut h = Hasher::new();
67     h.update(buf);
68     h.finalize()
69 }
70 
71 #[derive(Clone)]
72 enum State {
73     Baseline(baseline::State),
74     Specialized(specialized::State),
75 }
76 
77 #[derive(Clone)]
78 /// Represents an in-progress CRC32 computation.
79 pub struct Hasher {
80     amount: u64,
81     state: State,
82 }
83 
84 const DEFAULT_INIT_STATE: u32 = 0;
85 
86 impl Hasher {
87     /// Create a new `Hasher`.
88     ///
89     /// This will perform a CPU feature detection at runtime to select the most
90     /// optimal implementation for the current processor architecture.
new() -> Self91     pub fn new() -> Self {
92         Self::new_with_initial(DEFAULT_INIT_STATE)
93     }
94 
95     /// Create a new `Hasher` with an initial CRC32 state.
96     ///
97     /// This works just like `Hasher::new`, except that it allows for an initial
98     /// CRC32 state to be passed in.
new_with_initial(init: u32) -> Self99     pub fn new_with_initial(init: u32) -> Self {
100         Self::new_with_initial_len(init, 0)
101     }
102 
103     /// Create a new `Hasher` with an initial CRC32 state.
104     ///
105     /// As `new_with_initial`, but also accepts a length (in bytes). The
106     /// resulting object can then be used with `combine` to compute `crc(a ||
107     /// b)` from `crc(a)`, `crc(b)`, and `len(b)`.
new_with_initial_len(init: u32, amount: u64) -> Self108     pub fn new_with_initial_len(init: u32, amount: u64) -> Self {
109         Self::internal_new_specialized(init, amount)
110             .unwrap_or_else(|| Self::internal_new_baseline(init, amount))
111     }
112 
113     #[doc(hidden)]
114     // Internal-only API. Don't use.
internal_new_baseline(init: u32, amount: u64) -> Self115     pub fn internal_new_baseline(init: u32, amount: u64) -> Self {
116         Hasher {
117             amount,
118             state: State::Baseline(baseline::State::new(init)),
119         }
120     }
121 
122     #[doc(hidden)]
123     // Internal-only API. Don't use.
internal_new_specialized(init: u32, amount: u64) -> Option<Self>124     pub fn internal_new_specialized(init: u32, amount: u64) -> Option<Self> {
125         {
126             if let Some(state) = specialized::State::new(init) {
127                 return Some(Hasher {
128                     amount,
129                     state: State::Specialized(state),
130                 });
131             }
132         }
133         None
134     }
135 
136     /// Process the given byte slice and update the hash state.
update(&mut self, buf: &[u8])137     pub fn update(&mut self, buf: &[u8]) {
138         self.amount += buf.len() as u64;
139         match self.state {
140             State::Baseline(ref mut state) => state.update(buf),
141             State::Specialized(ref mut state) => state.update(buf),
142         }
143     }
144 
145     /// Finalize the hash state and return the computed CRC32 value.
finalize(self) -> u32146     pub fn finalize(self) -> u32 {
147         match self.state {
148             State::Baseline(state) => state.finalize(),
149             State::Specialized(state) => state.finalize(),
150         }
151     }
152 
153     /// Reset the hash state.
reset(&mut self)154     pub fn reset(&mut self) {
155         self.amount = 0;
156         match self.state {
157             State::Baseline(ref mut state) => state.reset(),
158             State::Specialized(ref mut state) => state.reset(),
159         }
160     }
161 
162     /// Combine the hash state with the hash state for the subsequent block of bytes.
combine(&mut self, other: &Self)163     pub fn combine(&mut self, other: &Self) {
164         self.amount += other.amount;
165         let other_crc = other.clone().finalize();
166         match self.state {
167             State::Baseline(ref mut state) => state.combine(other_crc, other.amount),
168             State::Specialized(ref mut state) => state.combine(other_crc, other.amount),
169         }
170     }
171 }
172 
173 impl fmt::Debug for Hasher {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result174     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175         f.debug_struct("crc32fast::Hasher").finish()
176     }
177 }
178 
179 impl Default for Hasher {
default() -> Self180     fn default() -> Self {
181         Self::new()
182     }
183 }
184 
185 impl hash::Hasher for Hasher {
write(&mut self, bytes: &[u8])186     fn write(&mut self, bytes: &[u8]) {
187         self.update(bytes)
188     }
189 
finish(&self) -> u64190     fn finish(&self) -> u64 {
191         u64::from(self.clone().finalize())
192     }
193 }
194 
195 #[cfg(test)]
196 mod test {
197     use super::Hasher;
198 
199     quickcheck! {
200         fn combine(bytes_1: Vec<u8>, bytes_2: Vec<u8>) -> bool {
201             let mut hash_a = Hasher::new();
202             hash_a.update(&bytes_1);
203             hash_a.update(&bytes_2);
204             let mut hash_b = Hasher::new();
205             hash_b.update(&bytes_2);
206             let mut hash_c = Hasher::new();
207             hash_c.update(&bytes_1);
208             hash_c.combine(&hash_b);
209 
210             hash_a.finalize() == hash_c.finalize()
211         }
212 
213         fn combine_from_len(bytes_1: Vec<u8>, bytes_2: Vec<u8>) -> bool {
214             let mut hash_a = Hasher::new();
215             hash_a.update(&bytes_1);
216             let a = hash_a.finalize();
217 
218             let mut hash_b = Hasher::new();
219             hash_b.update(&bytes_2);
220             let b = hash_b.finalize();
221 
222             let mut hash_ab = Hasher::new();
223             hash_ab.update(&bytes_1);
224             hash_ab.update(&bytes_2);
225             let ab = hash_ab.finalize();
226 
227             let mut reconstructed = Hasher::new_with_initial_len(a, bytes_1.len() as u64);
228             let hash_b_reconstructed = Hasher::new_with_initial_len(b, bytes_2.len() as u64);
229 
230             reconstructed.combine(&hash_b_reconstructed);
231 
232             reconstructed.finalize() == ab
233         }
234     }
235 }
236