1111//! A wrapper around another RNG that reseeds it after it
1212//! generates a certain number of random bytes.
1313
14- use core:: cmp:: max;
1514use { Rng , SeedableRng , Error , ErrorKind } ;
1615#[ cfg( feature="std" ) ]
1716use NewSeeded ;
1817
1918/// How many bytes of entropy the underling RNG is allowed to generate
2019/// before it is reseeded
21- const DEFAULT_GENERATION_THRESHOLD : u64 = 32 * 1024 ;
20+ const DEFAULT_RESEEDING_THRESHOLD : i64 = 32 * 1024 ;
2221
2322/// A wrapper around any RNG which reseeds the underlying RNG after it
2423/// has generated a certain number of random bytes.
@@ -32,8 +31,8 @@ const DEFAULT_GENERATION_THRESHOLD: u64 = 32 * 1024;
3231#[ derive( Debug , Clone ) ]
3332pub struct ReseedingRng < R , Rsdr : Reseeder < R > > {
3433 rng : R ,
35- generation_threshold : u64 ,
36- bytes_generated : u64 ,
34+ threshold : i64 ,
35+ bytes_until_reseed : i64 ,
3736 /// Controls the behaviour when reseeding the RNG.
3837 pub reseeder : Rsdr ,
3938}
@@ -44,13 +43,14 @@ impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
4443 /// # Arguments
4544 ///
4645 /// * `rng`: the random number generator to use.
47- /// * `generation_threshold `: the number of bytes of entropy at which to reseed the RNG.
46+ /// * `threshold `: the amount of generated bytes after which to reseed the RNG.
4847 /// * `reseeder`: the reseeding object to use.
49- pub fn new ( rng : R , generation_threshold : u64 , reseeder : Rsdr ) -> ReseedingRng < R , Rsdr > {
48+ pub fn new ( rng : R , threshold : u64 , reseeder : Rsdr ) -> ReseedingRng < R , Rsdr > {
49+ assert ! ( threshold <= :: core:: i64 :: MAX as u64 ) ;
5050 ReseedingRng {
5151 rng : rng,
52- generation_threshold : generation_threshold ,
53- bytes_generated : 0 ,
52+ threshold : threshold as i64 ,
53+ bytes_until_reseed : threshold as i64 ,
5454 reseeder : reseeder
5555 }
5656 }
@@ -59,101 +59,112 @@ impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
5959 /// generated exceed the threshold.
6060 ///
6161 /// On error, this may delay reseeding or not reseed at all.
62- pub fn reseed_if_necessary ( & mut self ) {
63- if self . bytes_generated >= self . generation_threshold {
64- let mut err_count = 0 ;
65- loop {
66- if let Err ( e) = self . reseeder . reseed ( & mut self . rng ) {
67- // TODO: log?
68- if e. kind . should_wait ( ) {
69- // Delay reseeding
70- let delay = max ( self . generation_threshold >> 8 , self . bytes_generated ) ;
71- self . bytes_generated -= delay;
72- break ;
73- } else if e. kind . should_retry ( ) {
74- if err_count > 4 { // arbitrary limit
75- // TODO: log details & cause?
76- break ; // give up trying to reseed
77- }
78- err_count += 1 ;
79- continue ; // immediate retry
80- } else {
62+ #[ inline( never) ]
63+ pub fn reseed ( & mut self ) {
64+ let mut err_count = 0 ;
65+ loop {
66+ if let Err ( e) = self . reseeder . reseed ( & mut self . rng ) {
67+ // TODO: log?
68+ if e. kind . should_wait ( ) {
69+ // Delay reseeding
70+ self . bytes_until_reseed = self . threshold >> 8 ;
71+ break ;
72+ } else if e. kind . should_retry ( ) {
73+ if err_count > 4 { // arbitrary limit
74+ // TODO: log details & cause?
8175 break ; // give up trying to reseed
8276 }
77+ err_count += 1 ;
78+ continue ; // immediate retry
8379 } else {
84- break ; // no reseeding
80+ break ; // give up trying to reseed
8581 }
82+ } else {
83+ break ; // no reseeding
8684 }
87- self . bytes_generated = 0 ;
8885 }
86+ self . bytes_until_reseed = self . threshold ;
8987 }
9088 /// Reseed the internal RNG if the number of bytes that have been
9189 /// generated exceed the threshold.
9290 ///
9391 /// If reseeding fails, return an error with the original cause. Note that
9492 /// if the cause has a permanent failure, we report a transient error and
9593 /// skip reseeding.
96- pub fn try_reseed_if_necessary ( & mut self ) -> Result < ( ) , Error > {
97- if self . bytes_generated >= self . generation_threshold {
98- if let Err ( err) = self . reseeder . reseed ( & mut self . rng ) {
99- let newkind = match err. kind {
100- a @ ErrorKind :: NotReady => a,
101- b @ ErrorKind :: Transient => b,
102- _ => {
103- self . bytes_generated = 0 ; // skip reseeding
104- ErrorKind :: Transient
105- }
106- } ;
107- return Err ( Error :: with_cause ( newkind, "reseeding failed" , err) ) ;
108- }
109- self . bytes_generated = 0 ;
94+ #[ inline( never) ]
95+ pub fn try_reseed ( & mut self ) -> Result < ( ) , Error > {
96+ if let Err ( err) = self . reseeder . reseed ( & mut self . rng ) {
97+ let newkind = match err. kind {
98+ a @ ErrorKind :: NotReady => a,
99+ b @ ErrorKind :: Transient => b,
100+ _ => {
101+ self . bytes_until_reseed = self . threshold ; // skip reseeding
102+ ErrorKind :: Transient
103+ }
104+ } ;
105+ return Err ( Error :: with_cause ( newkind, "reseeding failed" , err) ) ;
110106 }
107+ self . bytes_until_reseed = self . threshold ;
111108 Ok ( ( ) )
112109 }
113110}
114111
115112
116113impl < R : Rng , Rsdr : Reseeder < R > > Rng for ReseedingRng < R , Rsdr > {
117114 fn next_u32 ( & mut self ) -> u32 {
118- self . reseed_if_necessary ( ) ;
119- self . bytes_generated += 4 ;
120- self . rng . next_u32 ( )
115+ let value = self . rng . next_u32 ( ) ;
116+ self . bytes_until_reseed -= 4 ;
117+ if self . bytes_until_reseed <= 0 {
118+ self . reseed ( ) ;
119+ }
120+ value
121121 }
122122
123123 fn next_u64 ( & mut self ) -> u64 {
124- self . reseed_if_necessary ( ) ;
125- self . bytes_generated += 8 ;
126- self . rng . next_u64 ( )
124+ let value = self . rng . next_u64 ( ) ;
125+ self . bytes_until_reseed -= 8 ;
126+ if self . bytes_until_reseed <= 0 {
127+ self . reseed ( ) ;
128+ }
129+ value
127130 }
128131
129132 #[ cfg( feature = "i128_support" ) ]
130133 fn next_u128 ( & mut self ) -> u128 {
131- self . reseed_if_necessary ( ) ;
132- self . bytes_generated += 16 ;
133- self . rng . next_u128 ( )
134+ let value = self . rng . next_u128 ( ) ;
135+ self . bytes_until_reseed -= 16 ;
136+ if self . bytes_until_reseed <= 0 {
137+ self . reseed ( ) ;
138+ }
139+ value
134140 }
135141
136142 fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
137- self . reseed_if_necessary ( ) ;
138- self . bytes_generated += dest. len ( ) as u64 ;
139143 self . rng . fill_bytes ( dest) ;
144+ self . bytes_until_reseed -= dest. len ( ) as i64 ;
145+ if self . bytes_until_reseed <= 0 {
146+ self . reseed ( ) ;
147+ }
140148 }
141149
142150 fn try_fill ( & mut self , dest : & mut [ u8 ] ) -> Result < ( ) , Error > {
143- self . try_reseed_if_necessary ( ) ?;
144- self . bytes_generated += dest. len ( ) as u64 ;
145- self . rng . try_fill ( dest)
151+ self . rng . try_fill ( dest) ?;
152+ self . bytes_until_reseed -= dest. len ( ) as i64 ;
153+ if self . bytes_until_reseed <= 0 {
154+ self . try_reseed ( ) ?;
155+ }
156+ Ok ( ( ) )
146157 }
147158}
148159
149160impl < R : SeedableRng , Rsdr : Reseeder < R > > ReseedingRng < R , Rsdr > {
150161 /// Create a new `ReseedingRng` from the given reseeder and
151- /// seed. This uses a default value for `generation_threshold `.
162+ /// seed. This uses a default value for `threshold `.
152163 pub fn from_reseeder ( rsdr : Rsdr , seed : <R as SeedableRng >:: Seed ) -> ReseedingRng < R , Rsdr > {
153164 ReseedingRng {
154165 rng : SeedableRng :: from_seed ( seed) ,
155- generation_threshold : DEFAULT_GENERATION_THRESHOLD ,
156- bytes_generated : 0 ,
166+ threshold : DEFAULT_RESEEDING_THRESHOLD ,
167+ bytes_until_reseed : DEFAULT_RESEEDING_THRESHOLD ,
157168 reseeder : rsdr
158169 }
159170 }
0 commit comments