blueprint_std/
rand_helper.rs

1use rand::RngCore;
2
3#[cfg(not(feature = "std"))]
4use rand::prelude::StdRng;
5
6pub use rand::{
7    self, CryptoRng, Rng,
8    distributions::{Distribution, Standard},
9};
10
11/// Trait for generating uniform random values
12pub trait UniformRand: Sized {
13    fn rand<R: Rng + ?Sized>(rng: &mut R) -> Self;
14}
15
16impl<T> UniformRand for T
17where
18    Standard: Distribution<T>,
19{
20    #[inline]
21    fn rand<R: Rng + ?Sized>(rng: &mut R) -> Self {
22        rng.sample(Standard)
23    }
24}
25
26/// A random number generator that works in both std and `no_std` environments
27pub struct BlueprintRng(RngImpl);
28
29#[cfg(feature = "std")]
30type RngImpl = rand::rngs::OsRng;
31
32#[cfg(not(feature = "std"))]
33type RngImpl = StdRng;
34
35impl BlueprintRng {
36    /// Create a new cryptographically secure random number generator
37    #[must_use]
38    pub fn new() -> Self {
39        #[cfg(feature = "std")]
40        {
41            Self(rand::rngs::OsRng)
42        }
43        #[cfg(not(feature = "std"))]
44        {
45            test_rng()
46        }
47    }
48
49    /// Create a deterministic RNG from a seed (for testing only)
50    #[must_use]
51    pub fn from_seed(seed: [u8; 32]) -> Self {
52        #[cfg(feature = "std")]
53        {
54            // TODO: ??
55            let _ = seed;
56            // Always use OsRng in std for security
57            Self(rand::rngs::OsRng)
58        }
59        #[cfg(not(feature = "std"))]
60        {
61            use rand::SeedableRng;
62            Self(StdRng::from_seed(seed))
63        }
64    }
65}
66
67impl Default for BlueprintRng {
68    fn default() -> Self {
69        Self::new()
70    }
71}
72
73impl CryptoRng for BlueprintRng {}
74
75#[cfg(feature = "std")]
76impl RngCore for BlueprintRng {
77    fn next_u32(&mut self) -> u32 {
78        self.0.next_u32()
79    }
80    fn next_u64(&mut self) -> u64 {
81        self.0.next_u64()
82    }
83    fn fill_bytes(&mut self, dest: &mut [u8]) {
84        self.0.fill_bytes(dest);
85    }
86    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
87        self.0.try_fill_bytes(dest)
88    }
89}
90
91#[cfg(not(feature = "std"))]
92impl RngCore for BlueprintRng {
93    fn next_u32(&mut self) -> u32 {
94        self.0.r#gen()
95    }
96    fn next_u64(&mut self) -> u64 {
97        self.0.r#gen()
98    }
99    fn fill_bytes(&mut self, dest: &mut [u8]) {
100        self.0.fill_bytes(dest);
101    }
102    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
103        self.0.fill_bytes(dest);
104        Ok(())
105    }
106}
107
108/// Create a deterministic RNG for testing
109#[must_use]
110pub fn test_rng() -> BlueprintRng {
111    const TEST_SEED: [u8; 32] = [
112        1, 0, 0, 0, 23, 0, 0, 0, 200, 1, 0, 0, 210, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
113        0, 0, 0, 0,
114    ];
115    BlueprintRng::from_seed(TEST_SEED)
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121
122    #[test]
123    fn test_rng_generates_different_values() {
124        let mut rng = BlueprintRng::new();
125        assert_ne!(rng.next_u64(), rng.next_u64());
126    }
127
128    #[test]
129    fn test_deterministic_rng() {
130        #[cfg(not(feature = "std"))]
131        {
132            let mut rng1 = BlueprintRng::from_seed([1u8; 32]);
133            let mut rng2 = BlueprintRng::from_seed([1u8; 32]);
134            assert_eq!(rng1.next_u64(), rng2.next_u64());
135        }
136    }
137}