nanorand/rand/
wyrand.rs

1// Based off lemire's wyrand C++ code at https://github.com/lemire/testingRNG/blob/master/source/wyrand.h
2
3use crate::rand::{Rng, SeedableRng};
4use core::fmt::{self, Debug, Display, Formatter};
5#[cfg(feature = "zeroize")]
6use zeroize::Zeroize;
7
8/// An instance of the WyRand random number generator.
9/// Seeded from the system entropy generator when available.
10/// **This generator is _NOT_ cryptographically secure.**
11#[cfg_attr(feature = "zeroize", derive(Zeroize))]
12#[cfg_attr(feature = "zeroize", zeroize(drop))]
13pub struct WyRand {
14	seed: u64,
15}
16
17impl WyRand {
18	/// Create a new [`WyRand`] instance, seeding from the system's default source of entropy.
19	#[must_use]
20	pub fn new() -> Self {
21		Self::default()
22	}
23
24	/// Create a new [`WyRand`] instance, using a provided seed.
25	#[must_use]
26	pub const fn new_seed(seed: u64) -> Self {
27		Self { seed }
28	}
29}
30
31impl Default for WyRand {
32	/// Create a new [`WyRand`] instance, seeding from the system's default source of entropy.
33	fn default() -> Self {
34		let mut entropy: [u8; core::mem::size_of::<u64>()] = Default::default();
35		crate::entropy::system(&mut entropy);
36		Self {
37			seed: u64::from_ne_bytes(entropy),
38		}
39	}
40}
41
42impl Rng<8> for WyRand {
43	fn rand(&mut self) -> [u8; 8] {
44		self.seed = self.seed.wrapping_add(0xa0761d6478bd642f);
45		let t: u128 = (self.seed as u128).wrapping_mul((self.seed ^ 0xe7037ed1a0b428db) as u128);
46		let ret = (t.wrapping_shr(64) ^ t) as u64;
47		ret.to_ne_bytes()
48	}
49}
50
51impl Clone for WyRand {
52	fn clone(&self) -> Self {
53		Self { seed: self.seed }
54	}
55}
56
57impl Display for WyRand {
58	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
59		write!(f, "WyRand ({:p})", self)
60	}
61}
62
63impl Debug for WyRand {
64	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
65		f.debug_struct("WyRand")
66			.field("seed", &format_args!("0x{:x}", self.seed))
67			.finish()
68	}
69}
70
71impl SeedableRng<8, 8> for WyRand {
72	fn reseed(&mut self, seed: [u8; 8]) {
73		self.seed = u64::from_ne_bytes(seed);
74	}
75}