|
14 | 14 |
|
15 | 15 | #![deny(missing_docs)]
|
16 | 16 | #![deny(missing_debug_implementations)]
|
17 |
| -#![doc(test(attr(allow(unused_variables), deny(warnings))))] |
18 | 17 |
|
19 |
| -#![cfg_attr(not(all(feature="serde1", test)), no_std)] |
| 18 | +#![no_std] |
20 | 19 |
|
21 | 20 | extern crate rand_core;
|
22 | 21 |
|
23 | 22 | #[cfg(feature="serde1")] extern crate serde;
|
24 | 23 | #[cfg(feature="serde1")] #[macro_use] extern crate serde_derive;
|
25 | 24 |
|
26 |
| -// To test serialization we need bincode and the standard library |
27 |
| -#[cfg(all(feature="serde1", test))] extern crate bincode; |
28 |
| -#[cfg(all(feature="serde1", test))] extern crate std as core; |
| 25 | +use core::num::Wrapping as w; |
| 26 | +use core::{fmt, slice}; |
| 27 | +use rand_core::{RngCore, SeedableRng, Error, impls, le}; |
29 | 28 |
|
30 |
| -mod xorshift; |
| 29 | +/// An Xorshift random number generator. |
| 30 | +/// |
| 31 | +/// The Xorshift[^1] algorithm is not suitable for cryptographic purposes |
| 32 | +/// but is very fast. If you do not know for sure that it fits your |
| 33 | +/// requirements, use a more secure one such as `StdRng` or `OsRng`. |
| 34 | +/// |
| 35 | +/// [^1]: Marsaglia, George (July 2003). |
| 36 | +/// ["Xorshift RNGs"](https://www.jstatsoft.org/v08/i14/paper). |
| 37 | +/// *Journal of Statistical Software*. Vol. 8 (Issue 14). |
| 38 | +#[derive(Clone)] |
| 39 | +#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))] |
| 40 | +pub struct XorShiftRng { |
| 41 | + x: w<u32>, |
| 42 | + y: w<u32>, |
| 43 | + z: w<u32>, |
| 44 | + w: w<u32>, |
| 45 | +} |
31 | 46 |
|
32 |
| -pub use self::xorshift::XorShiftRng; |
| 47 | +// Custom Debug implementation that does not expose the internal state |
| 48 | +impl fmt::Debug for XorShiftRng { |
| 49 | + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 50 | + write!(f, "XorShiftRng {{}}") |
| 51 | + } |
| 52 | +} |
| 53 | + |
| 54 | +impl RngCore for XorShiftRng { |
| 55 | + #[inline] |
| 56 | + fn next_u32(&mut self) -> u32 { |
| 57 | + let x = self.x; |
| 58 | + let t = x ^ (x << 11); |
| 59 | + self.x = self.y; |
| 60 | + self.y = self.z; |
| 61 | + self.z = self.w; |
| 62 | + let w_ = self.w; |
| 63 | + self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8)); |
| 64 | + self.w.0 |
| 65 | + } |
| 66 | + |
| 67 | + #[inline] |
| 68 | + fn next_u64(&mut self) -> u64 { |
| 69 | + impls::next_u64_via_u32(self) |
| 70 | + } |
| 71 | + |
| 72 | + #[inline] |
| 73 | + fn fill_bytes(&mut self, dest: &mut [u8]) { |
| 74 | + impls::fill_bytes_via_next(self, dest) |
| 75 | + } |
| 76 | + |
| 77 | + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { |
| 78 | + Ok(self.fill_bytes(dest)) |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +impl SeedableRng for XorShiftRng { |
| 83 | + type Seed = [u8; 16]; |
| 84 | + |
| 85 | + fn from_seed(seed: Self::Seed) -> Self { |
| 86 | + let mut seed_u32 = [0u32; 4]; |
| 87 | + le::read_u32_into(&seed, &mut seed_u32); |
| 88 | + |
| 89 | + // Xorshift cannot be seeded with 0 and we cannot return an Error, but |
| 90 | + // also do not wish to panic (because a random seed can legitimately be |
| 91 | + // 0); our only option is therefore to use a preset value. |
| 92 | + if seed_u32.iter().all(|&x| x == 0) { |
| 93 | + seed_u32 = [0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED]; |
| 94 | + } |
| 95 | + |
| 96 | + XorShiftRng { |
| 97 | + x: w(seed_u32[0]), |
| 98 | + y: w(seed_u32[1]), |
| 99 | + z: w(seed_u32[2]), |
| 100 | + w: w(seed_u32[3]), |
| 101 | + } |
| 102 | + } |
| 103 | + |
| 104 | + fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> { |
| 105 | + let mut seed_u32 = [0u32; 4]; |
| 106 | + loop { |
| 107 | + unsafe { |
| 108 | + let ptr = seed_u32.as_mut_ptr() as *mut u8; |
| 109 | + |
| 110 | + let slice = slice::from_raw_parts_mut(ptr, 4 * 4); |
| 111 | + rng.try_fill_bytes(slice)?; |
| 112 | + } |
| 113 | + if !seed_u32.iter().all(|&x| x == 0) { break; } |
| 114 | + } |
| 115 | + |
| 116 | + Ok(XorShiftRng { |
| 117 | + x: w(seed_u32[0]), |
| 118 | + y: w(seed_u32[1]), |
| 119 | + z: w(seed_u32[2]), |
| 120 | + w: w(seed_u32[3]), |
| 121 | + }) |
| 122 | + } |
| 123 | +} |
0 commit comments