diff --git a/benches/generators.rs b/benches/generators.rs index 194039e7972..ce7d760962e 100644 --- a/benches/generators.rs +++ b/benches/generators.rs @@ -11,7 +11,7 @@ use test::{black_box, Bencher}; use rand::{Rng, NewSeeded, Sample, SeedFromRng, StdRng, OsRng, JitterRng, thread_rng}; use rand::prng::*; -use rand::reseeding::{ReseedingRng, ReseedWithNew}; +//use rand::reseeding::{ReseedingRng, ReseedWithNew}; macro_rules! gen_bytes { ($fnn:ident, $gen:ident) => { @@ -105,7 +105,7 @@ fn init_jitter(b: &mut Bencher) { } - +/* #[bench] fn reseeding_xorshift_bytes(b: &mut Bencher) { let mut rng = ReseedingRng::new(XorShiftRng::new().unwrap(), @@ -140,9 +140,9 @@ macro_rules! reseeding_uint { reseeding_uint!(reseeding_xorshift_u32, u32); reseeding_uint!(reseeding_xorshift_u64, u64); +*/ - - +/* #[bench] fn gen_bytes_threadrng(b: &mut Bencher) { let mut rng = thread_rng(); @@ -155,7 +155,7 @@ fn gen_bytes_threadrng(b: &mut Bencher) { }); b.bytes = BYTES_LEN as u64 * RAND_BENCH_N; } - +*/ macro_rules! reseeding_uint { ($fnn:ident, $ty:ty) => { #[bench] diff --git a/rand_core/src/lib.rs b/rand_core/src/lib.rs index 6fcd517dcb6..beb9de733fd 100644 --- a/rand_core/src/lib.rs +++ b/rand_core/src/lib.rs @@ -160,6 +160,14 @@ pub trait Rng { /// implemented for well-reviewed code implementing well-regarded algorithms. pub trait CryptoRng: Rng {} +/// FIXME +pub trait RngCore: Sized { + type Results: AsRef<[u32]>; + + fn init(seed: &[u32]) -> Self; + fn generate(&mut self, results: &mut Self::Results); + fn results_empty() -> Self::Results; +} impl<'a, R: Rng+?Sized> Rng for &'a mut R { fn next_u32(&mut self) -> u32 { diff --git a/src/prng/hc128.rs b/src/prng/hc128.rs index f50e27fc3d7..1c4dbb55b37 100644 --- a/src/prng/hc128.rs +++ b/src/prng/hc128.rs @@ -13,7 +13,7 @@ use core::fmt; use core::slice; -use rand_core::{impls, le}; +use rand_core::{impls, le, RngCore}; use {Rng, CryptoRng, SeedFromRng, SeedableRng, Error}; @@ -54,86 +54,38 @@ use {Rng, CryptoRng, SeedFromRng, SeedableRng, Error}; /// [4]: Shashwat Raizada (January 2015), /// ["Some Results On Analysis And Implementation Of HC-128 Stream Cipher"] /// (http://library.isical.ac.in:8080/jspui/bitstream/123456789/6636/1/TH431.pdf). +#[derive(Clone)] pub struct Hc128Rng { - state: Hc128, + core: Hc128, results: [u32; 16], index: usize, } -impl Clone for Hc128Rng { - fn clone(&self) -> Hc128Rng { - Hc128Rng { - state: self.state, - results: self.results, - index: self.index - } - } -} - -#[derive(Copy, Clone)] -struct Hc128 { +#[derive(Copy)] +pub struct Hc128 { t: [u32; 1024], counter1024: usize, } // Custom Debug implementation that does not expose the internal state -impl fmt::Debug for Hc128Rng { +impl fmt::Debug for Hc128 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Hc128Rng {{}}") + write!(f, "Hc128 {{}}") } } -impl Hc128Rng { - pub fn init(seed: &[u32]) -> Hc128Rng { - #[inline] - fn f1(x: u32) -> u32 { - x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3) - } - - #[inline] - fn f2(x: u32) -> u32 { - x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10) - } - - let mut t = [0u32; 1024]; - - // Expand the key and iv into P and Q - let (key, iv) = seed.split_at(4); - t[..4].copy_from_slice(key); - t[4..8].copy_from_slice(key); - t[8..12].copy_from_slice(iv); - t[12..16].copy_from_slice(iv); - - // Generate the 256 intermediate values W[16] ... W[256+16-1], and - // copy the last 16 generated values to the start op P. - for i in 16..256+16 { - t[i] = f2(t[i-2]).wrapping_add(t[i-7]).wrapping_add(f1(t[i-15])) - .wrapping_add(t[i-16]).wrapping_add(i as u32); - } - { - let (p1, p2) = t.split_at_mut(256); - p1[0..16].copy_from_slice(&p2[0..16]); - } - - // Generate both the P and Q tables - for i in 16..1024 { - t[i] = f2(t[i-2]).wrapping_add(t[i-7]).wrapping_add(f1(t[i-15])) - .wrapping_add(t[i-16]).wrapping_add(256 + i as u32); - } - - let mut state = Hc128Rng { - state: Hc128 { t: t, counter1024: 0 }, - results: [0; 16], - index: 0, - }; - - // run the cipher 1024 steps - for _ in 0..64 { state.state.sixteen_steps() }; - state.state.counter1024 = 0; +// Cannot be derived because [u32; 1024] does not implement Clone in +// Rust < 1.21.0 (since https://github.com/rust-lang/rust/pull/43690) +impl Clone for Hc128 { + fn clone(&self) -> Hc128 { + *self + } +} - // Prepare the first set of results - state.state.update(&mut state.results); - state +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for Hc128Rng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Hc128Rng {{}}") } } @@ -189,7 +141,105 @@ impl Hc128 { } } - fn update(&mut self, results: &mut [u32]) { + fn sixteen_steps(&mut self) { + assert!(self.counter1024 % 16 == 0); + + let cc = self.counter1024 % 512; + let dd = (cc + 16) % 512; + let ee = cc.wrapping_sub(16) % 512; + + if self.counter1024 < 512 { + // P block + self.t[cc+0] = self.step_p(cc+0, cc+1, ee+13, ee+6, ee+4); + self.t[cc+1] = self.step_p(cc+1, cc+2, ee+14, ee+7, ee+5); + self.t[cc+2] = self.step_p(cc+2, cc+3, ee+15, ee+8, ee+6); + self.t[cc+3] = self.step_p(cc+3, cc+4, cc+0, ee+9, ee+7); + self.t[cc+4] = self.step_p(cc+4, cc+5, cc+1, ee+10, ee+8); + self.t[cc+5] = self.step_p(cc+5, cc+6, cc+2, ee+11, ee+9); + self.t[cc+6] = self.step_p(cc+6, cc+7, cc+3, ee+12, ee+10); + self.t[cc+7] = self.step_p(cc+7, cc+8, cc+4, ee+13, ee+11); + self.t[cc+8] = self.step_p(cc+8, cc+9, cc+5, ee+14, ee+12); + self.t[cc+9] = self.step_p(cc+9, cc+10, cc+6, ee+15, ee+13); + self.t[cc+10] = self.step_p(cc+10, cc+11, cc+7, cc+0, ee+14); + self.t[cc+11] = self.step_p(cc+11, cc+12, cc+8, cc+1, ee+15); + self.t[cc+12] = self.step_p(cc+12, cc+13, cc+9, cc+2, cc+0); + self.t[cc+13] = self.step_p(cc+13, cc+14, cc+10, cc+3, cc+1); + self.t[cc+14] = self.step_p(cc+14, cc+15, cc+11, cc+4, cc+2); + self.t[cc+15] = self.step_p(cc+15, dd+0, cc+12, cc+5, cc+3); + } else { + // Q block + self.t[cc+512+0] = self.step_q(cc+0, cc+1, ee+13, ee+6, ee+4); + self.t[cc+512+1] = self.step_q(cc+1, cc+2, ee+14, ee+7, ee+5); + self.t[cc+512+2] = self.step_q(cc+2, cc+3, ee+15, ee+8, ee+6); + self.t[cc+512+3] = self.step_q(cc+3, cc+4, cc+0, ee+9, ee+7); + self.t[cc+512+4] = self.step_q(cc+4, cc+5, cc+1, ee+10, ee+8); + self.t[cc+512+5] = self.step_q(cc+5, cc+6, cc+2, ee+11, ee+9); + self.t[cc+512+6] = self.step_q(cc+6, cc+7, cc+3, ee+12, ee+10); + self.t[cc+512+7] = self.step_q(cc+7, cc+8, cc+4, ee+13, ee+11); + self.t[cc+512+8] = self.step_q(cc+8, cc+9, cc+5, ee+14, ee+12); + self.t[cc+512+9] = self.step_q(cc+9, cc+10, cc+6, ee+15, ee+13); + self.t[cc+512+10] = self.step_q(cc+10, cc+11, cc+7, cc+0, ee+14); + self.t[cc+512+11] = self.step_q(cc+11, cc+12, cc+8, cc+1, ee+15); + self.t[cc+512+12] = self.step_q(cc+12, cc+13, cc+9, cc+2, cc+0); + self.t[cc+512+13] = self.step_q(cc+13, cc+14, cc+10, cc+3, cc+1); + self.t[cc+512+14] = self.step_q(cc+14, cc+15, cc+11, cc+4, cc+2); + self.t[cc+512+15] = self.step_q(cc+15, dd+0, cc+12, cc+5, cc+3); + } + self.counter1024 += 16; + } +} + +impl RngCore for Hc128 { + type Results = [u32; 16]; + fn results_empty() -> Self::Results { [0u32; 16] } + + // FIXME: use array. + fn init(seed: &[u32]) -> Self { + #[inline] + fn f1(x: u32) -> u32 { + x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3) + } + + #[inline] + fn f2(x: u32) -> u32 { + x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10) + } + + let mut t = [0u32; 1024]; + + // Expand the key and iv into P and Q + let (key, iv) = seed.split_at(4); + t[..4].copy_from_slice(key); + t[4..8].copy_from_slice(key); + t[8..12].copy_from_slice(iv); + t[12..16].copy_from_slice(iv); + + // Generate the 256 intermediate values W[16] ... W[256+16-1], and + // copy the last 16 generated values to the start op P. + for i in 16..256+16 { + t[i] = f2(t[i-2]).wrapping_add(t[i-7]).wrapping_add(f1(t[i-15])) + .wrapping_add(t[i-16]).wrapping_add(i as u32); + } + { + let (p1, p2) = t.split_at_mut(256); + p1[0..16].copy_from_slice(&p2[0..16]); + } + + // Generate both the P and Q tables + for i in 16..1024 { + t[i] = f2(t[i-2]).wrapping_add(t[i-7]).wrapping_add(f1(t[i-15])) + .wrapping_add(t[i-16]).wrapping_add(256 + i as u32); + } + + let mut core = Hc128 { t: t, counter1024: 0 }; + + // run the cipher 1024 steps + for _ in 0..64 { core.sixteen_steps() }; + core.counter1024 = 0; + core + } + + fn generate(&mut self, results: &mut Self::Results) { assert!(self.counter1024 % 16 == 0); let cc = self.counter1024 % 512; @@ -235,60 +285,25 @@ impl Hc128 { } self.counter1024 = self.counter1024.wrapping_add(16); } +} - fn sixteen_steps(&mut self) { - assert!(self.counter1024 % 16 == 0); - - let cc = self.counter1024 % 512; - let dd = (cc + 16) % 512; - let ee = cc.wrapping_sub(16) % 512; - - if self.counter1024 < 512 { - // P block - self.t[cc+0] = self.step_p(cc+0, cc+1, ee+13, ee+6, ee+4); - self.t[cc+1] = self.step_p(cc+1, cc+2, ee+14, ee+7, ee+5); - self.t[cc+2] = self.step_p(cc+2, cc+3, ee+15, ee+8, ee+6); - self.t[cc+3] = self.step_p(cc+3, cc+4, cc+0, ee+9, ee+7); - self.t[cc+4] = self.step_p(cc+4, cc+5, cc+1, ee+10, ee+8); - self.t[cc+5] = self.step_p(cc+5, cc+6, cc+2, ee+11, ee+9); - self.t[cc+6] = self.step_p(cc+6, cc+7, cc+3, ee+12, ee+10); - self.t[cc+7] = self.step_p(cc+7, cc+8, cc+4, ee+13, ee+11); - self.t[cc+8] = self.step_p(cc+8, cc+9, cc+5, ee+14, ee+12); - self.t[cc+9] = self.step_p(cc+9, cc+10, cc+6, ee+15, ee+13); - self.t[cc+10] = self.step_p(cc+10, cc+11, cc+7, cc+0, ee+14); - self.t[cc+11] = self.step_p(cc+11, cc+12, cc+8, cc+1, ee+15); - self.t[cc+12] = self.step_p(cc+12, cc+13, cc+9, cc+2, cc+0); - self.t[cc+13] = self.step_p(cc+13, cc+14, cc+10, cc+3, cc+1); - self.t[cc+14] = self.step_p(cc+14, cc+15, cc+11, cc+4, cc+2); - self.t[cc+15] = self.step_p(cc+15, dd+0, cc+12, cc+5, cc+3); - } else { - // Q block - self.t[cc+512+0] = self.step_q(cc+0, cc+1, ee+13, ee+6, ee+4); - self.t[cc+512+1] = self.step_q(cc+1, cc+2, ee+14, ee+7, ee+5); - self.t[cc+512+2] = self.step_q(cc+2, cc+3, ee+15, ee+8, ee+6); - self.t[cc+512+3] = self.step_q(cc+3, cc+4, cc+0, ee+9, ee+7); - self.t[cc+512+4] = self.step_q(cc+4, cc+5, cc+1, ee+10, ee+8); - self.t[cc+512+5] = self.step_q(cc+5, cc+6, cc+2, ee+11, ee+9); - self.t[cc+512+6] = self.step_q(cc+6, cc+7, cc+3, ee+12, ee+10); - self.t[cc+512+7] = self.step_q(cc+7, cc+8, cc+4, ee+13, ee+11); - self.t[cc+512+8] = self.step_q(cc+8, cc+9, cc+5, ee+14, ee+12); - self.t[cc+512+9] = self.step_q(cc+9, cc+10, cc+6, ee+15, ee+13); - self.t[cc+512+10] = self.step_q(cc+10, cc+11, cc+7, cc+0, ee+14); - self.t[cc+512+11] = self.step_q(cc+11, cc+12, cc+8, cc+1, ee+15); - self.t[cc+512+12] = self.step_q(cc+12, cc+13, cc+9, cc+2, cc+0); - self.t[cc+512+13] = self.step_q(cc+13, cc+14, cc+10, cc+3, cc+1); - self.t[cc+512+14] = self.step_q(cc+14, cc+15, cc+11, cc+4, cc+2); - self.t[cc+512+15] = self.step_q(cc+15, dd+0, cc+12, cc+5, cc+3); +impl SeedFromRng for Hc128 { + 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)?; } - self.counter1024 += 16; + Ok(Hc128::init(&seed)) } } impl Rng for Hc128Rng { #[inline] fn next_u32(&mut self) -> u32 { - if self.index >= 16 { - self.state.update(&mut self.results); + if self.index >= self.results.len() { + self.core.generate(&mut self.results); self.index = 0; } @@ -299,8 +314,10 @@ impl Rng for Hc128Rng { #[inline] fn next_u64(&mut self) -> u64 { + let len = self.results.len(); + let index = self.index; - if index < 15 { + if index < len-1 { self.index += 2; // Read an u64 from the current index if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { @@ -310,15 +327,15 @@ impl Rng for Hc128Rng { let y = self.results[index + 1] as u64; (y << 32) | x } - } else if index >= 16 { - self.state.update(&mut self.results); + } else if index >= len { + self.core.generate(&mut self.results); self.index = 2; let x = self.results[0] as u64; let y = self.results[1] as u64; (y << 32) | x } else { - let x = self.results[15] as u64; - self.state.update(&mut self.results); + let x = self.results[len-1] as u64; + self.core.generate(&mut self.results); self.index = 1; let y = self.results[0] as u64; (y << 32) | x @@ -339,7 +356,7 @@ impl Rng for Hc128Rng { let mut filled = 0; // Continue filling from the current set of results - if self.index < 16 { + if self.index < self.results.len() { let (consumed_u32, filled_u8) = impls::fill_via_u32_chunks(&mut self.results[self.index..], dest); @@ -348,22 +365,20 @@ impl Rng for Hc128Rng { filled += filled_u8; } - let len_remainder = (dest.len() - filled) % 16; + let len_remainder = (dest.len() - filled) % self.results.len(); let len_direct = dest.len() - len_remainder; while filled < len_direct { - let dest_u32: &mut [u32] = unsafe { - slice::from_raw_parts_mut( - dest[filled..].as_mut_ptr() as *mut u8 as *mut u32, - 16) + let dest_u32: &mut ::Results = unsafe { + ::core::mem::transmute(dest[filled..].as_mut_ptr()) }; - self.state.update(dest_u32); - filled += 16 * 4; + self.core.generate(dest_u32); + filled += self.results.len() * 4; } - self.index = 16; + self.index = self.results.len(); if len_remainder > 0 { - self.state.update(&mut self.results); + self.core.generate(&mut self.results); let (consumed_u32, _) = impls::fill_via_u32_chunks(&mut self.results, @@ -377,8 +392,8 @@ impl Rng for Hc128Rng { fn fill_bytes(&mut self, dest: &mut [u8]) { let mut read_len = 0; while read_len < dest.len() { - if self.index >= 16 { - self.state.update(&mut self.results); + if self.index >= self.results.len() { + self.core.generate(&mut self.results); self.index = 0; } @@ -398,20 +413,28 @@ 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)) + let mut state = Hc128Rng { + core: Hc128::from_rng(other)?, + results: [0; 16], + index: 0, + }; + // Prepare the first set of results + state.core.generate(&mut state.results); + Ok(state) } } 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)) + let mut state = Hc128Rng { + core: Hc128::init(&le::convert_slice_32(&mut seed)), + results: [0; 16], + index: 0, + }; + // Prepare the first set of results + state.core.generate(&mut state.results); + state } } diff --git a/src/prng/mod.rs b/src/prng/mod.rs index 25ffdc81c57..e66479cd2a2 100644 --- a/src/prng/mod.rs +++ b/src/prng/mod.rs @@ -51,7 +51,7 @@ mod isaac_word; mod xorshift; pub use self::chacha::ChaChaRng; -pub use self::hc128::Hc128Rng; +pub use self::hc128::{Hc128Rng, Hc128}; pub use self::isaac::IsaacRng; pub use self::isaac64::Isaac64Rng; pub use self::isaac_word::IsaacWordRng; diff --git a/src/reseeding.rs b/src/reseeding.rs index 67e2543b0b3..37df2ce332c 100644 --- a/src/reseeding.rs +++ b/src/reseeding.rs @@ -11,10 +11,13 @@ //! A wrapper around another RNG that reseeds it after it //! generates a certain number of random bytes. -use {Rng, SeedableRng, Error, ErrorKind}; +use {Rng, SeedFromRng, SeedableRng, Error, ErrorKind, OsRng}; #[cfg(feature="std")] use NewSeeded; +use rand_core::{impls, RngCore}; + +/* /// How many bytes of entropy the underling RNG is allowed to generate /// before it is reseeded const DEFAULT_RESEEDING_THRESHOLD: i64 = 32 * 1024; @@ -171,6 +174,230 @@ impl> ReseedingRng { } } } +*/ + + + + +#[derive(Debug, Clone)] +pub struct ReseedingBlockRng> { + core: R, + results: R::Results, + index: usize, + + threshold: i64, + bytes_until_reseed: i64, + reseeder: Rsdr, +} + +impl> ReseedingBlockRng { + /// Create a new `ReseedingBlockRng` with the given parameters. + pub fn new(threshold: u64, reseeder: Rsdr) -> ReseedingBlockRng { + assert!(threshold <= ::core::i64::MAX as u64); + ReseedingBlockRng { + core: R::from_rng(OsRng::new().unwrap()).unwrap(), // FIXME + results: R::results_empty(), + index: 0, + + threshold: threshold as i64, + bytes_until_reseed: threshold as i64, + reseeder: reseeder, + } + } + + /// Reseed the internal RNG if the number of bytes that have been + /// generated exceed the threshold. + /// + /// On error, this may delay reseeding or not reseed at all. + #[inline(never)] + pub fn reseed(&mut self) { + let mut err_count = 0; + loop { + if let Err(e) = self.reseeder.reseed(&mut self.core) { + // TODO: log? + if e.kind.should_wait() { + // Delay reseeding + self.bytes_until_reseed = self.threshold >> 8; + break; + } else if e.kind.should_retry() { + if err_count > 4 { // arbitrary limit + // TODO: log details & cause? + break; // give up trying to reseed + } + err_count += 1; + continue; // immediate retry + } else { + break; // give up trying to reseed + } + } else { + break; // no reseeding + } + } + self.bytes_until_reseed = self.threshold; + } + + #[inline] + fn generate(&mut self) { + if self.bytes_until_reseed <= 0 { self.reseed(); } + self.bytes_until_reseed -= self.results.as_ref().len() as i64 * 4; + self.core.generate(&mut self.results); + } + +/* + /// Reseed the internal RNG if the number of bytes that have been + /// generated exceed the threshold. + /// + /// If reseeding fails, return an error with the original cause. Note that + /// if the cause has a permanent failure, we report a transient error and + /// skip reseeding. + #[inline(never)] + pub fn try_reseed(&mut self) -> Result<(), Error> { + if let Err(err) = self.reseeder.reseed(&mut self.rng) { + let newkind = match err.kind { + a @ ErrorKind::NotReady => a, + b @ ErrorKind::Transient => b, + _ => { + self.bytes_until_reseed = self.threshold; // skip reseeding + ErrorKind::Transient + } + }; + return Err(Error::with_cause(newkind, "reseeding failed", err)); + } + self.bytes_until_reseed = self.threshold; + Ok(()) + } +*/ +} + + +impl> Rng for ReseedingBlockRng { + #[inline] + fn next_u32(&mut self) -> u32 { + if self.index >= self.results.as_ref().len() { + self.generate(); + self.index = 0; + } + + let value = self.results.as_ref()[self.index]; + self.index += 1; + value + } + + fn next_u64(&mut self) -> u64 { + let len = self.results.as_ref().len(); + + let index = self.index; + if index < len-1 { + self.index += 2; + // Read an u64 from the current index + if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { + unsafe { *(&self.results.as_ref()[index] as *const u32 as *const u64) } + } else { + let x = self.results.as_ref()[index] as u64; + let y = self.results.as_ref()[index + 1] as u64; + (y << 32) | x + } + } else if index >= len { + self.generate(); + self.index = 2; + let x = self.results.as_ref()[0] as u64; + let y = self.results.as_ref()[1] as u64; + (y << 32) | x + } else { + let x = self.results.as_ref()[len-1] as u64; + self.generate(); + self.index = 1; + let y = self.results.as_ref()[0] as u64; + (y << 32) | x + } + } + + #[cfg(feature = "i128_support")] + fn next_u128(&mut self) -> u128 { + impls::next_u128_via_u64(self) // FIXME + } +/* + // As an optimization we try to write directly into the output buffer. + // This is only enabled for platforms where unaligned writes are known to + // be safe and fast. + // This improves performance by about 12%. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut filled = 0; + + // Continue filling from the current set of results + if self.index < self.results.as_ref().len() { + let (consumed_u32, filled_u8) = + impls::fill_via_u32_chunks(&mut self.results.as_ref()[self.index..], + dest); + + self.index += consumed_u32; + filled += filled_u8; + } + + let len_remainder = (dest.len() - filled) % self.results.as_ref().len(); + let len_direct = dest.len() - len_remainder; + + while filled < len_direct { + let dest_u32: &mut ::Results = unsafe { + ::core::mem::transmute(dest[filled..].as_mut_ptr()) + }; + self.core.generate(dest_u32); + filled += self.results.as_ref().len() * 4; + } + self.index = self.results.as_ref().len(); + + if len_remainder > 0 { + self.core.generate(&mut self.results); + + let (consumed_u32, _) = + impls::fill_via_u32_chunks(&mut self.results.as_ref(), + &mut dest[filled..]); + + self.index = consumed_u32; + } + } + + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +*/ + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut read_len = 0; + while read_len < dest.len() { + if self.index >= self.results.as_ref().len() { + self.core.generate(&mut self.results); + self.index = 0; + } +/* + let (consumed_u32, filled_u8) = + impls::fill_via_u32_chunks(&mut self.results.as_ref()[self.index..], + &mut dest[read_len..]); + + self.index += consumed_u32; + read_len += filled_u8; +*/ + } + } + + fn try_fill(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} + + + + + + + + + + + + + + + + /// Something that can be used to reseed an RNG via `ReseedingRng`. /// @@ -187,16 +414,18 @@ pub trait Reseeder { /// Reseed an RNG using `NewSeeded` to replace the current instance. #[cfg(feature="std")] -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ReseedWithNew; #[cfg(feature="std")] -impl Reseeder for ReseedWithNew { +impl Reseeder for ReseedWithNew { fn reseed(&mut self, rng: &mut R) -> Result<(), Error> { R::new().map(|result| *rng = result) } } + +/* #[cfg(test)] mod test { use std::iter::repeat; @@ -255,3 +484,4 @@ mod test { assert!(sum / v.len() as f64 != 0.0); } } +*/ diff --git a/src/thread_local.rs b/src/thread_local.rs index 8e26358028c..143a441081e 100644 --- a/src/thread_local.rs +++ b/src/thread_local.rs @@ -11,19 +11,19 @@ //! Thread-local handle to a random number generator use std::cell::RefCell; -use std::rc::Rc; -use {Rng, StdRng, NewSeeded, Distribution, Default, Sample, Error}; +use {Rng, NewSeeded, Distribution, Default, Sample, Error}; +use prng::Hc128; -use reseeding::{ReseedingRng, ReseedWithNew}; +use reseeding::{ReseedingBlockRng, ReseedWithNew}; -const THREAD_RNG_RESEED_THRESHOLD: u64 = 32_768*1024; -type ReseedingStdRng = ReseedingRng; +const THREAD_RNG_RESEED_THRESHOLD: u64 = 1 << 26; // 2^26 rounds = 2^28 bytes +type ReseedingStdRng = ReseedingBlockRng; /// The thread-local RNG. #[derive(Clone, Debug)] pub struct ThreadRng { - rng: Rc>, + rng: RefCell, } impl Rng for ThreadRng { @@ -52,15 +52,9 @@ impl Rng for ThreadRng { } thread_local!( - static THREAD_RNG_KEY: Rc> = { - let r = match StdRng::new() { - Ok(r) => r, - Err(e) => panic!("could not initialize thread_rng: {:?}", e) - }; - let rng = ReseedingRng::new(r, - THREAD_RNG_RESEED_THRESHOLD, - ReseedWithNew); - Rc::new(RefCell::new(rng)) + static THREAD_RNG_KEY: RefCell = { + let rng = ReseedingBlockRng::new(THREAD_RNG_RESEED_THRESHOLD, ReseedWithNew); + RefCell::new(rng) } );