diff --git a/rand_chacha/src/chacha.rs b/rand_chacha/src/chacha.rs index 17bcc5528d6..9565fc3540b 100644 --- a/rand_chacha/src/chacha.rs +++ b/rand_chacha/src/chacha.rs @@ -8,6 +8,7 @@ //! The ChaCha random number generator. +// TODO: remove #[cfg(not(feature = "std"))] use core; #[cfg(feature = "std")] use std as core; @@ -24,46 +25,23 @@ const BUF_BLOCKS: u8 = 4; // number of 32-bit words per ChaCha block (fixed by algorithm definition) const BLOCK_WORDS: u8 = 16; -pub struct Array64([T; 64]); -impl Default for Array64 -where T: Default -{ - #[rustfmt::skip] - fn default() -> Self { - Self([ - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - ]) - } -} -impl AsRef<[T]> for Array64 { - fn as_ref(&self) -> &[T] { +/// Type representing result of the ChaCha core iteration +#[derive(Eq, PartialEq, Default, Clone, Copy, Debug)] +pub struct Results([u64; 32]); + +impl AsRef<[u64]> for Results { + #[inline(always)] + fn as_ref(&self) -> &[u64] { &self.0 } } -impl AsMut<[T]> for Array64 { - fn as_mut(&mut self) -> &mut [T] { - &mut self.0 - } -} -impl Clone for Array64 -where T: Copy + Default -{ - fn clone(&self) -> Self { - let mut new = Self::default(); - new.0.copy_from_slice(&self.0); - new - } -} -impl fmt::Debug for Array64 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Array64 {{}}") + +impl AsMut<[u8; 256]> for Results { + #[inline(always)] + fn as_mut(&mut self) -> &mut [u8; 256] { + unsafe { + &mut *(self.0.as_mut_ptr() as *mut [u8; 256]) + } } } @@ -83,17 +61,11 @@ macro_rules! chacha_impl { } impl BlockRngCore for $ChaChaXCore { - type Item = u32; - type Results = Array64; + type Results = Results; #[inline] fn generate(&mut self, r: &mut Self::Results) { - // Fill slice of words by writing to equivalent slice of bytes, then fixing endianness. - self.state.refill4($rounds, unsafe { - &mut *(&mut *r as *mut Array64 as *mut [u8; 256]) - }); - for x in r.as_mut() { - *x = x.to_le(); - } + let r: &mut [u8; 256] = r.as_mut(); + self.state.refill4($rounds, r); } } @@ -162,6 +134,10 @@ macro_rules! chacha_impl { } impl RngCore for $ChaChaXRng { + #[inline] + fn next_bool(&mut self) -> bool { + self.rng.next_bool() + } #[inline] fn next_u32(&mut self) -> u32 { self.rng.next_u32() @@ -180,6 +156,7 @@ macro_rules! chacha_impl { } } + /* impl $ChaChaXRng { // The buffer is a 4-block window, i.e. it is always at a block-aligned position in the // stream but if the stream has been seeked it may not be self-aligned. @@ -245,6 +222,7 @@ macro_rules! chacha_impl { } } } + */ impl CryptoRng for $ChaChaXRng {} @@ -258,8 +236,7 @@ macro_rules! chacha_impl { impl PartialEq<$ChaChaXRng> for $ChaChaXRng { fn eq(&self, rhs: &$ChaChaXRng) -> bool { - self.rng.core.state.stream64_eq(&rhs.rng.core.state) - && self.get_word_pos() == rhs.get_word_pos() + self.rng.eq(&rhs.rng) } } impl Eq for $ChaChaXRng {} @@ -344,7 +321,7 @@ mod test { ]; assert_eq!(results, expected); } - +/* #[test] fn test_chacha_true_values_c() { // Test vector 4 from @@ -506,4 +483,5 @@ mod test { rng.set_word_pos(0); assert_eq!(rng.get_word_pos(), 0); } +*/ } diff --git a/rand_chacha/src/lib.rs b/rand_chacha/src/lib.rs index 24125b45e10..99857fc5fb1 100644 --- a/rand_chacha/src/lib.rs +++ b/rand_chacha/src/lib.rs @@ -16,7 +16,7 @@ #![deny(missing_docs)] #![deny(missing_debug_implementations)] #![doc(test(attr(allow(unused_variables), deny(warnings))))] -#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(not(feature = "std"), no_std)] // TODO: use `#![no_std]` pub use rand_core; diff --git a/rand_core/src/block.rs b/rand_core/src/block.rs index 005d071fbb6..bf934b31608 100644 --- a/rand_core/src/block.rs +++ b/rand_core/src/block.rs @@ -27,9 +27,18 @@ //! //! struct MyRngCore; //! +//! #[derive(Eq, PartialEq, Default)] +//! pub struct Results([u64; 8]); +//! +//! impl AsRef<[u64]> for Results { +//! #[inline(always)] +//! fn as_ref(&self) -> &[u64] { +//! &self.0 +//! } +//! } +//! //! impl BlockRngCore for MyRngCore { -//! type Item = u32; -//! type Results = [u32; 16]; +//! type Results = Results; //! //! fn generate(&mut self, results: &mut Self::Results) { //! unimplemented!() @@ -46,17 +55,17 @@ //! // optionally, also implement CryptoRng for MyRngCore //! //! // Final RNG. -//! let mut rng = BlockRng::::seed_from_u64(0); +//! type MyRng = BlockRng; +//! let mut rng = MyRng::seed_from_u64(0); //! println!("First value: {}", rng.next_u32()); //! ``` //! //! [`BlockRngCore`]: crate::block::BlockRngCore //! [`fill_bytes`]: RngCore::fill_bytes -use crate::impls::{fill_via_u32_chunks, fill_via_u64_chunks}; use crate::{CryptoRng, Error, RngCore, SeedableRng}; use core::convert::AsRef; -use core::fmt; +use core::{fmt, slice}; #[cfg(feature = "serde1")] use serde::{Deserialize, Serialize}; @@ -66,15 +75,52 @@ use serde::{Deserialize, Serialize}; /// /// See the [module][crate::block] documentation for details. pub trait BlockRngCore { - /// Results element type, e.g. `u32`. - type Item; - /// Results type. This is the 'block' an RNG implementing `BlockRngCore` - /// generates, which will usually be an array like `[u32; 16]`. - type Results: AsRef<[Self::Item]> + AsMut<[Self::Item]> + Default; + /// generates, which will usually be an array like `[u8; 64]`. + type Results: AsRef<[u64]> + Default + Sized; /// Generate a new block of results. fn generate(&mut self, results: &mut Self::Results); + + /// Try to generate a new block of results. + #[inline] + fn try_generate(&mut self, results: &mut Self::Results) -> Result<(), Error> { + self.generate(results); + Ok(()) + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +enum IndexLevel { + U1, + U8, + U32, + U64, +} + +impl IndexLevel { + #[inline(always)] + fn convert(&mut self, index: usize, level: Self) -> usize { + use IndexLevel::*; + let res = match (*self, level) { + (U1, U1) | (U8, U8) | (U32, U32) | (U64, U64) => return index, + (U1, U8) => (index / 8) + ((index & 0b111) != 0) as usize, + (U1, U32) => (index / 32) + ((index & 0b1_1111) != 0) as usize, + (U1, U64) => (index / 64) + ((index & 0b11_1111) != 0) as usize, + (U8, U1) => 8 * index, + (U8, U32) => (index / 4) + ((index & 0b11) != 0) as usize, + (U8, U64) => (index / 8) + ((index & 0b111) != 0) as usize, + (U32, U1) => 32 * index, + (U32, U8) => 4 * index, + (U32, U64) => (index / 2) + ((index & 0b1) != 0) as usize, + (U64, U1) => 64 * index, + (U64, U8) => 8 * index, + (U64, U32) => 2 * index, + }; + *self = level; + res + } } /// A wrapper type implementing [`RngCore`] for some type implementing @@ -112,13 +158,14 @@ pub trait BlockRngCore { /// [`next_u64`]: RngCore::next_u64 /// [`fill_bytes`]: RngCore::fill_bytes /// [`try_fill_bytes`]: RngCore::try_fill_bytes -#[derive(Clone)] +#[derive(Clone, Eq, PartialEq)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] -pub struct BlockRng { - results: R::Results, - index: usize, +pub struct BlockRng { /// The *core* part of the RNG, implementing the `generate` function. pub core: R, + results: R::Results, + index: usize, + level: IndexLevel, } // Custom Debug implementation that does not expose the contents of `results`. @@ -126,8 +173,9 @@ impl fmt::Debug for BlockRng { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("BlockRng") .field("core", &self.core) - .field("result_len", &self.results.as_ref().len()) + .field("result_len", &self.get_results_u8().len()) .field("index", &self.index) + .field("level", &self.level) .finish() } } @@ -137,279 +185,134 @@ impl BlockRng { /// `BlockRngCore`. Results will be generated on first use. #[inline] pub fn new(core: R) -> BlockRng { - let results_empty = R::Results::default(); - BlockRng { - core, - index: results_empty.as_ref().len(), - results: results_empty, - } + let results = R::Results::default(); + let index = 8*results.as_ref().len(); + BlockRng { core, results, index, level: IndexLevel::U8 } } - /// Get the index into the result buffer. - /// - /// If this is equal to or larger than the size of the result buffer then - /// the buffer is "empty" and `generate()` must be called to produce new - /// results. #[inline(always)] - pub fn index(&self) -> usize { - self.index - } - - /// Reset the number of available results. - /// This will force a new set of results to be generated on next use. - #[inline] - pub fn reset(&mut self) { - self.index = self.results.as_ref().len(); - } - - /// Generate a new set of results immediately, setting the index to the - /// given value. - #[inline] - pub fn generate_and_set(&mut self, index: usize) { - assert!(index < self.results.as_ref().len()); - self.core.generate(&mut self.results); - self.index = index; - } -} - -impl> RngCore for BlockRng -where - ::Results: AsRef<[u32]> + AsMut<[u32]>, -{ - #[inline] - fn next_u32(&mut self) -> u32 { - if self.index >= self.results.as_ref().len() { - self.generate_and_set(0); - } - - let value = self.results.as_ref()[self.index]; - self.index += 1; - value - } - - #[inline] - fn next_u64(&mut self) -> u64 { - let read_u64 = |results: &[u32], index| { - let data = &results[index..=index + 1]; - u64::from(data[1]) << 32 | u64::from(data[0]) - }; - - 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 - read_u64(self.results.as_ref(), index) - } else if index >= len { - self.generate_and_set(2); - read_u64(self.results.as_ref(), 0) - } else { - let x = u64::from(self.results.as_ref()[len - 1]); - self.generate_and_set(1); - let y = u64::from(self.results.as_ref()[0]); - (y << 32) | x - } - } - - #[inline] - 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.generate_and_set(0); - } - let (consumed_u32, filled_u8) = - fill_via_u32_chunks(&self.results.as_ref()[self.index..], &mut dest[read_len..]); - - self.index += consumed_u32; - read_len += filled_u8; + fn results_to_u8(results: &R::Results) -> &[u8] { + let buf = results.as_ref(); + unsafe { + slice::from_raw_parts(buf.as_ptr() as *const u8, 8 * buf.len()) } } #[inline(always)] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.fill_bytes(dest); - Ok(()) + fn get_results_u8(&self) -> &[u8] { + Self::results_to_u8(&self.results) } -} - -impl SeedableRng for BlockRng { - type Seed = R::Seed; #[inline(always)] - fn from_seed(seed: Self::Seed) -> Self { - Self::new(R::from_seed(seed)) - } - - #[inline(always)] - fn seed_from_u64(seed: u64) -> Self { - Self::new(R::seed_from_u64(seed)) + fn get_results_u32(&self) -> &[u32] { + let buf = self.results.as_ref(); + unsafe { + slice::from_raw_parts(buf.as_ptr() as *const u32, 2 * buf.len()) + } } #[inline(always)] - fn from_rng(rng: S) -> Result { - Ok(Self::new(R::from_rng(rng)?)) - } -} - -/// A wrapper type implementing [`RngCore`] for some type implementing -/// [`BlockRngCore`] with `u64` array buffer; i.e. this can be used to implement -/// a full RNG from just a `generate` function. -/// -/// This is similar to [`BlockRng`], but specialized for algorithms that operate -/// on `u64` values. -/// -/// No whole generated `u64` values are thrown away and all values are consumed -/// in-order. [`next_u64`] simply takes the next available `u64` value. -/// [`next_u32`] is however a bit special: half of a `u64` is consumed, leaving -/// the other half in the buffer. If the next function called is [`next_u32`] -/// then the other half is then consumed, however both [`next_u64`] and -/// [`fill_bytes`] discard the rest of any half-consumed `u64`s when called. -/// -/// [`fill_bytes`] and [`try_fill_bytes`] consume a whole number of `u64` -/// values. If the requested length is not a multiple of 8, some bytes will be -/// discarded. -/// -/// [`next_u32`]: RngCore::next_u32 -/// [`next_u64`]: RngCore::next_u64 -/// [`fill_bytes`]: RngCore::fill_bytes -/// [`try_fill_bytes`]: RngCore::try_fill_bytes -#[derive(Clone)] -#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] -pub struct BlockRng64 { - results: R::Results, - index: usize, - half_used: bool, // true if only half of the previous result is used - /// The *core* part of the RNG, implementing the `generate` function. - pub core: R, -} - -// Custom Debug implementation that does not expose the contents of `results`. -impl fmt::Debug for BlockRng64 { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("BlockRng64") - .field("core", &self.core) - .field("result_len", &self.results.as_ref().len()) - .field("index", &self.index) - .field("half_used", &self.half_used) - .finish() + fn get_results_u64(&self) -> &[u64] { + self.results.as_ref() } } -impl BlockRng64 { - /// Create a new `BlockRng` from an existing RNG implementing - /// `BlockRngCore`. Results will be generated on first use. +impl RngCore for BlockRng +where + ::Results: AsRef<[u64]> + Default + Sized, +{ #[inline] - pub fn new(core: R) -> BlockRng64 { - let results_empty = R::Results::default(); - BlockRng64 { - core, - index: results_empty.as_ref().len(), - half_used: false, - results: results_empty, + fn next_bool(&mut self) -> bool { + let index = self.level.convert(self.index, IndexLevel::U1); + match self.get_results_u8().get(index / 8) { + Some(&v) => { + self.index = index + 1; + (v >> (index % 8) & 1) != 0 + } + None => { + self.core.generate(&mut self.results); + self.index = 1; + (self.get_results_u8()[0] & 1) != 0 + } } } - /// Get the index into the result buffer. - /// - /// If this is equal to or larger than the size of the result buffer then - /// the buffer is "empty" and `generate()` must be called to produce new - /// results. - #[inline(always)] - pub fn index(&self) -> usize { - self.index + #[inline] + fn next_u32(&mut self) -> u32 { + let index = self.level.convert(self.index, IndexLevel::U32); + match self.get_results_u32().get(index) { + Some(&v) => { + self.index = index + 1; + v + } + None => { + self.core.generate(&mut self.results); + self.index = 1; + self.get_results_u32()[0] + } + }.to_le() } - /// Reset the number of available results. - /// This will force a new set of results to be generated on next use. #[inline] - pub fn reset(&mut self) { - self.index = self.results.as_ref().len(); - self.half_used = false; + fn next_u64(&mut self) -> u64 { + let index = self.level.convert(self.index, IndexLevel::U64); + match self.get_results_u64().get(index) { + Some(&v) => { + self.index = index + 1; + v + } + None => { + self.core.generate(&mut self.results); + self.index = 1; + self.get_results_u64()[0] + } + }.to_le() } - /// Generate a new set of results immediately, setting the index to the - /// given value. #[inline] - pub fn generate_and_set(&mut self, index: usize) { - assert!(index < self.results.as_ref().len()); - self.core.generate(&mut self.results); - self.index = index; - self.half_used = false; + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.try_fill_bytes(dest).unwrap(); } -} -impl> RngCore for BlockRng64 -where - ::Results: AsRef<[u64]> + AsMut<[u64]>, -{ #[inline] - fn next_u32(&mut self) -> u32 { - let mut index = self.index * 2 - self.half_used as usize; - if index >= self.results.as_ref().len() * 2 { - self.core.generate(&mut self.results); - self.index = 0; - // `self.half_used` is by definition `false` - self.half_used = false; - index = 0; - } - - self.half_used = !self.half_used; - self.index += self.half_used as usize; - - // Index as if this is a u32 slice. - unsafe { - let results = &*(self.results.as_ref() as *const [u64] as *const [u32]); - if cfg!(target_endian = "little") { - *results.get_unchecked(index) + fn try_fill_bytes(&mut self, mut dest: &mut [u8]) -> Result<(), Error> { + let index = self.level.convert(self.index, IndexLevel::U8); + + let rlen = self.get_results_u8().len(); + if index < rlen { + let dlen = dest.len(); + let res = self.get_results_u8(); + if dlen <= rlen - index { + dest.copy_from_slice(&res[index..index + dlen]); + self.index = index + dlen; + return Ok(()); } else { - *results.get_unchecked(index ^ 1) + let (l, r) = dest.split_at_mut(rlen - index); + l.copy_from_slice(&res[index..]); + dest = r; } } - } - #[inline] - fn next_u64(&mut self) -> u64 { - if self.index >= self.results.as_ref().len() { - self.core.generate(&mut self.results); - self.index = 0; + let mut buf = R::Results::default(); + let mut chunks = dest.chunks_exact_mut(rlen); + for chunk in &mut chunks { + self.core.try_generate(&mut buf)?; + chunk.copy_from_slice(Self::results_to_u8(&buf)); } - let value = self.results.as_ref()[self.index]; - self.index += 1; - self.half_used = false; - value - } - - #[inline] - fn fill_bytes(&mut self, dest: &mut [u8]) { - let mut read_len = 0; - self.half_used = false; - while read_len < dest.len() { - if self.index as usize >= self.results.as_ref().len() { - self.core.generate(&mut self.results); - self.index = 0; - } - - let (consumed_u64, filled_u8) = fill_via_u64_chunks( - &self.results.as_ref()[self.index as usize..], - &mut dest[read_len..], - ); - - self.index += consumed_u64; - read_len += filled_u8; + let rem = chunks.into_remainder(); + if !rem.is_empty() { + self.core.try_generate(&mut self.results)?; + rem.copy_from_slice(&self.get_results_u8()[..rem.len()]); + self.index = rem.len(); + } else { + self.index = rlen; } - } - - #[inline(always)] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.fill_bytes(dest); Ok(()) } } -impl SeedableRng for BlockRng64 { +impl SeedableRng for BlockRng { type Seed = R::Seed; #[inline(always)] diff --git a/rand_core/src/impls.rs b/rand_core/src/impls.rs index 79258364618..7609a73a1d6 100644 --- a/rand_core/src/impls.rs +++ b/rand_core/src/impls.rs @@ -132,6 +132,13 @@ pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) { fill_via_chunks!(src, dest, u64) } +/// Implement `next_bool` via `fill_bytes`, little-endian order. +pub fn next_bool_via_fill(rng: &mut R) -> bool { + let mut buf = [0; 1]; + rng.fill_bytes(&mut buf); + (buf[0] & 1) == 1 +} + /// Implement `next_u32` via `fill_bytes`, little-endian order. pub fn next_u32_via_fill(rng: &mut R) -> u32 { let mut buf = [0; 4]; diff --git a/rand_core/src/lib.rs b/rand_core/src/lib.rs index ff553a335ae..bcebe487226 100644 --- a/rand_core/src/lib.rs +++ b/rand_core/src/lib.rs @@ -110,6 +110,10 @@ pub mod le; /// struct CountingRng(u64); /// /// impl RngCore for CountingRng { +/// fn next_bool(&mut self) -> bool { +/// (self.next_u64() & 1) == 1 +/// } +/// /// fn next_u32(&mut self) -> u32 { /// self.next_u64() as u32 /// } @@ -135,6 +139,9 @@ pub mod le; /// [`next_u32`]: RngCore::next_u32 /// [`next_u64`]: RngCore::next_u64 pub trait RngCore { + /// Return the next random `bool`. + fn next_bool(&mut self) -> bool; + /// Return the next random `u32`. /// /// RNGs must implement at least one method from this trait directly. In @@ -378,6 +385,11 @@ pub trait SeedableRng: Sized { // Force inlining all functions, so that it is up to the `RngCore` // implementation and the optimizer to decide on inlining. impl<'a, R: RngCore + ?Sized> RngCore for &'a mut R { + #[inline(always)] + fn next_bool(&mut self) -> bool { + (**self).next_bool() + } + #[inline(always)] fn next_u32(&mut self) -> u32 { (**self).next_u32() @@ -404,6 +416,11 @@ impl<'a, R: RngCore + ?Sized> RngCore for &'a mut R { // implementation and the optimizer to decide on inlining. #[cfg(feature = "alloc")] impl RngCore for Box { + #[inline(always)] + fn next_bool(&mut self) -> bool { + (**self).next_bool() + } + #[inline(always)] fn next_u32(&mut self) -> u32 { (**self).next_u32() diff --git a/rand_core/src/os.rs b/rand_core/src/os.rs index 6cd1b9cf5de..376dfd39b65 100644 --- a/rand_core/src/os.rs +++ b/rand_core/src/os.rs @@ -50,6 +50,10 @@ pub struct OsRng; impl CryptoRng for OsRng {} impl RngCore for OsRng { + fn next_bool(&mut self) -> bool { + impls::next_bool_via_fill(self) + } + fn next_u32(&mut self) -> u32 { impls::next_u32_via_fill(self) } diff --git a/rand_hc/src/hc128.rs b/rand_hc/src/hc128.rs index 94d75778f75..cf44c05189b 100644 --- a/rand_hc/src/hc128.rs +++ b/rand_hc/src/hc128.rs @@ -67,6 +67,11 @@ const SEED_WORDS: usize = 8; // 128 bit key followed by 128 bit iv pub struct Hc128Rng(BlockRng); impl RngCore for Hc128Rng { + #[inline] + fn next_bool(&mut self) -> bool { + self.0.next_bool() + } + #[inline] fn next_u32(&mut self) -> u32 { self.0.next_u32() @@ -106,7 +111,7 @@ impl CryptoRng for Hc128Rng {} impl PartialEq for Hc128Rng { fn eq(&self, rhs: &Self) -> bool { - self.0.core == rhs.0.core && self.0.index() == rhs.0.index() + self.0.eq(&rhs.0) } } impl Eq for Hc128Rng {} @@ -125,9 +130,28 @@ impl fmt::Debug for Hc128Core { } } +/// Type representing result of the [`Hc128Core`] iteration +#[derive(Eq, PartialEq, Clone, Debug, Default)] +pub struct Results([u64; 8]); + +impl AsRef<[u64]> for Results { + #[inline(always)] + fn as_ref(&self) -> &[u64] { + &self.0 + } +} + +impl AsMut<[u32; 16]> for Results { + #[inline(always)] + fn as_mut(&mut self) -> &mut [u32; 16] { + unsafe { + &mut *(self.0.as_mut_ptr() as *mut [u32; 16]) + } + } +} + impl BlockRngCore for Hc128Core { - type Item = u32; - type Results = [u32; 16]; + type Results = Results; fn generate(&mut self, results: &mut Self::Results) { assert!(self.counter1024 % 16 == 0); @@ -142,6 +166,8 @@ impl BlockRngCore for Hc128Core { assert!(cc + 15 < 512); assert!(dd < 512); + let results: &mut [u32; 16] = results.as_mut(); + if self.counter1024 & 512 == 0 { // P block results[0] = self.step_p(cc+0, cc+1, ee+13, ee+6, ee+4); @@ -179,6 +205,9 @@ impl BlockRngCore for Hc128Core { results[14] = self.step_q(cc+14, cc+15, cc+11, cc+4, cc+2); results[15] = self.step_q(cc+15, dd+0, cc+12, cc+5, cc+3); } + for x in results { + *x = x.to_le(); + } self.counter1024 = self.counter1024.wrapping_add(16); } } diff --git a/rand_pcg/src/pcg128.rs b/rand_pcg/src/pcg128.rs index 58a8e36b7c1..e4e455b5b1c 100644 --- a/rand_pcg/src/pcg128.rs +++ b/rand_pcg/src/pcg128.rs @@ -95,6 +95,11 @@ impl SeedableRng for Lcg128Xsl64 { } impl RngCore for Lcg128Xsl64 { + #[inline] + fn next_bool(&mut self) -> bool { + (self.next_u64() & 1) == 1 + } + #[inline] fn next_u32(&mut self) -> u32 { self.next_u64() as u32 @@ -174,6 +179,11 @@ impl SeedableRng for Mcg128Xsl64 { } impl RngCore for Mcg128Xsl64 { + #[inline] + fn next_bool(&mut self) -> bool { + (self.next_u64() & 1) == 1 + } + #[inline] fn next_u32(&mut self) -> u32 { self.next_u64() as u32 diff --git a/rand_pcg/src/pcg64.rs b/rand_pcg/src/pcg64.rs index ed7442f9670..729b3832a47 100644 --- a/rand_pcg/src/pcg64.rs +++ b/rand_pcg/src/pcg64.rs @@ -94,6 +94,11 @@ impl SeedableRng for Lcg64Xsh32 { } impl RngCore for Lcg64Xsh32 { + #[inline] + fn next_bool(&mut self) -> bool { + (self.next_u32() & 1) == 1 + } + #[inline] fn next_u32(&mut self) -> u32 { let state = self.state; diff --git a/src/rngs/adapter/read.rs b/src/rngs/adapter/read.rs index a5b31cc1bdd..5b4e5f039e5 100644 --- a/src/rngs/adapter/read.rs +++ b/src/rngs/adapter/read.rs @@ -56,6 +56,12 @@ impl ReadRng { } impl RngCore for ReadRng { + fn next_bool(&mut self) -> bool { + let mut buf = [0; 1]; + self.fill_bytes(&mut buf); + (buf[0] & 1) == 1 + } + fn next_u32(&mut self) -> u32 { impls::next_u32_via_fill(self) } diff --git a/src/rngs/adapter/reseeding.rs b/src/rngs/adapter/reseeding.rs index 1977cb31906..65602338d9a 100644 --- a/src/rngs/adapter/reseeding.rs +++ b/src/rngs/adapter/reseeding.rs @@ -106,9 +106,13 @@ where // implements RngCore, but we can't specify that because ReseedingCore is private impl RngCore for ReseedingRng where - R: BlockRngCore + SeedableRng, - ::Results: AsRef<[u32]> + AsMut<[u32]>, + R: BlockRngCore + SeedableRng { + #[inline(always)] + fn next_bool(&mut self) -> bool { + self.0.next_bool() + } + #[inline(always)] fn next_u32(&mut self) -> u32 { self.0.next_u32() @@ -161,7 +165,6 @@ where R: BlockRngCore + SeedableRng, Rsdr: RngCore, { - type Item = ::Item; type Results = ::Results; fn generate(&mut self, results: &mut Self::Results) { @@ -172,7 +175,7 @@ where // returning from a non-inlined function. return self.reseed_and_generate(results, global_fork_counter); } - let num_bytes = results.as_ref().len() * size_of::(); + let num_bytes = results.as_ref().len(); self.bytes_until_reseed -= num_bytes as i64; self.inner.generate(results); } @@ -242,7 +245,7 @@ where trace!("Reseeding RNG (periodic reseed)"); } - let num_bytes = results.as_ref().len() * size_of::<::Item>(); + let num_bytes = results.as_ref().len(); if let Err(e) = self.reseed() { warn!("Reseeding RNG failed: {}", e); diff --git a/src/rngs/mock.rs b/src/rngs/mock.rs index a1745a490dd..6f2ae509f45 100644 --- a/src/rngs/mock.rs +++ b/src/rngs/mock.rs @@ -46,6 +46,11 @@ impl StepRng { } impl RngCore for StepRng { + #[inline] + fn next_bool(&mut self) -> bool { + (self.next_u64() & 1) == 1 + } + #[inline] fn next_u32(&mut self) -> u32 { self.next_u64() as u32 diff --git a/src/rngs/small.rs b/src/rngs/small.rs index fb0e0d119b6..fb1db94b7d2 100644 --- a/src/rngs/small.rs +++ b/src/rngs/small.rs @@ -81,6 +81,11 @@ type Rng = super::xoshiro128plusplus::Xoshiro128PlusPlus; pub struct SmallRng(Rng); impl RngCore for SmallRng { + #[inline(always)] + fn next_bool(&mut self) -> bool { + self.0.next_bool() + } + #[inline(always)] fn next_u32(&mut self) -> u32 { self.0.next_u32() diff --git a/src/rngs/std.rs b/src/rngs/std.rs index a90d86f7880..803abac0bde 100644 --- a/src/rngs/std.rs +++ b/src/rngs/std.rs @@ -37,6 +37,11 @@ pub(crate) use rand_hc::Hc128Core as Core; pub struct StdRng(Rng); impl RngCore for StdRng { + #[inline(always)] + fn next_bool(&mut self) -> bool { + self.0.next_bool() + } + #[inline(always)] fn next_u32(&mut self) -> u32 { self.0.next_u32() diff --git a/src/rngs/thread.rs b/src/rngs/thread.rs index 552851f1ec3..e8970c5c6dd 100644 --- a/src/rngs/thread.rs +++ b/src/rngs/thread.rs @@ -96,6 +96,14 @@ impl Default for ThreadRng { } impl RngCore for ThreadRng { + #[inline(always)] + fn next_bool(&mut self) -> bool { + // SAFETY: We must make sure to stop using `rng` before anyone else + // creates another mutable reference + let rng = unsafe { &mut *self.rng.get() }; + rng.next_bool() + } + #[inline(always)] fn next_u32(&mut self) -> u32 { // SAFETY: We must make sure to stop using `rng` before anyone else diff --git a/src/rngs/xoshiro128plusplus.rs b/src/rngs/xoshiro128plusplus.rs index ece98fafd6a..f32edb16ce2 100644 --- a/src/rngs/xoshiro128plusplus.rs +++ b/src/rngs/xoshiro128plusplus.rs @@ -59,6 +59,11 @@ impl SeedableRng for Xoshiro128PlusPlus { } impl RngCore for Xoshiro128PlusPlus { + #[inline] + fn next_bool(&mut self) -> bool { + self.next_u32() & 1 != 0 + } + #[inline] fn next_u32(&mut self) -> u32 { let result_starstar = self.s[0] diff --git a/src/rngs/xoshiro256plusplus.rs b/src/rngs/xoshiro256plusplus.rs index cd373c30669..026feb8ceb4 100644 --- a/src/rngs/xoshiro256plusplus.rs +++ b/src/rngs/xoshiro256plusplus.rs @@ -59,6 +59,11 @@ impl SeedableRng for Xoshiro256PlusPlus { } impl RngCore for Xoshiro256PlusPlus { + #[inline] + fn next_bool(&mut self) -> bool { + self.next_u64() & 1 != 0 + } + #[inline] fn next_u32(&mut self) -> u32 { // The lowest bits have some linear dependencies, so we use the