use super::{OsRng, Rng};
pub struct Xoshiro256 {
s: [u64; 4],
}
impl Xoshiro256 {
#[must_use]
pub fn new(s0: u64, s1: u64, s2: u64, s3: u64) -> Self {
assert!(
s0 | s1 | s2 | s3 != 0,
"xoshiro256: all-zero seed forbidden"
);
Self {
s: [s0, s1, s2, s3],
}
}
#[must_use]
pub fn from_os_rng() -> Self {
let mut os = OsRng::new();
loop {
let s = [os.next_u64(), os.next_u64(), os.next_u64(), os.next_u64()];
if s[0] | s[1] | s[2] | s[3] != 0 {
return Self { s };
}
}
}
#[inline]
fn step(&mut self) -> u64 {
let result = self.s[1].wrapping_mul(5).rotate_left(7).wrapping_mul(9);
let t = self.s[1] << 17;
self.s[2] ^= self.s[0];
self.s[3] ^= self.s[1];
self.s[1] ^= self.s[2];
self.s[0] ^= self.s[3];
self.s[2] ^= t;
self.s[3] = self.s[3].rotate_left(45);
result
}
}
impl Default for Xoshiro256 {
fn default() -> Self {
Self::from_os_rng()
}
}
impl Rng for Xoshiro256 {
fn next_u32(&mut self) -> u32 {
(self.step() >> 32) as u32
}
fn next_u64(&mut self) -> u64 {
self.step()
}
}
pub struct Xoroshiro128 {
s: [u64; 2],
}
impl Xoroshiro128 {
#[must_use]
pub fn new(s0: u64, s1: u64) -> Self {
assert!(s0 | s1 != 0, "xoroshiro128: all-zero seed forbidden");
Self { s: [s0, s1] }
}
#[must_use]
pub fn from_os_rng() -> Self {
let mut os = OsRng::new();
loop {
let s = [os.next_u64(), os.next_u64()];
if s[0] | s[1] != 0 {
return Self { s };
}
}
}
#[inline]
fn step(&mut self) -> u64 {
let s0 = self.s[0];
let s1 = self.s[1];
let result = s0.wrapping_mul(5).rotate_left(7).wrapping_mul(9);
let s1x = s1 ^ s0;
self.s[0] = s0.rotate_left(24) ^ s1x ^ (s1x << 16); self.s[1] = s1x.rotate_left(37); result
}
}
impl Default for Xoroshiro128 {
fn default() -> Self {
Self::from_os_rng()
}
}
impl Rng for Xoroshiro128 {
fn next_u32(&mut self) -> u32 {
(self.step() >> 32) as u32
}
fn next_u64(&mut self) -> u64 {
self.step()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn xoshiro256_reference() {
let mut rng = Xoshiro256::new(1, 2, 3, 4);
let v0 = rng.next_u64();
let v1 = rng.next_u64();
assert_ne!(v0, 0);
assert_ne!(v0, v1);
}
#[test]
fn xoroshiro128_reference() {
let mut rng = Xoroshiro128::new(1, 2);
let v0 = rng.next_u64();
let v1 = rng.next_u64();
assert_ne!(v0, 0);
assert_ne!(v0, v1);
}
#[test]
fn xoshiro256_next_u32_high_bits() {
let mut a = Xoshiro256::new(0xdead, 0xbeef, 0xcafe, 0xbabe);
let mut b = Xoshiro256::new(0xdead, 0xbeef, 0xcafe, 0xbabe);
assert_eq!(a.next_u32(), (b.next_u64() >> 32) as u32);
}
#[test]
fn zero_seed_rejected() {
let r = std::panic::catch_unwind(|| Xoshiro256::new(0, 0, 0, 0));
assert!(r.is_err());
}
#[test]
fn xoshiro256_deterministic() {
let mut a = Xoshiro256::new(0xdead, 0xbeef, 0xcafe, 0xbabe);
let mut b = Xoshiro256::new(0xdead, 0xbeef, 0xcafe, 0xbabe);
for _ in 0..10 {
assert_eq!(a.next_u64(), b.next_u64());
}
}
#[test]
fn xoroshiro128_deterministic() {
let mut a = Xoroshiro128::new(0xdead_beef, 0xcafe_babe);
let mut b = Xoroshiro128::new(0xdead_beef, 0xcafe_babe);
for _ in 0..10 {
assert_eq!(a.next_u64(), b.next_u64());
}
}
}