From 2241431f106b46c119f7018cd85ff49d69479e10 Mon Sep 17 00:00:00 2001 From: thelearnerofcode Date: Sat, 5 May 2018 09:39:33 -0400 Subject: [PATCH 1/2] Implemented XoShiro128 random number generator. --- benches/generators.rs | 5 ++- src/prng/mod.rs | 2 + src/prng/xoshiro128.rs | 97 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 src/prng/xoshiro128.rs diff --git a/benches/generators.rs b/benches/generators.rs index fc93561d844..378b42af109 100644 --- a/benches/generators.rs +++ b/benches/generators.rs @@ -11,7 +11,7 @@ use test::{black_box, Bencher}; use rand::{RngCore, Rng, SeedableRng, FromEntropy}; use rand::{StdRng, SmallRng, OsRng, EntropyRng, ReseedingRng}; -use rand::prng::{XorShiftRng, Hc128Rng, IsaacRng, Isaac64Rng, ChaChaRng}; +use rand::prng::{XorShiftRng, Hc128Rng, IsaacRng, Isaac64Rng, XoShiro128, ChaChaRng}; use rand::prng::hc128::Hc128Core; use rand::jitter::JitterRng; use rand::thread_rng; @@ -41,6 +41,7 @@ gen_bytes!(gen_bytes_isaac64, Isaac64Rng::from_entropy()); gen_bytes!(gen_bytes_std, StdRng::from_entropy()); gen_bytes!(gen_bytes_small, SmallRng::from_entropy()); gen_bytes!(gen_bytes_os, OsRng::new().unwrap()); +gen_bytes!(gen_bytes_xoshiro128, XoShiro128::from_entropy()); macro_rules! gen_uint { ($fnn:ident, $ty:ty, $gen:expr) => { @@ -67,6 +68,7 @@ gen_uint!(gen_u32_isaac64, u32, Isaac64Rng::from_entropy()); gen_uint!(gen_u32_std, u32, StdRng::from_entropy()); gen_uint!(gen_u32_small, u32, SmallRng::from_entropy()); gen_uint!(gen_u32_os, u32, OsRng::new().unwrap()); +gen_bytes!(gen_u32_xoshiro128, XoShiro128::from_entropy()); gen_uint!(gen_u64_xorshift, u64, XorShiftRng::from_entropy()); gen_uint!(gen_u64_chacha20, u64, ChaChaRng::from_entropy()); @@ -76,6 +78,7 @@ gen_uint!(gen_u64_isaac64, u64, Isaac64Rng::from_entropy()); gen_uint!(gen_u64_std, u64, StdRng::from_entropy()); gen_uint!(gen_u64_small, u64, SmallRng::from_entropy()); gen_uint!(gen_u64_os, u64, OsRng::new().unwrap()); +gen_bytes!(gen_u64_xoshiro128, XoShiro128::from_entropy()); // Do not test JitterRng like the others by running it RAND_BENCH_N times per, // measurement, because it is way too slow. Only run it once. diff --git a/src/prng/mod.rs b/src/prng/mod.rs index c4bd0032052..03b260621e2 100644 --- a/src/prng/mod.rs +++ b/src/prng/mod.rs @@ -44,6 +44,7 @@ pub mod chacha; pub mod hc128; pub mod isaac; pub mod isaac64; +mod xoshiro128; mod xorshift; mod isaac_array; @@ -53,3 +54,4 @@ pub use self::hc128::Hc128Rng; pub use self::isaac::IsaacRng; pub use self::isaac64::Isaac64Rng; pub use self::xorshift::XorShiftRng; +pub use self::xoshiro128::XoShiro128; \ No newline at end of file diff --git a/src/prng/xoshiro128.rs b/src/prng/xoshiro128.rs new file mode 100644 index 00000000000..bf863397bac --- /dev/null +++ b/src/prng/xoshiro128.rs @@ -0,0 +1,97 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! XoShiro128 generator + +use core::{fmt, slice}; +use rand_core::{RngCore, SeedableRng, Error, impls, le}; + +#[inline(always)] +fn rotl(x: u64, k: usize) -> u64 { + (x << k)| (x >> (64 - k)) +} + +/// An XoroShiro256 random number generator. +pub struct XoShiro128 { + s: [u64; 2] +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for XoShiro128 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "XoShiro128 {{}}") + } +} + +impl RngCore for XoShiro128 { + #[inline] + fn next_u32(&mut self) -> u32 { + self.next_u64() as u32 + } + + #[inline] + fn next_u64(&mut self) -> u64 { + let s0 = self.s[0]; + let mut s1 = self.s[1]; + let result = rotl(s0 * 5, 7) * 9; + + s1 ^= s0; + self.s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); + self.s[1] = rotl(s1, 37); + + result + } + + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + impls::fill_bytes_via_next(self, dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} + +impl SeedableRng for XoShiro128 { + type Seed = [u8; 16]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u64 = [0u64; 2]; + le::read_u64_into(&seed, &mut seed_u64); + + // XoShiro128 cannot be seeded with 0 and we cannot return an Error, but + // also do not wish to panic (because a random seed can legitimately be + // 0); our only option is therefore to use a preset value. + if seed_u64.iter().all(|&x| x == 0) { + seed_u64 = [0xBAD_5EED, 0xBAD_5EED]; + } + + XoShiro128 { + s: seed_u64 + } + } + + fn from_rng(mut rng: R) -> Result { + let mut seed_u64 = [0u64; 2]; + loop { + unsafe { + let ptr = seed_u64.as_mut_ptr() as *mut u8; + + let slice = slice::from_raw_parts_mut(ptr, 4 * 4); + rng.try_fill_bytes(slice)?; + } + if !seed_u64.iter().all(|&x| x == 0) { break; } + } + + Ok(XoShiro128 { + s: seed_u64 + }) + } +} \ No newline at end of file From 58f2382274259dd673f868eb534545dd7270c26c Mon Sep 17 00:00:00 2001 From: thelearnerofcode Date: Sat, 5 May 2018 09:50:33 -0400 Subject: [PATCH 2/2] Changed to wrapping numbers. --- src/prng/xoshiro128.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/prng/xoshiro128.rs b/src/prng/xoshiro128.rs index bf863397bac..74c2753f5de 100644 --- a/src/prng/xoshiro128.rs +++ b/src/prng/xoshiro128.rs @@ -10,17 +10,18 @@ //! XoShiro128 generator +use core::num::Wrapping as w; use core::{fmt, slice}; use rand_core::{RngCore, SeedableRng, Error, impls, le}; #[inline(always)] -fn rotl(x: u64, k: usize) -> u64 { +fn rotl(x: w, k: usize) -> w { (x << k)| (x >> (64 - k)) } /// An XoroShiro256 random number generator. pub struct XoShiro128 { - s: [u64; 2] + s: [w; 2] } // Custom Debug implementation that does not expose the internal state @@ -40,13 +41,13 @@ impl RngCore for XoShiro128 { fn next_u64(&mut self) -> u64 { let s0 = self.s[0]; let mut s1 = self.s[1]; - let result = rotl(s0 * 5, 7) * 9; + let result = rotl(s0 * w(5), 7) * w(9); s1 ^= s0; self.s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); self.s[1] = rotl(s1, 37); - result + result.0 } #[inline] @@ -74,7 +75,7 @@ impl SeedableRng for XoShiro128 { } XoShiro128 { - s: seed_u64 + s: [w(seed_u64[0]), w(seed_u64[0])] } } @@ -91,7 +92,7 @@ impl SeedableRng for XoShiro128 { } Ok(XoShiro128 { - s: seed_u64 + s: [w(seed_u64[0]), w(seed_u64[0])] }) } } \ No newline at end of file