]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | //! [![GitHub](https://img.shields.io/github/tag/oconnor663/blake2_simd.svg?label=GitHub)](https://github.com/oconnor663/blake2_simd) [![crates.io](https://img.shields.io/crates/v/blake2b_simd.svg)](https://crates.io/crates/blake2b_simd) [![Build Status](https://travis-ci.org/oconnor663/blake2_simd.svg?branch=master)](https://travis-ci.org/oconnor663/blake2_simd) |
2 | //! | |
3 | //! An implementation of the BLAKE2b and BLAKE2bp hash functions. See also | |
4 | //! [`blake2s_simd`](https://docs.rs/blake2s_simd). | |
5 | //! | |
6 | //! This crate includes: | |
7 | //! | |
8 | //! - 100% stable Rust. | |
9 | //! - SIMD implementations based on Samuel Neves' [`blake2-avx2`](https://github.com/sneves/blake2-avx2). | |
10 | //! These are very fast. For benchmarks, see [the Performance section of the | |
11 | //! README](https://github.com/oconnor663/blake2_simd#performance). | |
12 | //! - Portable, safe implementations for other platforms. | |
13 | //! - Dynamic CPU feature detection. Binaries include multiple implementations by default and | |
14 | //! choose the fastest one the processor supports at runtime. | |
15 | //! - All the features from the [the BLAKE2 spec](https://blake2.net/blake2.pdf), like adjustable | |
16 | //! length, keying, and associated data for tree hashing. | |
17 | //! - `no_std` support. The `std` Cargo feature is on by default, for CPU feature detection and | |
18 | //! for implementing `std::io::Write`. | |
19 | //! - Support for computing multiple BLAKE2b hashes in parallel, matching the efficiency of | |
20 | //! BLAKE2bp. See the [`many`](many/index.html) module. | |
21 | //! | |
22 | //! # Example | |
23 | //! | |
24 | //! ``` | |
25 | //! use blake2b_simd::{blake2b, Params}; | |
26 | //! | |
27 | //! let expected = "ca002330e69d3e6b84a46a56a6533fd79d51d97a3bb7cad6c2ff43b354185d6d\ | |
28 | //! c1e723fb3db4ae0737e120378424c714bb982d9dc5bbd7a0ab318240ddd18f8d"; | |
29 | //! let hash = blake2b(b"foo"); | |
30 | //! assert_eq!(expected, &hash.to_hex()); | |
31 | //! | |
32 | //! let hash = Params::new() | |
33 | //! .hash_length(16) | |
34 | //! .key(b"The Magic Words are Squeamish Ossifrage") | |
35 | //! .personal(b"L. P. Waterhouse") | |
36 | //! .to_state() | |
37 | //! .update(b"foo") | |
38 | //! .update(b"bar") | |
39 | //! .update(b"baz") | |
40 | //! .finalize(); | |
41 | //! assert_eq!("ee8ff4e9be887297cf79348dc35dab56", &hash.to_hex()); | |
42 | //! ``` | |
43 | ||
44 | #![cfg_attr(not(feature = "std"), no_std)] | |
45 | ||
46 | use arrayref::{array_refs, mut_array_refs}; | |
47 | use core::cmp; | |
48 | use core::fmt; | |
49 | use core::mem::size_of; | |
50 | ||
51 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
52 | mod avx2; | |
53 | mod portable; | |
54 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
55 | mod sse41; | |
56 | ||
57 | pub mod blake2bp; | |
58 | mod guts; | |
59 | pub mod many; | |
60 | ||
61 | #[cfg(test)] | |
62 | mod test; | |
63 | ||
64 | type Word = u64; | |
65 | type Count = u128; | |
66 | ||
67 | /// The max hash length. | |
68 | pub const OUTBYTES: usize = 8 * size_of::<Word>(); | |
69 | /// The max key length. | |
70 | pub const KEYBYTES: usize = 8 * size_of::<Word>(); | |
71 | /// The max salt length. | |
72 | pub const SALTBYTES: usize = 2 * size_of::<Word>(); | |
73 | /// The max personalization length. | |
74 | pub const PERSONALBYTES: usize = 2 * size_of::<Word>(); | |
75 | /// The number input bytes passed to each call to the compression function. Small benchmarks need | |
76 | /// to use an even multiple of `BLOCKBYTES`, or else their apparent throughput will be low. | |
77 | pub const BLOCKBYTES: usize = 16 * size_of::<Word>(); | |
78 | ||
79 | const IV: [Word; 8] = [ | |
80 | 0x6A09E667F3BCC908, | |
81 | 0xBB67AE8584CAA73B, | |
82 | 0x3C6EF372FE94F82B, | |
83 | 0xA54FF53A5F1D36F1, | |
84 | 0x510E527FADE682D1, | |
85 | 0x9B05688C2B3E6C1F, | |
86 | 0x1F83D9ABFB41BD6B, | |
87 | 0x5BE0CD19137E2179, | |
88 | ]; | |
89 | ||
90 | const SIGMA: [[u8; 16]; 12] = [ | |
91 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], | |
92 | [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], | |
93 | [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], | |
94 | [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], | |
95 | [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], | |
96 | [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], | |
97 | [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], | |
98 | [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], | |
99 | [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], | |
100 | [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0], | |
101 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], | |
102 | [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], | |
103 | ]; | |
104 | ||
105 | /// Compute the BLAKE2b hash of a slice of bytes all at once, using default | |
106 | /// parameters. | |
107 | /// | |
108 | /// # Example | |
109 | /// | |
110 | /// ``` | |
111 | /// # use blake2b_simd::{blake2b, Params}; | |
112 | /// let expected = "ca002330e69d3e6b84a46a56a6533fd79d51d97a3bb7cad6c2ff43b354185d6d\ | |
113 | /// c1e723fb3db4ae0737e120378424c714bb982d9dc5bbd7a0ab318240ddd18f8d"; | |
114 | /// let hash = blake2b(b"foo"); | |
115 | /// assert_eq!(expected, &hash.to_hex()); | |
116 | /// ``` | |
117 | pub fn blake2b(input: &[u8]) -> Hash { | |
118 | Params::new().hash(input) | |
119 | } | |
120 | ||
121 | /// A parameter builder that exposes all the non-default BLAKE2 features. | |
122 | /// | |
123 | /// Apart from `hash_length`, which controls the length of the final `Hash`, | |
124 | /// all of these parameters are just associated data that gets mixed with the | |
125 | /// input. For more details, see [the BLAKE2 spec](https://blake2.net/blake2.pdf). | |
126 | /// | |
127 | /// Several of the parameters have a valid range defined in the spec and | |
128 | /// documented below. Trying to set an invalid parameter will panic. | |
129 | /// | |
130 | /// # Example | |
131 | /// | |
132 | /// ``` | |
133 | /// # use blake2b_simd::Params; | |
134 | /// // Create a Params object with a secret key and a non-default length. | |
135 | /// let mut params = Params::new(); | |
136 | /// params.key(b"my secret key"); | |
137 | /// params.hash_length(16); | |
138 | /// | |
139 | /// // Use those params to hash an input all at once. | |
140 | /// let hash = params.hash(b"my input"); | |
141 | /// | |
142 | /// // Or use those params to build an incremental State. | |
143 | /// let mut state = params.to_state(); | |
144 | /// ``` | |
145 | #[derive(Clone)] | |
146 | pub struct Params { | |
147 | hash_length: u8, | |
148 | key_length: u8, | |
149 | key_block: [u8; BLOCKBYTES], | |
150 | salt: [u8; SALTBYTES], | |
151 | personal: [u8; PERSONALBYTES], | |
152 | fanout: u8, | |
153 | max_depth: u8, | |
154 | max_leaf_length: u32, | |
155 | node_offset: u64, | |
156 | node_depth: u8, | |
157 | inner_hash_length: u8, | |
158 | last_node: guts::LastNode, | |
159 | implementation: guts::Implementation, | |
160 | } | |
161 | ||
162 | impl Params { | |
163 | /// Equivalent to `Params::default()`. | |
164 | #[inline] | |
165 | pub fn new() -> Self { | |
166 | Self { | |
167 | hash_length: OUTBYTES as u8, | |
168 | key_length: 0, | |
169 | key_block: [0; BLOCKBYTES], | |
170 | salt: [0; SALTBYTES], | |
171 | personal: [0; PERSONALBYTES], | |
172 | // NOTE: fanout and max_depth don't default to zero! | |
173 | fanout: 1, | |
174 | max_depth: 1, | |
175 | max_leaf_length: 0, | |
176 | node_offset: 0, | |
177 | node_depth: 0, | |
178 | inner_hash_length: 0, | |
179 | last_node: guts::LastNode::No, | |
180 | implementation: guts::Implementation::detect(), | |
181 | } | |
182 | } | |
183 | ||
184 | #[inline(always)] | |
185 | fn to_words(&self) -> [Word; 8] { | |
186 | let (salt_left, salt_right) = array_refs!(&self.salt, SALTBYTES / 2, SALTBYTES / 2); | |
187 | let (personal_left, personal_right) = | |
188 | array_refs!(&self.personal, PERSONALBYTES / 2, PERSONALBYTES / 2); | |
189 | [ | |
190 | IV[0] | |
191 | ^ self.hash_length as u64 | |
192 | ^ (self.key_length as u64) << 8 | |
193 | ^ (self.fanout as u64) << 16 | |
194 | ^ (self.max_depth as u64) << 24 | |
195 | ^ (self.max_leaf_length as u64) << 32, | |
196 | IV[1] ^ self.node_offset, | |
197 | IV[2] ^ self.node_depth as u64 ^ (self.inner_hash_length as u64) << 8, | |
198 | IV[3], | |
199 | IV[4] ^ Word::from_le_bytes(*salt_left), | |
200 | IV[5] ^ Word::from_le_bytes(*salt_right), | |
201 | IV[6] ^ Word::from_le_bytes(*personal_left), | |
202 | IV[7] ^ Word::from_le_bytes(*personal_right), | |
203 | ] | |
204 | } | |
205 | ||
206 | /// Hash an input all at once with these parameters. | |
207 | #[inline] | |
208 | pub fn hash(&self, input: &[u8]) -> Hash { | |
209 | // If there's a key, just fall back to using the State. | |
210 | if self.key_length > 0 { | |
211 | return self.to_state().update(input).finalize(); | |
212 | } | |
213 | let mut words = self.to_words(); | |
214 | self.implementation.compress1_loop( | |
215 | input, | |
216 | &mut words, | |
217 | 0, | |
218 | self.last_node, | |
219 | guts::Finalize::Yes, | |
220 | guts::Stride::Serial, | |
221 | ); | |
222 | Hash { | |
223 | bytes: state_words_to_bytes(&words), | |
224 | len: self.hash_length, | |
225 | } | |
226 | } | |
227 | ||
228 | /// Construct a `State` object based on these parameters, for hashing input | |
229 | /// incrementally. | |
230 | pub fn to_state(&self) -> State { | |
231 | State::with_params(self) | |
232 | } | |
233 | ||
234 | /// Set the length of the final hash in bytes, from 1 to `OUTBYTES` (64). Apart from | |
235 | /// controlling the length of the final `Hash`, this is also associated data, and changing it | |
236 | /// will result in a totally different hash. | |
237 | #[inline] | |
238 | pub fn hash_length(&mut self, length: usize) -> &mut Self { | |
239 | assert!( | |
240 | 1 <= length && length <= OUTBYTES, | |
241 | "Bad hash length: {}", | |
242 | length | |
243 | ); | |
244 | self.hash_length = length as u8; | |
245 | self | |
246 | } | |
247 | ||
248 | /// Use a secret key, so that BLAKE2 acts as a MAC. The maximum key length is `KEYBYTES` (64). | |
249 | /// An empty key is equivalent to having no key at all. | |
250 | #[inline] | |
251 | pub fn key(&mut self, key: &[u8]) -> &mut Self { | |
252 | assert!(key.len() <= KEYBYTES, "Bad key length: {}", key.len()); | |
253 | self.key_length = key.len() as u8; | |
254 | self.key_block = [0; BLOCKBYTES]; | |
255 | self.key_block[..key.len()].copy_from_slice(key); | |
256 | self | |
257 | } | |
258 | ||
259 | /// At most `SALTBYTES` (16). Shorter salts are padded with null bytes. An empty salt is | |
260 | /// equivalent to having no salt at all. | |
261 | #[inline] | |
262 | pub fn salt(&mut self, salt: &[u8]) -> &mut Self { | |
263 | assert!(salt.len() <= SALTBYTES, "Bad salt length: {}", salt.len()); | |
264 | self.salt = [0; SALTBYTES]; | |
265 | self.salt[..salt.len()].copy_from_slice(salt); | |
266 | self | |
267 | } | |
268 | ||
269 | /// At most `PERSONALBYTES` (16). Shorter personalizations are padded with null bytes. An empty | |
270 | /// personalization is equivalent to having no personalization at all. | |
271 | #[inline] | |
272 | pub fn personal(&mut self, personalization: &[u8]) -> &mut Self { | |
273 | assert!( | |
274 | personalization.len() <= PERSONALBYTES, | |
275 | "Bad personalization length: {}", | |
276 | personalization.len() | |
277 | ); | |
278 | self.personal = [0; PERSONALBYTES]; | |
279 | self.personal[..personalization.len()].copy_from_slice(personalization); | |
280 | self | |
281 | } | |
282 | ||
283 | /// From 0 (meaning unlimited) to 255. The default is 1 (meaning sequential). | |
284 | #[inline] | |
285 | pub fn fanout(&mut self, fanout: u8) -> &mut Self { | |
286 | self.fanout = fanout; | |
287 | self | |
288 | } | |
289 | ||
290 | /// From 0 (meaning BLAKE2X B2 hashes), through 1 (the default, meaning sequential) to 255 (meaning unlimited). | |
291 | #[inline] | |
292 | pub fn max_depth(&mut self, depth: u8) -> &mut Self { | |
293 | self.max_depth = depth; | |
294 | self | |
295 | } | |
296 | ||
297 | /// From 0 (the default, meaning unlimited or sequential) to `2^32 - 1`. | |
298 | #[inline] | |
299 | pub fn max_leaf_length(&mut self, length: u32) -> &mut Self { | |
300 | self.max_leaf_length = length; | |
301 | self | |
302 | } | |
303 | ||
304 | /// From 0 (the default, meaning first, leftmost, leaf, or sequential) to `2^64 - 1`. | |
305 | #[inline] | |
306 | pub fn node_offset(&mut self, offset: u64) -> &mut Self { | |
307 | self.node_offset = offset; | |
308 | self | |
309 | } | |
310 | ||
311 | /// From 0 (the default, meaning leaf or sequential) to 255. | |
312 | #[inline] | |
313 | pub fn node_depth(&mut self, depth: u8) -> &mut Self { | |
314 | self.node_depth = depth; | |
315 | self | |
316 | } | |
317 | ||
318 | /// From 0 (the default, meaning sequential) to `OUTBYTES` (64). | |
319 | #[inline] | |
320 | pub fn inner_hash_length(&mut self, length: usize) -> &mut Self { | |
321 | assert!(length <= OUTBYTES, "Bad inner hash length: {}", length); | |
322 | self.inner_hash_length = length as u8; | |
323 | self | |
324 | } | |
325 | ||
326 | /// Indicates the rightmost node in a row. This can also be changed on the | |
327 | /// `State` object, potentially after hashing has begun. See | |
328 | /// [`State::set_last_node`]. | |
329 | /// | |
330 | /// [`State::set_last_node`]: struct.State.html#method.set_last_node | |
331 | #[inline] | |
332 | pub fn last_node(&mut self, last_node: bool) -> &mut Self { | |
333 | self.last_node = if last_node { | |
334 | guts::LastNode::Yes | |
335 | } else { | |
336 | guts::LastNode::No | |
337 | }; | |
338 | self | |
339 | } | |
340 | } | |
341 | ||
342 | impl Default for Params { | |
343 | fn default() -> Self { | |
344 | Self::new() | |
345 | } | |
346 | } | |
347 | ||
348 | impl fmt::Debug for Params { | |
349 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
350 | write!( | |
351 | f, | |
352 | "Params {{ hash_length: {}, key_length: {}, salt: {:?}, personal: {:?}, fanout: {}, \ | |
353 | max_depth: {}, max_leaf_length: {}, node_offset: {}, node_depth: {}, \ | |
354 | inner_hash_length: {}, last_node: {} }}", | |
355 | self.hash_length, | |
356 | // NB: Don't print the key itself. Debug shouldn't leak secrets. | |
357 | self.key_length, | |
358 | &self.salt, | |
359 | &self.personal, | |
360 | self.fanout, | |
361 | self.max_depth, | |
362 | self.max_leaf_length, | |
363 | self.node_offset, | |
364 | self.node_depth, | |
365 | self.inner_hash_length, | |
366 | self.last_node.yes(), | |
367 | ) | |
368 | } | |
369 | } | |
370 | ||
371 | /// An incremental hasher for BLAKE2b. | |
372 | /// | |
373 | /// To construct a `State` with non-default parameters, see `Params::to_state`. | |
374 | /// | |
375 | /// # Example | |
376 | /// | |
377 | /// ``` | |
378 | /// use blake2b_simd::{State, blake2b}; | |
379 | /// | |
380 | /// let mut state = blake2b_simd::State::new(); | |
381 | /// | |
382 | /// state.update(b"foo"); | |
383 | /// assert_eq!(blake2b(b"foo"), state.finalize()); | |
384 | /// | |
385 | /// state.update(b"bar"); | |
386 | /// assert_eq!(blake2b(b"foobar"), state.finalize()); | |
387 | /// ``` | |
388 | #[derive(Clone)] | |
389 | pub struct State { | |
390 | words: [Word; 8], | |
391 | count: Count, | |
392 | buf: [u8; BLOCKBYTES], | |
393 | buflen: u8, | |
394 | last_node: guts::LastNode, | |
395 | hash_length: u8, | |
396 | implementation: guts::Implementation, | |
397 | is_keyed: bool, | |
398 | } | |
399 | ||
400 | impl State { | |
401 | /// Equivalent to `State::default()` or `Params::default().to_state()`. | |
402 | pub fn new() -> Self { | |
403 | Self::with_params(&Params::default()) | |
404 | } | |
405 | ||
406 | fn with_params(params: &Params) -> Self { | |
407 | let mut state = Self { | |
408 | words: params.to_words(), | |
409 | count: 0, | |
410 | buf: [0; BLOCKBYTES], | |
411 | buflen: 0, | |
412 | last_node: params.last_node, | |
413 | hash_length: params.hash_length, | |
414 | implementation: params.implementation, | |
415 | is_keyed: params.key_length > 0, | |
416 | }; | |
417 | if state.is_keyed { | |
418 | state.buf = params.key_block; | |
419 | state.buflen = state.buf.len() as u8; | |
420 | } | |
421 | state | |
422 | } | |
423 | ||
424 | fn fill_buf(&mut self, input: &mut &[u8]) { | |
425 | let take = cmp::min(BLOCKBYTES - self.buflen as usize, input.len()); | |
426 | self.buf[self.buflen as usize..self.buflen as usize + take].copy_from_slice(&input[..take]); | |
427 | self.buflen += take as u8; | |
428 | *input = &input[take..]; | |
429 | } | |
430 | ||
431 | // If the state already has some input in its buffer, try to fill the buffer and perform a | |
432 | // compression. However, only do the compression if there's more input coming, otherwise it | |
433 | // will give the wrong hash it the caller finalizes immediately after. | |
434 | fn compress_buffer_if_possible(&mut self, input: &mut &[u8]) { | |
435 | if self.buflen > 0 { | |
436 | self.fill_buf(input); | |
437 | if !input.is_empty() { | |
438 | self.implementation.compress1_loop( | |
439 | &self.buf, | |
440 | &mut self.words, | |
441 | self.count, | |
442 | self.last_node, | |
443 | guts::Finalize::No, | |
444 | guts::Stride::Serial, | |
445 | ); | |
446 | self.count = self.count.wrapping_add(BLOCKBYTES as Count); | |
447 | self.buflen = 0; | |
448 | } | |
449 | } | |
450 | } | |
451 | ||
452 | /// Add input to the hash. You can call `update` any number of times. | |
453 | pub fn update(&mut self, mut input: &[u8]) -> &mut Self { | |
454 | // If we have a partial buffer, try to complete it. | |
455 | self.compress_buffer_if_possible(&mut input); | |
456 | // While there's more than a block of input left (which also means we cleared the buffer | |
457 | // above), compress blocks directly without copying. | |
458 | let mut end = input.len().saturating_sub(1); | |
459 | end -= end % BLOCKBYTES; | |
460 | if end > 0 { | |
461 | self.implementation.compress1_loop( | |
462 | &input[..end], | |
463 | &mut self.words, | |
464 | self.count, | |
465 | self.last_node, | |
466 | guts::Finalize::No, | |
467 | guts::Stride::Serial, | |
468 | ); | |
469 | self.count = self.count.wrapping_add(end as Count); | |
470 | input = &input[end..]; | |
471 | } | |
472 | // Buffer any remaining input, to be either compressed or finalized in a subsequent call. | |
473 | // Note that this represents some copying overhead, which in theory we could avoid in | |
474 | // all-at-once setting. A function hardcoded for exactly BLOCKSIZE input bytes is about 10% | |
475 | // faster than using this implementation for the same input. | |
476 | self.fill_buf(&mut input); | |
477 | self | |
478 | } | |
479 | ||
480 | /// Finalize the state and return a `Hash`. This method is idempotent, and calling it multiple | |
481 | /// times will give the same result. It's also possible to `update` with more input in between. | |
482 | pub fn finalize(&self) -> Hash { | |
483 | let mut words_copy = self.words; | |
484 | self.implementation.compress1_loop( | |
485 | &self.buf[..self.buflen as usize], | |
486 | &mut words_copy, | |
487 | self.count, | |
488 | self.last_node, | |
489 | guts::Finalize::Yes, | |
490 | guts::Stride::Serial, | |
491 | ); | |
492 | Hash { | |
493 | bytes: state_words_to_bytes(&words_copy), | |
494 | len: self.hash_length, | |
495 | } | |
496 | } | |
497 | ||
498 | /// Set a flag indicating that this is the last node of its level in a tree hash. This is | |
499 | /// equivalent to [`Params::last_node`], except that it can be set at any time before calling | |
500 | /// `finalize`. That allows callers to begin hashing a node without knowing ahead of time | |
501 | /// whether it's the last in its level. For more details about the intended use of this flag | |
502 | /// [the BLAKE2 spec]. | |
503 | /// | |
504 | /// [`Params::last_node`]: struct.Params.html#method.last_node | |
505 | /// [the BLAKE2 spec]: https://blake2.net/blake2.pdf | |
506 | pub fn set_last_node(&mut self, last_node: bool) -> &mut Self { | |
507 | self.last_node = if last_node { | |
508 | guts::LastNode::Yes | |
509 | } else { | |
510 | guts::LastNode::No | |
511 | }; | |
512 | self | |
513 | } | |
514 | ||
515 | /// Return the total number of bytes input so far. | |
516 | /// | |
517 | /// Note that `count` doesn't include the bytes of the key block, if any. | |
518 | /// It's exactly the total number of input bytes fed to `update`. | |
519 | pub fn count(&self) -> Count { | |
520 | let mut ret = self.count.wrapping_add(self.buflen as Count); | |
521 | if self.is_keyed { | |
522 | ret -= BLOCKBYTES as Count; | |
523 | } | |
524 | ret | |
525 | } | |
526 | } | |
527 | ||
528 | #[inline(always)] | |
529 | fn state_words_to_bytes(state_words: &[Word; 8]) -> [u8; OUTBYTES] { | |
530 | let mut bytes = [0; OUTBYTES]; | |
531 | { | |
532 | const W: usize = size_of::<Word>(); | |
533 | let refs = mut_array_refs!(&mut bytes, W, W, W, W, W, W, W, W); | |
534 | *refs.0 = state_words[0].to_le_bytes(); | |
535 | *refs.1 = state_words[1].to_le_bytes(); | |
536 | *refs.2 = state_words[2].to_le_bytes(); | |
537 | *refs.3 = state_words[3].to_le_bytes(); | |
538 | *refs.4 = state_words[4].to_le_bytes(); | |
539 | *refs.5 = state_words[5].to_le_bytes(); | |
540 | *refs.6 = state_words[6].to_le_bytes(); | |
541 | *refs.7 = state_words[7].to_le_bytes(); | |
542 | } | |
543 | bytes | |
544 | } | |
545 | ||
546 | #[cfg(feature = "std")] | |
547 | impl std::io::Write for State { | |
548 | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { | |
549 | self.update(buf); | |
550 | Ok(buf.len()) | |
551 | } | |
552 | ||
553 | fn flush(&mut self) -> std::io::Result<()> { | |
554 | Ok(()) | |
555 | } | |
556 | } | |
557 | ||
558 | impl fmt::Debug for State { | |
559 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
560 | // NB: Don't print the words. Leaking them would allow length extension. | |
561 | write!( | |
562 | f, | |
563 | "State {{ count: {}, hash_length: {}, last_node: {} }}", | |
564 | self.count(), | |
565 | self.hash_length, | |
566 | self.last_node.yes(), | |
567 | ) | |
568 | } | |
569 | } | |
570 | ||
571 | impl Default for State { | |
572 | fn default() -> Self { | |
573 | Self::with_params(&Params::default()) | |
574 | } | |
575 | } | |
576 | ||
577 | type HexString = arrayvec::ArrayString<[u8; 2 * OUTBYTES]>; | |
578 | ||
579 | /// A finalized BLAKE2 hash, with constant-time equality. | |
580 | #[derive(Clone, Copy)] | |
581 | pub struct Hash { | |
582 | bytes: [u8; OUTBYTES], | |
583 | len: u8, | |
584 | } | |
585 | ||
586 | impl Hash { | |
587 | /// Convert the hash to a byte slice. Note that if you're using BLAKE2 as a MAC, you need | |
588 | /// constant time equality, which `&[u8]` doesn't provide. | |
589 | pub fn as_bytes(&self) -> &[u8] { | |
590 | &self.bytes[..self.len as usize] | |
591 | } | |
592 | ||
593 | /// Convert the hash to a byte array. Note that if you're using BLAKE2 as a | |
594 | /// MAC, you need constant time equality, which arrays don't provide. This | |
595 | /// panics in debug mode if the length of the hash isn't `OUTBYTES`. | |
596 | #[inline] | |
597 | pub fn as_array(&self) -> &[u8; OUTBYTES] { | |
598 | debug_assert_eq!(self.len as usize, OUTBYTES); | |
599 | &self.bytes | |
600 | } | |
601 | ||
602 | /// Convert the hash to a lowercase hexadecimal | |
603 | /// [`ArrayString`](https://docs.rs/arrayvec/0.4/arrayvec/struct.ArrayString.html). | |
604 | pub fn to_hex(&self) -> HexString { | |
605 | bytes_to_hex(self.as_bytes()) | |
606 | } | |
607 | } | |
608 | ||
609 | fn bytes_to_hex(bytes: &[u8]) -> HexString { | |
610 | let mut s = arrayvec::ArrayString::new(); | |
611 | let table = b"0123456789abcdef"; | |
612 | for &b in bytes { | |
613 | s.push(table[(b >> 4) as usize] as char); | |
614 | s.push(table[(b & 0xf) as usize] as char); | |
615 | } | |
616 | s | |
617 | } | |
618 | ||
619 | /// This implementation is constant time, if the two hashes are the same length. | |
620 | impl PartialEq for Hash { | |
621 | fn eq(&self, other: &Hash) -> bool { | |
622 | constant_time_eq::constant_time_eq(&self.as_bytes(), &other.as_bytes()) | |
623 | } | |
624 | } | |
625 | ||
626 | /// This implementation is constant time, if the slice is the same length as the hash. | |
627 | impl PartialEq<[u8]> for Hash { | |
628 | fn eq(&self, other: &[u8]) -> bool { | |
629 | constant_time_eq::constant_time_eq(&self.as_bytes(), other) | |
630 | } | |
631 | } | |
632 | ||
633 | impl Eq for Hash {} | |
634 | ||
635 | impl AsRef<[u8]> for Hash { | |
636 | fn as_ref(&self) -> &[u8] { | |
637 | self.as_bytes() | |
638 | } | |
639 | } | |
640 | ||
641 | impl fmt::Debug for Hash { | |
642 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
643 | write!(f, "Hash(0x{})", self.to_hex()) | |
644 | } | |
645 | } | |
646 | ||
647 | // Paint a byte pattern that won't repeat, so that we don't accidentally miss | |
648 | // buffer offset bugs. This is the same as what Bao uses in its tests. | |
649 | #[cfg(test)] | |
650 | fn paint_test_input(buf: &mut [u8]) { | |
651 | let mut offset = 0; | |
652 | let mut counter: u32 = 1; | |
653 | while offset < buf.len() { | |
654 | let bytes = counter.to_le_bytes(); | |
655 | let take = cmp::min(bytes.len(), buf.len() - offset); | |
656 | buf[offset..][..take].copy_from_slice(&bytes[..take]); | |
657 | counter += 1; | |
658 | offset += take; | |
659 | } | |
660 | } | |
661 | ||
662 | // This module is pub for internal benchmarks only. Please don't use it. | |
663 | #[doc(hidden)] | |
664 | pub mod benchmarks { | |
665 | use super::*; | |
666 | ||
667 | pub fn force_portable(params: &mut Params) { | |
668 | params.implementation = guts::Implementation::portable(); | |
669 | } | |
670 | ||
671 | pub fn force_portable_blake2bp(params: &mut blake2bp::Params) { | |
672 | blake2bp::force_portable(params); | |
673 | } | |
674 | } |