Coverage Report

Created: 2026-07-10 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rfc6979-0.4.0/src/lib.rs
Line
Count
Source
1
#![no_std]
2
#![doc = include_str!("../README.md")]
3
#![forbid(unsafe_code, clippy::unwrap_used)]
4
#![warn(missing_docs, rust_2018_idioms)]
5
#![doc(
6
    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
7
    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
8
)]
9
10
//! ## Usage
11
//!
12
//! See also: the documentation for the [`generate_k`] function.
13
//!
14
//! ```
15
//! use hex_literal::hex;
16
//! use rfc6979::consts::U32;
17
//! use sha2::{Digest, Sha256};
18
//!
19
//! // NIST P-256 field modulus
20
//! const NIST_P256_MODULUS: [u8; 32] =
21
//!     hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
22
//!
23
//! // Public key for RFC6979 NIST P256/SHA256 test case
24
//! const RFC6979_KEY: [u8; 32] =
25
//!     hex!("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721");
26
//!
27
//! // Test message for RFC6979 NIST P256/SHA256 test case
28
//! const RFC6979_MSG: &[u8; 6] = b"sample";
29
//!
30
//! // Expected K for RFC6979 NIST P256/SHA256 test case
31
//! const RFC6979_EXPECTED_K: [u8; 32] =
32
//!     hex!("A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60");
33
//!
34
//! let h = Sha256::digest(RFC6979_MSG);
35
//! let aad = b"";
36
//! let k = rfc6979::generate_k::<Sha256, U32>(&RFC6979_KEY.into(), &NIST_P256_MODULUS.into(), &h, aad);
37
//! assert_eq!(k.as_slice(), &RFC6979_EXPECTED_K);
38
//! ```
39
40
mod ct_cmp;
41
42
pub use hmac::digest::generic_array::typenum::consts;
43
44
use hmac::{
45
    digest::{
46
        core_api::BlockSizeUser,
47
        generic_array::{ArrayLength, GenericArray},
48
        Digest, FixedOutput, FixedOutputReset, Mac,
49
    },
50
    SimpleHmac,
51
};
52
53
/// Array of bytes representing a scalar serialized as a big endian integer.
54
pub type ByteArray<Size> = GenericArray<u8, Size>;
55
56
/// Deterministically generate ephemeral scalar `k`.
57
///
58
/// Accepts the following parameters and inputs:
59
///
60
/// - `x`: secret key
61
/// - `n`: field modulus
62
/// - `h`: hash/digest of input message: must be reduced modulo `n` in advance
63
/// - `data`: additional associated data, e.g. CSRNG output used as added entropy
64
#[inline]
65
3.67k
pub fn generate_k<D, N>(
66
3.67k
    x: &ByteArray<N>,
67
3.67k
    n: &ByteArray<N>,
68
3.67k
    h: &ByteArray<N>,
69
3.67k
    data: &[u8],
70
3.67k
) -> ByteArray<N>
71
3.67k
where
72
3.67k
    D: Digest + BlockSizeUser + FixedOutput<OutputSize = N> + FixedOutputReset,
73
3.67k
    N: ArrayLength<u8>,
74
{
75
3.67k
    let mut hmac_drbg = HmacDrbg::<D>::new(x, h, data);
76
77
    loop {
78
3.67k
        let mut k = ByteArray::<N>::default();
79
3.67k
        hmac_drbg.fill_bytes(&mut k);
80
81
3.67k
        let k_is_zero = ct_cmp::ct_eq(&k, &ByteArray::default());
82
3.67k
        if (!k_is_zero & ct_cmp::ct_lt(&k, n)).into() {
83
3.67k
            return k;
84
0
        }
85
    }
86
3.67k
}
87
88
/// Internal implementation of `HMAC_DRBG` as described in NIST SP800-90A.
89
///
90
/// <https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final>
91
///
92
/// This is a HMAC-based deterministic random bit generator used compute a
93
/// deterministic ephemeral scalar `k`.
94
pub struct HmacDrbg<D>
95
where
96
    D: Digest + BlockSizeUser + FixedOutputReset,
97
{
98
    /// HMAC key `K` (see RFC 6979 Section 3.2.c)
99
    k: SimpleHmac<D>,
100
101
    /// Chaining value `V` (see RFC 6979 Section 3.2.c)
102
    v: GenericArray<u8, D::OutputSize>,
103
}
104
105
impl<D> HmacDrbg<D>
106
where
107
    D: Digest + BlockSizeUser + FixedOutputReset,
108
{
109
    /// Initialize `HMAC_DRBG`
110
3.67k
    pub fn new(entropy_input: &[u8], nonce: &[u8], additional_data: &[u8]) -> Self {
111
3.67k
        let mut k = SimpleHmac::new(&Default::default());
112
3.67k
        let mut v = GenericArray::default();
113
114
121k
        for b in &mut v {
115
117k
            *b = 0x01;
116
117k
        }
117
118
11.0k
        for i in 0..=1 {
119
7.34k
            k.update(&v);
120
7.34k
            k.update(&[i]);
121
7.34k
            k.update(entropy_input);
122
7.34k
            k.update(nonce);
123
7.34k
            k.update(additional_data);
124
7.34k
            k = SimpleHmac::new_from_slice(&k.finalize().into_bytes()).expect("HMAC error");
125
7.34k
126
7.34k
            // Steps 3.2.e,g: v = HMAC_k(v)
127
7.34k
            k.update(&v);
128
7.34k
            v = k.finalize_reset().into_bytes();
129
7.34k
        }
130
131
3.67k
        Self { k, v }
132
3.67k
    }
133
134
    /// Write the next `HMAC_DRBG` output to the given byte slice.
135
3.67k
    pub fn fill_bytes(&mut self, out: &mut [u8]) {
136
3.67k
        for out_chunk in out.chunks_mut(self.v.len()) {
137
3.67k
            self.k.update(&self.v);
138
3.67k
            self.v = self.k.finalize_reset().into_bytes();
139
3.67k
            out_chunk.copy_from_slice(&self.v[..out_chunk.len()]);
140
3.67k
        }
141
142
3.67k
        self.k.update(&self.v);
143
3.67k
        self.k.update(&[0x00]);
144
3.67k
        self.k =
145
3.67k
            SimpleHmac::new_from_slice(&self.k.finalize_reset().into_bytes()).expect("HMAC error");
146
3.67k
        self.k.update(&self.v);
147
3.67k
        self.v = self.k.finalize_reset().into_bytes();
148
3.67k
    }
149
}