darkfi/util/
pcg.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2026 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18
19use rand::{CryptoRng, Error, RngCore};
20
21pub struct Pcg32 {
22    state: u64,
23    increment: u64,
24}
25
26impl Pcg32 {
27    const MULTIPLIER: u64 = 6364136223846793005;
28    const INCREMENT: u64 = 1442695040888963407;
29
30    pub fn new(seed: u64) -> Self {
31        let mut rng = Self { state: 0, increment: Self::INCREMENT | 1 };
32        rng.state = rng.state.wrapping_add(seed);
33        rng.state = rng.state.wrapping_mul(Self::MULTIPLIER).wrapping_add(rng.increment);
34        rng
35    }
36
37    fn next_u32(&mut self) -> u32 {
38        let old_state = self.state;
39        self.state = old_state.wrapping_mul(Self::MULTIPLIER).wrapping_add(self.increment);
40        let xorshifted = ((old_state >> 18) ^ old_state) >> 27;
41        let rot = old_state >> 59;
42        ((xorshifted >> rot) | (xorshifted << ((!rot).wrapping_add(1) & 31))) as u32
43    }
44}
45
46impl CryptoRng for Pcg32 {}
47
48impl RngCore for Pcg32 {
49    fn next_u32(&mut self) -> u32 {
50        self.next_u32()
51    }
52
53    fn next_u64(&mut self) -> u64 {
54        ((self.next_u32() as u64) << 32) | (self.next_u32() as u64)
55    }
56
57    fn fill_bytes(&mut self, dest: &mut [u8]) {
58        let mut i = 0;
59        while i + 4 <= dest.len() {
60            let bytes = self.next_u32().to_le_bytes();
61            dest[i..i + 4].copy_from_slice(&bytes);
62            i += 4;
63        }
64        if i < dest.len() {
65            let bytes = self.next_u32().to_le_bytes();
66            for (j, dest_byte) in dest[i..].iter_mut().enumerate() {
67                *dest_byte = bytes[j];
68            }
69        }
70    }
71
72    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
73        self.fill_bytes(dest);
74        Ok(())
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn test_pcg() {
84        const ITERS: usize = 10000;
85
86        let mut rng0 = Pcg32::new(42);
87        let mut rng1 = Pcg32::new(42);
88
89        for i in 0..ITERS {
90            let a = rng0.next_u32();
91            let b = rng1.next_u32();
92            assert!(a == b);
93
94            let a = rng0.next_u64();
95            let b = rng1.next_u64();
96            assert!(a == b);
97
98            let mut buf0 = vec![0u8; i];
99            let mut buf1 = vec![0u8; i];
100            rng0.fill_bytes(&mut buf0);
101            rng1.fill_bytes(&mut buf1);
102            assert!(buf0 == buf1);
103        }
104    }
105}