|
@@ -0,0 +1,104 @@
|
|
|
|
|
+/* This file is part of DarkFi (https://dark.fi)
|
|
|
|
|
+ *
|
|
|
|
|
+ * Copyright (C) 2020-2023 Dyne.org foundation
|
|
|
|
|
+ *
|
|
|
|
|
+ * This program is free software: you can redistribute it and/or modify
|
|
|
|
|
+ * it under the terms of the GNU Affero General Public License as
|
|
|
|
|
+ * published by the Free Software Foundation, either version 3 of the
|
|
|
|
|
+ * License, or (at your option) any later version.
|
|
|
|
|
+ *
|
|
|
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
|
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
+ * GNU Affero General Public License for more details.
|
|
|
|
|
+ *
|
|
|
|
|
+ * You should have received a copy of the GNU Affero General Public License
|
|
|
|
|
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+use rand::{CryptoRng, Error, RngCore};
|
|
|
|
|
+
|
|
|
|
|
+pub struct Pcg32 {
|
|
|
|
|
+ state: u64,
|
|
|
|
|
+ increment: u64,
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+impl Pcg32 {
|
|
|
|
|
+ const MULTIPLIER: u64 = 6364136223846793005;
|
|
|
|
|
+ const INCREMENT: u64 = 1442695040888963407;
|
|
|
|
|
+
|
|
|
|
|
+ pub fn new(seed: u64) -> Self {
|
|
|
|
|
+ let mut rng = Self { state: 0, increment: Self::INCREMENT | 1 };
|
|
|
|
|
+ rng.state = rng.state.wrapping_add(seed);
|
|
|
|
|
+ rng.state = rng.state.wrapping_mul(Self::MULTIPLIER).wrapping_add(rng.increment);
|
|
|
|
|
+ rng
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fn next_u32(&mut self) -> u32 {
|
|
|
|
|
+ let old_state = self.state;
|
|
|
|
|
+ self.state = old_state.wrapping_mul(Self::MULTIPLIER).wrapping_add(self.increment);
|
|
|
|
|
+ let xorshifted = ((old_state >> 18) ^ old_state) >> 27;
|
|
|
|
|
+ let rot = old_state >> 59;
|
|
|
|
|
+ (xorshifted >> rot | xorshifted << ((!rot).wrapping_add(1) & 31)) as u32
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+impl CryptoRng for Pcg32 {}
|
|
|
|
|
+
|
|
|
|
|
+impl RngCore for Pcg32 {
|
|
|
|
|
+ fn next_u32(&mut self) -> u32 {
|
|
|
|
|
+ self.next_u32()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fn next_u64(&mut self) -> u64 {
|
|
|
|
|
+ (self.next_u32() as u64) << 32 | (self.next_u32() as u64)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
|
|
|
|
|
+ let mut i = 0;
|
|
|
|
|
+ while i + 4 <= dest.len() {
|
|
|
|
|
+ let bytes = self.next_u32().to_le_bytes();
|
|
|
|
|
+ dest[i..i + 4].copy_from_slice(&bytes);
|
|
|
|
|
+ i += 4;
|
|
|
|
|
+ }
|
|
|
|
|
+ if i < dest.len() {
|
|
|
|
|
+ let bytes = self.next_u32().to_le_bytes();
|
|
|
|
|
+ for (j, dest_byte) in dest[i..].iter_mut().enumerate() {
|
|
|
|
|
+ *dest_byte = bytes[j];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
|
|
|
|
+ Ok(self.fill_bytes(dest))
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#[cfg(test)]
|
|
|
|
|
+mod tests {
|
|
|
|
|
+ use super::*;
|
|
|
|
|
+
|
|
|
|
|
+ #[test]
|
|
|
|
|
+ fn test_pcg() {
|
|
|
|
|
+ const ITERS: usize = 10000;
|
|
|
|
|
+
|
|
|
|
|
+ let mut rng0 = Pcg32::new(42);
|
|
|
|
|
+ let mut rng1 = Pcg32::new(42);
|
|
|
|
|
+
|
|
|
|
|
+ for i in 0..ITERS {
|
|
|
|
|
+ let a = rng0.next_u32();
|
|
|
|
|
+ let b = rng1.next_u32();
|
|
|
|
|
+ assert!(a == b);
|
|
|
|
|
+
|
|
|
|
|
+ let a = rng0.next_u64();
|
|
|
|
|
+ let b = rng1.next_u64();
|
|
|
|
|
+ assert!(a == b);
|
|
|
|
|
+
|
|
|
|
|
+ let mut buf0 = vec![0u8; i];
|
|
|
|
|
+ let mut buf1 = vec![0u8; i];
|
|
|
|
|
+ rng0.fill_bytes(&mut buf0);
|
|
|
|
|
+ rng1.fill_bytes(&mut buf1);
|
|
|
|
|
+ assert!(buf0 == buf1);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|