1use crate::{Error, Result};
4
5use blake2::{
6 Blake2b512, Blake2bVarCore,
7 digest::{
8 Digest,
9 block_api::{UpdateCore, VariableOutputCore},
10 block_buffer::LazyBuffer,
11 },
12};
13
14pub fn blake2b_long(inputs: &[&[u8]], out: &mut [u8]) -> Result<()> {
15 if out.is_empty() {
16 return Err(Error::OutputTooShort);
17 }
18
19 let len_bytes = u32::try_from(out.len())
20 .map(u32::to_le_bytes)
21 .map_err(|_| Error::OutputTooLong)?;
22
23 if let Ok(mut hasher) = Blake2bVarCore::new(out.len()) {
25 let mut buf = LazyBuffer::new(&len_bytes);
26
27 for input in inputs {
28 buf.digest_blocks(input, |blocks| hasher.update_blocks(blocks));
29 }
30
31 let mut full_out = Default::default();
32 hasher.finalize_variable_core(&mut buf, &mut full_out);
33 let out_src = &full_out[..out.len()];
34 out.copy_from_slice(out_src);
35
36 return Ok(());
37 }
38
39 let half_hash_len = Blake2b512::output_size() / 2;
41 let mut digest = Blake2b512::new();
42
43 digest.update(len_bytes);
44 for input in inputs {
45 digest.update(input);
46 }
47 let mut last_output = digest.finalize();
48
49 let (first_chunk, mut out) = out.split_at_mut(half_hash_len);
51 first_chunk.copy_from_slice(&last_output[..half_hash_len]);
52
53 while out.len() > 64 {
58 let (chunk, tail) = out.split_at_mut(half_hash_len);
59 out = tail;
60 last_output = Blake2b512::digest(last_output);
61 chunk.copy_from_slice(&last_output[..half_hash_len]);
62 }
63
64 let mut hasher = Blake2bVarCore::new(out.len())
66 .expect("`out.len()` is guaranteed to be smaller or equal to 64");
67 let mut buf = LazyBuffer::new(&last_output);
68 let mut full_out = Default::default();
69 hasher.finalize_variable_core(&mut buf, &mut full_out);
70 let out_src = &full_out[..out.len()];
71 out.copy_from_slice(out_src);
72
73 Ok(())
74}