gadget_std/
rand_helper.rs

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