Update lfprng for better distribution, make it conform 'rand' package traits transitional_engine
authorunC0Rr
Wed, 04 Jan 2023 10:37:12 +0100
branchtransitional_engine
changeset 15931 9b73594ac986
parent 15930 f39f0f614dbf
child 15932 230dc46487ea
Update lfprng for better distribution, make it conform 'rand' package traits
rust/lfprng/Cargo.toml
rust/lfprng/src/lib.rs
--- a/rust/lfprng/Cargo.toml	Tue Jan 03 12:05:59 2023 +0100
+++ b/rust/lfprng/Cargo.toml	Wed Jan 04 10:37:12 2023 +0100
@@ -5,3 +5,4 @@
 edition = "2018"
 
 [dependencies]
+rand = "0.8"
--- a/rust/lfprng/src/lib.rs	Tue Jan 03 12:05:59 2023 +0100
+++ b/rust/lfprng/src/lib.rs	Wed Jan 04 10:37:12 2023 +0100
@@ -1,3 +1,5 @@
+use rand::{Error, RngCore, SeedableRng};
+
 pub struct LaggedFibonacciPRNG {
     circular_buffer: [u32; 64],
     index: usize,
@@ -5,7 +7,7 @@
 
 impl LaggedFibonacciPRNG {
     pub fn new(init_values: &[u8]) -> Self {
-        let mut buf = [0xa98765 + 68; 64];
+        let mut buf = [0xa98765; 64];
 
         for i in 0..std::cmp::min(init_values.len(), 54) {
             buf[i] = init_values[i] as u32;
@@ -30,10 +32,17 @@
 
     #[inline]
     fn get_next(&mut self) -> u32 {
+        const PRIME_NUM: u32 = 2147483629;
+
         self.index = (self.index + 1) & 0x3f;
-        self.circular_buffer[self.index] = (self.circular_buffer[(self.index + 40) & 0x3f]
-            + self.circular_buffer[(self.index + 9) & 0x3f])
-            & 0x7fffffff;
+        let next_value = self.circular_buffer[(self.index + 40) & 0x3f]
+            + self.circular_buffer[(self.index + 9) & 0x3f];
+
+        self.circular_buffer[self.index] = if next_value > PRIME_NUM {
+            next_value - PRIME_NUM
+        } else {
+            next_value
+        };
 
         self.circular_buffer[self.index]
     }
@@ -60,6 +69,32 @@
     }
 }
 
+impl RngCore for LaggedFibonacciPRNG {
+    fn next_u32(&mut self) -> u32 {
+        self.get_next().wrapping_add(self.get_next())
+    }
+
+    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]) {
+        dest.iter_mut().for_each(|x| *x = self.next_u32() as u8);
+    }
+
+    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+        Ok(self.fill_bytes(dest))
+    }
+}
+
+impl SeedableRng for LaggedFibonacciPRNG {
+    type Seed = [u8; 32];
+
+    fn from_seed(seed: Self::Seed) -> Self {
+        LaggedFibonacciPRNG::new(&seed)
+    }
+}
+
 #[cfg(test)]
 #[test]
 fn compatibility() {