anya_core/security/crypto/
random.rs

1use rand::distributions::Standard;
2use rand::rngs::OsRng;
3use rand::{distributions::Distribution, seq::SliceRandom, Rng, RngCore};
4use std::fmt;
5
6/// Error type for random number generation
7#[derive(Debug)]
8pub enum RandomError {
9    Generation(String),
10    Range(String),
11}
12
13impl fmt::Display for RandomError {
14    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15        match self {
16            RandomError::Generation(msg) => write!(f, "Random generation error: {msg}"),
17            RandomError::Range(msg) => write!(f, "Random range error: {msg}"),
18        }
19    }
20}
21
22impl std::error::Error for RandomError {}
23
24#[allow(dead_code)]
25type Result<T> = std::result::Result<T, RandomError>;
26
27/// Generate random bytes
28pub fn random_bytes(size: usize) -> Vec<u8> {
29    let mut rng = OsRng;
30    let mut bytes = vec![0u8; size];
31    rng.fill_bytes(&mut bytes);
32    bytes
33}
34
35/// Generate a random u64
36pub fn random_u64() -> u64 {
37    let mut rng = OsRng;
38    rng.gen()
39}
40
41/// Generate a random u32
42pub fn random_u32() -> u32 {
43    let mut rng = OsRng;
44    rng.gen()
45}
46
47/// Generate a random usize
48pub fn random_usize() -> usize {
49    let mut rng = OsRng;
50    rng.gen()
51}
52
53/// Generate a random f64
54pub fn random_f64() -> f64 {
55    let mut rng = OsRng;
56    rng.gen()
57}
58
59/// Generate a random number in the given range
60pub fn random_in_range<T>(min: T, max: T) -> T
61where
62    T: PartialOrd + Copy,
63    Standard: Distribution<T>,
64{
65    let mut rng = OsRng;
66    loop {
67        let val: T = rng.gen();
68        if val >= min && val <= max {
69            return val;
70        }
71    }
72}
73
74/// Generate a random boolean
75pub fn random_bool() -> bool {
76    let mut rng = OsRng;
77    rng.gen()
78}
79
80/// Shuffle a slice in place
81pub fn shuffle<T>(slice: &mut [T]) {
82    let mut rng = OsRng;
83    slice.shuffle(&mut rng);
84}
85
86/// Reseed the random number generator (no-op for OsRng)
87pub fn reseed() {
88    // OsRng doesn't need reseeding as it uses the OS entropy source
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn test_random_bytes() {
97        let bytes1 = random_bytes(32);
98        let bytes2 = random_bytes(32);
99        assert_eq!(bytes1.len(), 32);
100        assert_eq!(bytes2.len(), 32);
101        assert_ne!(bytes1, bytes2); // Should be different
102    }
103
104    #[test]
105    fn test_random_numbers() {
106        let num1 = random_u64();
107        let num2 = random_u64();
108        assert_ne!(num1, num2); // Very unlikely to be equal
109
110        let num3 = random_u32();
111        let num4 = random_u32();
112        assert_ne!(num3, num4);
113    }
114
115    #[test]
116    fn test_random_bool() {
117        // Just test it doesn't panic
118        let _b = random_bool();
119    }
120
121    #[test]
122    fn test_shuffle() {
123        let mut data = vec![1, 2, 3, 4, 5];
124        let original = data.clone();
125        shuffle(&mut data);
126        assert_eq!(data.len(), 5);
127        // Contains same elements (may be in same order by chance)
128        data.sort();
129        assert_eq!(data, original);
130    }
131}