|
25 | 25 |
|
26 | 26 | pub(crate) mod backend; |
27 | 27 | pub mod many; |
| 28 | +pub(crate) mod state; |
28 | 29 |
|
29 | 30 | mod params; |
30 | | - |
31 | 31 | #[cfg(test)] |
32 | 32 | mod test; |
33 | 33 |
|
34 | | -pub use self::params::Params; |
| 34 | +pub use self::{params::Params, state::State}; |
35 | 35 |
|
36 | | -use arrayref::mut_array_refs; |
37 | | -use core::{cmp, fmt, mem::size_of}; |
| 36 | +use core::{fmt, mem::size_of}; |
38 | 37 |
|
39 | 38 | pub(crate) type Word = u64; |
40 | 39 | pub(crate) type Count = u128; |
@@ -97,212 +96,6 @@ pub fn blake2b(input: &[u8]) -> Hash { |
97 | 96 | Params::new().hash(input) |
98 | 97 | } |
99 | 98 |
|
100 | | -/// An incremental hasher for BLAKE2b. |
101 | | -/// |
102 | | -/// To construct a `State` with non-default parameters, see `Params::to_state`. |
103 | | -/// |
104 | | -/// # Example |
105 | | -/// |
106 | | -/// ``` |
107 | | -/// use blake2::blake2b::{blake2b, State}; |
108 | | -/// |
109 | | -/// let mut state = State::new(); |
110 | | -/// |
111 | | -/// state.update(b"foo"); |
112 | | -/// assert_eq!(blake2b(b"foo"), state.finalize()); |
113 | | -/// |
114 | | -/// state.update(b"bar"); |
115 | | -/// assert_eq!(blake2b(b"foobar"), state.finalize()); |
116 | | -/// ``` |
117 | | -#[derive(Clone)] |
118 | | -pub struct State { |
119 | | - words: [Word; 8], |
120 | | - count: Count, |
121 | | - buf: [u8; BLOCKBYTES], |
122 | | - buflen: u8, |
123 | | - last_node: backend::LastNode, |
124 | | - hash_length: u8, |
125 | | - implementation: backend::Implementation, |
126 | | - is_keyed: bool, |
127 | | -} |
128 | | - |
129 | | -impl State { |
130 | | - /// Equivalent to `State::default()` or `Params::default().to_state()`. |
131 | | - pub fn new() -> Self { |
132 | | - Self::with_params(&Params::default()) |
133 | | - } |
134 | | - |
135 | | - fn with_params(params: &Params) -> Self { |
136 | | - let mut state = Self { |
137 | | - words: params.to_words(), |
138 | | - count: 0, |
139 | | - buf: [0; BLOCKBYTES], |
140 | | - buflen: 0, |
141 | | - last_node: params.last_node, |
142 | | - hash_length: params.hash_length, |
143 | | - implementation: params.implementation, |
144 | | - is_keyed: params.key_length > 0, |
145 | | - }; |
146 | | - if state.is_keyed { |
147 | | - state.buf = params.key_block; |
148 | | - state.buflen = state.buf.len() as u8; |
149 | | - } |
150 | | - state |
151 | | - } |
152 | | - |
153 | | - fn fill_buf(&mut self, input: &mut &[u8]) { |
154 | | - let take = cmp::min(BLOCKBYTES - self.buflen as usize, input.len()); |
155 | | - self.buf[self.buflen as usize..self.buflen as usize + take].copy_from_slice(&input[..take]); |
156 | | - self.buflen += take as u8; |
157 | | - *input = &input[take..]; |
158 | | - } |
159 | | - |
160 | | - // If the state already has some input in its buffer, try to fill the buffer and perform a |
161 | | - // compression. However, only do the compression if there's more input coming, otherwise it |
162 | | - // will give the wrong hash it the caller finalizes immediately after. |
163 | | - fn compress_buffer_if_possible(&mut self, input: &mut &[u8]) { |
164 | | - if self.buflen > 0 { |
165 | | - self.fill_buf(input); |
166 | | - if !input.is_empty() { |
167 | | - self.implementation.compress1_loop( |
168 | | - &self.buf, |
169 | | - &mut self.words, |
170 | | - self.count, |
171 | | - self.last_node, |
172 | | - backend::Finalize::No, |
173 | | - backend::Stride::Serial, |
174 | | - ); |
175 | | - self.count = self.count.wrapping_add(BLOCKBYTES as Count); |
176 | | - self.buflen = 0; |
177 | | - } |
178 | | - } |
179 | | - } |
180 | | - |
181 | | - /// Add input to the hash. You can call `update` any number of times. |
182 | | - pub fn update(&mut self, mut input: &[u8]) -> &mut Self { |
183 | | - // If we have a partial buffer, try to complete it. |
184 | | - self.compress_buffer_if_possible(&mut input); |
185 | | - // While there's more than a block of input left (which also means we cleared the buffer |
186 | | - // above), compress blocks directly without copying. |
187 | | - let mut end = input.len().saturating_sub(1); |
188 | | - end -= end % BLOCKBYTES; |
189 | | - if end > 0 { |
190 | | - self.implementation.compress1_loop( |
191 | | - &input[..end], |
192 | | - &mut self.words, |
193 | | - self.count, |
194 | | - self.last_node, |
195 | | - backend::Finalize::No, |
196 | | - backend::Stride::Serial, |
197 | | - ); |
198 | | - self.count = self.count.wrapping_add(end as Count); |
199 | | - input = &input[end..]; |
200 | | - } |
201 | | - // Buffer any remaining input, to be either compressed or finalized in a subsequent call. |
202 | | - // Note that this represents some copying overhead, which in theory we could avoid in |
203 | | - // all-at-once setting. A function hardcoded for exactly BLOCKSIZE input bytes is about 10% |
204 | | - // faster than using this implementation for the same input. |
205 | | - self.fill_buf(&mut input); |
206 | | - self |
207 | | - } |
208 | | - |
209 | | - /// Finalize the state and return a `Hash`. This method is idempotent, and calling it multiple |
210 | | - /// times will give the same result. It's also possible to `update` with more input in between. |
211 | | - pub fn finalize(&self) -> Hash { |
212 | | - let mut words_copy = self.words; |
213 | | - self.implementation.compress1_loop( |
214 | | - &self.buf[..self.buflen as usize], |
215 | | - &mut words_copy, |
216 | | - self.count, |
217 | | - self.last_node, |
218 | | - backend::Finalize::Yes, |
219 | | - backend::Stride::Serial, |
220 | | - ); |
221 | | - Hash { |
222 | | - bytes: state_words_to_bytes(&words_copy), |
223 | | - len: self.hash_length, |
224 | | - } |
225 | | - } |
226 | | - |
227 | | - /// Set a flag indicating that this is the last node of its level in a tree hash. This is |
228 | | - /// equivalent to [`Params::last_node`], except that it can be set at any time before calling |
229 | | - /// `finalize`. That allows callers to begin hashing a node without knowing ahead of time |
230 | | - /// whether it's the last in its level. For more details about the intended use of this flag |
231 | | - /// [the BLAKE2 spec]. |
232 | | - /// |
233 | | - /// [`Params::last_node`]: struct.Params.html#method.last_node |
234 | | - /// [the BLAKE2 spec]: https://blake2.net/blake2.pdf |
235 | | - pub fn set_last_node(&mut self, last_node: bool) -> &mut Self { |
236 | | - self.last_node = if last_node { |
237 | | - backend::LastNode::Yes |
238 | | - } else { |
239 | | - backend::LastNode::No |
240 | | - }; |
241 | | - self |
242 | | - } |
243 | | - |
244 | | - /// Return the total number of bytes input so far. |
245 | | - /// |
246 | | - /// Note that `count` doesn't include the bytes of the key block, if any. |
247 | | - /// It's exactly the total number of input bytes fed to `update`. |
248 | | - pub fn count(&self) -> Count { |
249 | | - let mut ret = self.count.wrapping_add(self.buflen as Count); |
250 | | - if self.is_keyed { |
251 | | - ret -= BLOCKBYTES as Count; |
252 | | - } |
253 | | - ret |
254 | | - } |
255 | | -} |
256 | | - |
257 | | -#[inline(always)] |
258 | | -pub(crate) fn state_words_to_bytes(state_words: &[Word; 8]) -> [u8; OUTBYTES] { |
259 | | - let mut bytes = [0; OUTBYTES]; |
260 | | - { |
261 | | - const W: usize = size_of::<Word>(); |
262 | | - let refs = mut_array_refs!(&mut bytes, W, W, W, W, W, W, W, W); |
263 | | - *refs.0 = state_words[0].to_le_bytes(); |
264 | | - *refs.1 = state_words[1].to_le_bytes(); |
265 | | - *refs.2 = state_words[2].to_le_bytes(); |
266 | | - *refs.3 = state_words[3].to_le_bytes(); |
267 | | - *refs.4 = state_words[4].to_le_bytes(); |
268 | | - *refs.5 = state_words[5].to_le_bytes(); |
269 | | - *refs.6 = state_words[6].to_le_bytes(); |
270 | | - *refs.7 = state_words[7].to_le_bytes(); |
271 | | - } |
272 | | - bytes |
273 | | -} |
274 | | - |
275 | | -#[cfg(feature = "std")] |
276 | | -impl std::io::Write for State { |
277 | | - fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { |
278 | | - self.update(buf); |
279 | | - Ok(buf.len()) |
280 | | - } |
281 | | - |
282 | | - fn flush(&mut self) -> std::io::Result<()> { |
283 | | - Ok(()) |
284 | | - } |
285 | | -} |
286 | | - |
287 | | -impl fmt::Debug for State { |
288 | | - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
289 | | - // NB: Don't print the words. Leaking them would allow length extension. |
290 | | - write!( |
291 | | - f, |
292 | | - "State {{ count: {}, hash_length: {}, last_node: {} }}", |
293 | | - self.count(), |
294 | | - self.hash_length, |
295 | | - self.last_node.yes(), |
296 | | - ) |
297 | | - } |
298 | | -} |
299 | | - |
300 | | -impl Default for State { |
301 | | - fn default() -> Self { |
302 | | - Self::with_params(&Params::default()) |
303 | | - } |
304 | | -} |
305 | | - |
306 | 99 | type HexString = arrayvec::ArrayString<[u8; 2 * OUTBYTES]>; |
307 | 100 |
|
308 | 101 | /// A finalized BLAKE2 hash, with constant-time equality. |
@@ -381,7 +174,7 @@ pub(crate) fn paint_test_input(buf: &mut [u8]) { |
381 | 174 | let mut counter: u32 = 1; |
382 | 175 | while offset < buf.len() { |
383 | 176 | let bytes = counter.to_le_bytes(); |
384 | | - let take = cmp::min(bytes.len(), buf.len() - offset); |
| 177 | + let take = core::cmp::min(bytes.len(), buf.len() - offset); |
385 | 178 | buf[offset..][..take].copy_from_slice(&bytes[..take]); |
386 | 179 | counter += 1; |
387 | 180 | offset += take; |
|
0 commit comments