]> git.proxmox.com Git - rustc.git/blob - vendor/rfc6979/src/lib.rs
New upstream version 1.70.0+dfsg2
[rustc.git] / vendor / rfc6979 / src / lib.rs
1 #![doc = include_str!("../README.md")]
2
3 //! ## Usage
4 //!
5 //! See also: the documentation for the [`generate_k`] function.
6 //!
7 //! ```
8 //! use crypto_bigint::{ArrayEncoding, U256};
9 //! use sha2::{Digest, Sha256};
10 //!
11 //! // NIST P-256 field modulus
12 //! const NIST_P256_MODULUS: U256 =
13 //! U256::from_be_hex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
14 //!
15 //! // Public key for RFC6979 NIST P256/SHA256 test case
16 //! const RFC6979_KEY: U256 =
17 //! U256::from_be_hex("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721");
18 //!
19 //! // Test message for RFC6979 NIST P256/SHA256 test case
20 //! const RFC6979_MSG: &[u8; 6] = b"sample";
21 //!
22 //! // Expected K for RFC6979 NIST P256/SHA256 test case
23 //! const RFC6979_EXPECTED_K: U256 =
24 //! U256::from_be_hex("A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60");
25 //!
26 //! let h = Sha256::digest(RFC6979_MSG);
27 //! let aad = b"";
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());
30 //! ```
31
32 #![no_std]
33 #![cfg_attr(docsrs, feature(doc_cfg))]
34 #![forbid(unsafe_code, clippy::unwrap_used)]
35 #![warn(missing_docs, rust_2018_idioms)]
36 #![doc(
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"
39 )]
40
41 use crypto_bigint::{ArrayEncoding, ByteArray, Integer};
42 use hmac::{
43 digest::{
44 core_api::BlockSizeUser, generic_array::GenericArray, Digest, FixedOutput,
45 FixedOutputReset, Mac,
46 },
47 SimpleHmac,
48 };
49 use zeroize::{Zeroize, Zeroizing};
50
51 /// Deterministically generate ephemeral scalar `k`.
52 ///
53 /// Accepts the following parameters and inputs:
54 ///
55 /// - `x`: secret key
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
59 #[inline]
60 pub fn generate_k<D, I>(x: &I, n: &I, h: &ByteArray<I>, data: &[u8]) -> Zeroizing<I>
61 where
62 D: Digest + BlockSizeUser + FixedOutput<OutputSize = I::ByteSize> + FixedOutputReset,
63 I: ArrayEncoding + Integer + Zeroize,
64 {
65 let mut x = x.to_be_byte_array();
66 let mut hmac_drbg = HmacDrbg::<D>::new(&x, h, data);
67 x.zeroize();
68
69 loop {
70 let mut bytes = ByteArray::<I>::default();
71 hmac_drbg.fill_bytes(&mut bytes);
72 let k = I::from_be_byte_array(bytes);
73
74 if (!k.is_zero() & k.ct_lt(n)).into() {
75 return Zeroizing::new(k);
76 }
77 }
78 }
79
80 /// Internal implementation of `HMAC_DRBG` as described in NIST SP800-90A.
81 ///
82 /// <https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final>
83 ///
84 /// This is a HMAC-based deterministic random bit generator used compute a
85 /// deterministic ephemeral scalar `k`.
86 pub struct HmacDrbg<D>
87 where
88 D: Digest + BlockSizeUser + FixedOutputReset,
89 {
90 /// HMAC key `K` (see RFC 6979 Section 3.2.c)
91 k: SimpleHmac<D>,
92
93 /// Chaining value `V` (see RFC 6979 Section 3.2.c)
94 v: GenericArray<u8, D::OutputSize>,
95 }
96
97 impl<D> HmacDrbg<D>
98 where
99 D: Digest + BlockSizeUser + FixedOutputReset,
100 {
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();
105
106 for b in &mut v {
107 *b = 0x01;
108 }
109
110 for i in 0..=1 {
111 k.update(&v);
112 k.update(&[i]);
113 k.update(entropy_input);
114 k.update(nonce);
115 k.update(additional_data);
116 k = SimpleHmac::new_from_slice(&k.finalize().into_bytes()).expect("HMAC error");
117
118 // Steps 3.2.e,g: v = HMAC_k(v)
119 k.update(&v);
120 v = k.finalize_reset().into_bytes();
121 }
122
123 Self { k, v }
124 }
125
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()]);
132 }
133
134 self.k.update(&self.v);
135 self.k.update(&[0x00]);
136 self.k =
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();
140 }
141 }