1use crate::hacl::drbg;
6pub use rand::{CryptoRng, RngCore};
8
9#[derive(Debug)]
10pub enum Error {
11 InvalidInput,
13 UnsupportedAlgorithm,
15 UnableToGenerate,
17}
18
19impl std::fmt::Display for Error {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 f.write_fmt(format_args!("{self:?}"))
22 }
23}
24
25impl std::error::Error for Error {}
26
27pub struct Drbg {
28 state: drbg::Drbg,
29 ctr: u32, }
31
32impl Drbg {
33 #[cfg(feature = "rand")]
39 pub fn new(alg: super::digest::Algorithm) -> Result<Self, Error> {
40 let mut entropy = [0u8; 16];
41 rand::rngs::OsRng.fill_bytes(&mut entropy);
42 Self::personalized(alg, &entropy, &[], "os seeded libcrux")
43 }
44
45 pub fn new_with_entropy(alg: super::digest::Algorithm, entropy: &[u8]) -> Result<Self, Error> {
48 Self::personalized(alg, entropy, &[], "libcrux")
49 }
50
51 pub fn personalized(
55 alg: super::digest::Algorithm,
56 entropy: &[u8],
57 nonce: &[u8],
58 personalization: &str,
59 ) -> Result<Self, Error> {
60 let algorithm = match alg {
61 crate::digest::Algorithm::Sha1 => drbg::Algorithm::Sha1,
62 crate::digest::Algorithm::Sha256 => drbg::Algorithm::Sha2_256,
63 crate::digest::Algorithm::Sha384 => drbg::Algorithm::Sha2_384,
64 crate::digest::Algorithm::Sha512 => drbg::Algorithm::Sha2_512,
65 crate::digest::Algorithm::Sha224
66 | crate::digest::Algorithm::Blake2s
67 | crate::digest::Algorithm::Blake2b
68 | crate::digest::Algorithm::Sha3_224
69 | crate::digest::Algorithm::Sha3_256
70 | crate::digest::Algorithm::Sha3_384
71 | crate::digest::Algorithm::Sha3_512 => return Err(Error::UnsupportedAlgorithm),
72 };
73
74 let state = drbg::Drbg::new(algorithm, entropy, nonce, personalization)
75 .map_err(|_| Error::InvalidInput)?;
76 Ok(Self { state, ctr: 0 })
77 }
78
79 #[cfg(feature = "rand")]
81 #[inline(always)]
82 fn auto_reseed(&mut self) -> Result<(), Error> {
83 if self.ctr > 512 {
84 let mut entropy = [0u8; 16];
85 rand::rngs::OsRng.fill_bytes(&mut entropy);
86 self.reseed(&entropy, b"reseed")?;
87 self.ctr = 0;
88 } else {
89 self.ctr += 1;
90 }
91 Ok(())
92 }
93
94 #[cfg(not(feature = "rand"))]
95 #[inline(always)]
96 fn auto_reseed(&mut self) -> Result<(), Error> {
97 Ok(())
98 }
99
100 pub fn reseed(&mut self, entropy: &[u8], additional_input: &[u8]) -> Result<(), Error> {
102 self.state
103 .reseed(entropy, additional_input)
104 .map_err(|_| Error::InvalidInput)
105 }
106
107 pub fn generate(&mut self, output: &mut [u8]) -> Result<(), Error> {
113 self.auto_reseed()?;
114 self.state
115 .generate(output, &[])
116 .map_err(|_| Error::UnableToGenerate)
117 }
118
119 pub fn generate_with_input(
125 &mut self,
126 output: &mut [u8],
127 additional_input: &[u8],
128 ) -> Result<(), Error> {
129 self.auto_reseed()?;
130 self.state
131 .generate(output, additional_input)
132 .map_err(|_| Error::UnableToGenerate)
133 }
134
135 pub fn generate_vec(&mut self, len: usize) -> Result<Vec<u8>, Error> {
142 self.auto_reseed()?;
143 let mut output = vec![0u8; len];
144 self.state
145 .generate(&mut output, &[])
146 .map_err(|_| Error::UnableToGenerate)
147 .map(|()| output)
148 }
149
150 pub fn generate_array<const LEN: usize>(&mut self) -> Result<[u8; LEN], Error> {
157 self.auto_reseed()?;
158 let mut output = [0u8; LEN];
159 self.state
160 .generate(&mut output, &[])
161 .map_err(|_| Error::UnableToGenerate)
162 .map(|()| output)
163 }
164
165 pub fn reseed_required(&self) -> bool {
167 self.ctr > 512
168 }
169}
170
171impl RngCore for Drbg {
173 fn next_u32(&mut self) -> u32 {
174 todo!()
175 }
176
177 fn next_u64(&mut self) -> u64 {
178 todo!()
179 }
180
181 fn fill_bytes(&mut self, dest: &mut [u8]) {
182 self.generate(dest).unwrap()
183 }
184
185 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
186 self.generate(dest).map_err(rand::Error::new)
187 }
188}
189
190impl CryptoRng for Drbg {}