1 #![doc = include_str!("../README.md")]
5 //! See also: the documentation for the [`generate_k`] function.
8 //! use crypto_bigint::{ArrayEncoding, U256};
9 //! use sha2::{Digest, Sha256};
11 //! // NIST P-256 field modulus
12 //! const NIST_P256_MODULUS: U256 =
13 //! U256::from_be_hex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
15 //! // Public key for RFC6979 NIST P256/SHA256 test case
16 //! const RFC6979_KEY: U256 =
17 //! U256::from_be_hex("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721");
19 //! // Test message for RFC6979 NIST P256/SHA256 test case
20 //! const RFC6979_MSG: &[u8; 6] = b"sample";
22 //! // Expected K for RFC6979 NIST P256/SHA256 test case
23 //! const RFC6979_EXPECTED_K: U256 =
24 //! U256::from_be_hex("A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60");
26 //! let h = Sha256::digest(RFC6979_MSG);
28 //! let k = rfc6979::generate_k::<Sha256, U256>(&RFC6979_KEY, &NIST_P256_MODULUS, &h, aad);
29 //! assert_eq!(&k.to_be_byte_array(), &RFC6979_EXPECTED_K.to_be_byte_array());
33 #![cfg_attr(docsrs, feature(doc_cfg))]
34 #![forbid(unsafe_code, clippy::unwrap_used)]
35 #![warn(missing_docs, rust_2018_idioms)]
37 html_logo_url
= "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
38 html_favicon_url
= "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
41 use crypto_bigint
::{ArrayEncoding, ByteArray, Integer}
;
44 core_api
::BlockSizeUser
, generic_array
::GenericArray
, Digest
, FixedOutput
,
45 FixedOutputReset
, Mac
,
49 use zeroize
::{Zeroize, Zeroizing}
;
51 /// Deterministically generate ephemeral scalar `k`.
53 /// Accepts the following parameters and inputs:
56 /// - `n`: field modulus
57 /// - `h`: hash/digest of input message: must be reduced modulo `n` in advance
58 /// - `data`: additional associated data, e.g. CSRNG output used as added entropy
60 pub fn generate_k
<D
, I
>(x
: &I
, n
: &I
, h
: &ByteArray
<I
>, data
: &[u8]) -> Zeroizing
<I
>
62 D
: Digest
+ BlockSizeUser
+ FixedOutput
<OutputSize
= I
::ByteSize
> + FixedOutputReset
,
63 I
: ArrayEncoding
+ Integer
+ Zeroize
,
65 let mut x
= x
.to_be_byte_array();
66 let mut hmac_drbg
= HmacDrbg
::<D
>::new(&x
, h
, data
);
70 let mut bytes
= ByteArray
::<I
>::default();
71 hmac_drbg
.fill_bytes(&mut bytes
);
72 let k
= I
::from_be_byte_array(bytes
);
74 if (!k
.is_zero() & k
.ct_lt(n
)).into() {
75 return Zeroizing
::new(k
);
80 /// Internal implementation of `HMAC_DRBG` as described in NIST SP800-90A.
82 /// <https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final>
84 /// This is a HMAC-based deterministic random bit generator used compute a
85 /// deterministic ephemeral scalar `k`.
86 pub struct HmacDrbg
<D
>
88 D
: Digest
+ BlockSizeUser
+ FixedOutputReset
,
90 /// HMAC key `K` (see RFC 6979 Section 3.2.c)
93 /// Chaining value `V` (see RFC 6979 Section 3.2.c)
94 v
: GenericArray
<u8, D
::OutputSize
>,
99 D
: Digest
+ BlockSizeUser
+ FixedOutputReset
,
101 /// Initialize `HMAC_DRBG`
102 pub fn new(entropy_input
: &[u8], nonce
: &[u8], additional_data
: &[u8]) -> Self {
103 let mut k
= SimpleHmac
::new(&Default
::default());
104 let mut v
= GenericArray
::default();
113 k
.update(entropy_input
);
115 k
.update(additional_data
);
116 k
= SimpleHmac
::new_from_slice(&k
.finalize().into_bytes()).expect("HMAC error");
118 // Steps 3.2.e,g: v = HMAC_k(v)
120 v
= k
.finalize_reset().into_bytes();
126 /// Write the next `HMAC_DRBG` output to the given byte slice.
127 pub fn fill_bytes(&mut self, out
: &mut [u8]) {
128 for out_chunk
in out
.chunks_mut(self.v
.len()) {
129 self.k
.update(&self.v
);
130 self.v
= self.k
.finalize_reset().into_bytes();
131 out_chunk
.copy_from_slice(&self.v
[..out_chunk
.len()]);
134 self.k
.update(&self.v
);
135 self.k
.update(&[0x00]);
137 SimpleHmac
::new_from_slice(&self.k
.finalize_reset().into_bytes()).expect("HMAC error");
138 self.k
.update(&self.v
);
139 self.v
= self.k
.finalize_reset().into_bytes();