Skip to main content

aws_lc_rs/
rand.rs

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//! ```
28use crate::aws_lc::RAND_bytes;
29use crate::error::Unspecified;
30use crate::fips::indicator_check;
31use 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)]
60pub mod unsealed {
61    pub use super::sealed::*;
62}
63
64/// A secure random number generator.
65pub 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
83impl<T> SecureRandom for T
84where
85    T: sealed::SecureRandom,
86{
87    #[inline]
88    fn fill(&self, dest: &mut [u8]) -> Result<(), Unspecified> {
89        self.fill_impl(dest)
90    }
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`.
103pub struct Random<T: RandomlyConstructable>(T);
104
105impl<T: RandomlyConstructable> Random<T> {
106    /// Expose the random value.
107    #[inline]
108    pub fn expose(self) -> T {
109        self.0
110    }
111}
112
113/// Generate the new random value using `rng`.
114///
115/// # Errors
116/// `error::Unspecified` if unable to fill buffer.
117#[inline]
118pub fn generate<T: RandomlyConstructable>(
119    rng: &dyn SecureRandom,
120) -> Result<Random<T>, Unspecified> {
121    let mut r = T::zero();
122    rng.fill(r.as_mut_bytes())?;
123    Ok(Random(r))
124}
125
126pub(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        fn zero() -> Self {
149            [0; T]
150        }
151
152        #[inline]
153        fn as_mut_bytes(&mut self) -> &mut [u8] {
154            &mut self[..]
155        }
156    }
157}
158
159/// A type that can be returned by `aws_lc_rs::rand::generate()`.
160pub trait RandomlyConstructable: sealed::RandomlyConstructable {}
161
162impl<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)]
172pub struct SystemRandom(());
173
174const SYSTEM_RANDOM: SystemRandom = SystemRandom(());
175
176impl SystemRandom {
177    /// Constructs a new `SystemRandom`.
178    #[inline]
179    #[must_use]
180    pub fn new() -> Self {
181        Self::default()
182    }
183}
184
185impl Default for SystemRandom {
186    fn default() -> Self {
187        SYSTEM_RANDOM
188    }
189}
190
191impl sealed::SecureRandom for SystemRandom {
192    #[inline]
193    fn fill_impl(&self, dest: &mut [u8]) -> Result<(), Unspecified> {
194        fill(dest)
195    }
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`.
205pub fn fill(dest: &mut [u8]) -> Result<(), Unspecified> {
206    if 1 != indicator_check!(unsafe { RAND_bytes(dest.as_mut_ptr(), dest.len()) }) {
207        return Err(Unspecified);
208    }
209    Ok(())
210}
211
212#[cfg(test)]
213mod 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}