Skip to main content

ic_rand/
lib.rs

1
2
3pub mod true_rng{
4    use candid::Principal;
5    use ic_cdk::call;
6
7    pub async fn async_generate() -> Result<usize, String> {
8        let (random_bytes,): (Vec<u8>,) = call(Principal::management_canister(), "raw_rand", ()).await.map_err(|err| format!("{:?}", err))?;
9        
10        // Determine the size of `usize` and pad the bytes accordingly
11        const USIZE_SIZE: usize = std::mem::size_of::<usize>();
12        let mut padded_bytes = [0u8; std::mem::size_of::<usize>()];
13        
14        let len = random_bytes.len().min(USIZE_SIZE);
15        padded_bytes[USIZE_SIZE - len..USIZE_SIZE].copy_from_slice(&random_bytes[0..len]);
16        
17        let random_number = usize::from_be_bytes(padded_bytes);
18    
19        Ok(random_number)
20    }
21
22    pub fn generate() -> Result<usize, String> {
23
24        let future = async_generate(); // this creates a future
25        let result = futures::executor::block_on(future); // blocks on the future
26
27        result
28    }
29}
30
31pub mod rng{
32    use std::hash::{DefaultHasher, Hash, Hasher};
33    use std::ops::{Add, Mul, Rem};
34    use std::num::Wrapping;
35    use num_traits::{PrimInt, FromPrimitive, Unsigned, Bounded};
36
37    pub fn random_seed() -> usize {
38        let x = 42usize;
39        let y = &x as *const usize as usize;
40        let stack_value = &x as *const usize as usize;
41        let stack_value2 = &y as *const usize as usize;
42        
43        // Combine memory address and hash
44        let mut hasher = DefaultHasher::new();
45        stack_value.hash(&mut hasher);
46        stack_value2.hash(&mut hasher);
47        ic_cdk::api::time().hash(&mut hasher);
48        let hash = hasher.finish() as usize;
49        
50        // Use smaller constants and valid shifts
51        let mut seed = y ^ (hash << 7) ^ (stack_value >> 3);
52        seed = seed.wrapping_add(0x9e3779b9); // Golden ratio constant
53        seed = seed ^ (seed >> 31); // Use shift within range
54        seed = seed.wrapping_mul(0x85ebca6b); // Smaller multiplier
55        seed = seed ^ (seed >> 31); // Use shift within range
56        seed = seed.wrapping_mul(0xc2b2ae35); // Smaller multiplier
57        seed = seed ^ (seed >> 31); // Use shift within range
58    
59        seed
60    }
61    
62    pub struct RandomNumberGenerator<T>
63    where
64        T: PrimInt + FromPrimitive + Unsigned + Bounded + Mul<Output = T>,
65    {
66        seed: Wrapping<T>,
67        a: Wrapping<T>, // Multiplier
68        c: Wrapping<T>, // Increment
69        m: Wrapping<T>, // Modulus
70    }
71    
72    impl<T> RandomNumberGenerator<T>
73    where
74        T: PrimInt + FromPrimitive + Unsigned + Bounded ,
75        Wrapping<T>: Mul<Output = Wrapping<T>> +  Add<Output = Wrapping<T>> + Rem<Output = Wrapping<T>>
76
77    {
78        /// Creates a new `RandomNumberGenerator` with user-provided `a`, `c`, and `m`.
79        pub fn new_custom(seed: T, a: T, c: T, m: T) -> Self {
80            RandomNumberGenerator {
81                seed: Wrapping(seed),
82                a: Wrapping(a),
83                c: Wrapping(c),
84                m: Wrapping(m),
85            }
86        }
87    
88        /// Creates a new `RandomNumberGenerator` with default values for `a`, `c`, and `m`.
89        pub fn new() -> Self {
90            let (a, c, m) = Self::default_values();
91            RandomNumberGenerator {
92                seed: Wrapping(T::from(random_seed()).unwrap_or_else(T::min_value)),
93                a: Wrapping(a),
94                c: Wrapping(c),
95                m: Wrapping(m),
96            }
97        }
98    
99        /// Generates the next random number in the sequence.
100        pub fn next(&mut self) -> T {
101            self.seed = (self.a * self.seed + self.c) % self.m;
102            self.seed.0
103        }
104    
105        /// Generates a random number in the range [0, max).
106        pub fn range(&mut self, max: T) -> T {
107            self.next() % max
108        }
109    
110        /// Choose default values based on the size of `T`.
111        fn default_values() -> (T, T, T) {
112            let bits = T::zero().count_zeros();
113            match bits {
114                8 => (
115                    T::from(13).unwrap(),           // Smaller constants for `u8`
116                    T::from(7).unwrap(),
117                    T::from(31).unwrap(),           // Use a small modulus for `u8`
118                ),
119                16 => (
120                    T::from(25173).unwrap(),        // Common values for `u16`
121                    T::from(13849).unwrap(),
122                    T::from(2u32.pow(16) - 1).unwrap(),        // 2^16
123                ),
124                32 => (
125                    T::from(1664525).unwrap(),      // Larger constants for `u32`
126                    T::from(1013904223).unwrap(),
127                    T::from(2u64.pow(32) - 1).unwrap(),  // 2^32
128                ),
129                _ => (
130                    T::from(1664525).unwrap(),      // Default values
131                    T::from(1013904223).unwrap(),
132                    T::from(2u64.pow(32)).unwrap(),
133                )
134            }
135        }
136    }
137}