1#![cfg_attr(not(feature = "std"), no_std)]
45
46use core::cmp;
47use core::fmt;
48use core::mem::size_of;
49
50#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
51mod avx2;
52mod portable;
53#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
54mod sse41;
55
56pub mod blake2bp;
57mod guts;
58pub mod many;
59
60#[cfg(test)]
61mod test;
62
63type Word = u64;
64type Count = u128;
65
66pub const OUTBYTES: usize = 8 * size_of::<Word>();
68pub const KEYBYTES: usize = 8 * size_of::<Word>();
70pub const SALTBYTES: usize = 2 * size_of::<Word>();
72pub const PERSONALBYTES: usize = 2 * size_of::<Word>();
74pub const BLOCKBYTES: usize = 16 * size_of::<Word>();
77
78const IV: [Word; 8] = [
79 0x6A09E667F3BCC908,
80 0xBB67AE8584CAA73B,
81 0x3C6EF372FE94F82B,
82 0xA54FF53A5F1D36F1,
83 0x510E527FADE682D1,
84 0x9B05688C2B3E6C1F,
85 0x1F83D9ABFB41BD6B,
86 0x5BE0CD19137E2179,
87];
88
89const SIGMA: [[u8; 16]; 12] = [
90 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
91 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
92 [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
93 [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
94 [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
95 [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
96 [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
97 [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
98 [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
99 [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
100 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
101 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
102];
103
104pub fn blake2b(input: &[u8]) -> Hash {
117 Params::new().hash(input)
118}
119
120#[derive(Clone)]
145pub struct Params {
146 hash_length: u8,
147 key_length: u8,
148 key_block: [u8; BLOCKBYTES],
149 salt: [u8; SALTBYTES],
150 personal: [u8; PERSONALBYTES],
151 fanout: u8,
152 max_depth: u8,
153 max_leaf_length: u32,
154 node_offset: u64,
155 node_depth: u8,
156 inner_hash_length: u8,
157 last_node: guts::LastNode,
158 implementation: guts::Implementation,
159}
160
161impl Params {
162 #[inline]
164 pub fn new() -> Self {
165 Self {
166 hash_length: OUTBYTES as u8,
167 key_length: 0,
168 key_block: [0; BLOCKBYTES],
169 salt: [0; SALTBYTES],
170 personal: [0; PERSONALBYTES],
171 fanout: 1,
173 max_depth: 1,
174 max_leaf_length: 0,
175 node_offset: 0,
176 node_depth: 0,
177 inner_hash_length: 0,
178 last_node: guts::LastNode::No,
179 implementation: guts::Implementation::detect(),
180 }
181 }
182
183 #[inline(always)]
184 fn to_words(&self) -> [Word; 8] {
185 let salt_left: &[u8; SALTBYTES / 2] = (&self.salt[..SALTBYTES / 2]).try_into().unwrap();
186 let salt_right: &[u8; SALTBYTES / 2] = (&self.salt[SALTBYTES / 2..]).try_into().unwrap();
187 let personal_left: &[u8; PERSONALBYTES / 2] =
188 (&self.personal[..PERSONALBYTES / 2]).try_into().unwrap();
189 let personal_right: &[u8; PERSONALBYTES / 2] =
190 (&self.personal[PERSONALBYTES / 2..]).try_into().unwrap();
191 [
192 IV[0]
193 ^ self.hash_length as u64
194 ^ (self.key_length as u64) << 8
195 ^ (self.fanout as u64) << 16
196 ^ (self.max_depth as u64) << 24
197 ^ (self.max_leaf_length as u64) << 32,
198 IV[1] ^ self.node_offset,
199 IV[2] ^ self.node_depth as u64 ^ (self.inner_hash_length as u64) << 8,
200 IV[3],
201 IV[4] ^ Word::from_le_bytes(*salt_left),
202 IV[5] ^ Word::from_le_bytes(*salt_right),
203 IV[6] ^ Word::from_le_bytes(*personal_left),
204 IV[7] ^ Word::from_le_bytes(*personal_right),
205 ]
206 }
207
208 #[inline]
210 pub fn hash(&self, input: &[u8]) -> Hash {
211 if self.key_length > 0 {
213 return self.to_state().update(input).finalize();
214 }
215 let mut words = self.to_words();
216 self.implementation.compress1_loop(
217 input,
218 &mut words,
219 0,
220 self.last_node,
221 guts::Finalize::Yes,
222 guts::Stride::Serial,
223 );
224 Hash {
225 bytes: state_words_to_bytes(&words),
226 len: self.hash_length,
227 }
228 }
229
230 pub fn to_state(&self) -> State {
233 State::with_params(self)
234 }
235
236 #[inline]
240 pub fn hash_length(&mut self, length: usize) -> &mut Self {
241 assert!(
242 1 <= length && length <= OUTBYTES,
243 "Bad hash length: {}",
244 length
245 );
246 self.hash_length = length as u8;
247 self
248 }
249
250 #[inline]
253 pub fn key(&mut self, key: &[u8]) -> &mut Self {
254 assert!(key.len() <= KEYBYTES, "Bad key length: {}", key.len());
255 self.key_length = key.len() as u8;
256 self.key_block = [0; BLOCKBYTES];
257 self.key_block[..key.len()].copy_from_slice(key);
258 self
259 }
260
261 #[inline]
264 pub fn salt(&mut self, salt: &[u8]) -> &mut Self {
265 assert!(salt.len() <= SALTBYTES, "Bad salt length: {}", salt.len());
266 self.salt = [0; SALTBYTES];
267 self.salt[..salt.len()].copy_from_slice(salt);
268 self
269 }
270
271 #[inline]
274 pub fn personal(&mut self, personalization: &[u8]) -> &mut Self {
275 assert!(
276 personalization.len() <= PERSONALBYTES,
277 "Bad personalization length: {}",
278 personalization.len()
279 );
280 self.personal = [0; PERSONALBYTES];
281 self.personal[..personalization.len()].copy_from_slice(personalization);
282 self
283 }
284
285 #[inline]
287 pub fn fanout(&mut self, fanout: u8) -> &mut Self {
288 self.fanout = fanout;
289 self
290 }
291
292 #[inline]
294 pub fn max_depth(&mut self, depth: u8) -> &mut Self {
295 self.max_depth = depth;
296 self
297 }
298
299 #[inline]
301 pub fn max_leaf_length(&mut self, length: u32) -> &mut Self {
302 self.max_leaf_length = length;
303 self
304 }
305
306 #[inline]
308 pub fn node_offset(&mut self, offset: u64) -> &mut Self {
309 self.node_offset = offset;
310 self
311 }
312
313 #[inline]
315 pub fn node_depth(&mut self, depth: u8) -> &mut Self {
316 self.node_depth = depth;
317 self
318 }
319
320 #[inline]
322 pub fn inner_hash_length(&mut self, length: usize) -> &mut Self {
323 assert!(length <= OUTBYTES, "Bad inner hash length: {}", length);
324 self.inner_hash_length = length as u8;
325 self
326 }
327
328 #[inline]
334 pub fn last_node(&mut self, last_node: bool) -> &mut Self {
335 self.last_node = if last_node {
336 guts::LastNode::Yes
337 } else {
338 guts::LastNode::No
339 };
340 self
341 }
342}
343
344impl Default for Params {
345 fn default() -> Self {
346 Self::new()
347 }
348}
349
350impl fmt::Debug for Params {
351 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
352 write!(
353 f,
354 "Params {{ hash_length: {}, key_length: {}, salt: {:?}, personal: {:?}, fanout: {}, \
355 max_depth: {}, max_leaf_length: {}, node_offset: {}, node_depth: {}, \
356 inner_hash_length: {}, last_node: {} }}",
357 self.hash_length,
358 self.key_length,
360 &self.salt,
361 &self.personal,
362 self.fanout,
363 self.max_depth,
364 self.max_leaf_length,
365 self.node_offset,
366 self.node_depth,
367 self.inner_hash_length,
368 self.last_node.yes(),
369 )
370 }
371}
372
373#[derive(Clone)]
391pub struct State {
392 words: [Word; 8],
393 count: Count,
394 buf: [u8; BLOCKBYTES],
395 buflen: u8,
396 last_node: guts::LastNode,
397 hash_length: u8,
398 implementation: guts::Implementation,
399 is_keyed: bool,
400}
401
402impl State {
403 pub fn new() -> Self {
405 Self::with_params(&Params::default())
406 }
407
408 fn with_params(params: &Params) -> Self {
409 let mut state = Self {
410 words: params.to_words(),
411 count: 0,
412 buf: [0; BLOCKBYTES],
413 buflen: 0,
414 last_node: params.last_node,
415 hash_length: params.hash_length,
416 implementation: params.implementation,
417 is_keyed: params.key_length > 0,
418 };
419 if state.is_keyed {
420 state.buf = params.key_block;
421 state.buflen = state.buf.len() as u8;
422 }
423 state
424 }
425
426 fn fill_buf(&mut self, input: &mut &[u8]) {
427 let take = cmp::min(BLOCKBYTES - self.buflen as usize, input.len());
428 self.buf[self.buflen as usize..self.buflen as usize + take].copy_from_slice(&input[..take]);
429 self.buflen += take as u8;
430 *input = &input[take..];
431 }
432
433 fn compress_buffer_if_possible(&mut self, input: &mut &[u8]) {
437 if self.buflen > 0 {
438 self.fill_buf(input);
439 if !input.is_empty() {
440 self.implementation.compress1_loop(
441 &self.buf,
442 &mut self.words,
443 self.count,
444 self.last_node,
445 guts::Finalize::No,
446 guts::Stride::Serial,
447 );
448 self.count = self.count.wrapping_add(BLOCKBYTES as Count);
449 self.buflen = 0;
450 }
451 }
452 }
453
454 pub fn update(&mut self, mut input: &[u8]) -> &mut Self {
456 self.compress_buffer_if_possible(&mut input);
458 let mut end = input.len().saturating_sub(1);
461 end -= end % BLOCKBYTES;
462 if end > 0 {
463 self.implementation.compress1_loop(
464 &input[..end],
465 &mut self.words,
466 self.count,
467 self.last_node,
468 guts::Finalize::No,
469 guts::Stride::Serial,
470 );
471 self.count = self.count.wrapping_add(end as Count);
472 input = &input[end..];
473 }
474 self.fill_buf(&mut input);
479 self
480 }
481
482 pub fn finalize(&self) -> Hash {
485 let mut words_copy = self.words;
486 self.implementation.compress1_loop(
487 &self.buf[..self.buflen as usize],
488 &mut words_copy,
489 self.count,
490 self.last_node,
491 guts::Finalize::Yes,
492 guts::Stride::Serial,
493 );
494 Hash {
495 bytes: state_words_to_bytes(&words_copy),
496 len: self.hash_length,
497 }
498 }
499
500 pub fn set_last_node(&mut self, last_node: bool) -> &mut Self {
509 self.last_node = if last_node {
510 guts::LastNode::Yes
511 } else {
512 guts::LastNode::No
513 };
514 self
515 }
516
517 pub fn count(&self) -> Count {
522 let mut ret = self.count.wrapping_add(self.buflen as Count);
523 if self.is_keyed {
524 ret -= BLOCKBYTES as Count;
525 }
526 ret
527 }
528}
529
530#[inline(always)]
531fn state_words_to_bytes(state_words: &[Word; 8]) -> [u8; OUTBYTES] {
532 let mut bytes = [0; OUTBYTES];
533 {
534 const W: usize = size_of::<Word>();
535 *<&mut [u8; W]>::try_from(&mut bytes[0 * W..][..W]).unwrap() = state_words[0].to_le_bytes();
536 *<&mut [u8; W]>::try_from(&mut bytes[1 * W..][..W]).unwrap() = state_words[1].to_le_bytes();
537 *<&mut [u8; W]>::try_from(&mut bytes[2 * W..][..W]).unwrap() = state_words[2].to_le_bytes();
538 *<&mut [u8; W]>::try_from(&mut bytes[3 * W..][..W]).unwrap() = state_words[3].to_le_bytes();
539 *<&mut [u8; W]>::try_from(&mut bytes[4 * W..][..W]).unwrap() = state_words[4].to_le_bytes();
540 *<&mut [u8; W]>::try_from(&mut bytes[5 * W..][..W]).unwrap() = state_words[5].to_le_bytes();
541 *<&mut [u8; W]>::try_from(&mut bytes[6 * W..][..W]).unwrap() = state_words[6].to_le_bytes();
542 *<&mut [u8; W]>::try_from(&mut bytes[7 * W..][..W]).unwrap() = state_words[7].to_le_bytes();
543 }
544 bytes
545}
546
547#[cfg(feature = "std")]
548impl std::io::Write for State {
549 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
550 self.update(buf);
551 Ok(buf.len())
552 }
553
554 fn flush(&mut self) -> std::io::Result<()> {
555 Ok(())
556 }
557}
558
559impl fmt::Debug for State {
560 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
561 write!(
563 f,
564 "State {{ count: {}, hash_length: {}, last_node: {} }}",
565 self.count(),
566 self.hash_length,
567 self.last_node.yes(),
568 )
569 }
570}
571
572impl Default for State {
573 fn default() -> Self {
574 Self::with_params(&Params::default())
575 }
576}
577
578type HexString = arrayvec::ArrayString<{ 2 * OUTBYTES }>;
579
580#[derive(Clone, Copy)]
582pub struct Hash {
583 bytes: [u8; OUTBYTES],
584 len: u8,
585}
586
587impl Hash {
588 pub fn as_bytes(&self) -> &[u8] {
591 &self.bytes[..self.len as usize]
592 }
593
594 #[inline]
598 pub fn as_array(&self) -> &[u8; OUTBYTES] {
599 debug_assert_eq!(self.len as usize, OUTBYTES);
600 &self.bytes
601 }
602
603 pub fn to_hex(&self) -> HexString {
606 bytes_to_hex(self.as_bytes())
607 }
608}
609
610fn bytes_to_hex(bytes: &[u8]) -> HexString {
611 let mut s = arrayvec::ArrayString::new();
612 let table = b"0123456789abcdef";
613 for &b in bytes {
614 s.push(table[(b >> 4) as usize] as char);
615 s.push(table[(b & 0xf) as usize] as char);
616 }
617 s
618}
619
620impl From<[u8; OUTBYTES]> for Hash {
621 fn from(bytes: [u8; OUTBYTES]) -> Self {
622 Self {
623 bytes,
624 len: OUTBYTES as u8,
625 }
626 }
627}
628
629impl From<&[u8; OUTBYTES]> for Hash {
630 fn from(bytes: &[u8; OUTBYTES]) -> Self {
631 Self::from(*bytes)
632 }
633}
634
635impl PartialEq for Hash {
637 fn eq(&self, other: &Hash) -> bool {
638 constant_time_eq::constant_time_eq(&self.as_bytes(), &other.as_bytes())
639 }
640}
641
642impl PartialEq<[u8]> for Hash {
644 fn eq(&self, other: &[u8]) -> bool {
645 constant_time_eq::constant_time_eq(&self.as_bytes(), other)
646 }
647}
648
649impl Eq for Hash {}
650
651impl AsRef<[u8]> for Hash {
652 fn as_ref(&self) -> &[u8] {
653 self.as_bytes()
654 }
655}
656
657impl fmt::Debug for Hash {
658 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
659 write!(f, "Hash(0x{})", self.to_hex())
660 }
661}
662
663#[cfg(test)]
666fn paint_test_input(buf: &mut [u8]) {
667 let mut offset = 0;
668 let mut counter: u32 = 1;
669 while offset < buf.len() {
670 let bytes = counter.to_le_bytes();
671 let take = cmp::min(bytes.len(), buf.len() - offset);
672 buf[offset..][..take].copy_from_slice(&bytes[..take]);
673 counter += 1;
674 offset += take;
675 }
676}
677
678#[doc(hidden)]
680pub mod benchmarks {
681 use super::*;
682
683 pub fn force_portable(params: &mut Params) {
684 params.implementation = guts::Implementation::portable();
685 }
686
687 pub fn force_portable_blake2bp(params: &mut blake2bp::Params) {
688 blake2bp::force_portable(params);
689 }
690}