diff --git a/benches/generators.rs b/benches/generators.rs index d02d2d43bbd..ec603d198cf 100644 --- a/benches/generators.rs +++ b/benches/generators.rs @@ -9,7 +9,7 @@ const BYTES_LEN: usize = 1024; use std::mem::size_of; use test::{black_box, Bencher}; -use rand::{Rng, NewSeeded, Sample, SeedFromRng, StdRng, OsRng, JitterRng}; +use rand::{Rng, NewSeeded, Sample, SeedableRng, StdRng, OsRng, JitterRng}; use rand::prng::*; macro_rules! gen_bytes { diff --git a/rand_core/src/lib.rs b/rand_core/src/lib.rs index d660fe1c846..c587c97e6f6 100644 --- a/rand_core/src/lib.rs +++ b/rand_core/src/lib.rs @@ -43,7 +43,7 @@ extern crate core; #[cfg(feature="std")] use std::error::Error as stdError; -use core::fmt; +use core::{fmt, slice, mem}; pub mod impls; @@ -206,25 +206,6 @@ impl Rng for Box { } -/// Support mechanism for creating random number generators seeded by other -/// generators. All PRNGs should support this to enable `NewSeeded` support, -/// which should be the preferred way of creating randomly-seeded generators. -/// -/// There are two subtle differences between `SeedFromRng::from_rng` and -/// `SeedableRng::from_seed` (beyond the obvious): first, that `from_rng` has -/// no reproducibility requirement, and second, that `from_rng` may directly -/// fill internal states larger than `SeedableRng::Seed`, where `from_seed` may -/// need some extra step to expand the input. -pub trait SeedFromRng: Sized { - /// Creates a new instance, seeded from another `Rng`. - /// - /// Seeding from a cryptographic generator should be fine. On the other - /// hand, seeding a simple numerical generator from another of the same - /// type sometimes has serious side effects such as effectively cloning the - /// generator. - fn from_rng(rng: R) -> Result; -} - mod private { pub trait Sealed {} impl Sealed for S where S: super::SeedRestriction {} @@ -232,43 +213,59 @@ mod private { /// The seed type is restricted to these types. This trait is sealed to prevent /// user-extension. -/// +/// /// Use of byte-arrays avoids endianness issues. We may extend this to allow /// byte arrays of other lengths in the future. -pub trait SeedRestriction: private::Sealed {} +pub trait SeedRestriction: private::Sealed + + ::core::default::Default + + ::core::convert::AsMut<[u8]> {} impl SeedRestriction for [u8; 8] {} impl SeedRestriction for [u8; 16] {} impl SeedRestriction for [u8; 32] {} -/// A random number generator that can be explicitly seeded to produce -/// the same stream of randomness multiple times (i.e. is reproducible). -/// -/// Note: this should only be implemented by reproducible generators (i.e. -/// where the algorithm is fixed and results should be the same across -/// platforms). This should not be implemented by wrapper types which choose -/// the underlying implementation based on platform, or which may change the -/// algorithm used in the future. This is to ensure that manual seeding of PRNGs -/// actually does yield reproducible results. +/// A random number generator that can be explicitly seeded. +/// +/// There are two subtle differences between `from_rng` and`from_seed` (beyond +/// the obvious): first, that `from_rng` has no reproducibility requirement, and +/// second, that `from_rng` may directly fill internal states larger than +/// `SeedableRng::Seed`, where `from_seed` may need some extra step to expand +/// the input. pub trait SeedableRng: Sized { /// Seed type. type Seed: SeedRestriction; - + /// Create a new PRNG using the given seed. - /// + /// /// Each PRNG should implement this. - /// + /// /// Reproducibility is required; that is, a fixed PRNG seeded using this /// function with a fixed seed should produce the same sequence of output /// today, and in the future. PRNGs not able to satisfy this should make - /// clear notes in their documentation or not implement `SeedableRng` at - /// all. It is however not required that this function yield the same state - /// as a reference implementation of the PRNG given equivalent seed; if - /// necessary another constructor should be used. - /// + /// clear notes in their documentation. It is however not required that this + /// function yield the same state as a reference implementation of the PRNG + /// given equivalent seed; if necessary another constructor should be used. + /// /// It may be expected that bits in the seed are well distributed, i.e. that /// values like 0, 1 and (size - 1) are unlikely. Users with poorly /// distributed input should use `from_hashable`. fn from_seed(seed: Self::Seed) -> Self; + + /// Create a new PRNG seeded from another `Rng`. + /// + /// Seeding from a cryptographic generator should be fine. On the other + /// hand, seeding a simple numerical generator from another of the same + /// type sometimes has serious side effects such as effectively cloning the + /// generator. + fn from_rng(mut rng: R) -> Result { + let mut seed = Self::Seed::default(); + let size = mem::size_of::() as usize; + unsafe { + let ptr = seed.as_mut().as_mut_ptr() as *mut u8; + let slice = slice::from_raw_parts_mut(ptr, size); + rng.try_fill(slice)?; + } + Ok(Self::from_seed(seed)) + } } @@ -396,69 +393,51 @@ impl stdError for Error { /// Little-Endian order has been chosen for internal usage; this makes some /// useful functions available. pub mod le { - use core::slice; - + use core::ptr; + /// Helper function to turn a slice into an array reference - + /// Read a `u32` from a byte sequence, in litte-endian order /// /// Consider usage with the `arrayref` crate. pub fn read_u32(bytes: &[u8; 4]) -> u32 { unsafe{ *(bytes as *const [u8; 4] as *const u32) }.to_le() } - + /// Read a `u64` from a byte sequence, in litte-endian order /// /// Consider usage with the `arrayref` crate. pub fn read_u64(bytes: &[u8; 8]) -> u64 { unsafe{ *(bytes as *const [u8; 8] as *const u64) }.to_le() } - - /// Convert a byte slice to a `u32` slice and mutate endianness in-place - pub fn convert_slice_32(bytes: &mut [u8]) -> &mut [u32] { - assert_eq!(bytes.len() % 4, 0); - let l = bytes.len() / 4; - let p = bytes.as_ptr() as *mut u8 as *mut u32; - let s = unsafe{ slice::from_raw_parts_mut(p, l) }; - for i in s.iter_mut() { - *i = (*i).to_le(); - } - s - } - - /// Convert a byte slice to a `u64` slice and mutate endianness in-place - pub fn convert_slice_64(bytes: &mut [u8]) -> &mut [u64] { - assert_eq!(bytes.len() % 8, 0); - let l = bytes.len() / 8; - let p = bytes.as_ptr() as *mut u8 as *mut u64; - let s = unsafe{ slice::from_raw_parts_mut(p, l) }; - for i in s.iter_mut() { - *i = (*i).to_le(); - } - s - } - - #[cfg(test)] - mod tests { - use super::*; - #[test] - - fn test_read() { - assert_eq!(read_u32(&[1, 2, 3, 4]), 0x04030201); - assert_eq!(read_u64(&[1, 2, 3, 4, 5, 6, 7, 8]), 0x0807060504030201); - - { - let mut bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; - let slice = convert_slice_32(&mut bytes[..]); - assert_eq!(slice[0], 0x04030201); - assert_eq!(slice[3], 0x100F0E0D); + + macro_rules! read_slice { + ($src:expr, $dst:expr, $size:expr, $which:ident) => {{ + assert_eq!($src.len(), $size * $dst.len()); + + unsafe { + ptr::copy_nonoverlapping( + $src.as_ptr(), + $dst.as_mut_ptr() as *mut u8, + $src.len()); } - { - let mut bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; - let slice = convert_slice_64(&mut bytes[..]); - assert_eq!(slice[0], 0x0807060504030201); - assert_eq!(slice[1], 0x100F0E0D0C0B0A09); + for v in $dst.iter_mut() { + *v = v.$which(); } - } + }}; + } + + /// Reads unsigned 32 bit integers from `src` into `dst`. + /// Borrowed from the `byteorder` crate. + #[inline] + pub fn read_u32_into(src: &[u8], dst: &mut [u32]) { + read_slice!(src, dst, 4, to_le); + } + + /// Reads unsigned 64 bit integers from `src` into `dst`. + /// Borrowed from the `byteorder` crate. + #[inline] + pub fn read_u64_into(src: &[u8], dst: &mut [u64]) { + read_slice!(src, dst, 8, to_le); } } diff --git a/src/lib.rs b/src/lib.rs index 9ce3f0a67e1..4f83e2b7413 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -257,7 +257,7 @@ extern crate rand_core; // core traits and types -pub use rand_core::{Rng, CryptoRng, SeedFromRng, SeedableRng, Error, ErrorKind}; +pub use rand_core::{Rng, CryptoRng, SeedableRng, Error, ErrorKind}; // external rngs pub use jitter::JitterRng; @@ -315,11 +315,11 @@ mod thread_local; /// Seeding mechanism for PRNGs, providing a `new` function. /// This is the recommended way to create (pseudo) random number generators, -/// unless a deterministic seed is desired (in which case the `SeedableRng` -/// trait should be used directly). +/// unless a deterministic seed is desired (in which case +/// `SeedableRng::from_seed` should be used). /// /// Note: this trait is automatically implemented for any PRNG implementing -/// `SeedFromRng` and is not intended to be implemented by users. +/// `SeedableRng` and is not intended to be implemented by users. /// /// ## Example /// @@ -330,7 +330,7 @@ mod thread_local; /// println!("Random die roll: {}", rng.gen_range(1, 7)); /// ``` #[cfg(feature="std")] -pub trait NewSeeded: SeedFromRng { +pub trait NewSeeded: SeedableRng { /// Creates a new instance, automatically seeded with fresh entropy. /// /// Normally this will use `OsRng`, but if that fails `JitterRng` will be @@ -340,14 +340,14 @@ pub trait NewSeeded: SeedFromRng { } #[cfg(feature="std")] -impl NewSeeded for R { +impl NewSeeded for R { fn new() -> Result { // Note: error handling would be easier with try/catch blocks - fn new_os() -> Result { + fn new_os() -> Result { let mut r = OsRng::new()?; T::from_rng(&mut r) } - fn new_jitter() -> Result { + fn new_jitter() -> Result { let mut r = JitterRng::new()?; T::from_rng(&mut r) } @@ -461,32 +461,34 @@ impl Sample for R { /// cannot be guaranteed to be reproducible. For this reason, `StdRng` does /// not support `SeedableRng`. #[derive(Clone, Debug)] -pub struct StdRng { - rng: IsaacWordRng, -} +pub struct StdRng(IsaacWordRng); impl Rng for StdRng { fn next_u32(&mut self) -> u32 { - self.rng.next_u32() + self.0.next_u32() } fn next_u64(&mut self) -> u64 { - self.rng.next_u64() + self.0.next_u64() } #[cfg(feature = "i128_support")] fn next_u128(&mut self) -> u128 { - self.rng.next_u128() + self.0.next_u128() } fn fill_bytes(&mut self, dest: &mut [u8]) { - self.rng.fill_bytes(dest); + self.0.fill_bytes(dest); } fn try_fill(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.rng.try_fill(dest) + self.0.try_fill(dest) } } -impl SeedFromRng for StdRng { - fn from_rng(other: R) -> Result { - IsaacWordRng::from_rng(other).map(|rng| StdRng{ rng }) +impl SeedableRng for StdRng { + type Seed = ::Seed; + fn from_seed(seed: Self::Seed) -> Self { + StdRng(IsaacWordRng::from_seed(seed)) + } + fn from_rng(rng: R) -> Result { + IsaacWordRng::from_rng(rng).map(|rng| StdRng(rng)) } } diff --git a/src/prng/chacha.rs b/src/prng/chacha.rs index d651d510027..b371480505a 100644 --- a/src/prng/chacha.rs +++ b/src/prng/chacha.rs @@ -11,18 +11,13 @@ //! The ChaCha random number generator. use core::fmt; -use rand_core::impls; -use {Rng, CryptoRng, SeedFromRng, SeedableRng, Error}; +use rand_core::{impls, le}; +use {Rng, CryptoRng, SeedableRng, Error}; -const KEY_WORDS : usize = 8; // 8 words for the 256-bit key -const STATE_WORDS : usize = 16; -const CHACHA_ROUNDS: u32 = 20; // Cryptographically secure from 8 upwards as of this writing - -const CHACHA_EMPTY: ChaChaRng = ChaChaRng { - buffer: [0; STATE_WORDS], - state: [0; STATE_WORDS], - index: STATE_WORDS - }; +const SEED_WORDS: usize = 8; // 8 words for the 256-bit key +const STATE_WORDS: usize = 16; +const CHACHA_ROUNDS: u32 = 20; // Cryptographically secure from 8 upwards as of + // this writing /// A random number generator that uses the ChaCha20 algorithm [1]. /// @@ -106,9 +101,7 @@ impl ChaChaRng { /// - 2917185654 /// - 2419978656 pub fn new_unseeded() -> ChaChaRng { - let mut rng = CHACHA_EMPTY; - rng.init(&[0; KEY_WORDS]); - rng + ChaChaRng::init([0; SEED_WORDS]) } /// Sets the internal 128-bit ChaCha counter to @@ -157,22 +150,15 @@ impl ChaChaRng { /// ``` /// [1]: Daniel J. Bernstein. [*Extending the Salsa20 /// nonce.*](http://cr.yp.to/papers.html#xsalsa) - fn init(&mut self, key: &[u32; KEY_WORDS]) { - self.state[0] = 0x61707865; - self.state[1] = 0x3320646E; - self.state[2] = 0x79622D32; - self.state[3] = 0x6B206574; - - for i in 0..KEY_WORDS { - self.state[4+i] = key[i]; - } - - self.state[12] = 0; - self.state[13] = 0; - self.state[14] = 0; - self.state[15] = 0; - - self.index = STATE_WORDS; + fn init(seed: [u32; SEED_WORDS]) -> Self { + ChaChaRng { + buffer: [0; STATE_WORDS], + state: [0x61707865, 0x3320646E, 0x79622D32, 0x6B206574, // constants + seed[0], seed[1], seed[2], seed[3], // seed + seed[4], seed[5], seed[6], seed[7], // seed + 0, 0, 0, 0], // counter + index: STATE_WORDS, // generate on first use + } } /// Refill the internal output buffer (`self.buffer`) @@ -238,36 +224,19 @@ impl Rng for ChaChaRng { impl CryptoRng for ChaChaRng {} -impl SeedFromRng for ChaChaRng { - fn from_rng(mut other: R) -> Result { - let mut key = [0; KEY_WORDS]; - for word in key.iter_mut() { - *word = other.next_u32(); - } - let mut rng = CHACHA_EMPTY; - rng.init(&key); - Ok(rng) - } -} - impl SeedableRng for ChaChaRng { - type Seed = [u8; 32]; - fn from_seed(mut seed: Self::Seed) -> Self { - let mut rng = CHACHA_EMPTY; - let p = &mut seed as *mut [u8; 32] as *mut [u32; 8]; - let key = unsafe{ &mut *p }; - for k in key.iter_mut() { - *k = k.to_le(); - } - rng.init(key); - rng + type Seed = [u8; SEED_WORDS*4]; + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u32 = [0u32; SEED_WORDS]; + le::read_u32_into(&seed, &mut seed_u32); + ChaChaRng::init(seed_u32) } } #[cfg(test)] mod test { - use {Rng, SeedableRng, SeedFromRng}; + use {Rng, SeedableRng}; use super::ChaChaRng; #[test] diff --git a/src/prng/hc128.rs b/src/prng/hc128.rs index f50e27fc3d7..41a6362a3e8 100644 --- a/src/prng/hc128.rs +++ b/src/prng/hc128.rs @@ -10,12 +10,11 @@ //! The HC-128 random number generator. -use core::fmt; -use core::slice; - +use core::{fmt, slice}; use rand_core::{impls, le}; +use {Rng, CryptoRng, SeedableRng, Error}; -use {Rng, CryptoRng, SeedFromRng, SeedableRng, Error}; +const SEED_WORDS: usize = 8; // 128 bit key followed by 128 bit iv /// A cryptographically secure random number generator that uses the HC-128 /// algorithm. @@ -84,7 +83,7 @@ impl fmt::Debug for Hc128Rng { } impl Hc128Rng { - pub fn init(seed: &[u32]) -> Hc128Rng { + fn init(seed: [u32; SEED_WORDS]) -> Self { #[inline] fn f1(x: u32) -> u32 { x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3) @@ -124,15 +123,12 @@ impl Hc128Rng { let mut state = Hc128Rng { state: Hc128 { t: t, counter1024: 0 }, results: [0; 16], - index: 0, + index: 16, // generate on first use }; // run the cipher 1024 steps for _ in 0..64 { state.state.sixteen_steps() }; state.state.counter1024 = 0; - - // Prepare the first set of results - state.state.update(&mut state.results); state } } @@ -396,22 +392,12 @@ impl Rng for Hc128Rng { } } -impl SeedFromRng for Hc128Rng { - fn from_rng(mut other: R) -> Result { - let mut seed = [0u32; 8]; - unsafe { - let ptr = seed.as_mut_ptr() as *mut u8; - let slice = slice::from_raw_parts_mut(ptr, 8 * 4); - other.try_fill(slice)?; - } - Ok(Hc128Rng::init(&seed)) - } -} - impl SeedableRng for Hc128Rng { - type Seed = [u8; 32]; /* 128 bit key followed by 128 bit iv */ - fn from_seed(mut seed: Self::Seed) -> Self { - Hc128Rng::init(&le::convert_slice_32(&mut seed)) + type Seed = [u8; SEED_WORDS*4]; + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u32 = [0u32; SEED_WORDS]; + le::read_u32_into(&seed, &mut seed_u32); + Hc128Rng::init(seed_u32) } } diff --git a/src/prng/isaac.rs b/src/prng/isaac.rs index bd82e306a74..6950d08c17e 100644 --- a/src/prng/isaac.rs +++ b/src/prng/isaac.rs @@ -10,13 +10,10 @@ //! The ISAAC random number generator. -use core::slice; +use core::{fmt, slice}; use core::num::Wrapping as w; -use core::fmt; - use rand_core::{impls, le}; - -use {Rng, SeedFromRng, SeedableRng, Error}; +use {Rng, SeedableRng, Error}; #[allow(non_camel_case_types)] type w32 = w; @@ -309,18 +306,14 @@ fn init(mut mem: [w32; RAND_SIZE], rounds: u32) -> IsaacRng { } } - let mut rng = IsaacRng { + IsaacRng { rsl: [0; RAND_SIZE], mem: mem, a: w(0), b: w(0), c: w(0), - index: 0, - }; - - // Prepare the first set of results - rng.isaac(); - rng + index: RAND_SIZE as u32, // generate on first use + } } fn mix(a: &mut w32, b: &mut w32, c: &mut w32, d: &mut w32, @@ -335,34 +328,39 @@ fn mix(a: &mut w32, b: &mut w32, c: &mut w32, d: &mut w32, *h ^= *a >> 9; *c += *h; *a += *b; } -impl SeedFromRng for IsaacRng { +impl SeedableRng for IsaacRng { + type Seed = [u8; 32]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u32 = [0u32; 8]; + le::read_u32_into(&seed, &mut seed_u32); + let mut seed_extended = [w(0); RAND_SIZE]; + for (x, y) in seed_extended.iter_mut().zip(seed_u32.iter()) { + *x = w(*y); + } + init(seed_extended, 2) + } + fn from_rng(mut other: R) -> Result { - let mut key = [w(0); RAND_SIZE]; + // Custom `from_rng` implementations that fills the entire state + let mut seed = [w(0u32); RAND_SIZE]; unsafe { - let ptr = key.as_mut_ptr() as *mut u8; + let ptr = seed.as_mut_ptr() as *mut u8; let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 4); other.try_fill(slice)?; } - - Ok(init(key, 2)) - } -} - -impl SeedableRng for IsaacRng { - type Seed = [u8; 32]; - fn from_seed(mut seed: Self::Seed) -> Self { - let mut key = [w(0); RAND_SIZE]; - for (x, y) in key.iter_mut().zip(le::convert_slice_32(&mut seed[..]).iter()) { - *x = w(*y); + for i in seed.iter_mut() { + *i = w(i.0.to_le()); } - init(key, 2) + + Ok(init(seed, 2)) } } #[cfg(test)] mod test { - use {Rng, SeedableRng, SeedFromRng}; + use {Rng, SeedableRng}; use super::IsaacRng; #[test] @@ -372,12 +370,13 @@ mod test { let mut rng1 = IsaacRng::from_hashable("some weak seed"); rng1.next_u32(); */ - let mut rng2 = IsaacRng::from_rng(&mut ::test::rng()).unwrap(); - rng2.next_u32(); - + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; - let mut rng3 = IsaacRng::from_seed(seed); - rng3.next_u32(); + let mut rng2 = IsaacRng::from_seed(seed); + assert_eq!(rng2.next_u32(), 2869442790); + + let mut rng3 = IsaacRng::from_rng(&mut rng2).unwrap(); + assert_eq!(rng3.next_u32(), 3094074039); } #[test] diff --git a/src/prng/isaac64.rs b/src/prng/isaac64.rs index 2fc6e5c3513..85da60e6b4a 100644 --- a/src/prng/isaac64.rs +++ b/src/prng/isaac64.rs @@ -10,13 +10,10 @@ //! The ISAAC-64 random number generator. -use core::slice; +use core::{fmt, slice}; use core::num::Wrapping as w; -use core::fmt; - use rand_core::{impls, le}; - -use {Rng, SeedFromRng, SeedableRng, Error}; +use {Rng, SeedableRng, Error}; #[allow(non_camel_case_types)] type w64 = w; @@ -288,19 +285,15 @@ fn init(mut mem: [w64; RAND_SIZE], rounds: u32) -> Isaac64Rng { } } - let mut rng = Isaac64Rng { + Isaac64Rng { rsl: [0; RAND_SIZE], mem: mem, a: w(0), b: w(0), c: w(0), - index: 0, + index: RAND_SIZE as u32, // generate on first use half_used: false, - }; - - // Prepare the first set of results - rng.isaac64(); - rng + } } fn mix(a: &mut w64, b: &mut w64, c: &mut w64, d: &mut w64, @@ -315,34 +308,39 @@ fn mix(a: &mut w64, b: &mut w64, c: &mut w64, d: &mut w64, *h -= *d; *e ^= *g << 14; *g += *h; } -impl SeedFromRng for Isaac64Rng { +impl SeedableRng for Isaac64Rng { + type Seed = [u8; 32]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u64 = [0u64; 4]; + le::read_u64_into(&seed, &mut seed_u64); + let mut seed_extended = [w(0); RAND_SIZE]; + for (x, y) in seed_extended.iter_mut().zip(seed_u64.iter()) { + *x = w(*y); + } + init(seed_extended, 2) + } + fn from_rng(mut other: R) -> Result { - let mut key = [w(0); RAND_SIZE]; + // Custom `from_rng` implementations that fills the entire state + let mut seed = [w(0u64); RAND_SIZE]; unsafe { - let ptr = key.as_mut_ptr() as *mut u8; + let ptr = seed.as_mut_ptr() as *mut u8; let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 8); other.try_fill(slice)?; } - - Ok(init(key, 2)) - } -} - -impl SeedableRng for Isaac64Rng { - type Seed = [u8; 32]; - fn from_seed(mut seed: Self::Seed) -> Self { - let mut key = [w(0); RAND_SIZE]; - for (x, y) in key.iter_mut().zip(le::convert_slice_64(&mut seed[..]).iter()) { - *x = w(*y); + for i in seed.iter_mut() { + *i = w(i.0.to_le()); } - init(key, 2) + + Ok(init(seed, 2)) } } #[cfg(test)] mod test { - use {Rng, SeedableRng, SeedFromRng}; + use {Rng, SeedableRng}; use super::Isaac64Rng; #[test] @@ -352,13 +350,13 @@ mod test { let mut rng1 = Isaac64Rng::from_hashable("some weak seed"); rng1.next_u64(); */ - let mut rng2 = Isaac64Rng::from_rng(&mut ::test::rng()).unwrap(); - rng2.next_u64(); - - let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; - let mut rng3 = Isaac64Rng::from_seed(seed); - rng3.next_u64(); - + + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng2 = Isaac64Rng::from_seed(seed); + assert_eq!(rng2.next_u64(), 14964555543728284049); + + let mut rng3 = Isaac64Rng::from_rng(&mut rng2).unwrap(); + assert_eq!(rng3.next_u64(), 919595328260451758); } #[test] diff --git a/src/prng/isaac_word.rs b/src/prng/isaac_word.rs index 330656b3b8b..1770244f048 100644 --- a/src/prng/isaac_word.rs +++ b/src/prng/isaac_word.rs @@ -10,7 +10,7 @@ //! The ISAAC random number generator. -use {Rng, SeedFromRng, Error}; +use {Rng, SeedableRng, Error}; #[cfg(target_pointer_width = "32")] type WordRngType = super::isaac::IsaacRng; @@ -40,12 +40,12 @@ impl Rng for IsaacWordRng { fn next_u64(&mut self) -> u64 { self.0.next_u64() } - + #[cfg(feature = "i128_support")] fn next_u128(&mut self) -> u128 { self.0.next_u128() } - + fn fill_bytes(&mut self, dest: &mut [u8]) { self.0.fill_bytes(dest) } @@ -55,8 +55,14 @@ impl Rng for IsaacWordRng { } } -impl SeedFromRng for IsaacWordRng { - fn from_rng(other: R) -> Result { - WordRngType::from_rng(other).map(|rng| IsaacWordRng(rng)) +impl SeedableRng for IsaacWordRng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + IsaacWordRng(WordRngType::from_seed(seed)) + } + + fn from_rng(rng: R) -> Result { + WordRngType::from_rng(rng).map(|rng| IsaacWordRng(rng)) } } diff --git a/src/prng/xorshift.rs b/src/prng/xorshift.rs index 4fb829bba56..d2b237663b5 100644 --- a/src/prng/xorshift.rs +++ b/src/prng/xorshift.rs @@ -11,8 +11,8 @@ //! Xorshift generators use core::num::Wrapping as w; -use core::fmt; -use {Rng, SeedFromRng, SeedableRng, Error}; +use core::{fmt, slice}; +use {Rng, SeedableRng, Error}; use rand_core::le; /// An Xorshift[1] random number @@ -57,20 +57,6 @@ impl XorShiftRng { } } -impl SeedFromRng for XorShiftRng { - fn from_rng(mut rng: R) -> Result { - let mut tuple: (u32, u32, u32, u32); - loop { - tuple = (rng.next_u32(), rng.next_u32(), rng.next_u32(), rng.next_u32()); - if tuple != (0, 0, 0, 0) { - break; - } - } - let (x, y, z, w_) = tuple; - Ok(XorShiftRng { x: w(x), y: w(y), z: w(z), w: w(w_) }) - } -} - impl Rng for XorShiftRng { #[inline] fn next_u32(&mut self) -> u32 { @@ -103,16 +89,40 @@ impl Rng for XorShiftRng { impl SeedableRng for XorShiftRng { type Seed = [u8; 16]; - /// Create a new XorShiftRng. This will panic if `seed` is entirely 0. + fn from_seed(seed: Self::Seed) -> Self { - assert!(!seed.iter().all(|&x| x == 0), - "XorShiftRng::from_seed called with an all zero seed."); + let mut seed_u32 = [0u32; 4]; + le::read_u32_into(&seed, &mut seed_u32); + + if seed_u32.iter().all(|&x| x == 0) { + seed_u32 = [0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED]; + } XorShiftRng { - x: w(le::read_u32(array_ref!(seed, 0, 4))), - y: w(le::read_u32(array_ref!(seed, 4, 4))), - z: w(le::read_u32(array_ref!(seed, 8, 4))), - w: w(le::read_u32(array_ref!(seed, 12, 4))), + x: w(seed_u32[0]), + y: w(seed_u32[1]), + z: w(seed_u32[2]), + w: w(seed_u32[3]), } } + + fn from_rng(mut rng: R) -> Result { + let mut seed_u32 = [0u32; 4]; + loop { + unsafe { + let ptr = seed_u32.as_mut_ptr() as *mut u8; + + let slice = slice::from_raw_parts_mut(ptr, 4 * 4); + rng.try_fill(slice)?; + } + if !seed_u32.iter().all(|&x| x == 0) { break; } + } + + Ok(XorShiftRng { + x: w(seed_u32[0]), + y: w(seed_u32[1]), + z: w(seed_u32[2]), + w: w(seed_u32[3]), + }) + } }