Skip to main content

vitaminc_random/
generatable.rs

1//! A trait for types that can be generated randomly.
2//! The random number generator is passed as an argument to the `generate` method
3//! and must be a [SafeRand].
4//!
5//! ## Example
6//!
7//! ```rust
8//! # mod vitaminc { pub mod random { pub use vitaminc_random::*; } }
9//! use vitaminc::random::{Generatable, SafeRand, SeedableRng};
10//! use std::num::NonZeroU16;
11//!
12//! let mut rng = SafeRand::from_entropy().expect("Failed to seed RNG");
13//! let value: NonZeroU16 = Generatable::random(&mut rng).unwrap();
14//! ```
15//!
16use crate::{RandomError, SafeRand};
17use std::num::NonZeroU16;
18use vitaminc_protected::{Controlled, Equatable, Exportable, Protected, Usage};
19
20/// A trait for types that can be generated randomly.
21/// The random number generator is passed as an argument to the `generate` method
22/// and must implement the `SafeRand` trait.
23pub trait Generatable: Sized {
24    fn random(rng: &mut SafeRand) -> Result<Self, RandomError>;
25}
26
27impl Generatable for NonZeroU16 {
28    fn random(rng: &mut SafeRand) -> Result<Self, RandomError> {
29        let mut buf: [u8; 2] = [0, 0];
30        use rand::RngExt;
31        rng.fill(&mut buf);
32        if let Some(value) = NonZeroU16::new(u16::from_be_bytes(buf)) {
33            Ok(value)
34        } else {
35            // Because a 0 would be an invalid value we must try again (rejection sampling)
36            Self::random(rng)
37        }
38    }
39}
40
41macro_rules! impl_generatable_for_int {
42    ($($t:ty),*) => {
43        $(
44            impl Generatable for $t {
45                fn random(rng: &mut SafeRand) -> Result<Self, RandomError> {
46                    use rand::RngExt;
47                    Ok(rng.random())
48                }
49            }
50        )*
51    };
52}
53
54impl_generatable_for_int!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
55
56impl<const N: usize> Generatable for [u8; N] {
57    fn random(rng: &mut SafeRand) -> Result<Self, RandomError> {
58        // TODO: Consider using MaybeUninit or array::from_fn
59        let mut buf: [u8; N] = [0; N];
60        use rand::RngExt;
61        rng.fill(&mut buf);
62        Ok(buf)
63    }
64}
65
66impl<T, G> Generatable for Protected<T>
67where
68    G: Generatable,
69    Self: Controlled<Inner = G>,
70{
71    fn random(rng: &mut SafeRand) -> Result<Self, RandomError> {
72        Self::generate_ok(|| Generatable::random(rng))
73    }
74}
75
76impl<T, G> Generatable for Exportable<T>
77where
78    G: Generatable,
79    Self: Controlled<Inner = G>,
80{
81    fn random(rng: &mut SafeRand) -> Result<Self, RandomError> {
82        Self::generate_ok(|| Generatable::random(rng))
83    }
84}
85
86impl<T, G> Generatable for Equatable<T>
87where
88    G: Generatable,
89    Self: Controlled<Inner = G>,
90{
91    fn random(rng: &mut SafeRand) -> Result<Self, RandomError> {
92        Self::generate_ok(|| Generatable::random(rng))
93    }
94}
95
96impl<T, S, G> Generatable for Usage<T, S>
97where
98    G: Generatable,
99    Self: Controlled<Inner = G>,
100{
101    fn random(rng: &mut SafeRand) -> Result<Self, RandomError> {
102        Self::generate_ok(|| Generatable::random(rng))
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::Generatable;
109    use crate::SafeRand;
110    use zeroize::Zeroize;
111
112    fn assert_generatable<T>(rng: &mut SafeRand) -> T
113    where
114        T: super::Generatable,
115    {
116        T::random(rng).unwrap()
117    }
118
119    fn test_generate_controlled<T: Generatable + Zeroize>(rng: &mut SafeRand) {
120        use super::*;
121        let _: Protected<T> = assert_generatable(rng);
122        let _: Exportable<Protected<T>> = assert_generatable(rng);
123        let _: Equatable<Protected<T>> = assert_generatable(rng);
124        let _: Exportable<Equatable<Protected<T>>> = assert_generatable(rng);
125        let _: Usage<Protected<T>> = assert_generatable(rng);
126        let _: Usage<Equatable<Protected<T>>> = assert_generatable(rng);
127    }
128
129    #[test]
130    fn test_generate_array() -> Result<(), crate::RandomError> {
131        let mut rng = SafeRand::from_entropy()?;
132        let _: [u8; 4] = assert_generatable(&mut rng);
133        let _: [u8; 8] = assert_generatable(&mut rng);
134        let _: [u8; 16] = assert_generatable(&mut rng);
135        let _: [u8; 32] = assert_generatable(&mut rng);
136        let _: [u8; 64] = assert_generatable(&mut rng);
137        let _: [u8; 128] = assert_generatable(&mut rng);
138        let _: [u8; 256] = assert_generatable(&mut rng);
139        test_generate_controlled::<[u8; 4]>(&mut rng);
140        test_generate_controlled::<[u8; 8]>(&mut rng);
141        test_generate_controlled::<[u8; 16]>(&mut rng);
142        test_generate_controlled::<[u8; 32]>(&mut rng);
143        test_generate_controlled::<[u8; 64]>(&mut rng);
144        test_generate_controlled::<[u8; 128]>(&mut rng);
145        test_generate_controlled::<[u8; 256]>(&mut rng);
146        Ok(())
147    }
148
149    #[test]
150    fn test_numeric_primitives() -> Result<(), crate::RandomError> {
151        let mut rng = SafeRand::from_entropy()?;
152        let _: u8 = assert_generatable(&mut rng);
153        let _: u16 = assert_generatable(&mut rng);
154        let _: u32 = assert_generatable(&mut rng);
155        let _: u64 = assert_generatable(&mut rng);
156        let _: u128 = assert_generatable(&mut rng);
157        let _: i8 = assert_generatable(&mut rng);
158        let _: i16 = assert_generatable(&mut rng);
159        let _: i32 = assert_generatable(&mut rng);
160        let _: i64 = assert_generatable(&mut rng);
161        let _: i128 = assert_generatable(&mut rng);
162        test_generate_controlled::<u8>(&mut rng);
163        test_generate_controlled::<u16>(&mut rng);
164        test_generate_controlled::<u32>(&mut rng);
165        test_generate_controlled::<u64>(&mut rng);
166        test_generate_controlled::<u128>(&mut rng);
167        test_generate_controlled::<i8>(&mut rng);
168        test_generate_controlled::<i16>(&mut rng);
169        test_generate_controlled::<i32>(&mut rng);
170        test_generate_controlled::<i64>(&mut rng);
171        test_generate_controlled::<i128>(&mut rng);
172        Ok(())
173    }
174}