/rust/registry/src/index.crates.io-1949cf8c6b5b557f/aws-lc-rs-1.16.3/src/rand.rs
Line | Count | Source |
1 | | // Copyright 2015-2016 Brian Smith. |
2 | | // SPDX-License-Identifier: ISC |
3 | | // Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. |
4 | | // SPDX-License-Identifier: Apache-2.0 OR ISC |
5 | | |
6 | | //! Cryptographic pseudo-random number generation. |
7 | | //! |
8 | | //! An application should create a single `SystemRandom` and then use it for |
9 | | //! all randomness generation. See `SystemRandom`'s documentation for more |
10 | | //! details. |
11 | | |
12 | | //! # Example |
13 | | //! ``` |
14 | | //! use aws_lc_rs::{rand, rand::SecureRandom}; |
15 | | //! |
16 | | //! // Using `rand::fill` |
17 | | //! let mut rand_bytes = [0u8; 32]; |
18 | | //! rand::fill(&mut rand_bytes).unwrap(); |
19 | | //! |
20 | | //! // Using `SystemRandom` |
21 | | //! let rng = rand::SystemRandom::new(); |
22 | | //! rng.fill(&mut rand_bytes).unwrap(); |
23 | | //! |
24 | | //! // Using `rand::generate` |
25 | | //! let random_array = rand::generate(&rng).unwrap(); |
26 | | //! let more_rand_bytes: [u8; 64] = random_array.expose(); |
27 | | //! ``` |
28 | | use crate::aws_lc::RAND_bytes; |
29 | | use crate::error::Unspecified; |
30 | | use crate::fips::indicator_check; |
31 | | use core::fmt::Debug; |
32 | | |
33 | | /// Re-exports of sealed traits for development testing. |
34 | | /// |
35 | | /// This module is only available when the `dev-tests-only` feature is enabled. |
36 | | /// It exposes the [`SecureRandom`](unsealed::SecureRandom) trait, allowing consumers |
37 | | /// to provide their own implementations (e.g., a deterministic RNG) for testing purposes. |
38 | | /// |
39 | | /// # Example |
40 | | /// |
41 | | /// ```ignore |
42 | | /// use aws_lc_rs::rand::{unsealed, SecureRandom}; |
43 | | /// use aws_lc_rs::error::Unspecified; |
44 | | /// |
45 | | /// #[derive(Debug)] |
46 | | /// struct DeterministicRandom(u8); |
47 | | /// |
48 | | /// impl unsealed::SecureRandom for DeterministicRandom { |
49 | | /// fn fill_impl(&self, dest: &mut [u8]) -> Result<(), Unspecified> { |
50 | | /// for (i, byte) in dest.iter_mut().enumerate() { |
51 | | /// *byte = self.0.wrapping_add(i as u8); |
52 | | /// } |
53 | | /// Ok(()) |
54 | | /// } |
55 | | /// } |
56 | | /// ``` |
57 | | #[cfg(any(dev_tests_only, aws_lc_rs_docsrs))] |
58 | | #[cfg_attr(aws_lc_rs_docsrs, doc(cfg(feature = "dev-tests-only")))] |
59 | | #[allow(unused_imports)] |
60 | | pub mod unsealed { |
61 | | pub use super::sealed::*; |
62 | | } |
63 | | |
64 | | /// A secure random number generator. |
65 | | pub trait SecureRandom: sealed::SecureRandom { |
66 | | /// Fills `dest` with random bytes. |
67 | | /// |
68 | | /// # Errors |
69 | | /// `error::Unspecified` if unable to fill `dest`. |
70 | | fn fill(&self, dest: &mut [u8]) -> Result<(), Unspecified>; |
71 | | |
72 | | /// Fills `dest` with random bytes. |
73 | | /// |
74 | | /// This method is only available when the `dev-tests-only` feature is enabled. |
75 | | /// |
76 | | /// # Errors |
77 | | /// `error::Unspecified` if unable to fill `dest`. |
78 | | #[cfg(any(test, dev_tests_only, aws_lc_rs_docsrs))] |
79 | | #[cfg_attr(aws_lc_rs_docsrs, doc(cfg(feature = "dev-tests-only")))] |
80 | | fn mut_fill(&mut self, dest: &mut [u8]) -> Result<(), Unspecified>; |
81 | | } |
82 | | |
83 | | impl<T> SecureRandom for T |
84 | | where |
85 | | T: sealed::SecureRandom, |
86 | | { |
87 | | #[inline] |
88 | 0 | fn fill(&self, dest: &mut [u8]) -> Result<(), Unspecified> { |
89 | 0 | self.fill_impl(dest) |
90 | 0 | } Unexecuted instantiation: <aws_lc_rs::rand::SystemRandom as aws_lc_rs::rand::SecureRandom>::fill Unexecuted instantiation: <_ as aws_lc_rs::rand::SecureRandom>::fill |
91 | | |
92 | | #[inline] |
93 | | #[cfg(any(test, dev_tests_only, aws_lc_rs_docsrs))] |
94 | | fn mut_fill(&mut self, dest: &mut [u8]) -> Result<(), Unspecified> { |
95 | | self.fill_impl(dest) |
96 | | } |
97 | | } |
98 | | |
99 | | /// A random value constructed from a `SecureRandom` that hasn't been exposed |
100 | | /// through any safe Rust interface. |
101 | | /// |
102 | | /// Intentionally does not implement any traits other than `Sized`. |
103 | | pub struct Random<T: RandomlyConstructable>(T); |
104 | | |
105 | | impl<T: RandomlyConstructable> Random<T> { |
106 | | /// Expose the random value. |
107 | | #[inline] |
108 | 0 | pub fn expose(self) -> T { |
109 | 0 | self.0 |
110 | 0 | } |
111 | | } |
112 | | |
113 | | /// Generate the new random value using `rng`. |
114 | | /// |
115 | | /// # Errors |
116 | | /// `error::Unspecified` if unable to fill buffer. |
117 | | #[inline] |
118 | 0 | pub fn generate<T: RandomlyConstructable>( |
119 | 0 | rng: &dyn SecureRandom, |
120 | 0 | ) -> Result<Random<T>, Unspecified> { |
121 | 0 | let mut r = T::zero(); |
122 | 0 | rng.fill(r.as_mut_bytes())?; |
123 | 0 | Ok(Random(r)) |
124 | 0 | } |
125 | | |
126 | | pub(crate) mod sealed { |
127 | | use crate::error; |
128 | | |
129 | | /// A sealed trait for secure random number generation. |
130 | | pub trait SecureRandom: core::fmt::Debug { |
131 | | /// Fills `dest` with random bytes. |
132 | | /// |
133 | | /// # Errors |
134 | | /// Returns `error::Unspecified` if unable to fill `dest`. |
135 | | fn fill_impl(&self, dest: &mut [u8]) -> Result<(), error::Unspecified>; |
136 | | } |
137 | | |
138 | | /// A sealed trait for types that can be randomly constructed. |
139 | | pub trait RandomlyConstructable: Sized { |
140 | | /// Returns a zeroed instance of the type. |
141 | | fn zero() -> Self; |
142 | | /// Returns a mutable byte slice of the value. |
143 | | fn as_mut_bytes(&mut self) -> &mut [u8]; |
144 | | } |
145 | | |
146 | | impl<const T: usize> RandomlyConstructable for [u8; T] { |
147 | | #[inline] |
148 | 0 | fn zero() -> Self { |
149 | 0 | [0; T] |
150 | 0 | } |
151 | | |
152 | | #[inline] |
153 | 0 | fn as_mut_bytes(&mut self) -> &mut [u8] { |
154 | 0 | &mut self[..] |
155 | 0 | } |
156 | | } |
157 | | } |
158 | | |
159 | | /// A type that can be returned by `aws_lc_rs::rand::generate()`. |
160 | | pub trait RandomlyConstructable: sealed::RandomlyConstructable {} |
161 | | |
162 | | impl<T> RandomlyConstructable for T where T: sealed::RandomlyConstructable {} |
163 | | |
164 | | /// A secure random number generator where the random values come from the |
165 | | /// underlying *AWS-LC* libcrypto. |
166 | | /// |
167 | | /// A single `SystemRandom` may be shared across multiple threads safely. |
168 | | // |
169 | | // # FIPS |
170 | | // Use this implementation for retrieving random bytes. |
171 | | #[derive(Clone, Debug)] |
172 | | pub struct SystemRandom(()); |
173 | | |
174 | | const SYSTEM_RANDOM: SystemRandom = SystemRandom(()); |
175 | | |
176 | | impl SystemRandom { |
177 | | /// Constructs a new `SystemRandom`. |
178 | | #[inline] |
179 | | #[must_use] |
180 | 0 | pub fn new() -> Self { |
181 | 0 | Self::default() |
182 | 0 | } Unexecuted instantiation: <aws_lc_rs::rand::SystemRandom>::new Unexecuted instantiation: <aws_lc_rs::rand::SystemRandom>::new |
183 | | } |
184 | | |
185 | | impl Default for SystemRandom { |
186 | 0 | fn default() -> Self { |
187 | 0 | SYSTEM_RANDOM |
188 | 0 | } |
189 | | } |
190 | | |
191 | | impl sealed::SecureRandom for SystemRandom { |
192 | | #[inline] |
193 | 0 | fn fill_impl(&self, dest: &mut [u8]) -> Result<(), Unspecified> { |
194 | 0 | fill(dest) |
195 | 0 | } Unexecuted instantiation: <aws_lc_rs::rand::SystemRandom as aws_lc_rs::rand::sealed::SecureRandom>::fill_impl Unexecuted instantiation: <aws_lc_rs::rand::SystemRandom as aws_lc_rs::rand::sealed::SecureRandom>::fill_impl |
196 | | } |
197 | | |
198 | | /// Fills `dest` with random bytes. |
199 | | /// |
200 | | // # FIPS |
201 | | // Use this for retrieving random bytes or [`SystemRandom`]. |
202 | | // |
203 | | /// # Errors |
204 | | /// `error::Unspecified` if unable to fill `dest`. |
205 | 0 | pub fn fill(dest: &mut [u8]) -> Result<(), Unspecified> { |
206 | 0 | if 1 != indicator_check!(unsafe { RAND_bytes(dest.as_mut_ptr(), dest.len()) }) { |
207 | 0 | return Err(Unspecified); |
208 | 0 | } |
209 | 0 | Ok(()) |
210 | 0 | } |
211 | | |
212 | | #[cfg(test)] |
213 | | mod tests { |
214 | | use crate::rand; |
215 | | use core::array::IntoIter; |
216 | | |
217 | | use crate::rand::{generate, SecureRandom, SystemRandom}; |
218 | | |
219 | | #[test] |
220 | | fn test_secure_random_fill() { |
221 | | // Collect enough random values so that the assertions below should never fail again |
222 | | let mut random_array = [0u8; 1009]; |
223 | | let rng = SystemRandom::new(); |
224 | | rng.fill(&mut random_array).unwrap(); |
225 | | |
226 | | let (mean, variance) = mean_variance(&mut random_array.into_iter()); |
227 | | assert!((106f64..150f64).contains(&mean), "Mean: {mean}"); |
228 | | assert!(variance > 8f64); |
229 | | println!("Mean: {mean} Variance: {variance}"); |
230 | | } |
231 | | |
232 | | #[test] |
233 | | fn test_rand_fill() { |
234 | | // Collect enough random values so that the assertions below should never fail again |
235 | | let mut random_array = [0u8; 1009]; |
236 | | rand::fill(&mut random_array).unwrap(); |
237 | | |
238 | | let (mean, variance) = mean_variance(&mut random_array.into_iter()); |
239 | | assert!((106f64..150f64).contains(&mean), "Mean: {mean}"); |
240 | | assert!(variance > 8f64); |
241 | | println!("Mean: {mean} Variance: {variance}"); |
242 | | } |
243 | | |
244 | | #[test] |
245 | | fn test_randomly_constructable() { |
246 | | let rando = SystemRandom::new(); |
247 | | let random_array = generate(&rando).unwrap(); |
248 | | // Collect enough random values so that the assertions below should never fail again |
249 | | let random_array: [u8; 1009] = random_array.expose(); |
250 | | let (mean, variance) = mean_variance(&mut random_array.into_iter()); |
251 | | assert!((106f64..150f64).contains(&mean), "Mean: {mean}"); |
252 | | assert!(variance > 8f64); |
253 | | println!("Mean: {mean} Variance: {variance}"); |
254 | | } |
255 | | |
256 | | fn mean_variance<T: Into<f64>, const N: usize>(iterable: &mut IntoIter<T, N>) -> (f64, f64) { |
257 | | let iter = iterable; |
258 | | let mean: Option<T> = iter.next(); |
259 | | let mut mean = mean.unwrap().into(); |
260 | | let mut var_squared = 0f64; |
261 | | let mut count = 1f64; |
262 | | for value in iter.by_ref() { |
263 | | count += 1f64; |
264 | | let value = value.into(); |
265 | | let prev_mean = mean; |
266 | | mean = prev_mean + (value - prev_mean) / count; |
267 | | var_squared = |
268 | | var_squared + ((value - prev_mean) * (value - mean) - var_squared) / count; |
269 | | } |
270 | | |
271 | | (mean, var_squared.sqrt()) |
272 | | } |
273 | | } |