Coverage Report

Created: 2026-11-12 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rfc6979-0.6.0/src/hmac_drbg.rs
Line
Count
Source
1
use core::fmt::{self, Debug};
2
use hmac::{
3
    KeyInit, SimpleHmac,
4
    digest::{Digest, Mac, OutputSizeUser, array::Array, block_api::BlockSizeUser},
5
};
6
7
/// Implementation of [NIST SP800-90A]'s `HMAC_DRBG` HMAC-based deterministic random bit generator.
8
///
9
/// [NIST SP800-90A]: https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final
10
// TODO(tarcieri): extract this into the `hmacdrbg` crate: RustCrypto/CSRNGs#7
11
pub(crate) struct HmacDrbg<D>
12
where
13
    D: OutputSizeUser,
14
{
15
    /// HMAC key `K` (see RFC 6979 Section 3.2.c)
16
    k: Array<u8, D::OutputSize>,
17
18
    /// Chaining value `V` (see RFC 6979 Section 3.2.c)
19
    v: Array<u8, D::OutputSize>,
20
}
21
22
impl<D> HmacDrbg<D>
23
where
24
    D: BlockSizeUser + Digest,
25
{
26
    /// Initialize `HMAC_DRBG`.
27
    #[must_use]
28
2.16k
    pub(crate) fn new(entropy_input: &[u8], nonce: &[u8], personalization_string: &[u8]) -> Self {
29
2.16k
        let mut drbg = Self {
30
2.16k
            k: Array::default(),
31
2.16k
            v: Array::default(),
32
2.16k
        };
33
2.16k
        drbg.v.fill(0x01);
34
2.16k
        drbg.update(&[entropy_input, nonce, personalization_string]);
35
2.16k
        drbg
36
2.16k
    }
37
38
    /// Write the next `HMAC_DRBG` output to the given byte slice.
39
2.16k
    pub(crate) fn fill_bytes(&mut self, out: &mut [u8]) {
40
2.16k
        for out_chunk in out.chunks_mut(self.v.len()) {
41
2.16k
            self.update_v();
42
2.16k
            out_chunk.copy_from_slice(&self.v[..out_chunk.len()]);
43
2.16k
        }
44
45
2.16k
        self.update(&[]);
46
2.16k
    }
47
48
    /// Update `K` and `V` using the provided seed material.
49
4.32k
    fn update(&mut self, inputs: &[&[u8]]) {
50
4.32k
        let mut hmac = self.hmac_k();
51
4.32k
        hmac.update(&self.v);
52
4.32k
        hmac.update(&[0x00]);
53
6.48k
        inputs.iter().for_each(|&input| hmac.update(input));
54
55
4.32k
        self.k = hmac.finalize().into_bytes();
56
4.32k
        self.update_v();
57
58
4.32k
        if !inputs.is_empty() {
59
2.16k
            let mut hmac = self.hmac_k();
60
2.16k
            hmac.update(&self.v);
61
2.16k
            hmac.update(&[0x01]);
62
6.48k
            inputs.iter().for_each(|&input| hmac.update(input));
63
64
2.16k
            self.k = hmac.finalize().into_bytes();
65
2.16k
            self.update_v();
66
2.16k
        }
67
4.32k
    }
68
69
    /// Update `V = HMAC(K, V)`.
70
8.64k
    fn update_v(&mut self) {
71
8.64k
        let mut hmac = self.hmac_k();
72
8.64k
        hmac.update(&self.v);
73
8.64k
        self.v = hmac.finalize().into_bytes();
74
8.64k
    }
75
76
    /// Initialize HMAC using the current value of `K`.
77
15.1k
    fn hmac_k(&self) -> SimpleHmac<D> {
78
15.1k
        SimpleHmac::<D>::new_from_slice(&self.k).expect("HMAC key should be valid")
79
15.1k
    }
80
}
81
82
impl<D> Debug for HmacDrbg<D>
83
where
84
    D: OutputSizeUser,
85
{
86
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87
        f.debug_struct("HmacDrbg").finish_non_exhaustive()
88
    }
89
}
90
91
#[cfg(test)]
92
mod tests {
93
    use super::HmacDrbg;
94
    use hex_literal::hex;
95
    use sha2::Sha256;
96
97
    // ECDSA with K-163+SHA-256.
98
    #[test]
99
    fn rfc6979_appendix_a1_k163() {
100
        let x = hex!("009A4D6792295A7F730FC3F2B49CBC0F62E862272F");
101
102
        // NOTE: this input is `SHA256("sample")` with `bits2octets` applied in advance
103
        let h = hex!("01795EDF0D54DB760F156D0DAC04C0322B3A204224");
104
105
        let mut drbg = HmacDrbg::<Sha256>::new(&x, &h, &[]);
106
        let mut out = [0u8; 21];
107
        drbg.fill_bytes(&mut out);
108
        assert_eq!(out, hex!("9305A46DE7FF8EB107194DEBD3FD48AA20D5E7656C"));
109
    }
110
}