1use crate::hazmat::FromDigest;
7use elliptic_curve_flow::{
8 generic_array::GenericArray,
9 group::ff::PrimeField,
10 ops::Invert,
11 zeroize::{Zeroize, Zeroizing},
12 FieldBytes, FieldSize, NonZeroScalar, PrimeCurve, ProjectiveArithmetic, Scalar,
13};
14use hmac::{Hmac, Mac, NewMac};
15use signature_flow::digest::{BlockInput, FixedOutput, Reset, Update};
16
17pub fn generate_k<C, D>(
20 secret_scalar: &NonZeroScalar<C>,
21 msg_digest: D,
22 additional_data: &[u8],
23) -> Zeroizing<NonZeroScalar<C>>
24where
25 C: PrimeCurve + ProjectiveArithmetic,
26 D: FixedOutput<OutputSize = FieldSize<C>> + BlockInput + Clone + Default + Reset + Update,
27 Scalar<C>: FromDigest<C> + Invert<Output = Scalar<C>> + Zeroize,
28{
29 let mut x = secret_scalar.to_repr();
30 let h1 = Scalar::<C>::from_digest(msg_digest).to_repr();
31 let mut hmac_drbg = HmacDrbg::<D>::new(&x, &h1, additional_data);
32 x.zeroize();
33
34 loop {
35 let mut tmp = FieldBytes::<C>::default();
36 hmac_drbg.generate_into(&mut tmp);
37 if let Some(k) = NonZeroScalar::from_repr(tmp).into() {
38 return Zeroizing::new(k);
39 }
40 }
41}
42
43struct HmacDrbg<D>
50where
51 D: BlockInput + FixedOutput + Clone + Default + Reset + Update,
52{
53 k: Hmac<D>,
55
56 v: GenericArray<u8, D::OutputSize>,
58}
59
60impl<D> HmacDrbg<D>
61where
62 D: BlockInput + FixedOutput + Clone + Default + Reset + Update,
63{
64 pub fn new(entropy_input: &[u8], nonce: &[u8], additional_data: &[u8]) -> Self {
66 let mut k = Hmac::new(&Default::default());
67 let mut v = GenericArray::default();
68
69 for b in &mut v {
70 *b = 0x01;
71 }
72
73 for i in 0..=1 {
74 k.update(&v);
75 k.update(&[i]);
76 k.update(entropy_input);
77 k.update(nonce);
78 k.update(additional_data);
79 k = Hmac::new_from_slice(&k.finalize().into_bytes()).expect("HMAC error");
80
81 k.update(&v);
83 v = k.finalize_reset().into_bytes();
84 }
85
86 Self { k, v }
87 }
88
89 pub fn generate_into(&mut self, out: &mut [u8]) {
91 for out_chunk in out.chunks_mut(self.v.len()) {
92 self.k.update(&self.v);
93 self.v = self.k.finalize_reset().into_bytes();
94 out_chunk.copy_from_slice(&self.v[..out_chunk.len()]);
95 }
96
97 self.k.update(&self.v);
98 self.k.update(&[0x00]);
99 self.k = Hmac::new_from_slice(&self.k.finalize_reset().into_bytes()).expect("HMAC error");
100 self.k.update(&self.v);
101 self.v = self.k.finalize_reset().into_bytes();
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::generate_k;
108 use elliptic_curve_flow::{dev::NonZeroScalar, group::ff::PrimeField};
109 use hex_literal::hex;
110 use sha2::{Digest, Sha256};
111
112 #[test]
115 fn appendix_2_5_test_vector() {
116 let x = NonZeroScalar::from_repr(
117 hex!("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721").into(),
118 )
119 .unwrap();
120
121 let digest = Sha256::new().chain("sample");
122 let k = generate_k(&x, digest, &[]);
123
124 assert_eq!(
125 k.to_repr().as_slice(),
126 &hex!("a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60")[..]
127 );
128 }
129}