1use crate::error::Error;
20use crate::memory::{clear_internal_memory, clear_internal_memory_u64};
21#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
22use core::sync::atomic::{AtomicU8, Ordering};
23
24#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
25mod avx2;
26#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
27mod avx512;
28#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
29mod sse41;
30
31pub const BLOCKBYTES: usize = 128;
33pub const OUTBYTES: usize = 64;
35pub const KEYBYTES: usize = 64;
37pub const SALTBYTES: usize = 16;
39pub const PERSONALBYTES: usize = 16;
41
42const HALFBYTES: usize = OUTBYTES / 2;
44
45const PARAMBYTES: usize = 64;
47
48pub const IV: [u64; 8] = [
50 0x6a09e667f3bcc908,
51 0xbb67ae8584caa73b,
52 0x3c6ef372fe94f82b,
53 0xa54ff53a5f1d36f1,
54 0x510e527fade682d1,
55 0x9b05688c2b3e6c1f,
56 0x1f83d9abfb41bd6b,
57 0x5be0cd19137e2179,
58];
59
60const SIGMA: [[usize; 16]; 12] = [
62 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
63 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
64 [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
65 [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
66 [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
67 [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
68 [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
69 [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
70 [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
71 [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
72 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
73 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
74];
75
76#[inline]
79fn load64(src: &[u8]) -> u64 {
80 let mut bytes = [0u8; 8];
81 let n = if src.len() < 8 { src.len() } else { 8 };
82 bytes[..n].copy_from_slice(&src[..n]);
83 u64::from_le_bytes(bytes)
84}
85
86#[inline(always)]
91#[allow(clippy::too_many_arguments)]
92fn g(
93 v: &mut [u64; 16],
94 m: &[u64; 16],
95 s: &[usize; 16],
96 i: usize,
97 a: usize,
98 b: usize,
99 c: usize,
100 d: usize,
101) {
102 v[a] = v[a].wrapping_add(v[b]).wrapping_add(m[s[2 * i]]);
105 v[d] = (v[d] ^ v[a]).rotate_right(32);
106 v[c] = v[c].wrapping_add(v[d]);
107 v[b] = (v[b] ^ v[c]).rotate_right(24);
108 v[a] = v[a].wrapping_add(v[b]).wrapping_add(m[s[2 * i + 1]]);
109 v[d] = (v[d] ^ v[a]).rotate_right(16);
110 v[c] = v[c].wrapping_add(v[d]);
111 v[b] = (v[b] ^ v[c]).rotate_right(63);
112}
113
114fn compress_scalar(h: &mut [u64; 8], t: &[u64; 2], f: &[u64; 2], m: &[u64; 16]) {
116 let mut v = [0u64; 16];
117 v[..8].copy_from_slice(h);
118 v[8] = IV[0];
119 v[9] = IV[1];
120 v[10] = IV[2];
121 v[11] = IV[3];
122 v[12] = IV[4] ^ t[0];
123 v[13] = IV[5] ^ t[1];
124 v[14] = IV[6] ^ f[0];
125 v[15] = IV[7] ^ f[1];
126
127 for s in &SIGMA {
128 g(&mut v, m, s, 0, 0, 4, 8, 12);
129 g(&mut v, m, s, 1, 1, 5, 9, 13);
130 g(&mut v, m, s, 2, 2, 6, 10, 14);
131 g(&mut v, m, s, 3, 3, 7, 11, 15);
132 g(&mut v, m, s, 4, 0, 5, 10, 15);
133 g(&mut v, m, s, 5, 1, 6, 11, 12);
134 g(&mut v, m, s, 6, 2, 7, 8, 13);
135 g(&mut v, m, s, 7, 3, 4, 9, 14);
136 }
137
138 for (i, word) in h.iter_mut().enumerate() {
139 *word ^= v[i] ^ v[i + 8];
140 }
141}
142
143#[derive(Copy, Clone, Debug, PartialEq, Eq)]
157#[repr(u8)]
158pub enum Blake2bBackend {
159 Scalar = 0,
161 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
163 Sse41 = 1,
164 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
166 Avx2 = 2,
167 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
169 Avx512 = 3,
170}
171
172impl Blake2bBackend {
173 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
175 pub const ALL: &'static [Blake2bBackend] = &[
176 Blake2bBackend::Scalar,
177 Blake2bBackend::Sse41,
178 Blake2bBackend::Avx2,
179 Blake2bBackend::Avx512,
180 ];
181 #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
183 pub const ALL: &'static [Blake2bBackend] = &[Blake2bBackend::Scalar];
184
185 #[must_use]
187 pub const fn name(self) -> &'static str {
188 match self {
189 Blake2bBackend::Scalar => "scalar",
190 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
191 Blake2bBackend::Sse41 => "sse4.1",
192 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
193 Blake2bBackend::Avx2 => "avx2",
194 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
195 Blake2bBackend::Avx512 => "avx512",
196 }
197 }
198
199 #[must_use]
201 pub fn is_available(self) -> bool {
202 match self {
203 Blake2bBackend::Scalar => true,
204 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
205 Blake2bBackend::Sse41 => have_sse41(),
206 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
207 Blake2bBackend::Avx2 => have_avx2(),
208 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
209 Blake2bBackend::Avx512 => have_avx512vl(),
210 }
211 }
212
213 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
214 const fn from_u8(value: u8) -> Blake2bBackend {
215 match value {
216 1 => Blake2bBackend::Sse41,
217 2 => Blake2bBackend::Avx2,
218 3 => Blake2bBackend::Avx512,
219 _ => Blake2bBackend::Scalar,
220 }
221 }
222}
223
224impl core::fmt::Display for Blake2bBackend {
225 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
226 f.write_str(self.name())
227 }
228}
229
230#[cfg(all(feature = "std", any(target_arch = "x86", target_arch = "x86_64")))]
231fn have_sse41() -> bool {
232 std::arch::is_x86_feature_detected!("sse4.1")
233}
234
235#[cfg(all(
236 not(feature = "std"),
237 any(target_arch = "x86", target_arch = "x86_64")
238))]
239fn have_sse41() -> bool {
240 cfg!(target_feature = "sse4.1")
241}
242
243#[cfg(all(
254 not(miri),
255 feature = "std",
256 target_arch = "x86_64",
257 target_os = "macos"
258))]
259fn prefer_sse41() -> bool {
260 use core::ffi::{c_char, c_int, c_void};
261
262 unsafe extern "C" {
263 fn sysctlbyname(
264 name: *const c_char,
265 oldp: *mut c_void,
266 oldlenp: *mut usize,
267 newp: *mut c_void,
268 newlen: usize,
269 ) -> c_int;
270 }
271
272 let mut translated: c_int = 0;
273 let mut translated_len = core::mem::size_of::<c_int>();
274 let result = unsafe {
278 sysctlbyname(
279 c"sysctl.proc_translated".as_ptr(),
280 (&raw mut translated).cast(),
281 &raw mut translated_len,
282 core::ptr::null_mut(),
283 0,
284 )
285 };
286 have_sse41()
287 && !(result == 0
288 && translated_len == core::mem::size_of::<c_int>()
289 && translated == 1)
290}
291
292#[cfg(all(
293 not(miri),
294 any(target_arch = "x86", target_arch = "x86_64"),
295 not(all(feature = "std", target_arch = "x86_64", target_os = "macos"))
296))]
297fn prefer_sse41() -> bool {
298 have_sse41()
299}
300
301#[cfg(all(feature = "std", any(target_arch = "x86", target_arch = "x86_64")))]
302fn have_avx2() -> bool {
303 std::arch::is_x86_feature_detected!("avx2")
304}
305
306#[cfg(all(
307 not(feature = "std"),
308 any(target_arch = "x86", target_arch = "x86_64")
309))]
310fn have_avx2() -> bool {
311 cfg!(target_feature = "avx2")
312}
313
314#[cfg(all(feature = "std", any(target_arch = "x86", target_arch = "x86_64")))]
315fn have_avx512vl() -> bool {
316 std::arch::is_x86_feature_detected!("avx2")
317 && std::arch::is_x86_feature_detected!("avx512f")
318 && std::arch::is_x86_feature_detected!("avx512vl")
319}
320
321#[cfg(all(
322 not(feature = "std"),
323 any(target_arch = "x86", target_arch = "x86_64")
324))]
325fn have_avx512vl() -> bool {
326 cfg!(all(
327 target_feature = "avx2",
328 target_feature = "avx512f",
329 target_feature = "avx512vl"
330 ))
331}
332
333#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
334const BACKEND_UNINIT: u8 = u8::MAX;
335#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
336static DETECTED_BACKEND: AtomicU8 = AtomicU8::new(BACKEND_UNINIT);
337
338#[must_use]
341pub fn detect_blake2b_backend() -> Blake2bBackend {
342 #[cfg(miri)]
345 return Blake2bBackend::Scalar;
346
347 #[cfg(not(miri))]
348 {
349 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
350 if have_avx512vl() {
351 return Blake2bBackend::Avx512;
352 }
353
354 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
355 if have_avx2() {
356 return Blake2bBackend::Avx2;
357 }
358
359 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
360 if prefer_sse41() {
361 return Blake2bBackend::Sse41;
362 }
363
364 Blake2bBackend::Scalar
365 }
366}
367
368#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
370#[cold]
371#[inline(never)]
372fn detect_and_cache_blake2b_backend() -> Blake2bBackend {
373 let detected = detect_blake2b_backend();
374 DETECTED_BACKEND.store(detected as u8, Ordering::Relaxed);
377 detected
378}
379
380#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
382#[inline]
383#[must_use]
384pub fn blake2b_backend() -> Blake2bBackend {
385 let cached = DETECTED_BACKEND.load(Ordering::Relaxed);
386 if cached == BACKEND_UNINIT {
387 detect_and_cache_blake2b_backend()
388 } else {
389 Blake2bBackend::from_u8(cached)
390 }
391}
392
393#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
395#[inline]
396#[must_use]
397pub const fn blake2b_backend() -> Blake2bBackend {
398 Blake2bBackend::Scalar
399}
400
401#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
402type CompressFn = unsafe fn(&mut [u64; 8], &[u64; 2], &[u64; 2], &[u64; 16]);
403
404#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
408#[derive(Copy, Clone)]
409struct ScalarCompress;
410#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
411type CompressFn = ScalarCompress;
412
413#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
414unsafe fn compress_scalar_backend(
415 h: &mut [u64; 8],
416 t: &[u64; 2],
417 f: &[u64; 2],
418 m: &[u64; 16],
419) {
420 compress_scalar(h, t, f, m);
421}
422
423#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
424fn compress_fn(backend: Blake2bBackend) -> CompressFn {
425 match backend {
426 Blake2bBackend::Scalar => compress_scalar_backend,
427 Blake2bBackend::Sse41 => sse41::compress,
428 Blake2bBackend::Avx2 => avx2::compress,
429 Blake2bBackend::Avx512 => avx512::compress,
430 }
431}
432
433#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
434fn compress_fn(_backend: Blake2bBackend) -> CompressFn {
435 ScalarCompress
436}
437
438unsafe fn compress_parsed_with(
440 compress: CompressFn,
441 h: &mut [u64; 8],
442 t: &[u64; 2],
443 f: &[u64; 2],
444 m: &[u64; 16],
445) {
446 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
447 {
448 unsafe { compress(h, t, f, m) };
450 }
451
452 #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
453 {
454 let ScalarCompress = compress;
455 compress_scalar(h, t, f, m);
456 }
457}
458
459fn compress_with(
464 compress: CompressFn,
465 h: &mut [u64; 8],
466 t: &[u64; 2],
467 f: &[u64; 2],
468 block: &[u8],
469) {
470 let mut m = [0u64; 16];
471 for (word, chunk) in m.iter_mut().zip(block.chunks_exact(8)) {
472 *word = load64(chunk);
473 }
474
475 unsafe { compress_parsed_with(compress, h, t, f, &m) };
480}
481
482pub struct Blake2b {
490 h: [u64; 8],
491 t: [u64; 2],
492 f: [u64; 2],
493 buf: [u8; BLOCKBYTES],
494 buflen: usize,
496 outlen: usize,
497 last_node: bool,
501 compress: CompressFn,
503}
504
505impl Blake2b {
506 pub fn new(outlen: usize) -> Result<Blake2b, Error> {
514 Blake2b::init_param(outlen, 0, blake2b_backend())
515 }
516
517 pub unsafe fn new_with_backend(
527 outlen: usize,
528 backend: Blake2bBackend,
529 ) -> Result<Blake2b, Error> {
530 Blake2b::init_param(outlen, 0, backend)
531 }
532
533 pub fn with_key(outlen: usize, key: &[u8]) -> Result<Blake2b, Error> {
543 if outlen == 0 || outlen > OUTBYTES {
545 return Err(Error::IncorrectParameter);
546 }
547 if key.is_empty() || key.len() > KEYBYTES {
548 return Err(Error::IncorrectParameter);
549 }
550
551 let mut state = Blake2b::init_param(outlen, key.len(), blake2b_backend())?;
552
553 let mut block = [0u8; BLOCKBYTES];
555 block[..key.len()].copy_from_slice(key);
556 state.update(&block);
557 clear_internal_memory(&mut block);
558
559 Ok(state)
560 }
561
562 fn init_param(
577 outlen: usize,
578 keylen: usize,
579 backend: Blake2bBackend,
580 ) -> Result<Blake2b, Error> {
581 if outlen == 0 || outlen > OUTBYTES {
582 return Err(Error::IncorrectParameter);
583 }
584 if keylen > KEYBYTES {
585 return Err(Error::IncorrectParameter);
586 }
587
588 let mut param = [0u8; PARAMBYTES];
589 param[0] = outlen as u8;
591 param[1] = keylen as u8;
592 param[2] = 1; param[3] = 1; let mut h = IV;
597 for (word, chunk) in h.iter_mut().zip(param.chunks_exact(8)) {
598 *word ^= load64(chunk);
599 }
600
601 Ok(Blake2b {
602 h,
603 t: [0; 2],
604 f: [0; 2],
605 buf: [0; BLOCKBYTES],
606 buflen: 0,
607 outlen,
608 last_node: false,
609 compress: compress_fn(backend),
610 })
611 }
612
613 #[inline]
616 fn increment_counter(&mut self, inc: u64) {
617 self.t[0] = self.t[0].wrapping_add(inc);
618 self.t[1] = self.t[1].wrapping_add(u64::from(self.t[0] < inc));
619 }
620
621 #[inline]
623 fn set_lastblock(&mut self) {
624 if self.last_node {
625 self.f[1] = !0;
626 }
627 self.f[0] = !0;
628 }
629
630 pub fn update(&mut self, input: &[u8]) {
637 if input.is_empty() {
638 return;
639 }
640 if self.f[0] != 0 {
643 return;
644 }
645
646 let mut pin = input;
647
648 if self.buflen + pin.len() > BLOCKBYTES {
649 let left = self.buflen;
651 let fill = BLOCKBYTES - left;
652 self.buf[left..].copy_from_slice(&pin[..fill]);
653 self.increment_counter(BLOCKBYTES as u64);
654 compress_with(self.compress, &mut self.h, &self.t, &self.f, &self.buf);
655 self.buflen = 0;
656 pin = &pin[fill..];
657
658 while pin.len() > BLOCKBYTES {
660 let (block, rest) = pin.split_at(BLOCKBYTES);
662 self.increment_counter(BLOCKBYTES as u64);
663 compress_with(self.compress, &mut self.h, &self.t, &self.f, block);
664 pin = rest;
665 }
666 }
667
668 self.buf[self.buflen..self.buflen + pin.len()].copy_from_slice(pin);
671 self.buflen += pin.len();
672 }
673
674 pub fn finalize(mut self, out: &mut [u8]) -> Result<(), Error> {
686 if out.len() < self.outlen {
687 return Err(Error::IncorrectParameter);
688 }
689 if self.f[0] != 0 {
691 return Err(Error::IncorrectParameter);
692 }
693
694 self.increment_counter(self.buflen as u64);
695 self.set_lastblock();
696 for byte in &mut self.buf[self.buflen..] {
698 *byte = 0;
699 }
700 compress_with(self.compress, &mut self.h, &self.t, &self.f, &self.buf);
701
702 let mut buffer = [0u8; OUTBYTES];
703 for (chunk, word) in buffer.chunks_exact_mut(8).zip(self.h.iter()) {
704 chunk.copy_from_slice(&word.to_le_bytes());
705 }
706 out[..self.outlen].copy_from_slice(&buffer[..self.outlen]);
707
708 clear_internal_memory(&mut buffer);
709 Ok(())
711 }
712}
713
714impl Drop for Blake2b {
715 fn drop(&mut self) {
716 clear_internal_memory(&mut self.buf);
720 clear_internal_memory_u64(&mut self.h);
721 clear_internal_memory_u64(&mut self.t);
722 clear_internal_memory_u64(&mut self.f);
723 }
724}
725
726pub fn blake2b(out: &mut [u8], input: &[u8]) -> Result<(), Error> {
735 let backend = blake2b_backend();
736 unsafe { blake2b_with_backend(out, input, backend) }
738}
739
740pub unsafe fn blake2b_with_backend(
749 out: &mut [u8],
750 input: &[u8],
751 backend: Blake2bBackend,
752) -> Result<(), Error> {
753 let mut state = unsafe { Blake2b::new_with_backend(out.len(), backend)? };
755 state.update(input);
756 state.finalize(out)
757}
758
759pub fn blake2b_long(out: &mut [u8], input: &[u8]) -> Result<(), Error> {
778 let backend = blake2b_backend();
779 unsafe { blake2b_long_with_backend(out, input, backend) }
781}
782
783pub unsafe fn blake2b_long_with_backend(
793 out: &mut [u8],
794 input: &[u8],
795 backend: Blake2bBackend,
796) -> Result<(), Error> {
797 let Ok(outlen) = u32::try_from(out.len()) else {
799 return Err(Error::IncorrectParameter);
800 };
801 let outlen_bytes = outlen.to_le_bytes();
802
803 if out.len() <= OUTBYTES {
804 let mut state = unsafe { Blake2b::new_with_backend(out.len(), backend)? };
807 state.update(&outlen_bytes);
808 state.update(input);
809 return state.finalize(out);
810 }
811
812 let mut out_buffer = [0u8; OUTBYTES];
813 let mut in_buffer;
814
815 let mut state = unsafe { Blake2b::new_with_backend(OUTBYTES, backend)? };
817 state.update(&outlen_bytes);
818 state.update(input);
819 state.finalize(&mut out_buffer)?;
820
821 let (head, mut tail) = out.split_at_mut(HALFBYTES);
824 head.copy_from_slice(&out_buffer[..HALFBYTES]);
825
826 while tail.len() > OUTBYTES {
827 in_buffer = out_buffer;
828 unsafe { blake2b_with_backend(&mut out_buffer, &in_buffer, backend)? };
830 let (head, rest) = tail.split_at_mut(HALFBYTES);
831 head.copy_from_slice(&out_buffer[..HALFBYTES]);
832 tail = rest;
833 }
834
835 let toproduce = tail.len();
838 in_buffer = out_buffer;
839 unsafe { blake2b_with_backend(&mut out_buffer[..toproduce], &in_buffer, backend)? };
841 tail.copy_from_slice(&out_buffer[..toproduce]);
842
843 clear_internal_memory(&mut out_buffer);
844 clear_internal_memory(&mut in_buffer);
845 Ok(())
846}
847
848#[cfg(test)]
849mod tests {
850 use super::*;
851 use alloc::string::String;
852 use alloc::vec;
853 use alloc::vec::Vec;
854
855 #[test]
856 fn detection_selects_the_preferred_executable_backend() {
857 let expected = {
858 #[cfg(miri)]
860 {
861 Blake2bBackend::Scalar
862 }
863 #[cfg(all(not(miri), any(target_arch = "x86", target_arch = "x86_64")))]
864 {
865 if have_avx512vl() {
866 Blake2bBackend::Avx512
867 } else if have_avx2() {
868 Blake2bBackend::Avx2
869 } else if prefer_sse41() {
870 Blake2bBackend::Sse41
871 } else {
872 Blake2bBackend::Scalar
873 }
874 }
875 #[cfg(all(
876 not(miri),
877 not(any(target_arch = "x86", target_arch = "x86_64"))
878 ))]
879 {
880 Blake2bBackend::Scalar
881 }
882 };
883
884 assert_eq!(detect_blake2b_backend(), expected);
885 assert_eq!(blake2b_backend(), expected);
886 assert!(expected.is_available());
887 }
888
889 #[test]
893 fn compression_backends_match_scalar() {
894 fn next(x: &mut u64) -> u64 {
895 *x ^= *x << 13;
896 *x ^= *x >> 7;
897 *x ^= *x << 17;
898 *x
899 }
900
901 for &backend in Blake2bBackend::ALL {
902 if !backend.is_available() {
903 continue;
904 }
905
906 let implementation = compress_fn(backend);
907 let mut seed = 0x243f_6a88_85a3_08d3;
908 for case in 0..128 {
909 let mut expected = [0u64; 8];
910 for word in &mut expected {
911 *word = next(&mut seed);
912 }
913 let mut actual = expected;
914 let t = [next(&mut seed), next(&mut seed)];
915 let f = [
916 if case & 1 == 0 { 0 } else { u64::MAX },
917 if case & 2 == 0 { 0 } else { u64::MAX },
918 ];
919 let mut m = [0u64; 16];
920 for word in &mut m {
921 *word = next(&mut seed);
922 }
923
924 compress_scalar(&mut expected, &t, &f, &m);
925 unsafe { compress_parsed_with(implementation, &mut actual, &t, &f, &m) };
927 assert_eq!(expected, actual, "backend={}", backend.name());
928 }
929 }
930 }
931
932 #[test]
936 fn full_backends_match_scalar() {
937 let input: Vec<u8> = (0..=255).chain(0..=31).collect();
938 let input_lengths = [0, 1, 63, 64, 65, 127, 128, 129, 255, 256, 288];
939 let output_lengths = [1, 16, 32, 63, 64, 65, 96, 127, 128, 1024];
940
941 for &backend in Blake2bBackend::ALL {
942 if !backend.is_available() {
943 continue;
944 }
945 for &input_len in &input_lengths {
946 for &output_len in &output_lengths {
947 let mut expected = vec![0u8; output_len];
948 let mut actual = vec![0u8; output_len];
949 unsafe {
952 blake2b_long_with_backend(
953 &mut expected,
954 &input[..input_len],
955 Blake2bBackend::Scalar,
956 )
957 .expect("valid lengths");
958 blake2b_long_with_backend(
959 &mut actual,
960 &input[..input_len],
961 backend,
962 )
963 .expect("valid lengths");
964 }
965 assert_eq!(expected, actual, "backend={} input={input_len} out={output_len}", backend.name());
966 }
967 }
968 }
969 }
970
971 const EMPTY_512: &str = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
983 const ABC_512: &str = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";
984
985 #[rustfmt::skip]
986 const SEQ_INPUT_512: &[(usize, &str)] = &[
987 (0, "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce"),
988 (1, "2fa3f686df876995167e7c2e5d74c4c7b6e48f8068fe0e44208344d480f7904c36963e44115fe3eb2a3ac8694c28bcb4f5a0f3276f2e79487d8219057a506e4b"),
989 (63, "d10bf9a15b1c9fc8d41f89bb140bf0be08d2f3666176d13baac4d381358ad074c9d4748c300520eb026daeaea7c5b158892fde4e8ec17dc998dcd507df26eb63"),
990 (64, "2fc6e69fa26a89a5ed269092cb9b2a449a4409a7a44011eecad13d7c4b0456602d402fa5844f1a7a758136ce3d5d8d0e8b86921ffff4f692dd95bdc8e5ff0052"),
991 (127, "b6292669ccd38d5f01caae96ba272c76a879a45743afa0725d83b9ebb26665b731f1848c52f11972b6644f554c064fa90780dbbbf3a89d4fc31f67df3e5857ef"),
992 (128, "2319e3789c47e2daa5fe807f61bec2a1a6537fa03f19ff32e87eecbfd64b7e0e8ccff439ac333b040f19b0c4ddd11a61e24ac1fe0f10a039806c5dcc0da3d115"),
993 (129, "f59711d44a031d5f97a9413c065d1e614c417ede998590325f49bad2fd444d3e4418be19aec4e11449ac1a57207898bc57d76a1bcf3566292c20c683a5c4648f"),
994 (255, "5b21c5fd8868367612474fa2e70e9cfa2201ffeee8fafab5797ad58fefa17c9b5b107da4a3db6320baaf2c8617d5a51df914ae88da3867c2d41f0cc14fa67928"),
995 (256, "1ecc896f34d3f9cac484c73f75f6a5fb58ee6784be41b35f46067b9c65c63a6794d3d744112c653f73dd7deb6666204c5a9bfa5b46081fc10fdbe7884fa5cbf8"),
996 (257, "d8bfe068de0b4f9fa876a3f8024eb9f7b0029fd5dcf251199e065cee89e1a282c8dbf0442f2ade7294ac1c6be19b388dc990c34d8cb79f5f10c54fa813834fda"),
997 (383, "6af23f91ca3ca49b5c8267ea6e6e6597d34b0ae22d17634d2f48e6877f92809cc0a4f3fd9344ce154814493bd35c776923f9492e3733ac8cbc600e963dc78257"),
998 (384, "49b3d01a1f21431d4a9b65e0450bb0444b7d1deb81131d650d9cbefcad7436a0e51050445af39f3f1312dbe3e2d03601ba309d3bc3c46bc5bdc768feebe176fb"),
999 ];
1000
1001 #[rustfmt::skip]
1002 const ABC_SHORT_DIGESTS: &[(usize, &str)] = &[
1003 (1, "6b"),
1004 (20, "384264f676f39536840523f284921cdc68b6846b"),
1005 (32, "bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319"),
1006 (63, "eb5324bb0b0f9ca27381f22f5e49604d7c341b77371fe5bf61fb643c8ab481c7555ef17c9b9e7c92f0daafff6c0d748cab97d2b267bf53f8225c173ea26f3e"),
1007 (64, "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"),
1008 ];
1009
1010 #[rustfmt::skip]
1011 const KEYED64_512: &[(usize, &str)] = &[
1012 (0, "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568"),
1013 (1, "961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd"),
1014 (2, "da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965"),
1015 (3, "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1"),
1016 (64, "65676d800617972fbd87e4b9514e1c67402b7a331096d3bfac22f1abb95374abc942f16e9ab0ead33b87c91968a6e509e119ff07787b3ef483e1dcdccf6e3022"),
1017 (127, "76d2d819c92bce55fa8e092ab1bf9b9eab237a25267986cacf2b8ee14d214d730dc9a5aa2d7b596e86a1fd8fa0804c77402d2fcd45083688b218b1cdfa0dcbcb"),
1018 (128, "72065ee4dd91c2d8509fa1fc28a37c7fc9fa7d5b3f8ad3d0d7a25626b57b1b44788d4caf806290425f9890a3a2a35a905ab4b37acfd0da6e4517b2525c9651e4"),
1019 (129, "64475dfe7600d7171bea0b394e27c9b00d8e74dd1e416a79473682ad3dfdbb706631558055cfc8a40e07bd015a4540dcdea15883cbbf31412df1de1cd4152b91"),
1020 (255, "142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461"),
1021 ];
1022
1023 const KEY16_ABC_512: &str = "4c76bc7ad0fc52e4bde231b38727c331172cfe3eeaf10cd2fa5c65abbdb8faeaad2da338531b382ac103f10ccaf41f74d8870d016c48b269c0d9a5cf5752c8c3";
1024
1025 #[rustfmt::skip]
1026 const LONG_EMPTY: &[(usize, &str)] = &[
1027 (1, "88"),
1028 (4, "431894c5"),
1029 (32, "547578a45cc5d4a6e6ad0b59905a85e08527c2b1420604e157772e7bf02c2672"),
1030 (63, "dc0d3ff9a4218744635fbae40331d1e69bf28200e2a268c722b8e10256ce8f75956f8f0481f99dae0ca012527475952d63614424d71e7848129d9947140c39"),
1031 (64, "7fedd5af05184f3700cb1986bf39663bc06501e6455da2b643d47bc1c01302bea32e4e9ec6b29f4d151c6348788b59d4e02e69e4199a886d5b36fc3e5200ab04"),
1032 (65, "8e8b922d272035d878f074418dd8fadac41f5865ae0dc5066383237e85104c776bcad5ae3396429e5048b46920bc0d7ad39ccbf77d99aeca1fe4702407b8603cb0"),
1033 (72, "e6e2acf2db332da1bea83127d5fb3f8aefbd9d1307efe4f09a813450828b782a157773321d11891262adfb5d1143bcf1ce3c50f7e453b0fcf2c36e08bb0480a8ec5fe940f653191d"),
1034 (96, "2933619da44b6063c6ad2f7e7caf776e62c3d5cc563e7c441cb33ec3274ef6c8b2755787b8ae7343ed71089edac2f1f07af6e830fe875a3ee6977bf71c8f8e45b0cb0ca86f192a71bf186ef9044c8022f828e1de4a1883282ea4617ffb950090"),
1035 (97, "bbc187c6e4d8525655d0ada62d16eed59f3db3ab07e04fb0483fd4ae21d88b980947a1cf35bf02acf14d5cd7587598b710c421f79f6538692f3cb9d8e8a3532b0a40bc2db816471ac4d29bb3908b4d76ffb2b6cc465720242985ac7fba5634873a"),
1036 (127, "e547a0bef8c8fa5f56835b345361b67798b31bdea276c15ce8e85b28cf4f3c9f9dc6bf1a5e8bd98aeb7357c08b4676c5470dbfeffc1f02aa59a75c2635e60e8584b718a3062fbe95c7389e1f2a039b410ae89d0d98b532e1b1e8d55a15bfde6e2e7c0a736e510a121c9583e6fe88b7fd53fb5702bb111eca534963b98eb11e"),
1037 (128, "b29368bb02ce0ae43090fe9aae30fb003364b966dce7007296855bbe48c4bacfdb0b66313b1b6d1445ec8f738605f82d14d1bdac5c08a3e82e5af784071c6390b8c1bcecf371bbb2b5518bbc3819b0bde7b4d1584fdf3a0160fcd94c4cb321ef8596457211899cbb5d60dafb837177151fe257d44642c8b6b28909c3a8272ec7"),
1038 (129, "dfb78002c8bf1fa06b57e467781f9ba22d9905fd141102c7fc20b4d2dbd39a594e25803dbbba9059c9dbce98c146902f92e8b416c6339d4e6f12d94659a545fe5cb5bde3e818926cd127e8a716ed36f845af0512a80c683193d85762e2c6b3328cc57a75b56be044869047d45184857df32585645bd643bb2b37a75d4352602c14"),
1039 (1024, "845b3c40f4155e5f90e2b72ed952c88d976b45ccdd74d419cea79a6ae874a0170481acf57ad997333f407aa75655962ef2041f129406aca1b0e03ada5e43a21e83a3c04f04af6603100772c73497d884d01ef8ad0bc756973ac54fb564516844f7dc5eb12af3240c937af768018fed5ef81da41a1ede4e2f22b82c635979a6f619d66b96d82a4b2ff6917b0c889e7c2f87dbdb98ad5d5c33f7def3962f280ea3f12f2856b0bcf3c755f761c5c076af39f73a1bc0d7c333b21655af1917dc8fb32294168224fd49712606dc5aa95dcd92d59109d02f9aeb7c3ab01017aadd0116f4fbd0ca6b8a451b66c42229cc0ceaefb29de10b8c1f26d4a87d2bc6848c859857d34920dda2140822055a7decdf1cbb9aead07cec689d891972aa463bc3677f3885dc78d91b3ccfd2137ae02a16716c454c8a59fc287afe65f95d3e238925e50191a49d329bb601b3d746ac1fd8d5f4c5983015b7760b7bd863d4d7c92152fdffb60df7c7194d7f39326cc67bd1d83204d4999f4a9e5cde6f7c8fd5bd343d0490bcb917c011ccd6f1c167b22bb3a3488083965677ee135945815f467d0bb7201a35392154e57c52750b98a7a9fca0d0789f4863c494ca1b5474f48cbda149d6a62e5c1bc087f6ac831bb32df43b5e66188dff97bb7f89f5e92c219c830450935c60a250e3ba1cc5e14f24003694cefb30219c241097f61a2110f1848e7f194ef6bb27a110c2db9b54d75909a77fb857ef2bb1a6b36a5e2a20bca79549fdfa9e668cadd0cc82d23cdc6d75cf65932a6a34a6bdb07a5ca54e16410ac0414ae9115ca776667add778094f313a3ebed2707043cbe4994846eb9c725df1cb84a42fe1311cb781408b4bb8e5645348f1fd0565005f8e17a36dcc4f12d473f600521c9dc8eb3aa495c80e9ad2b1d80e328116f13c3d0fd4cb5ec4e508fbb802368febdea52abf93dfd8aebe937b8435c01a5c701ff5348f0290b89ea2fde8f7b16c9713e8c6bdcae3bc69f73de3e3a16b4ff3d17c4b2d922d37036b5703ed3031bae4ec1abfc8bc94facb4202474acc3c659754beab08bbc5281e9b467f75c7cc5db648d7c2a566b6e95567d2a7acd70646859e243278238bdb279f1c0c16d943c230a0f56d0b74c05266a6996ac791f3e2a8e1e90b31330599cc9fc8d2973fb93535b560cca2f15208f9259c08982a81b9f0612cf42ea8c9ef613d2a7a44c4bf5debfa0d8b6ef7d0b6a858892e1be00a794540f6c227573c20b2bd7cef2a8a71c16a3592b6f7ab381b7b2545388f3879a1c81c05383242b8776fe4db9d8cc064702111796828c400609b6a7d247198c1867a9937ff9a2913f16a58b5f9c4451d853ce9b602763319df8b4911c8cf62901232768b3a5fe6323d85deac32ea6bc96022cd65eac1c760427c23c4da56812651b7e123a8a4a16ec794db78a0f5f8f107851"),
1040 ];
1041
1042 #[rustfmt::skip]
1043 const LONG_ABC: &[(usize, &str)] = &[
1044 (1, "79"),
1045 (4, "3e6c02ac"),
1046 (32, "6cfcbf5d43e547674bfbc009070570bcb84e272d359c1e9277e416d74cbbe1c6"),
1047 (63, "dcb6b07bc6dc2bc0095962ee05ccce1905972d78956e7118b050166e21d7262eea5924bcef9b3efc50ec39e6cae5edf759e9979d7bffb9898356e3a76b83ab"),
1048 (64, "f32577a3172f56657d531faaa43077bb8c9726ada7bb04dd337ec5a65454abff241ad6b87a72440e5127c6f9caa70327f2a699096e52d163eb52d9cd99620593"),
1049 (65, "77baa447fe6f777c9bcb519545ce80badaf08ecb973fbb4ff45af7d8b569ec7caad65f72669d05153cdeaa563a162bb5ae4c42214551593816008dc560c5a65391"),
1050 (72, "13ac1def3e362ae0a78cdcb810a81885c95926cabee9dee40b46f9fc31cfa58a3e4e098a7beea541ca0b9002f89434898fc85990e937d91ddd70754b10d5316ad4fd8cd64564db92"),
1051 (96, "41b5590d909a09f99c2c5475f782ba721397c7dc626736a3b5b0b369bab78af24a800ffd07bd9b94e073fe5451b20caf770b68afe0839842b4723550bdf083cf9e205e5304aaec1584f10008285f563252fcfcf207ca8c755d1652168b9024af"),
1052 (97, "c82ccb541fdbecd1ce8090f61f39905cbf4bc03cebd133a002c7babe4ea204fba111552004c5a5338c62d4c7561af5de2665d24d30de9407b9ba1a6ab372054d3e6fdd0c7aa46b48980189af43f3502d68d007a02b1c4efe04c13b9f39d932f335"),
1053 (127, "29519d9954a0791d76c47164bbedf2f4fb71a7742dc15073cbb6b5daf34adb2f8d5ddd992dda0f1abbb46838676e2e7340bc82510f3f71e97982400b085024553fcaa92f91f31442c5084d3ecd03728597818c3b6fcb1ec9dd660aa5773ebc21626d5467972bc349a08c866f4f6eb3a5f944a76ca22d39bbabcebe565cb98a"),
1054 (128, "e03f682135fde8cb7caea3c8ad7c0a7e78efb026e119732d27b1eea7ba92335a7eb8825c755809add7833e7f75e7a5915bb1b3e70eca7b61bec34cd8c486f8005b05f94166103045f120f568fa1952f24e2a032a35d96e5a61fe520090178a4b60490d839f773b71f88589442d94bf5614c401e1a49b7d4d6e34782c0130e1c2"),
1055 (129, "81795998330577749c80da69a830b48e222555c721afd94d76dd0f9f2f6c6d18a441f42634e58d17da51d9979ae5638530dbe5db52b33bf8b3f4c3bfdd00287d055c3c4ac752f4996544c83253ee7a663a3c42b8e547d1f0a83bb34eb93aa12215687105cf925cd8d26b794b9ba4eefb3a1eea534a48be42894ddd5de35f354e4c"),
1056 (1024, "4038a0ea5c85fa5a0ea62fd668347bd44afd8da63438fd92fb08bee04dbe89ace70e7b8f4e9379b208c138b444e4434164437f03da914150722aaa902eb35fa0e710cfd7239e719b99c987f6b3d6f068d76e949c68084e608d280634fae1ea8423d431b6fa6c8b9b73f5343ea98aa27b95dc901e6e237a10251620aee94ee5b1d29651f228c8ba90ca3600c8e9f5b273f1a3dd9c011222db6085a566acf250cb07268dd47a4dfdc171b99f571dc84a38dd7ae4cf6b7b3c6581c9625b27bb4a0bcca537a34cd7a8f78e0c050f0089a25c5d2cd72de4f96ee451796df7d0f116591a8b33b0ee5105df5b4ff5c372cac6a1a24fb3ede74fef08f9b9f75d5ece43f4904461a3605cba1841daadeb1bf81e94807d99d4892c8b8a3b088584695d7bc39b29d467db4fbf09971598fdf02e23bb42c2aebb5d70ce213b12e4d330b2121dde4a548c0d62bfde70ad51cd06a51181d6df33fe65aaa55fd0a4f9c25e3f8f094848c05158bf47d8f05b204527a3064d190ef4813a97c404935ecf04244075c5c8370cfb0a6ec66479a10534abe3195a95b0875e813674e6f0bd6b11ad3890cafe09740b3aad45e7629de7324fc94e76023fca6dda84a1f1eefd751234e6d6d7de72666ddb84cf0d5e2a42505f3125439926c8449da9b67ccfc16892509901c19dc32595db48866951281e91c3973295a6ab375b54233c9d0441c081b0ba8074b816b59742042198a38a519ff06a2430edd4a9ba9b8fb874f9a895973877e5a2207c86a0f78cf952188337c2bc608974040c149e355e23315a338dd64f27bee9faff79fec5e5234ec52ffeddcfbd81d2c3db2888f36ec4199a730db5befbc30e75833240999ad8f9008eeab8ac6989a5ede8f46e3190ca9aff38717aa52dbc73b609b89a6b340355e6f5f81b95bf8e54f8a69f4e2bf95bd4c2e438589e4ffe2e91f286e40f78fb5972405ad546178ca1b91908a03ebf04228665d2313ceeff42a14cb8c1105731142398cb39aac140f5bbcf64514c5b33f31f27142ac08ea189dda4124f05221fa80fae12ee8fcc476e16af15b83274fcf98ffb29291ba1adb22ec944a0e8aef1dcca32545fd8751a07ed61d071ac735e782909e3a210d9b4262f0b6e5923a034985bf81aa837d76820f9e6cbb3e17eca941c0512ddca18c4b173e89390fee8407c903a6f8ef19460d0f800155cbb95899b828f21a09cba10a6464790ee766bfbd3a43be7594678a994d950a82aac89e24c1ab0fad8c364de19d2ba1a92663f4930d13b9b8a7fbbdac83bb74c4f9ba25a0c53aee93ebaab93e677c67f963eeefc06666dbe499222c1eccb16ab17de6533ce3336aa329bd4af8a09b19078a98dd48ef08da6762f125e673682d8822123b6d0fe99c97fda5e58406c64c157c76bb0a4bd1fc3f8fe819e96fbfdc50ba0194abc940ec7cdc9fff8a0"),
1057 ];
1058
1059 #[rustfmt::skip]
1060 const LONG_SEQ72: &[(usize, &str)] = &[
1061 (1, "fa"),
1062 (4, "ca513e0a"),
1063 (32, "36592a3c3e0dfcff6e0efcf362b2a8e68eb0a1563c041ba4272309536ae39b47"),
1064 (63, "5352b4a8ebcc8d25cfbfcca3226d9ed9567deae28f887ebcb9707534f83dbbad521370e0665dd1aa052b9f2086c72c1196fe325082d221edee0b3668ebac82"),
1065 (64, "2c6f5fa62d9b0549bfaae2b39e99afca0e624754e43f71bf8b2df8ead7151e3694fb51c7b4ec6de9b4f66426863ce4a520d7f84db5051250f5b4181f04aa4949"),
1066 (65, "9321f69a406e6ab17f116b5bdc619b9e794806601069888795e1e36eb382839f6189ffa17b35028daabbc9bf1db409643b9981fb4bb1764fb33325cdb6deafbad6"),
1067 (72, "906f3255cf91dc0af4da3697e8d7f1e5e1898157e63cd3e5c5de65a52130e486134b8c5598b255b83a48ac1826fc4107f60bd5adaee8660aa92df8612817463d0f15a00ba0e5fde5"),
1068 (96, "fb57485ec7a6d6c983353a051998d1ab68014821cca42c53e4c99ebe828f880f155105341c88adc44ff28118362581b73c5d4a65cee3a2d7dfb0f74623a0451220f27107948a281513191a0aa327bfd816d6b46be21d3237b7377cfe7174b11b"),
1069 (97, "e712e0864d944a484faef1107faa299d64a416d4b0348c560fb0e358488910571c63f872540695b85212a4b39f438b3c1ad21ed4148db9232c0bfa1231e04519a81c3ac662ffae2219b320d4a29c15760633ec7a3b04d69c96542016ce5e7aea80"),
1070 (127, "bda04620f38590a5a2a218564c97544a6572828775ea75d961b5c3ddfaeb769d38631639eceadb0aeb0def8ba5617a26a9aa88682cdd323428def92841d7edf2eb3375c29f24014e9c75a07c176528d102c8fa9ae28d7d6ce190cde38b943b12a4a8c1337fef010f815ab2cf25222cef2a9b9a451f1163288bf5add7a18495"),
1071 (128, "28739f1ddc548d8fa52f866c2eceaea11c2ea05d8e17f184df19bd2dc8210fde317df70bdaf91a1482ecca54d5b9ef0557bf817c41cc528257f25ed633ac6938e5b3f417606fe55559f57ed67d6accf9e32131348cdbb073896a6452405c9b83302800ddce561f96f4bb56f489338f0958e142aee3d326caee27fbaacd33fc27"),
1072 (129, "cae345ac89bc5a3cc819e2b9aae53f06a49c606b1de4376e30b23929d239ff046d92e34a1a6eeb3e1f474ed212b545d76aa1e4d88af7f17326a8ae255bdf9582a5692934d3016ab0f7fe78f95a8bd3db1da1678b0a78a636ef91914b53765313095247aa29a410522e3a060254c7b285243e34e049864bbdf4f3518aeb676cf5b7"),
1073 (1024, "d5f4c304b4be42af53855c080628693f4c741bfe3378766e5dd6b78097ba90b7140c2f3dc0960ae214ae1820dd8b008839ba2ebce72d123662eef7bd75204b3f4a9eea9a2e4a33637bbe28d1bb8d3b201cd85b324ccb5da17e2dccf1efd6d28be4159259adfce532dd62a973cc3c98c60547aabcf6abcb9283e30e581ba7e19f4c702faf54759a6aad67e950659ab8c9a5041a9c76e58fcb3a28ca9f43a280bee1d7cc86e0af6f890285e24e989d4771fdd8177cfba4db926f5938b8da89a85dc7fc312fda86a60938b6691da0ce86a7a6f8445bf0fd0cf49aefe39d476d7c91ab92e93339e887180d4e081cda235fcb39be7369a2fd73f21481ca305d2ba0e32caa2c464a109dc3e14062ea2d7a700b4752c31a8cc504d91289e46776f8fdeb4042e6de3f90361b5de27dacd4b6404154350e83570d06d0092de308069c1d58cb9a9dd2fce2f98cf73b1eabdb207b47136c6215e3a51b56d3a9078c0b92e2ba6848e4596636e45f0f074941adfcf5a7868ccdf97b62aa3a74b0d4ecc4ca4a25aaa086ec2b741ddf38637d0b88db86348917480c74871588cfe8a73d8911068b070081d8b88201791019b45da05f082cf21019963ff08104d73876c8b654451e4ad62b9accb64d6c8f5a8c7bb32ac1aac968ac48b95fc116b563244d7c64afd05a64acab82b9affb43357cfd430404113717baff8fc1cfb258315d9764f911c88914d976475f0e97d4d01d553c2394b00576326f1268e1e84b14750349b07e260177e3e84b779e201a50668d1957b608dad8422477d1785c71cd3ae7ca97957fdb2777c15328d4097c3108cd697f8933854c9e6a16f8c49ab0323bf24284ad57b0ee3852ffdbd7b7f05836c5910aec4c2cc7ec71b613b0fed9a816ad079b37de526cd0eba925f86932d59f84535e7f5d12fc14b2776cf09d34d1e73e5762255fdfca677e4bca438b6527e3bbfde8ba590e64373d46cb26c7e6cf8636925ddd8b5e509a69640d03e1fdb4e95321f7a195487544906f39e00fcbded63a9c3a88f1acb72f44b9a804c80338c777292b040ad175581a8e76d58cbae7240754d0d8aef79321447da39f556edf32003d160faadc579692c982d0e85146e5ca1909ca42de9d2bc11538f81c525866cd6c5019319cb3f44e5d97f915ca3a8ae53337d7d90c03cf00ea2986aebc3b141e1e9f78e9f1f58e29e5a5b1c2622c0ee2e8d12a9945d8b58ac43d8d9aababa1f93d1bcb640eb5e51aafae9873f3ccd25d784ccc8aec4f7a864295b50fff28b2c4f994f8f92d7c14475e284b2fbe6cd2e04a2f9ff5f0cd002a64ec3c66e8565dd74fa8d16a54e35d393c7d50a05f0f36ed0dc7b70f8907c99865757af2055714c4c695cd3c8bbe1cb4028d0bcb444f3561445356ebd40c3ba6acc9446c5942112fd8911f41fbd98ce10f4a9415476b9336122c9127"),
1074 ];
1075
1076 #[rustfmt::skip]
1077 const LONG_SEQ1024_IN: &[(usize, &str)] = &[
1078 (4, "b9c129b4"),
1079 (32, "6d65b7906fb326296197c405be7dee4c4ab2b6e40d4a959b99ceca5dd907275d"),
1080 (64, "7cd0c105b0a21a9f0f03ff8b3a94d72c58898ab95d904d685b02314aeb94ec4a587caa362abf5c4ec14732f590b304153bb2b0198200b7b334398be40fac7fb8"),
1081 (65, "adad4ba5075f72879db895fd08670fb41fce21d2e45e502f16b16d293d802d39ec97836223e8137674097b08ebff26b52456e84d461f1b68009d59ff0bd8c5806b"),
1082 (1024, "53acc9238374ecbd78f622b71ced7e0d62c200a0581d1be678330f3b924ae12ec932bc461d07e53072da275b4826828588c077e0dbdb8814d151a1abcbe8ffaf8f3444a17f9ca7c783867763942c931a715b2e9d91af4ebaa3b27ef3142f2c373eb38e1638efc3580ab6acd7b4f95ab05370916142fab304238408ae13049818d9ed5486c4e6ef801e7e210c39815a3daf4d07a02f7183a92a3380fc329ed4e5fb4f0f398bf8b53571accadd084458d6b681c5d34b0749aed210c85f0f96df6b250d470a46f99a57ebff9fe6037c1d3012f4f9dcfd0bf541f3aafb22a466237f62978526e5ff94a21daa12c662c4f468167e942ab3a1a257c3e5e61f7df0951867f4d73e1728c4fbb3e7e22569e1f41511e530652fc5b369c6a6154ecbf4bf0133c27fa18820cae10681748548fd0b24c7718834c273efcf8ee2dc430029a5af9e71d83f0e5dd97db328c6606c947c50435b091ca956e2017d0bb8dc95c59d787fbbf62796447fae7cedc2d7adc7e26212954a527991c36726f0c0b389e9389bfb065cd5ebb8ffbac8e7dcd44d0c6a18bc25c0bb7705253ef6c130dd19be2c7ffeec1f83edab0f94a132bed6debdf6186f025b7d209f8e5391a707870d6fa87790ba3b29f8f9b2b0d4606dbe709b4a544c4fb685351e170870336308d601900c346fa0488b2f0c48dee77ee9e1a4e5805004870b7719df90840994a7793a20187cc6aa8f5e0927e43102c6d260bbbd8750a5c4873e595a738f47a18f68cea2e92ff6b62301d25d5b57cbb484c1ea5ec44f3c1bddf8bda3b1de0f62cfa5543a69c086cfd4b9cbccf0c14040973f2c8fc90e09d2f0a089463101c1b49c2a179d72ef0d2910e158d4caa706c7de2aaf23115ea7c0ba51de990eba8f80c849834d9640a0fdd8975b6ee50c0774cd4fa8a84b35d6159acd325fba6540ff6e5387b7dfeb499d3cee87e4650823457e59fc51eafdd888d8413f833abc28af35713c355381799d58b46d9caeb8235b466827fc952acd70926677f73a65239a9a4b9f42ba48250996c08080629ed749df15ac2e4334107e7ffd6916ec301717c0e47a3fd060f12f2fd8b863a720316b1ec65282d0a57c908eb0095a09f99c0c69acd66772c346d3ce325222b24cef45ca80302263e7f3e5f5bbddf194d81e542fc51540f7eaa7e4d9eca93b57c238b1f283b4203025d55cde0330a14ef84dc8bf656095045cae80fcbb25b8f05a7bc099d5d379ce5bad52429613c6ff193b01b620df850b82bec94f84a0d5a7c1523207bff87f979d71f50842f498742af12e73374d8bdf0981b2dc4ebb6530d39a05c0aa692f254e870736e3f45eed6f4131f90a372e4fd1b5a2c0d5d37470f44787a281a8526a67801ce2838b53eaa3c7665539790750cdfa15c620e5df0503c7577854bb6304f5ce270f9170584224aa992b83b35173"),
1083 ];
1084
1085 const STREAM_SEQ300: &str = "d9cf5983dc6b34c0fa1f0226926855ad3eccd2bcdcd8f8053b9a80664d33b5afcc32fd21c70ea14f4ef50ca97c3203c4d1803159f0e01bb6cb1d1c83db52b63c";
1086
1087 const SWEEP: &str = "88cd3776d2b82923db5e42a2050d4490522ea9b7c10ef5b83d28a2dd59df25c48ff553afac387458ce7e3d2082d976667ea0142b9a5c2c973cc501f9999ec33a";
1091
1092 fn hex(bytes: &[u8]) -> String {
1097 const DIGITS: [u8; 16] = *b"0123456789abcdef";
1098 let mut s = String::with_capacity(bytes.len() * 2);
1099 for byte in bytes {
1100 s.push(char::from(DIGITS[usize::from(*byte >> 4)]));
1101 s.push(char::from(DIGITS[usize::from(*byte & 0x0f)]));
1102 }
1103 s
1104 }
1105
1106 fn seq(n: usize) -> Vec<u8> {
1108 (0..n).map(|i| (i & 0xff) as u8).collect()
1109 }
1110
1111 fn one_shot(outlen: usize, input: &[u8]) -> Vec<u8> {
1112 let mut out = vec![0u8; outlen];
1113 blake2b(&mut out, input).expect("outlen in 1..=64");
1114 out
1115 }
1116
1117 #[test]
1123 fn published_512_vectors() {
1124 assert_eq!(hex(&one_shot(64, b"")), EMPTY_512);
1125 assert_eq!(hex(&one_shot(64, b"abc")), ABC_512);
1126
1127 let mut out = [0u8; 64];
1129 let state = Blake2b::new(64).expect("outlen 64");
1130 state.finalize(&mut out).expect("64-byte buffer");
1131 assert_eq!(hex(&out), EMPTY_512);
1132
1133 let mut state = Blake2b::new(64).expect("outlen 64");
1134 state.update(b"a");
1135 state.update(b"b");
1136 state.update(b"c");
1137 state.finalize(&mut out).expect("64-byte buffer");
1138 assert_eq!(hex(&out), ABC_512);
1139 }
1140
1141 #[test]
1144 fn block_boundary_input_lengths() {
1145 for &(len, expected) in SEQ_INPUT_512 {
1146 let input = seq(len);
1147 assert_eq!(hex(&one_shot(64, &input)), expected, "inlen {len}");
1148 }
1149 }
1150
1151 #[test]
1154 fn short_digest_lengths() {
1155 for &(outlen, expected) in ABC_SHORT_DIGESTS {
1156 assert_eq!(hex(&one_shot(outlen, b"abc")), expected, "outlen {outlen}");
1157 }
1158 assert_ne!(ABC_SHORT_DIGESTS[2].1, &ABC_512[..64]);
1160 }
1161
1162 #[test]
1165 fn keyed_vectors() {
1166 let key = seq(64);
1167 for &(len, expected) in KEYED64_512 {
1168 let input = seq(len);
1169 let mut out = [0u8; 64];
1170 let mut state = Blake2b::with_key(64, &key).expect("64-byte key");
1171 state.update(&input);
1172 state.finalize(&mut out).expect("64-byte buffer");
1173 assert_eq!(hex(&out), expected, "keyed inlen {len}");
1174 }
1175
1176 let mut out = [0u8; 64];
1177 let mut state = Blake2b::with_key(64, &key[..16]).expect("16-byte key");
1178 state.update(b"abc");
1179 state.finalize(&mut out).expect("64-byte buffer");
1180 assert_eq!(hex(&out), KEY16_ABC_512);
1181 }
1182
1183 #[test]
1186 fn streaming_chunks_match_one_shot() {
1187 let input = seq(300);
1188 let mut out = [0u8; 64];
1189 let mut state = Blake2b::new(64).expect("outlen 64");
1190 state.update(&input[..1]);
1191 state.update(&input[1..127]); state.update(&input[127..128]); state.update(&input[128..128]); state.update(&input[128..]);
1195 state.finalize(&mut out).expect("64-byte buffer");
1196
1197 assert_eq!(hex(&out), STREAM_SEQ300);
1198 assert_eq!(hex(&out), hex(&one_shot(64, &input)));
1199 }
1200
1201 #[test]
1204 fn blake2b_long_vectors() {
1205 for &(outlen, expected) in LONG_EMPTY {
1206 let mut out = vec![0u8; outlen];
1207 blake2b_long(&mut out, b"").expect("valid outlen");
1208 assert_eq!(hex(&out), expected, "long empty outlen {outlen}");
1209 }
1210 for &(outlen, expected) in LONG_ABC {
1211 let mut out = vec![0u8; outlen];
1212 blake2b_long(&mut out, b"abc").expect("valid outlen");
1213 assert_eq!(hex(&out), expected, "long abc outlen {outlen}");
1214 }
1215 let seq72 = seq(72);
1216 for &(outlen, expected) in LONG_SEQ72 {
1217 let mut out = vec![0u8; outlen];
1218 blake2b_long(&mut out, &seq72).expect("valid outlen");
1219 assert_eq!(hex(&out), expected, "long seq72 outlen {outlen}");
1220 }
1221 let seq1024 = seq(1024);
1222 for &(outlen, expected) in LONG_SEQ1024_IN {
1223 let mut out = vec![0u8; outlen];
1224 blake2b_long(&mut out, &seq1024).expect("valid outlen");
1225 assert_eq!(hex(&out), expected, "long seq1024-in outlen {outlen}");
1226 }
1227 }
1228
1229 #[test]
1232 fn blake2b_long_branches_differ() {
1233 let mut short = [0u8; 64];
1234 blake2b_long(&mut short, b"abc").expect("outlen 64");
1235 let mut long = [0u8; 65];
1236 blake2b_long(&mut long, b"abc").expect("outlen 65");
1237 assert_ne!(short[..], long[..64]);
1238 }
1239
1240 #[test]
1241 fn blake2b_long_rejects_zero_outlen() {
1242 assert_eq!(
1244 blake2b_long(&mut [], b"abc"),
1245 Err(Error::IncorrectParameter)
1246 );
1247 }
1248
1249 #[test]
1250 fn init_rejects_bad_outlen_and_key() {
1251 assert_eq!(Blake2b::new(0).err(), Some(Error::IncorrectParameter));
1252 assert_eq!(Blake2b::new(65).err(), Some(Error::IncorrectParameter));
1253 assert!(Blake2b::new(1).is_ok());
1254 assert!(Blake2b::new(64).is_ok());
1255
1256 let key = seq(65);
1257 assert_eq!(
1258 Blake2b::with_key(64, &key).err(),
1259 Some(Error::IncorrectParameter)
1260 );
1261 assert_eq!(
1262 Blake2b::with_key(64, &[]).err(),
1263 Some(Error::IncorrectParameter)
1264 );
1265 assert_eq!(
1266 Blake2b::with_key(0, &key[..1]).err(),
1267 Some(Error::IncorrectParameter)
1268 );
1269
1270 assert_eq!(
1272 blake2b(&mut [], b"abc").err(),
1273 Some(Error::IncorrectParameter)
1274 );
1275 assert_eq!(
1276 blake2b(&mut [0u8; 65], b"abc").err(),
1277 Some(Error::IncorrectParameter)
1278 );
1279 }
1280
1281 #[test]
1284 fn finalize_writes_exactly_outlen_bytes() {
1285 let mut out = [0xAAu8; 128];
1286 let mut state = Blake2b::new(32).expect("outlen 32");
1287 state.update(b"abc");
1288 state.finalize(&mut out).expect("128 >= 32");
1289 assert_eq!(hex(&out[..32]), ABC_SHORT_DIGESTS[2].1);
1290 assert!(out[32..].iter().all(|b| *b == 0xAA));
1291
1292 let mut short = [0u8; 31];
1293 let state = Blake2b::new(32).expect("outlen 32");
1294 assert_eq!(state.finalize(&mut short), Err(Error::IncorrectParameter));
1295 }
1296
1297 #[test]
1301 fn reused_state_is_rejected() {
1302 let mut state = Blake2b::new(64).expect("outlen 64");
1303 state.update(b"abc");
1304 state.f[0] = !0; state.update(b"more"); assert_eq!(state.buflen, 3);
1308
1309 let mut out = [0u8; 64];
1310 assert_eq!(state.finalize(&mut out), Err(Error::IncorrectParameter));
1311 }
1312
1313 #[test]
1328 fn sweep_matches_c_reference() {
1329 let mut acc = Blake2b::new(64).expect("outlen 64");
1330
1331 for inlen in 0..=300 {
1333 acc.update(&one_shot(64, &seq(inlen)));
1334 }
1335
1336 let in200 = seq(200);
1338 for outlen in 1..=64 {
1339 acc.update(&one_shot(outlen, &in200));
1340 }
1341
1342 for outlen in 1..=300usize {
1344 let mut out = vec![0u8; outlen];
1345 blake2b_long(&mut out, &seq(outlen % 137)).expect("valid outlen");
1346 acc.update(&out);
1347 }
1348
1349 let in260 = seq(260);
1351 for split in 0..=260 {
1352 let mut state = Blake2b::new(64).expect("outlen 64");
1353 state.update(&in260[..split]);
1354 state.update(&in260[split..]);
1355 let mut digest = [0u8; 64];
1356 state.finalize(&mut digest).expect("64-byte buffer");
1357 acc.update(&digest);
1358 }
1359
1360 let mut out = [0u8; 64];
1361 acc.finalize(&mut out).expect("64-byte buffer");
1362 assert_eq!(hex(&out), SWEEP);
1363 }
1364
1365 #[test]
1368 fn parameter_block_layout() {
1369 let state = Blake2b::new(32).expect("outlen 32");
1370 assert_eq!(state.h[0], IV[0] ^ 0x0101_0020);
1371 assert_eq!(state.h[1..], IV[1..]);
1372 assert_eq!(state.outlen, 32);
1373
1374 let key = seq(16);
1376 let keyed = Blake2b::with_key(64, &key).expect("16-byte key");
1377 assert_eq!(keyed.h[0], IV[0] ^ 0x0101_1040);
1378 assert_eq!(keyed.h[1..], IV[1..]);
1379
1380 assert_eq!(keyed.buflen, BLOCKBYTES);
1384 assert_eq!(keyed.t, [0, 0]);
1385 assert_eq!(keyed.buf[..16], key[..]);
1386 assert!(keyed.buf[16..].iter().all(|b| *b == 0));
1387 }
1388
1389 #[test]
1392 fn counter_increments_and_carries() {
1393 let mut state = Blake2b::new(64).expect("outlen 64");
1394 state.update(&seq(300));
1395 assert_eq!(state.t, [256, 0]);
1397 assert_eq!(state.buflen, 44);
1398
1399 let mut state = Blake2b::new(64).expect("outlen 64");
1400 state.t[0] = u64::MAX - 1;
1401 state.increment_counter(2);
1402 assert_eq!(state.t, [0, 1]);
1403 }
1404}