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
63type Word = u32;
64type Count = u64;
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 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
80];
81
82const SIGMA: [[u8; 16]; 10] = [
83 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
84 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
85 [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
86 [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
87 [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
88 [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
89 [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
90 [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
91 [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
92 [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
93];
94
95pub fn blake2s(input: &[u8]) -> Hash {
107 Params::new().hash(input)
108}
109
110#[derive(Clone)]
135pub struct Params {
136 hash_length: u8,
137 key_length: u8,
138 key_block: [u8; BLOCKBYTES],
139 salt: [u8; SALTBYTES],
140 personal: [u8; PERSONALBYTES],
141 fanout: u8,
142 max_depth: u8,
143 max_leaf_length: u32,
144 node_offset: u64,
145 node_depth: u8,
146 inner_hash_length: u8,
147 last_node: guts::LastNode,
148 implementation: guts::Implementation,
149}
150
151impl Params {
152 #[inline]
154 pub fn new() -> Self {
155 Self {
156 hash_length: OUTBYTES as u8,
157 key_length: 0,
158 key_block: [0; BLOCKBYTES],
159 salt: [0; SALTBYTES],
160 personal: [0; PERSONALBYTES],
161 fanout: 1,
163 max_depth: 1,
164 max_leaf_length: 0,
165 node_offset: 0,
166 node_depth: 0,
167 inner_hash_length: 0,
168 last_node: guts::LastNode::No,
169 implementation: guts::Implementation::detect(),
170 }
171 }
172
173 #[inline(always)]
174 fn to_words(&self) -> [Word; 8] {
175 let (salt_left, salt_right) = array_refs!(&self.salt, SALTBYTES / 2, SALTBYTES / 2);
176 let (personal_left, personal_right) =
177 array_refs!(&self.personal, PERSONALBYTES / 2, PERSONALBYTES / 2);
178 [
179 IV[0]
180 ^ self.hash_length as u32
181 ^ (self.key_length as u32) << 8
182 ^ (self.fanout as u32) << 16
183 ^ (self.max_depth as u32) << 24,
184 IV[1] ^ self.max_leaf_length,
185 IV[2] ^ self.node_offset as u32,
186 IV[3]
187 ^ (self.node_offset >> 32) as u32
188 ^ (self.node_depth as u32) << 16
189 ^ (self.inner_hash_length as u32) << 24,
190 IV[4] ^ Word::from_le_bytes(*salt_left),
191 IV[5] ^ Word::from_le_bytes(*salt_right),
192 IV[6] ^ Word::from_le_bytes(*personal_left),
193 IV[7] ^ Word::from_le_bytes(*personal_right),
194 ]
195 }
196
197 #[inline]
199 pub fn hash(&self, input: &[u8]) -> Hash {
200 if self.key_length > 0 {
202 return self.to_state().update(input).finalize();
203 }
204 let mut words = self.to_words();
205 self.implementation.compress1_loop(
206 input,
207 &mut words,
208 0,
209 self.last_node,
210 guts::Finalize::Yes,
211 guts::Stride::Serial,
212 );
213 Hash {
214 bytes: state_words_to_bytes(&words),
215 len: self.hash_length,
216 }
217 }
218
219 pub fn to_state(&self) -> State {
222 State::with_params(self)
223 }
224
225 #[inline]
229 pub fn hash_length(&mut self, length: usize) -> &mut Self {
230 assert!(
231 1 <= length && length <= OUTBYTES,
232 "Bad hash length: {}",
233 length
234 );
235 self.hash_length = length as u8;
236 self
237 }
238
239 #[inline]
242 pub fn key(&mut self, key: &[u8]) -> &mut Self {
243 assert!(key.len() <= KEYBYTES, "Bad key length: {}", key.len());
244 self.key_length = key.len() as u8;
245 self.key_block = [0; BLOCKBYTES];
246 self.key_block[..key.len()].copy_from_slice(key);
247 self
248 }
249
250 #[inline]
253 pub fn salt(&mut self, salt: &[u8]) -> &mut Self {
254 assert!(salt.len() <= SALTBYTES, "Bad salt length: {}", salt.len());
255 self.salt = [0; SALTBYTES];
256 self.salt[..salt.len()].copy_from_slice(salt);
257 self
258 }
259
260 #[inline]
263 pub fn personal(&mut self, personalization: &[u8]) -> &mut Self {
264 assert!(
265 personalization.len() <= PERSONALBYTES,
266 "Bad personalization length: {}",
267 personalization.len()
268 );
269 self.personal = [0; PERSONALBYTES];
270 self.personal[..personalization.len()].copy_from_slice(personalization);
271 self
272 }
273
274 #[inline]
276 pub fn fanout(&mut self, fanout: u8) -> &mut Self {
277 self.fanout = fanout;
278 self
279 }
280
281 #[inline]
283 pub fn max_depth(&mut self, depth: u8) -> &mut Self {
284 self.max_depth = depth;
285 self
286 }
287
288 #[inline]
290 pub fn max_leaf_length(&mut self, length: u32) -> &mut Self {
291 self.max_leaf_length = length;
292 self
293 }
294
295 #[inline]
297 pub fn node_offset(&mut self, offset: u64) -> &mut Self {
298 assert!(offset < (1 << 48), "Bad node offset: {}", offset);
299 self.node_offset = offset;
300 self
301 }
302
303 #[inline]
305 pub fn node_depth(&mut self, depth: u8) -> &mut Self {
306 self.node_depth = depth;
307 self
308 }
309
310 #[inline]
312 pub fn inner_hash_length(&mut self, length: usize) -> &mut Self {
313 assert!(length <= OUTBYTES, "Bad inner hash length: {}", length);
314 self.inner_hash_length = length as u8;
315 self
316 }
317
318 #[inline]
324 pub fn last_node(&mut self, last_node: bool) -> &mut Self {
325 self.last_node = if last_node {
326 guts::LastNode::Yes
327 } else {
328 guts::LastNode::No
329 };
330 self
331 }
332}
333
334impl Default for Params {
335 fn default() -> Self {
336 Self::new()
337 }
338}
339
340impl fmt::Debug for Params {
341 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
342 write!(
343 f,
344 "Params {{ hash_length: {}, key_length: {}, salt: {:?}, personal: {:?}, fanout: {}, \
345 max_depth: {}, max_leaf_length: {}, node_offset: {}, node_depth: {}, \
346 inner_hash_length: {}, last_node: {} }}",
347 self.hash_length,
348 self.key_length,
350 &self.salt,
351 &self.personal,
352 self.fanout,
353 self.max_depth,
354 self.max_leaf_length,
355 self.node_offset,
356 self.node_depth,
357 self.inner_hash_length,
358 self.last_node.yes(),
359 )
360 }
361}
362
363#[derive(Clone)]
381pub struct State {
382 words: [Word; 8],
383 count: Count,
384 buf: [u8; BLOCKBYTES],
385 buflen: u8,
386 last_node: guts::LastNode,
387 hash_length: u8,
388 implementation: guts::Implementation,
389 is_keyed: bool,
390}
391
392impl State {
393 pub fn new() -> Self {
395 Self::with_params(&Params::default())
396 }
397
398 fn with_params(params: &Params) -> Self {
399 let mut state = Self {
400 words: params.to_words(),
401 count: 0,
402 buf: [0; BLOCKBYTES],
403 buflen: 0,
404 last_node: params.last_node,
405 hash_length: params.hash_length,
406 implementation: params.implementation,
407 is_keyed: params.key_length > 0,
408 };
409 if state.is_keyed {
410 state.buf = params.key_block;
411 state.buflen = state.buf.len() as u8;
412 }
413 state
414 }
415
416 fn fill_buf(&mut self, input: &mut &[u8]) {
417 let take = cmp::min(BLOCKBYTES - self.buflen as usize, input.len());
418 self.buf[self.buflen as usize..self.buflen as usize + take].copy_from_slice(&input[..take]);
419 self.buflen += take as u8;
420 *input = &input[take..];
421 }
422
423 fn compress_buffer_if_possible(&mut self, input: &mut &[u8]) {
427 if self.buflen > 0 {
428 self.fill_buf(input);
429 if !input.is_empty() {
430 self.implementation.compress1_loop(
431 &self.buf,
432 &mut self.words,
433 self.count,
434 self.last_node,
435 guts::Finalize::No,
436 guts::Stride::Serial,
437 );
438 self.count = self.count.wrapping_add(BLOCKBYTES as Count);
439 self.buflen = 0;
440 }
441 }
442 }
443
444 pub fn update(&mut self, mut input: &[u8]) -> &mut Self {
446 self.compress_buffer_if_possible(&mut input);
448 let mut end = input.len().saturating_sub(1);
451 end -= end % BLOCKBYTES;
452 if end > 0 {
453 self.implementation.compress1_loop(
454 &input[..end],
455 &mut self.words,
456 self.count,
457 self.last_node,
458 guts::Finalize::No,
459 guts::Stride::Serial,
460 );
461 self.count = self.count.wrapping_add(end as Count);
462 input = &input[end..];
463 }
464 self.fill_buf(&mut input);
469 self
470 }
471
472 pub fn finalize(&self) -> Hash {
475 let mut words_copy = self.words;
476 self.implementation.compress1_loop(
477 &self.buf[..self.buflen as usize],
478 &mut words_copy,
479 self.count,
480 self.last_node,
481 guts::Finalize::Yes,
482 guts::Stride::Serial,
483 );
484 Hash {
485 bytes: state_words_to_bytes(&words_copy),
486 len: self.hash_length,
487 }
488 }
489
490 pub fn set_last_node(&mut self, last_node: bool) -> &mut Self {
499 self.last_node = if last_node {
500 guts::LastNode::Yes
501 } else {
502 guts::LastNode::No
503 };
504 self
505 }
506
507 pub fn count(&self) -> Count {
512 let mut ret = self.count.wrapping_add(self.buflen as Count);
513 if self.is_keyed {
514 ret -= BLOCKBYTES as Count;
515 }
516 ret
517 }
518}
519
520#[inline(always)]
521fn state_words_to_bytes(state_words: &[Word; 8]) -> [u8; OUTBYTES] {
522 let mut bytes = [0; OUTBYTES];
523 {
524 const W: usize = size_of::<Word>();
525 let refs = mut_array_refs!(&mut bytes, W, W, W, W, W, W, W, W);
526 *refs.0 = state_words[0].to_le_bytes();
527 *refs.1 = state_words[1].to_le_bytes();
528 *refs.2 = state_words[2].to_le_bytes();
529 *refs.3 = state_words[3].to_le_bytes();
530 *refs.4 = state_words[4].to_le_bytes();
531 *refs.5 = state_words[5].to_le_bytes();
532 *refs.6 = state_words[6].to_le_bytes();
533 *refs.7 = state_words[7].to_le_bytes();
534 }
535 bytes
536}
537
538#[cfg(feature = "std")]
539impl std::io::Write for State {
540 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
541 self.update(buf);
542 Ok(buf.len())
543 }
544
545 fn flush(&mut self) -> std::io::Result<()> {
546 Ok(())
547 }
548}
549
550impl fmt::Debug for State {
551 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
552 write!(
554 f,
555 "State {{ count: {}, hash_length: {}, last_node: {} }}",
556 self.count(),
557 self.hash_length,
558 self.last_node.yes(),
559 )
560 }
561}
562
563impl Default for State {
564 fn default() -> Self {
565 Self::with_params(&Params::default())
566 }
567}
568
569type HexString = arrayvec::ArrayString<{ 2 * OUTBYTES }>;
570
571#[derive(Clone, Copy)]
573pub struct Hash {
574 bytes: [u8; OUTBYTES],
575 len: u8,
576}
577
578impl Hash {
579 pub fn as_bytes(&self) -> &[u8] {
582 &self.bytes[..self.len as usize]
583 }
584
585 #[inline]
589 pub fn as_array(&self) -> &[u8; OUTBYTES] {
590 debug_assert_eq!(self.len as usize, OUTBYTES);
591 &self.bytes
592 }
593
594 pub fn to_hex(&self) -> HexString {
597 bytes_to_hex(self.as_bytes())
598 }
599}
600
601fn bytes_to_hex(bytes: &[u8]) -> HexString {
602 let mut s = arrayvec::ArrayString::new();
603 let table = b"0123456789abcdef";
604 for &b in bytes {
605 s.push(table[(b >> 4) as usize] as char);
606 s.push(table[(b & 0xf) as usize] as char);
607 }
608 s
609}
610
611impl From<[u8; OUTBYTES]> for Hash {
612 fn from(bytes: [u8; OUTBYTES]) -> Self {
613 Self {
614 bytes,
615 len: OUTBYTES as u8,
616 }
617 }
618}
619
620impl From<&[u8; OUTBYTES]> for Hash {
621 fn from(bytes: &[u8; OUTBYTES]) -> Self {
622 Self::from(*bytes)
623 }
624}
625
626impl PartialEq for Hash {
628 fn eq(&self, other: &Hash) -> bool {
629 constant_time_eq::constant_time_eq(&self.as_bytes(), &other.as_bytes())
630 }
631}
632
633impl PartialEq<[u8]> for Hash {
635 fn eq(&self, other: &[u8]) -> bool {
636 constant_time_eq::constant_time_eq(&self.as_bytes(), other)
637 }
638}
639
640impl Eq for Hash {}
641
642impl AsRef<[u8]> for Hash {
643 fn as_ref(&self) -> &[u8] {
644 self.as_bytes()
645 }
646}
647
648impl fmt::Debug for Hash {
649 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
650 write!(f, "Hash(0x{})", self.to_hex())
651 }
652}
653
654#[cfg(test)]
657fn paint_test_input(buf: &mut [u8]) {
658 let mut offset = 0;
659 let mut counter: u32 = 1;
660 while offset < buf.len() {
661 let bytes = counter.to_le_bytes();
662 let take = cmp::min(bytes.len(), buf.len() - offset);
663 buf[offset..][..take].copy_from_slice(&bytes[..take]);
664 counter += 1;
665 offset += take;
666 }
667}
668
669#[doc(hidden)]
671pub mod benchmarks {
672 use super::*;
673
674 pub fn force_portable(params: &mut Params) {
675 params.implementation = guts::Implementation::portable();
676 }
677
678 pub fn force_portable_blake2sp(params: &mut blake2sp::Params) {
679 blake2sp::force_portable(params);
680 }
681}