1#![cfg_attr(not(feature = "std"), no_std)]
44
45use arrayref::{array_refs, mut_array_refs};
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 blake2sp;
57mod guts;
58pub mod many;
59
60#[cfg(test)]
61mod test;
62
63pub use guts::{Implementation, Platform};
64
65type Word = u32;
66type Count = u64;
67
68pub const OUTBYTES: usize = 8 * size_of::<Word>();
70pub const KEYBYTES: usize = 8 * size_of::<Word>();
72pub const SALTBYTES: usize = 2 * size_of::<Word>();
74pub const PERSONALBYTES: usize = 2 * size_of::<Word>();
76pub const BLOCKBYTES: usize = 16 * size_of::<Word>();
79
80#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "avx2"))]
81const EMPTY_PARAMS: Params = Params::new_for_implementation(Implementation(Platform::AVX2));
82
83#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), all(not(target_feature = "avx2"),target_feature = "sse4.1")))]
84const EMPTY_PARAMS: Params = Params::new_for_implementation(Implementation(Platform::SSE41));
85
86#[cfg(not(
87 any(
88 all(
89 any(target_arch = "x86", target_arch = "x86_64"),
90 target_feature = "avx2"
91 ),
92 all(
93 any(target_arch = "x86", target_arch = "x86_64"),
94 target_feature = "sse4.1"
95 ),
96 )
97))]
98const EMPTY_PARAMS: Params = Params::new_for_implementation(Implementation(Platform::Portable));
99
100const EMPTY_WORDS: [Word; 8] = EMPTY_PARAMS.empty_words();
101
102const IV: [Word; 8] = [
103 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
104];
105
106const SIGMA: [[u8; 16]; 10] = [
107 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
108 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
109 [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
110 [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
111 [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
112 [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
113 [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
114 [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
115 [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
116 [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
117];
118
119pub fn blake2s(input: &[u8]) -> Hash {
131 Params::new().hash(input)
132}
133
134pub fn blake2s_const(input: &[u8]) -> Hash {
135 EMPTY_PARAMS.hash_without_state(input)
136}
137
138#[derive(Clone)]
163pub struct Params {
164 hash_length: u8,
165 key_length: u8,
166 key_block: [u8; BLOCKBYTES],
167 salt: [u8; SALTBYTES],
168 personal: [u8; PERSONALBYTES],
169 fanout: u8,
170 max_depth: u8,
171 max_leaf_length: u32,
172 node_offset: u64,
173 node_depth: u8,
174 inner_hash_length: u8,
175 last_node: guts::LastNode,
176 implementation: guts::Implementation,
177}
178
179impl Params {
180 #[inline]
182 pub fn new() -> Self {
183 Self {
184 hash_length: OUTBYTES as u8,
185 key_length: 0,
186 key_block: [0; BLOCKBYTES],
187 salt: [0; SALTBYTES],
188 personal: [0; PERSONALBYTES],
189 fanout: 1,
191 max_depth: 1,
192 max_leaf_length: 0,
193 node_offset: 0,
194 node_depth: 0,
195 inner_hash_length: 0,
196 last_node: guts::LastNode::No,
197 implementation: guts::Implementation::detect(),
198 }
199 }
200
201 #[inline]
203 pub const fn new_for_implementation(implementation: Implementation) -> Self {
204 Self {
205 hash_length: OUTBYTES as u8,
206 key_length: 0,
207 key_block: [0; BLOCKBYTES],
208 salt: [0; SALTBYTES],
209 personal: [0; PERSONALBYTES],
210 fanout: 1,
212 max_depth: 1,
213 max_leaf_length: 0,
214 node_offset: 0,
215 node_depth: 0,
216 inner_hash_length: 0,
217 last_node: guts::LastNode::No,
218 implementation: implementation,
219 }
220 }
221
222 #[inline(always)]
223 fn to_words(&self) -> [Word; 8] {
224 let (salt_left, salt_right) = array_refs!(&self.salt, SALTBYTES / 2, SALTBYTES / 2);
225 let (personal_left, personal_right) =
226 array_refs!(&self.personal, PERSONALBYTES / 2, PERSONALBYTES / 2);
227 [
228 IV[0]
229 ^ self.hash_length as u32
230 ^ (self.key_length as u32) << 8
231 ^ (self.fanout as u32) << 16
232 ^ (self.max_depth as u32) << 24,
233 IV[1] ^ self.max_leaf_length,
234 IV[2] ^ self.node_offset as u32,
235 IV[3]
236 ^ (self.node_offset >> 32) as u32
237 ^ (self.node_depth as u32) << 16
238 ^ (self.inner_hash_length as u32) << 24,
239 IV[4] ^ Word::from_le_bytes(*salt_left),
240 IV[5] ^ Word::from_le_bytes(*salt_right),
241 IV[6] ^ Word::from_le_bytes(*personal_left),
242 IV[7] ^ Word::from_le_bytes(*personal_right),
243 ]
244 }
245
246 #[inline(always)]
247 const fn empty_words(&self) -> [Word; 8] {
248 [
249 IV[0]
250 ^ self.hash_length as u32
251 ^ (self.key_length as u32) << 8
252 ^ (self.fanout as u32) << 16
253 ^ (self.max_depth as u32) << 24,
254 IV[1] ^ self.max_leaf_length,
255 IV[2] ^ self.node_offset as u32,
256 IV[3]
257 ^ (self.node_offset >> 32) as u32
258 ^ (self.node_depth as u32) << 16
259 ^ (self.inner_hash_length as u32) << 24,
260 IV[4] ^ 0,
261 IV[5] ^ 0,
262 IV[6] ^ 0,
263 IV[7] ^ 0,
264 ]
265 }
266
267 #[inline]
269 pub fn hash(&self, input: &[u8]) -> Hash {
270 if self.key_length > 0 {
272 return self.to_state().update(input).finalize();
273 }
274 let mut words = self.to_words();
275 self.implementation.compress1_loop(
276 input,
277 &mut words,
278 0,
279 self.last_node,
280 guts::Finalize::Yes,
281 guts::Stride::Serial,
282 );
283 Hash {
284 bytes: state_words_to_bytes(&words),
285 len: self.hash_length,
286 }
287 }
288
289 #[inline]
291 pub fn hash_without_state(&self, input: &[u8]) -> Hash {
292 let mut words = EMPTY_WORDS;
293 self.implementation.compress1_loop(
294 input,
295 &mut words,
296 0,
297 self.last_node,
298 guts::Finalize::Yes,
299 guts::Stride::Serial,
300 );
301 Hash {
302 bytes: state_words_to_bytes(&words),
303 len: self.hash_length,
304 }
305 }
306
307 pub fn to_state(&self) -> State {
310 State::with_params(self)
311 }
312
313 #[inline]
317 pub fn hash_length(&mut self, length: usize) -> &mut Self {
318 assert!(
319 1 <= length && length <= OUTBYTES,
320 "Bad hash length: {}",
321 length
322 );
323 self.hash_length = length as u8;
324 self
325 }
326
327 #[inline]
330 pub fn key(&mut self, key: &[u8]) -> &mut Self {
331 assert!(key.len() <= KEYBYTES, "Bad key length: {}", key.len());
332 self.key_length = key.len() as u8;
333 self.key_block = [0; BLOCKBYTES];
334 self.key_block[..key.len()].copy_from_slice(key);
335 self
336 }
337
338 #[inline]
341 pub fn salt(&mut self, salt: &[u8]) -> &mut Self {
342 assert!(salt.len() <= SALTBYTES, "Bad salt length: {}", salt.len());
343 self.salt = [0; SALTBYTES];
344 self.salt[..salt.len()].copy_from_slice(salt);
345 self
346 }
347
348 #[inline]
351 pub fn personal(&mut self, personalization: &[u8]) -> &mut Self {
352 assert!(
353 personalization.len() <= PERSONALBYTES,
354 "Bad personalization length: {}",
355 personalization.len()
356 );
357 self.personal = [0; PERSONALBYTES];
358 self.personal[..personalization.len()].copy_from_slice(personalization);
359 self
360 }
361
362 #[inline]
364 pub fn fanout(&mut self, fanout: u8) -> &mut Self {
365 self.fanout = fanout;
366 self
367 }
368
369 #[inline]
371 pub fn max_depth(&mut self, depth: u8) -> &mut Self {
372 self.max_depth = depth;
373 self
374 }
375
376 #[inline]
378 pub fn max_leaf_length(&mut self, length: u32) -> &mut Self {
379 self.max_leaf_length = length;
380 self
381 }
382
383 #[inline]
385 pub fn node_offset(&mut self, offset: u64) -> &mut Self {
386 assert!(offset < (1 << 48), "Bad node offset: {}", offset);
387 self.node_offset = offset;
388 self
389 }
390
391 #[inline]
393 pub fn node_depth(&mut self, depth: u8) -> &mut Self {
394 self.node_depth = depth;
395 self
396 }
397
398 #[inline]
400 pub fn inner_hash_length(&mut self, length: usize) -> &mut Self {
401 assert!(length <= OUTBYTES, "Bad inner hash length: {}", length);
402 self.inner_hash_length = length as u8;
403 self
404 }
405
406 #[inline]
412 pub fn last_node(&mut self, last_node: bool) -> &mut Self {
413 self.last_node = if last_node {
414 guts::LastNode::Yes
415 } else {
416 guts::LastNode::No
417 };
418 self
419 }
420}
421
422impl Default for Params {
423 fn default() -> Self {
424 Self::new()
425 }
426}
427
428impl fmt::Debug for Params {
429 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
430 write!(
431 f,
432 "Params {{ hash_length: {}, key_length: {}, salt: {:?}, personal: {:?}, fanout: {}, \
433 max_depth: {}, max_leaf_length: {}, node_offset: {}, node_depth: {}, \
434 inner_hash_length: {}, last_node: {} }}",
435 self.hash_length,
436 self.key_length,
438 &self.salt,
439 &self.personal,
440 self.fanout,
441 self.max_depth,
442 self.max_leaf_length,
443 self.node_offset,
444 self.node_depth,
445 self.inner_hash_length,
446 self.last_node.yes(),
447 )
448 }
449}
450
451#[derive(Clone)]
469pub struct State {
470 words: [Word; 8],
471 count: Count,
472 buf: [u8; BLOCKBYTES],
473 buflen: u8,
474 last_node: guts::LastNode,
475 hash_length: u8,
476 implementation: guts::Implementation,
477 is_keyed: bool,
478}
479
480impl State {
481 pub fn new() -> Self {
483 Self::with_params(&Params::default())
484 }
485
486 fn with_params(params: &Params) -> Self {
487 let mut state = Self {
488 words: params.to_words(),
489 count: 0,
490 buf: [0; BLOCKBYTES],
491 buflen: 0,
492 last_node: params.last_node,
493 hash_length: params.hash_length,
494 implementation: params.implementation,
495 is_keyed: params.key_length > 0,
496 };
497 if state.is_keyed {
498 state.buf = params.key_block;
499 state.buflen = state.buf.len() as u8;
500 }
501 state
502 }
503
504 fn fill_buf(&mut self, input: &mut &[u8]) {
505 let take = cmp::min(BLOCKBYTES - self.buflen as usize, input.len());
506 self.buf[self.buflen as usize..self.buflen as usize + take].copy_from_slice(&input[..take]);
507 self.buflen += take as u8;
508 *input = &input[take..];
509 }
510
511 fn compress_buffer_if_possible(&mut self, input: &mut &[u8]) {
515 if self.buflen > 0 {
516 self.fill_buf(input);
517 if !input.is_empty() {
518 self.implementation.compress1_loop(
519 &self.buf,
520 &mut self.words,
521 self.count,
522 self.last_node,
523 guts::Finalize::No,
524 guts::Stride::Serial,
525 );
526 self.count = self.count.wrapping_add(BLOCKBYTES as Count);
527 self.buflen = 0;
528 }
529 }
530 }
531
532 pub fn update(&mut self, mut input: &[u8]) -> &mut Self {
534 self.compress_buffer_if_possible(&mut input);
536 let mut end = input.len().saturating_sub(1);
539 end -= end % BLOCKBYTES;
540 if end > 0 {
541 self.implementation.compress1_loop(
542 &input[..end],
543 &mut self.words,
544 self.count,
545 self.last_node,
546 guts::Finalize::No,
547 guts::Stride::Serial,
548 );
549 self.count = self.count.wrapping_add(end as Count);
550 input = &input[end..];
551 }
552 self.fill_buf(&mut input);
557 self
558 }
559
560 pub fn finalize(&self) -> Hash {
563 let mut words_copy = self.words;
564 self.implementation.compress1_loop(
565 &self.buf[..self.buflen as usize],
566 &mut words_copy,
567 self.count,
568 self.last_node,
569 guts::Finalize::Yes,
570 guts::Stride::Serial,
571 );
572 Hash {
573 bytes: state_words_to_bytes(&words_copy),
574 len: self.hash_length,
575 }
576 }
577
578 pub fn set_last_node(&mut self, last_node: bool) -> &mut Self {
587 self.last_node = if last_node {
588 guts::LastNode::Yes
589 } else {
590 guts::LastNode::No
591 };
592 self
593 }
594
595 pub fn count(&self) -> Count {
600 let mut ret = self.count.wrapping_add(self.buflen as Count);
601 if self.is_keyed {
602 ret -= BLOCKBYTES as Count;
603 }
604 ret
605 }
606}
607
608#[inline(always)]
609fn state_words_to_bytes(state_words: &[Word; 8]) -> [u8; OUTBYTES] {
610 let mut bytes = [0; OUTBYTES];
611 {
612 const W: usize = size_of::<Word>();
613 let refs = mut_array_refs!(&mut bytes, W, W, W, W, W, W, W, W);
614 *refs.0 = state_words[0].to_le_bytes();
615 *refs.1 = state_words[1].to_le_bytes();
616 *refs.2 = state_words[2].to_le_bytes();
617 *refs.3 = state_words[3].to_le_bytes();
618 *refs.4 = state_words[4].to_le_bytes();
619 *refs.5 = state_words[5].to_le_bytes();
620 *refs.6 = state_words[6].to_le_bytes();
621 *refs.7 = state_words[7].to_le_bytes();
622 }
623 bytes
624}
625
626#[cfg(feature = "std")]
627impl std::io::Write for State {
628 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
629 self.update(buf);
630 Ok(buf.len())
631 }
632
633 fn flush(&mut self) -> std::io::Result<()> {
634 Ok(())
635 }
636}
637
638impl fmt::Debug for State {
639 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
640 write!(
642 f,
643 "State {{ count: {}, hash_length: {}, last_node: {} }}",
644 self.count(),
645 self.hash_length,
646 self.last_node.yes(),
647 )
648 }
649}
650
651impl Default for State {
652 fn default() -> Self {
653 Self::with_params(&Params::default())
654 }
655}
656
657type HexString = arrayvec::ArrayString<[u8; 2 * OUTBYTES]>;
658
659#[derive(Clone, Copy)]
661pub struct Hash {
662 bytes: [u8; OUTBYTES],
663 len: u8,
664}
665
666impl Hash {
667 pub fn as_bytes(&self) -> &[u8] {
670 &self.bytes[..self.len as usize]
671 }
672
673 #[inline]
677 pub fn as_array(&self) -> &[u8; OUTBYTES] {
678 debug_assert_eq!(self.len as usize, OUTBYTES);
679 &self.bytes
680 }
681
682 pub fn to_hex(&self) -> HexString {
685 bytes_to_hex(self.as_bytes())
686 }
687}
688
689fn bytes_to_hex(bytes: &[u8]) -> HexString {
690 let mut s = arrayvec::ArrayString::new();
691 let table = b"0123456789abcdef";
692 for &b in bytes {
693 s.push(table[(b >> 4) as usize] as char);
694 s.push(table[(b & 0xf) as usize] as char);
695 }
696 s
697}
698
699impl PartialEq for Hash {
701 fn eq(&self, other: &Hash) -> bool {
702 constant_time_eq::constant_time_eq(&self.as_bytes(), &other.as_bytes())
703 }
704}
705
706impl PartialEq<[u8]> for Hash {
708 fn eq(&self, other: &[u8]) -> bool {
709 constant_time_eq::constant_time_eq(&self.as_bytes(), other)
710 }
711}
712
713impl Eq for Hash {}
714
715impl AsRef<[u8]> for Hash {
716 fn as_ref(&self) -> &[u8] {
717 self.as_bytes()
718 }
719}
720
721impl fmt::Debug for Hash {
722 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
723 write!(f, "Hash(0x{})", self.to_hex())
724 }
725}
726
727#[cfg(test)]
730fn paint_test_input(buf: &mut [u8]) {
731 let mut offset = 0;
732 let mut counter: u32 = 1;
733 while offset < buf.len() {
734 let bytes = counter.to_le_bytes();
735 let take = cmp::min(bytes.len(), buf.len() - offset);
736 buf[offset..][..take].copy_from_slice(&bytes[..take]);
737 counter += 1;
738 offset += take;
739 }
740}
741
742#[doc(hidden)]
744pub mod benchmarks {
745 use super::*;
746
747 pub fn force_portable(params: &mut Params) {
748 params.implementation = guts::Implementation::portable();
749 }
750
751 pub fn force_portable_blake2sp(params: &mut blake2sp::Params) {
752 blake2sp::force_portable(params);
753 }
754}