Skip to main content

lib_q_random/
deterministic_rng.rs

1//! Lightweight deterministic RNG for STARK/ZKP testing.
2//!
3//! NOT cryptographically secure. Use only for deterministic test vectors,
4//! hiding commitment salt, and other non-security-critical randomness.
5
6use core::convert::Infallible;
7
8use rand_core::{
9    SeedableRng,
10    TryRng,
11};
12
13/// Deterministic xorshift64 RNG.
14///
15/// Satisfies `rand_core::RngCore + SeedableRng + Clone` with no alloc.
16/// Used in STARK/ZKP as the `R` type parameter for `MerkleTreeHidingMmcs`
17/// and `HidingFriPcs`.
18#[derive(Clone, Copy, Debug)]
19pub struct DeterministicRng {
20    state: u64,
21}
22
23impl DeterministicRng {
24    /// Create from a `u64` seed (mirrors `SmallRng::seed_from_u64`).
25    #[must_use]
26    pub fn seed_from_u64(seed: u64) -> Self {
27        // splitmix64 initializer so seed=0 still gives a non-zero state
28        let mut s = seed.wrapping_add(0x9E37_79B9_7F4A_7C15);
29        s = (s ^ (s >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
30        s = (s ^ (s >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
31        s ^= s >> 31;
32        Self {
33            state: if s == 0 { 1 } else { s },
34        }
35    }
36
37    #[inline]
38    fn next_u64_inner(&mut self) -> u64 {
39        // xorshift64
40        let mut x = self.state;
41        x ^= x << 13;
42        x ^= x >> 7;
43        x ^= x << 17;
44        self.state = x;
45        x
46    }
47}
48
49impl TryRng for DeterministicRng {
50    type Error = Infallible;
51
52    fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
53        Ok((self.next_u64_inner() & 0xFFFF_FFFF) as u32)
54    }
55
56    fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
57        Ok(self.next_u64_inner())
58    }
59
60    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
61        let mut i = 0;
62        while i < dest.len() {
63            let u = self.next_u64_inner().to_le_bytes();
64            let n = (dest.len() - i).min(8);
65            dest[i..i + n].copy_from_slice(&u[..n]);
66            i += n;
67        }
68        Ok(())
69    }
70}
71
72impl SeedableRng for DeterministicRng {
73    type Seed = [u8; 8];
74
75    fn from_seed(seed: Self::Seed) -> Self {
76        Self::seed_from_u64(u64::from_le_bytes(seed))
77    }
78}