Coverage Report

Created: 2026-03-23 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/argon2-0.5.3/src/blake2b_long.rs
Line
Count
Source
1
//! The variable length hash function used in the Argon2 algorithm.
2
3
use crate::{Error, Result};
4
5
use blake2::{
6
    digest::{self, Digest, VariableOutput},
7
    Blake2b512, Blake2bVar,
8
};
9
10
use core::convert::TryFrom;
11
12
0
pub fn blake2b_long(inputs: &[&[u8]], out: &mut [u8]) -> Result<()> {
13
0
    if out.is_empty() {
14
0
        return Err(Error::OutputTooShort);
15
0
    }
16
17
0
    let len_bytes = u32::try_from(out.len())
18
0
        .map(|v| v.to_le_bytes())
19
0
        .map_err(|_| Error::OutputTooLong)?;
20
21
    // Use blake2b directly if the output is small enough.
22
0
    if out.len() <= Blake2b512::output_size() {
23
0
        let mut digest = Blake2bVar::new(out.len()).map_err(|_| Error::OutputTooLong)?;
24
25
        // Conflicting method name from `Digest` and `Update` traits
26
0
        digest::Update::update(&mut digest, &len_bytes);
27
28
0
        for input in inputs {
29
0
            digest::Update::update(&mut digest, input);
30
0
        }
31
32
0
        digest
33
0
            .finalize_variable(out)
34
0
            .map_err(|_| Error::OutputTooLong)?;
35
36
0
        return Ok(());
37
0
    }
38
39
    // Calculate longer hashes by first calculating a full 64 byte hash
40
0
    let half_hash_len = Blake2b512::output_size() / 2;
41
0
    let mut digest = Blake2b512::new();
42
43
0
    digest.update(len_bytes);
44
0
    for input in inputs {
45
0
        digest.update(input);
46
0
    }
47
0
    let mut last_output = digest.finalize();
48
49
    // Then we write the first 32 bytes of this hash to the output
50
0
    out[..half_hash_len].copy_from_slice(&last_output[..half_hash_len]);
51
52
    // Next, we write a number of 32 byte blocks to the output.
53
    // Each block is the first 32 bytes of the hash of the last block.
54
    // The very last block of the output is excluded, and has a variable
55
    // length in range [1, 32].
56
0
    let mut counter = 0;
57
0
    let out_len = out.len();
58
0
    for chunk in out[half_hash_len..]
59
0
        .chunks_exact_mut(half_hash_len)
60
0
        .take_while(|_| {
61
0
            counter += half_hash_len;
62
0
            out_len - counter > 64
63
0
        })
64
0
    {
65
0
        last_output = Blake2b512::digest(last_output);
66
0
        chunk.copy_from_slice(&last_output[..half_hash_len]);
67
0
    }
68
69
    // Calculate the last block with VarBlake2b.
70
0
    let last_block_size = out.len() - counter;
71
0
    let mut digest = Blake2bVar::new(last_block_size).map_err(|_| Error::OutputTooLong)?;
72
73
0
    digest::Update::update(&mut digest, &last_output);
74
0
    digest
75
0
        .finalize_variable(&mut out[counter..])
76
0
        .expect("invalid Blake2bVar out length");
77
78
0
    Ok(())
79
0
}