@@ -136,17 +136,19 @@ pub trait CryptoGenerator: Generator {}
136136#[ derive( Clone ) ]
137137pub struct BlockRng < G : Generator > {
138138 results : G :: Output ,
139- index : usize ,
140139 /// The *core* part of the RNG, implementing the `generate` function.
141140 pub core : G ,
142141}
143142
144143// Custom Debug implementation that does not expose the contents of `results`.
145- impl < G : Generator + fmt:: Debug > fmt:: Debug for BlockRng < G > {
144+ impl < W : Word , const N : usize , G > fmt:: Debug for BlockRng < G >
145+ where
146+ G : Generator < Output = [ W ; N ] > + fmt:: Debug ,
147+ {
146148 fn fmt ( & self , fmt : & mut fmt:: Formatter ) -> fmt:: Result {
147149 fmt. debug_struct ( "BlockRng" )
148150 . field ( "core" , & self . core )
149- . field ( "index" , & self . index )
151+ . field ( "index" , & self . index ( ) )
150152 . finish ( )
151153 }
152154}
@@ -157,55 +159,103 @@ impl<G: Generator> Drop for BlockRng<G> {
157159 }
158160}
159161
160- impl < W : Copy + Default , const N : usize , G : Generator < Output = [ W ; N ] > > BlockRng < G > {
162+ impl < W : Word + Default , const N : usize , G : Generator < Output = [ W ; N ] > > BlockRng < G > {
161163 /// Create a new `BlockRng` from an existing RNG implementing
162164 /// `Generator`. Results will be generated on first use.
163165 #[ inline]
164166 pub fn new ( core : G ) -> BlockRng < G > {
165- BlockRng {
166- core,
167- index : N ,
168- results : [ W :: default ( ) ; N ] ,
167+ let mut results = [ W :: default ( ) ; N ] ;
168+ results[ 0 ] = W :: from_usize ( N ) ;
169+ BlockRng { core, results }
170+ }
171+
172+ /// Reconstruct from a core and a remaining-results buffer.
173+ ///
174+ /// This may be used to deserialize using a `core` and the output of
175+ /// [`Self::remaining_results`].
176+ ///
177+ /// Returns `None` if `remaining_results` is too long.
178+ pub fn reconstruct ( core : G , remaining_results : & [ W ] ) -> Option < Self > {
179+ let mut results = [ W :: default ( ) ; N ] ;
180+ if remaining_results. len ( ) < N {
181+ let index = N - remaining_results. len ( ) ;
182+ results[ index..] . copy_from_slice ( remaining_results) ;
183+ results[ 0 ] = W :: from_usize ( index) ;
184+ Some ( BlockRng { results, core } )
185+ } else {
186+ None
169187 }
170188 }
171189}
172190
173- impl < W : Clone , const N : usize , G : Generator < Output = [ W ; N ] > > BlockRng < G > {
191+ impl < W : Word , const N : usize , G : Generator < Output = [ W ; N ] > > BlockRng < G > {
174192 /// Get the index into the result buffer.
175193 ///
176194 /// If this is equal to or larger than the size of the result buffer then
177195 /// the buffer is "empty" and `generate()` must be called to produce new
178196 /// results.
179197 #[ inline( always) ]
180198 pub fn index ( & self ) -> usize {
181- self . index
199+ self . results [ 0 ] . into_usize ( )
200+ }
201+
202+ #[ inline( always) ]
203+ fn set_index ( & mut self , index : usize ) {
204+ debug_assert ! ( 0 < index && index <= N ) ;
205+ self . results [ 0 ] = W :: from_usize ( index) ;
182206 }
183207
184208 /// Reset the number of available results.
185209 /// This will force a new set of results to be generated on next use.
186210 #[ inline]
187211 pub fn reset ( & mut self ) {
188- self . index = N ;
212+ self . set_index ( N ) ;
189213 }
190214
191- /// Generate a new set of results immediately, setting the index to the
192- /// given value.
215+ /// Updates the index and buffer contents
216+ ///
217+ /// If `index == 0`, this marks the buffer as "empty", causing generation on
218+ /// next use.
219+ ///
220+ /// If `index > 0`, this generates a new block immediately then sets the
221+ /// index.
193222 #[ inline]
194223 pub fn generate_and_set ( & mut self , index : usize ) {
224+ if index == 0 {
225+ self . set_index ( N ) ;
226+ return ;
227+ }
228+
195229 assert ! ( index < N ) ;
196230 self . core . generate ( & mut self . results ) ;
197- self . index = index;
231+ self . set_index ( index) ;
232+ }
233+
234+ /// Access the unused part of the results buffer
235+ ///
236+ /// The length of the returned slice is guaranteed to be less than the
237+ /// length of `<Self as Generator>::Output` (i.e. less than `N` where
238+ /// `Output = [W; N]`).
239+ ///
240+ /// This is a low-level interface intended for serialization.
241+ /// Results are not marked as consumed.
242+ #[ inline]
243+ pub fn remaining_results ( & self ) -> & [ W ] {
244+ let index = self . index ( ) ;
245+ & self . results [ index..]
198246 }
199247
200248 /// Generate the next word (e.g. `u32`)
201249 #[ inline]
202250 pub fn next_word ( & mut self ) -> W {
203- if self . index >= N {
204- self . generate_and_set ( 0 ) ;
251+ let mut index = self . index ( ) ;
252+ if index >= N {
253+ self . core . generate ( & mut self . results ) ;
254+ index = 0 ;
205255 }
206256
207- let value = self . results [ self . index ] . clone ( ) ;
208- self . index += 1 ;
257+ let value = self . results [ index] ;
258+ self . set_index ( index + 1 ) ;
209259 value
210260 }
211261}
@@ -214,25 +264,24 @@ impl<const N: usize, G: Generator<Output = [u32; N]>> BlockRng<G> {
214264 /// Generate a `u64` from two `u32` words
215265 #[ inline]
216266 pub fn next_u64_from_u32 ( & mut self ) -> u64 {
217- let read_u64 = |results : & [ u32 ] , index| {
218- let data = & results[ index..=index + 1 ] ;
219- ( u64:: from ( data[ 1 ] ) << 32 ) | u64:: from ( data[ 0 ] )
220- } ;
221-
222- let index = self . index ;
267+ let index = self . index ( ) ;
268+ let ( lo, hi) ;
223269 if index < N - 1 {
224- self . index += 2 ;
225- // Read an u64 from the current index
226- read_u64 ( & self . results , index)
270+ lo = self . results [ index ] ;
271+ hi = self . results [ index + 1 ] ;
272+ self . set_index ( index + 2 ) ;
227273 } else if index >= N {
228- self . generate_and_set ( 2 ) ;
229- read_u64 ( & self . results , 0 )
274+ self . core . generate ( & mut self . results ) ;
275+ lo = self . results [ 0 ] ;
276+ hi = self . results [ 1 ] ;
277+ self . set_index ( 2 ) ;
230278 } else {
231- let x = u64 :: from ( self . results [ N - 1 ] ) ;
232- self . generate_and_set ( 1 ) ;
233- let y = u64 :: from ( self . results [ 0 ] ) ;
234- ( y << 32 ) | x
279+ lo = self . results [ N - 1 ] ;
280+ self . core . generate ( & mut self . results ) ;
281+ hi = self . results [ 0 ] ;
282+ self . set_index ( 1 ) ;
235283 }
284+ ( u64:: from ( hi) << 32 ) | u64:: from ( lo)
236285 }
237286}
238287
@@ -242,13 +291,15 @@ impl<W: Word, const N: usize, G: Generator<Output = [W; N]>> BlockRng<G> {
242291 pub fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
243292 let mut read_len = 0 ;
244293 while read_len < dest. len ( ) {
245- if self . index >= N {
246- self . generate_and_set ( 0 ) ;
294+ let mut index = self . index ( ) ;
295+ if index >= N {
296+ self . core . generate ( & mut self . results ) ;
297+ index = 0 ;
247298 }
248299 let ( consumed_u32, filled_u8) =
249- fill_via_chunks ( & self . results [ self . index ..] , & mut dest[ read_len..] ) ;
300+ fill_via_chunks ( & self . results [ index..] , & mut dest[ read_len..] ) ;
250301
251- self . index += consumed_u32;
302+ self . set_index ( index + consumed_u32) ;
252303 read_len += filled_u8;
253304 }
254305 }
0 commit comments