1#![cfg_attr(not(feature = "std"), no_std)]
45
46use arrayref::{array_refs, mut_array_refs};
47use core::cmp;
48use core::fmt;
49use core::mem::size_of;
50
51#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
52mod avx2;
53mod portable;
54#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
55mod sse41;
56
57pub mod blake2bp;
58mod guts;
59pub mod many;
60
61#[cfg(test)]
62mod test;
63
64type Word = u64;
65type Count = u128;
66
67pub const OUTBYTES: usize = 8 * size_of::<Word>();
69pub const KEYBYTES: usize = 8 * size_of::<Word>();
71pub const SALTBYTES: usize = 2 * size_of::<Word>();
73pub const PERSONALBYTES: usize = 2 * size_of::<Word>();
75pub const BLOCKBYTES: usize = 16 * size_of::<Word>();
78
79const IV: [Word; 8] = [
80 0x6A09E667F3BCC908,
81 0xBB67AE8584CAA73B,
82 0x3C6EF372FE94F82B,
83 0xA54FF53A5F1D36F1,
84 0x510E527FADE682D1,
85 0x9B05688C2B3E6C1F,
86 0x1F83D9ABFB41BD6B,
87 0x5BE0CD19137E2179,
88];
89
90const 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
105pub fn blake2b(input: &[u8]) -> Hash {
118 Params::new().hash(input)
119}
120
121#[derive(Clone)]
146pub 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
162impl Params {
163 #[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 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 #[inline]
208 pub fn hash(&self, input: &[u8]) -> Hash {
209 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 pub fn to_state(&self) -> State {
231 State::with_params(self)
232 }
233
234 #[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 #[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 #[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 #[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 #[inline]
285 pub fn fanout(&mut self, fanout: u8) -> &mut Self {
286 self.fanout = fanout;
287 self
288 }
289
290 #[inline]
292 pub fn max_depth(&mut self, depth: u8) -> &mut Self {
293 self.max_depth = depth;
294 self
295 }
296
297 #[inline]
299 pub fn max_leaf_length(&mut self, length: u32) -> &mut Self {
300 self.max_leaf_length = length;
301 self
302 }
303
304 #[inline]
306 pub fn node_offset(&mut self, offset: u64) -> &mut Self {
307 self.node_offset = offset;
308 self
309 }
310
311 #[inline]
313 pub fn node_depth(&mut self, depth: u8) -> &mut Self {
314 self.node_depth = depth;
315 self
316 }
317
318 #[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 #[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
342impl Default for Params {
343 fn default() -> Self {
344 Self::new()
345 }
346}
347
348impl 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 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#[derive(Clone)]
389pub 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
400impl State {
401 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 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 pub fn update(&mut self, mut input: &[u8]) -> &mut Self {
454 self.compress_buffer_if_possible(&mut input);
456 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 self.fill_buf(&mut input);
477 self
478 }
479
480 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 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 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)]
529fn 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")]
547impl 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
558impl fmt::Debug for State {
559 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
560 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
571impl Default for State {
572 fn default() -> Self {
573 Self::with_params(&Params::default())
574 }
575}
576
577type HexString = arrayvec::ArrayString<{ 2 * OUTBYTES }>;
578
579#[derive(Clone, Copy)]
581pub struct Hash {
582 bytes: [u8; OUTBYTES],
583 len: u8,
584}
585
586impl Hash {
587 pub fn as_bytes(&self) -> &[u8] {
590 &self.bytes[..self.len as usize]
591 }
592
593 #[inline]
597 pub fn as_array(&self) -> &[u8; OUTBYTES] {
598 debug_assert_eq!(self.len as usize, OUTBYTES);
599 &self.bytes
600 }
601
602 pub fn to_hex(&self) -> HexString {
605 bytes_to_hex(self.as_bytes())
606 }
607}
608
609fn 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
619impl From<[u8; OUTBYTES]> for Hash {
620 fn from(bytes: [u8; OUTBYTES]) -> Self {
621 Self {
622 bytes,
623 len: OUTBYTES as u8,
624 }
625 }
626}
627
628impl From<&[u8; OUTBYTES]> for Hash {
629 fn from(bytes: &[u8; OUTBYTES]) -> Self {
630 Self::from(*bytes)
631 }
632}
633
634impl PartialEq for Hash {
636 fn eq(&self, other: &Hash) -> bool {
637 constant_time_eq::constant_time_eq(&self.as_bytes(), &other.as_bytes())
638 }
639}
640
641impl PartialEq<[u8]> for Hash {
643 fn eq(&self, other: &[u8]) -> bool {
644 constant_time_eq::constant_time_eq(&self.as_bytes(), other)
645 }
646}
647
648impl Eq for Hash {}
649
650impl AsRef<[u8]> for Hash {
651 fn as_ref(&self) -> &[u8] {
652 self.as_bytes()
653 }
654}
655
656impl fmt::Debug for Hash {
657 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
658 write!(f, "Hash(0x{})", self.to_hex())
659 }
660}
661
662#[cfg(test)]
665fn paint_test_input(buf: &mut [u8]) {
666 let mut offset = 0;
667 let mut counter: u32 = 1;
668 while offset < buf.len() {
669 let bytes = counter.to_le_bytes();
670 let take = cmp::min(bytes.len(), buf.len() - offset);
671 buf[offset..][..take].copy_from_slice(&bytes[..take]);
672 counter += 1;
673 offset += take;
674 }
675}
676
677#[doc(hidden)]
679pub mod benchmarks {
680 use super::*;
681
682 pub fn force_portable(params: &mut Params) {
683 params.implementation = guts::Implementation::portable();
684 }
685
686 pub fn force_portable_blake2bp(params: &mut blake2bp::Params) {
687 blake2bp::force_portable(params);
688 }
689}