From 4c5ee3adf99ac787eddf2d0ec4d571c6f0ddd218 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 20 Aug 2026 10:35:03 +0000 Subject: [PATCH 1/5] Remove fns BlockRng::{reconstruct, remaining_results} --- src/block.rs | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/src/block.rs b/src/block.rs index a18219b4..4f6f1e24 100644 --- a/src/block.rs +++ b/src/block.rs @@ -144,24 +144,6 @@ impl> BlockRng< results[0] = W::from_usize(N); BlockRng { core, results } } - - /// 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 { - 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 }) - } else { - None - } - } } impl> BlockRng { @@ -213,20 +195,6 @@ impl> BlockRng { if index >= N { 0 } else { index } } - /// 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 - /// `Output = [W; N]`). - /// - /// This is a low-level interface intended for serialization. - /// Results are not marked as consumed. - #[inline] - pub fn remaining_results(&self) -> &[W] { - let index = self.index(); - &self.results[index..] - } - /// Generate the next word (e.g. `u32`) #[inline] pub fn next_word(&mut self) -> W { From de70d4356b8acf27c366e1118c1e06aef6091dbc Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 20 Aug 2026 08:19:52 +0000 Subject: [PATCH 2/5] Document fn Generator::drop --- src/block.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/block.rs b/src/block.rs index 4f6f1e24..ed7e2507 100644 --- a/src/block.rs +++ b/src/block.rs @@ -92,7 +92,8 @@ pub trait Generator { /// Destruct the output buffer /// /// This method is called on [`Drop`] of the [`Self::Output`] buffer. - /// The default implementation does nothing. + /// The default implementation does nothing; an overriding implementation + /// might be used to (securely) erase results. #[inline] fn drop(&mut self, output: &mut Self::Output) { let _ = output; @@ -129,6 +130,7 @@ where } } +/// Calls [`Generator::drop`] on the output buffer impl Drop for BlockRng { fn drop(&mut self) { self.core.drop(&mut self.results); From df1ed0adb57ec130575be952c9607fafa0f6bc9c Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 20 Aug 2026 09:30:28 +0000 Subject: [PATCH 3/5] Add assoc. type Generator::Word --- src/block.rs | 14 +++++++++----- tests/block.rs | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/block.rs b/src/block.rs index ed7e2507..6fe7dfb8 100644 --- a/src/block.rs +++ b/src/block.rs @@ -23,6 +23,7 @@ //! } //! //! impl Generator for MyRngCore { +//! type Word = u32; //! type Output = [u32; 8]; //! //! fn generate(&mut self, output: &mut Self::Output) { @@ -79,9 +80,12 @@ use core::fmt; /// A random (block) generator pub trait Generator { + /// The word type. + type Word: Word; + /// The output type. /// - /// For use with [`rand_core::block`](crate::block) code this must be `[u32; _]` or `[u64; _]`. + /// For use with [`rand_core::block`](crate::block) code this must be `[Self::Word; _]`. type Output; /// Generate a new block of `output`. @@ -137,7 +141,7 @@ impl Drop for BlockRng { } } -impl> BlockRng { +impl> BlockRng { /// Create a new `BlockRng` from an existing RNG implementing /// `Generator`. Results will be generated on first use. #[inline] @@ -148,7 +152,7 @@ impl> BlockRng< } } -impl> BlockRng { +impl> BlockRng { /// Get the index into the result buffer. /// /// If this is equal to or larger than the size of the result buffer then @@ -212,7 +216,7 @@ impl> BlockRng { } } -impl> BlockRng { +impl> BlockRng { /// Generate a `u64` from two `u32` words #[inline] pub fn next_u64_from_u32(&mut self) -> u64 { @@ -239,7 +243,7 @@ impl> BlockRng { } } -impl> BlockRng { +impl> BlockRng { /// Fill `dest` #[inline] pub fn fill_bytes(&mut self, dest: &mut [u8]) { diff --git a/tests/block.rs b/tests/block.rs index ef818183..11fa8af9 100644 --- a/tests/block.rs +++ b/tests/block.rs @@ -12,6 +12,7 @@ struct DummyRng { } impl Generator for DummyRng { + type Word = u32; type Output = [u32; RESULTS_LEN]; fn generate(&mut self, output: &mut Self::Output) { From 455ca45cc99082ee212c0f8c2002c3825cdc7515 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 20 Aug 2026 09:48:45 +0000 Subject: [PATCH 4/5] Add fn Generator::erase --- src/block.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/block.rs b/src/block.rs index 6fe7dfb8..926c936a 100644 --- a/src/block.rs +++ b/src/block.rs @@ -93,6 +93,17 @@ pub trait Generator { /// This must fill `output` with random data. fn generate(&mut self, output: &mut Self::Output); + /// Erase results from the output buffer + /// + /// This method is called after values from the buffer are consumed and + /// before the buffer is deconstructed. + /// The default implementation does nothing; an overriding implementation + /// might be used for fast erasure of consumed values. + #[inline] + fn erase(slice: &mut [Self::Word]) { + let _ = slice; + } + /// Destruct the output buffer /// /// This method is called on [`Drop`] of the [`Self::Output`] buffer. @@ -211,6 +222,7 @@ impl> BlockRng< } let value = self.results[index]; + G::erase(&mut self.results[index..index + 1]); self.set_index(index + 1); value } @@ -227,6 +239,7 @@ impl> BlockRng { lo = self.results[index]; hi = self.results[index + 1]; new_index = index + 2; + G::erase(&mut self.results[index..new_index]); } else { lo = self.results[N - 1]; self.core.generate(&mut self.results); @@ -237,6 +250,7 @@ impl> BlockRng { hi = self.results[1]; new_index = 2; } + G::erase(&mut self.results[0..new_index]); } self.set_index(new_index); (u64::from(hi) << 32) | u64::from(lo) @@ -277,6 +291,8 @@ impl> BlockRng< break; } } + + G::erase(&mut self.results[0..index]); self.set_index(index); } } From 45fb1f9609a874e146a118bb9c697e96293d6cad Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 20 Aug 2026 08:25:25 +0000 Subject: [PATCH 5/5] Let fn Generator::generate return usize --- src/block.rs | 35 ++++++++++++++++++++--------------- tests/block.rs | 3 ++- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/block.rs b/src/block.rs index 926c936a..4e525ce7 100644 --- a/src/block.rs +++ b/src/block.rs @@ -26,9 +26,10 @@ //! type Word = u32; //! type Output = [u32; 8]; //! -//! fn generate(&mut self, output: &mut Self::Output) { +//! fn generate(&mut self, output: &mut Self::Output) -> usize { //! // Write a new block to output... //! # *output = self.state; +//! # 0 //! } //! } //! @@ -90,8 +91,10 @@ pub trait Generator { /// Generate a new block of `output`. /// - /// This must fill `output` with random data. - fn generate(&mut self, output: &mut Self::Output); + /// This must fill `output` with random data and return the first usable + /// index. The return value must be less than the length. + #[must_use] + fn generate(&mut self, output: &mut Self::Output) -> usize; /// Erase results from the output buffer /// @@ -197,9 +200,10 @@ impl> BlockRng< return; } - assert!(n < N); - self.core.generate(&mut self.results); - self.set_index(n); + let index = self.core.generate(&mut self.results); + let index = index.max(n); + assert!(index < N); + self.set_index(index); } /// Get the number of words consumed since the start of the block @@ -217,8 +221,8 @@ impl> BlockRng< pub fn next_word(&mut self) -> W { let mut index = self.index(); if index >= N { - self.core.generate(&mut self.results); - index = 0; + index = self.core.generate(&mut self.results); + assert!(index < N); } let value = self.results[index]; @@ -242,13 +246,14 @@ impl> BlockRng { G::erase(&mut self.results[index..new_index]); } else { lo = self.results[N - 1]; - self.core.generate(&mut self.results); - hi = self.results[0]; - new_index = 1; + new_index = self.core.generate(&mut self.results); + assert!(new_index + 1 < N); + hi = self.results[new_index]; + new_index += 1; if index >= N { lo = hi; - hi = self.results[1]; - new_index = 2; + hi = self.results[new_index]; + new_index += 1; } G::erase(&mut self.results[0..new_index]); } @@ -265,8 +270,8 @@ impl> BlockRng< let mut index = self.index(); while read_len < dest.len() { if index >= N { - self.core.generate(&mut self.results); - index = 0; + index = self.core.generate(&mut self.results); + assert!(index < N); } let size = core::mem::size_of::(); diff --git a/tests/block.rs b/tests/block.rs index 11fa8af9..85130ef8 100644 --- a/tests/block.rs +++ b/tests/block.rs @@ -15,11 +15,12 @@ impl Generator for DummyRng { type Word = u32; type Output = [u32; RESULTS_LEN]; - fn generate(&mut self, output: &mut Self::Output) { + fn generate(&mut self, output: &mut Self::Output) -> usize { for item in output { *item = self.counter; self.counter = self.counter.wrapping_add(3511615421); } + 0 } }