diff --git a/CHANGELOG.md b/CHANGELOG.md index 5befbf89..c54b7634 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `BlockRng::reset` method ([#44]) - `BlockRng::index` method (replaced with `BlockRng::word_offset`) ([#44]) - `Generator::Item` associated type ([#26]) +- `CryptoBlockRng` ([#68]) [0.10.0]: https://github.com/rust-random/rand_core/compare/v0.9.3...HEAD @@ -60,6 +61,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#53]: https://github.com/rust-random/rand_core/pull/53 [#56]: https://github.com/rust-random/rand_core/pull/56 [#58]: https://github.com/rust-random/rand_core/pull/58 +[#68]: https://github.com/rust-random/rand_core/pull/68 [rust-random/rand]: https://github.com/rust-random/rand [rust-random/rand_core]: https://github.com/rust-random/rand_core diff --git a/src/block.rs b/src/block.rs index c3a65d2a..a4c64278 100644 --- a/src/block.rs +++ b/src/block.rs @@ -1,29 +1,25 @@ -//! The [`Generator`] trait and [`BlockRng`] +//! The [`BlockRng`] trait and [`BlockBuffer`] //! -//! Trait [`Generator`] and marker trait [`CryptoGenerator`] may be implemented -//! by block-generators; that is PRNGs whose output is a *block* of words, such -//! as `[u32; 16]`. +//! Trait [`BlockRng`] may be implemented by block-generators; that is PRNGs +//! whose output is a *block* of words, such as `[u32; 16]`. //! -//! The struct [`BlockRng`] wraps such a [`Generator`] together with an output -//! buffer and implements several methods (e.g. [`BlockRng::next_word`]) to -//! assist in the implementation of [`TryRng`]. Note that (unlike in earlier -//! versions of `rand_core`) [`BlockRng`] itself does not implement [`TryRng`] -//! since in practice we found it was always beneficial to use a wrapper type -//! over [`BlockRng`]. +//! The struct [`BlockBuffer`] may be used with a [`BlockRng`] to implement +//! [`TryRng`]. Note that (unlike in earlier versions of `rand_core`) +//! [`BlockBuffer`] itself does not implement [`TryRng`]. //! //! # Example //! //! ``` //! use core::convert::Infallible; //! use rand_core::{Rng, SeedableRng, TryRng}; -//! use rand_core::block::{Generator, BlockRng}; +//! use rand_core::block::{BlockRng, BlockBuffer}; //! //! struct MyRngCore { //! // Generator state ... //! # state: [u32; 8], //! } //! -//! impl Generator for MyRngCore { +//! impl BlockRng for MyRngCore { //! type Output = [u32; 8]; //! //! fn generate(&mut self, output: &mut Self::Output) { @@ -32,17 +28,22 @@ //! } //! } //! -//! // Our RNG is a wrapper over BlockRng -//! pub struct MyRng(BlockRng); +//! // Our RNG is a wrapper over BlockBuffer +//! pub struct MyRng { +//! core: MyRngCore, +//! buffer: BlockBuffer, +//! } //! //! impl SeedableRng for MyRng { //! type Seed = [u8; 32]; //! fn from_seed(seed: Self::Seed) -> Self { -//! let core = MyRngCore { -//! // ... -//! # state: rand_core::utils::read_words(&seed), -//! }; -//! MyRng(BlockRng::new(core)) +//! MyRng { +//! core: MyRngCore { +//! // ... +//! # state: rand_core::utils::read_words(&seed), +//! }, +//! buffer: BlockBuffer::default(), +//! } //! } //! } //! @@ -51,17 +52,17 @@ //! //! #[inline] //! fn try_next_u32(&mut self) -> Result { -//! Ok(self.0.next_word()) +//! Ok(self.buffer.next_word(&mut self.core)) //! } //! //! #[inline] //! fn try_next_u64(&mut self) -> Result { -//! Ok(self.0.next_u64_from_u32()) +//! Ok(self.buffer.next_u64_from_u32(&mut self.core)) //! } //! //! #[inline] //! fn try_fill_bytes(&mut self, bytes: &mut [u8]) -> Result<(), Infallible> { -//! Ok(self.0.fill_bytes(bytes)) +//! Ok(self.buffer.fill_bytes(&mut self.core, bytes)) //! } //! } //! @@ -72,23 +73,13 @@ //! # assert_eq!(rng.next_u32(), 1171109249); //! ``` //! -//! # ReseedingRng -//! -//! The [`Generator`] trait supports usage of [`rand::rngs::ReseedingRng`]. -//! This requires that [`SeedableRng`] be implemented on the "core" generator. -//! Additionally, it may be useful to implement [`CryptoGenerator`]. -//! (This is in addition to any implementations on an [`TryRng`] type.) -//! -//! [`Generator`]: crate::block::Generator //! [`TryRng`]: crate::TryRng //! [`SeedableRng`]: crate::SeedableRng -//! [`rand::rngs::ReseedingRng`]: https://docs.rs/rand/latest/rand/rngs/struct.ReseedingRng.html use crate::utils::Word; -use core::fmt; /// A random (block) generator -pub trait Generator { +pub trait BlockRng { /// The output type. /// /// For use with [`rand_core::block`](crate::block) code this must be `[u32; _]` or `[u64; _]`. @@ -98,32 +89,12 @@ pub trait Generator { /// /// This must fill `output` with random data. fn generate(&mut self, output: &mut Self::Output); - - /// Destruct the output buffer - /// - /// This method is called on [`Drop`] of the [`Self::Output`] buffer. - /// The default implementation does nothing. - #[inline] - fn drop(&mut self, output: &mut Self::Output) { - let _ = output; - } } -/// A cryptographically secure generator -/// -/// This is a marker trait used to indicate that a [`Generator`] implementation -/// is supposed to be cryptographically secure. -/// -/// Mock generators should not implement this trait *except* under a -/// `#[cfg(test)]` attribute to ensure that mock "crypto" generators cannot be -/// used in production. -/// -/// See [`TryCryptoRng`](crate::TryCryptoRng) docs for more information. -pub trait CryptoGenerator: Generator {} - -/// RNG functionality for a block [`Generator`] +/// Buffer providing RNG methods over a [`BlockRng`] /// -/// This type encompasses a [`Generator`] [`core`](Self::core) and a buffer. +/// This type does not encapuslate a [`BlockRng`], but is designed to be used +/// alongside one. /// It provides optimized implementations of methods required by an [`Rng`]. /// /// All values are consumed in-order of generation. No whole words (e.g. `u32` @@ -133,60 +104,41 @@ pub trait CryptoGenerator: Generator {} /// /// [`Rng`]: crate::Rng #[derive(Clone)] -pub struct BlockRng { +#[allow(missing_debug_implementations)] +pub struct BlockBuffer { results: G::Output, - /// The *core* part of the RNG, implementing the `generate` function. - pub core: G, -} - -// Custom Debug implementation that does not expose the contents of `results`. -impl fmt::Debug for BlockRng -where - G: Generator + fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("BlockRng") - .field("core", &self.core) - .finish_non_exhaustive() - } } -impl Drop for BlockRng { - fn drop(&mut self) { - self.core.drop(&mut self.results); - } -} - -impl> BlockRng { - /// Create a new `BlockRng` from an existing RNG implementing - /// `Generator`. Results will be generated on first use. +impl> Default for BlockBuffer { #[inline] - pub fn new(core: G) -> BlockRng { + fn default() -> BlockBuffer { let mut results = [W::default(); N]; results[0] = W::from_usize(N); - BlockRng { core, results } + BlockBuffer { results } } +} +impl> BlockBuffer { /// Reconstruct from a core and a remaining-results buffer. /// /// This may be used to deserialize using a `core` and the output of /// [`Self::remaining_results`]. /// /// Returns `None` if `remaining_results` is too long. - pub fn reconstruct(core: G, remaining_results: &[W]) -> Option { + pub fn reconstruct(remaining_results: &[W]) -> Option { let mut results = [W::default(); N]; if remaining_results.len() < N { let index = N - remaining_results.len(); results[index..].copy_from_slice(remaining_results); results[0] = W::from_usize(index); - Some(BlockRng { results, core }) + Some(BlockBuffer { results }) } else { None } } } -impl> BlockRng { +impl> BlockBuffer { /// Get the index into the result buffer. /// /// If this is equal to or larger than the size of the result buffer then @@ -214,14 +166,14 @@ impl> BlockRng { /// This method will panic if `n >= N` where `N` is the buffer size (in /// words). #[inline] - pub fn reset_and_skip(&mut self, n: usize) { + pub fn reset_and_skip(&mut self, core: &mut G, n: usize) { if n == 0 { self.set_index(N); return; } assert!(n < N); - self.core.generate(&mut self.results); + core.generate(&mut self.results); self.set_index(n); } @@ -238,7 +190,7 @@ impl> BlockRng { /// Access the unused part of the results buffer /// /// The length of the returned slice is guaranteed to be less than the - /// length of `::Output` (i.e. less than `N` where + /// length of `::Output` (i.e. less than `N` where /// `Output = [W; N]`). /// /// This is a low-level interface intended for serialization. @@ -251,10 +203,10 @@ impl> BlockRng { /// Generate the next word (e.g. `u32`) #[inline] - pub fn next_word(&mut self) -> W { + pub fn next_word(&mut self, core: &mut G) -> W { let mut index = self.index(); if index >= N { - self.core.generate(&mut self.results); + core.generate(&mut self.results); index = 0; } @@ -264,10 +216,10 @@ impl> BlockRng { } } -impl> BlockRng { +impl> BlockBuffer { /// Generate a `u64` from two `u32` words #[inline] - pub fn next_u64_from_u32(&mut self) -> u64 { + pub fn next_u64_from_u32(&mut self, core: &mut G) -> u64 { let index = self.index(); let mut new_index; let (mut lo, mut hi); @@ -277,7 +229,7 @@ impl> BlockRng { new_index = index + 2; } else { lo = self.results[N - 1]; - self.core.generate(&mut self.results); + core.generate(&mut self.results); hi = self.results[0]; new_index = 1; if index >= N { @@ -291,15 +243,15 @@ impl> BlockRng { } } -impl> BlockRng { +impl> BlockBuffer { /// Fill `dest` #[inline] - pub fn fill_bytes(&mut self, dest: &mut [u8]) { + pub fn fill_bytes(&mut self, core: &mut G, dest: &mut [u8]) { let mut read_len = 0; let mut index = self.index(); while read_len < dest.len() { if index >= N { - self.core.generate(&mut self.results); + core.generate(&mut self.results); index = 0; } diff --git a/tests/block.rs b/tests/block.rs index ef818183..7c301b7d 100644 --- a/tests/block.rs +++ b/tests/block.rs @@ -1,7 +1,7 @@ //! Tests for the `block` module items use rand_core::{ SeedableRng, - block::{BlockRng, Generator}, + block::{BlockBuffer, BlockRng}, }; const RESULTS_LEN: usize = 16; @@ -11,7 +11,7 @@ struct DummyRng { counter: u32, } -impl Generator for DummyRng { +impl BlockRng for DummyRng { type Output = [u32; RESULTS_LEN]; fn generate(&mut self, output: &mut Self::Output) { @@ -34,37 +34,41 @@ impl SeedableRng for DummyRng { #[test] fn blockrng_next_u32_vs_next_u64() { - let mut rng1 = BlockRng::new(DummyRng::from_seed([1, 2, 3, 4])); + let mut core1 = DummyRng::from_seed([1, 2, 3, 4]); + let mut core2 = core1.clone(); + let mut core3 = core1.clone(); + let mut rng1 = BlockBuffer::default(); let mut rng2 = rng1.clone(); let mut rng3 = rng1.clone(); let mut a = [0; 16]; - a[..4].copy_from_slice(&rng1.next_word().to_le_bytes()); - a[4..12].copy_from_slice(&rng1.next_u64_from_u32().to_le_bytes()); - a[12..].copy_from_slice(&rng1.next_word().to_le_bytes()); + a[..4].copy_from_slice(&rng1.next_word(&mut core1).to_le_bytes()); + a[4..12].copy_from_slice(&rng1.next_u64_from_u32(&mut core1).to_le_bytes()); + a[12..].copy_from_slice(&rng1.next_word(&mut core1).to_le_bytes()); let mut b = [0; 16]; - b[..4].copy_from_slice(&rng2.next_word().to_le_bytes()); - b[4..8].copy_from_slice(&rng2.next_word().to_le_bytes()); - b[8..].copy_from_slice(&rng2.next_u64_from_u32().to_le_bytes()); + b[..4].copy_from_slice(&rng2.next_word(&mut core2).to_le_bytes()); + b[4..8].copy_from_slice(&rng2.next_word(&mut core2).to_le_bytes()); + b[8..].copy_from_slice(&rng2.next_u64_from_u32(&mut core2).to_le_bytes()); assert_eq!(a, b); let mut c = [0; 16]; - c[..8].copy_from_slice(&rng3.next_u64_from_u32().to_le_bytes()); - c[8..12].copy_from_slice(&rng3.next_word().to_le_bytes()); - c[12..].copy_from_slice(&rng3.next_word().to_le_bytes()); + c[..8].copy_from_slice(&rng3.next_u64_from_u32(&mut core3).to_le_bytes()); + c[8..12].copy_from_slice(&rng3.next_word(&mut core3).to_le_bytes()); + c[12..].copy_from_slice(&rng3.next_word(&mut core3).to_le_bytes()); assert_eq!(a, c); } #[test] fn blockrng_next_u64() { - let mut rng = BlockRng::new(DummyRng::from_seed([1, 2, 3, 4])); + let mut core = DummyRng::from_seed([1, 2, 3, 4]); + let mut rng = BlockBuffer::default(); let result_size = RESULTS_LEN; for _i in 0..result_size / 2 - 1 { - rng.next_u64_from_u32(); + rng.next_u64_from_u32(&mut core); } - rng.next_word(); + rng.next_word(&mut core); - let _ = rng.next_u64_from_u32(); + let _ = rng.next_u64_from_u32(&mut core); assert_eq!(rng.word_offset(), 1); }