/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 | | } |