11
11
//! A wrapper around another RNG that reseeds it after it
12
12
//! generates a certain number of random bytes.
13
13
14
- use core:: cmp:: max;
15
14
use { Rng , SeedableRng , Error , ErrorKind } ;
16
15
#[ cfg( feature="std" ) ]
17
16
use NewSeeded ;
18
17
19
18
/// How many bytes of entropy the underling RNG is allowed to generate
20
19
/// before it is reseeded
21
- const DEFAULT_GENERATION_THRESHOLD : u64 = 32 * 1024 ;
20
+ const DEFAULT_RESEEDING_THRESHOLD : i64 = 32 * 1024 ;
22
21
23
22
/// A wrapper around any RNG which reseeds the underlying RNG after it
24
23
/// has generated a certain number of random bytes.
@@ -32,8 +31,8 @@ const DEFAULT_GENERATION_THRESHOLD: u64 = 32 * 1024;
32
31
#[ derive( Debug , Clone ) ]
33
32
pub struct ReseedingRng < R , Rsdr : Reseeder < R > > {
34
33
rng : R ,
35
- generation_threshold : u64 ,
36
- bytes_generated : u64 ,
34
+ threshold : i64 ,
35
+ bytes_until_reseed : i64 ,
37
36
/// Controls the behaviour when reseeding the RNG.
38
37
pub reseeder : Rsdr ,
39
38
}
@@ -44,116 +43,122 @@ impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
44
43
/// # Arguments
45
44
///
46
45
/// * `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 number of generated bytes after which to reseed the RNG.
48
47
/// * `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 ) ;
50
50
ReseedingRng {
51
51
rng : rng,
52
- generation_threshold : generation_threshold ,
53
- bytes_generated : 0 ,
52
+ threshold : threshold as i64 ,
53
+ bytes_until_reseed : threshold as i64 ,
54
54
reseeder : reseeder
55
55
}
56
56
}
57
57
58
- /// Reseed the internal RNG if the number of bytes that have been
59
- /// generated exceed the threshold.
60
- ///
58
+ /// Reseed the internal RNG.
61
59
/// 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 {
81
- break ; // give up trying to reseed
60
+ #[ inline( never) ]
61
+ pub fn reseed ( & mut self ) {
62
+ self . bytes_until_reseed = self . threshold ;
63
+ let mut err_count = 0 ;
64
+ loop {
65
+ if let Err ( e) = self . reseeder . reseed ( & mut self . rng ) {
66
+ // TODO: log?
67
+ if e. kind . should_wait ( ) {
68
+ // Delay reseeding
69
+ self . bytes_until_reseed = self . threshold >> 8 ;
70
+ } else if e. kind . should_retry ( ) {
71
+ err_count += 1 ;
72
+ if err_count <= 5 { // arbitrary limit
73
+ continue ; // retry immediately
82
74
}
83
- } else {
84
- break ; // no reseeding
85
75
}
76
+ // give up trying to reseed
86
77
}
87
- self . bytes_generated = 0 ;
78
+ break ; // successfully reseeded, delayed, or given up.
88
79
}
89
80
}
81
+
90
82
/// Reseed the internal RNG if the number of bytes that have been
91
83
/// generated exceed the threshold.
92
84
///
93
85
/// If reseeding fails, return an error with the original cause. Note that
94
86
/// if the cause has a permanent failure, we report a transient error and
95
87
/// 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 ;
88
+ #[ inline( never) ]
89
+ pub fn try_reseed ( & mut self ) -> Result < ( ) , Error > {
90
+ if let Err ( err) = self . reseeder . reseed ( & mut self . rng ) {
91
+ let newkind = match err. kind {
92
+ a @ ErrorKind :: NotReady => a,
93
+ b @ ErrorKind :: Transient => b,
94
+ _ => {
95
+ self . bytes_until_reseed = self . threshold ; // skip reseeding
96
+ ErrorKind :: Transient
97
+ }
98
+ } ;
99
+ return Err ( Error :: with_cause ( newkind, "reseeding failed" , err) ) ;
110
100
}
101
+ self . bytes_until_reseed = self . threshold ;
111
102
Ok ( ( ) )
112
103
}
113
104
}
114
105
115
106
116
107
impl < R : Rng , Rsdr : Reseeder < R > > Rng for ReseedingRng < R , Rsdr > {
117
108
fn next_u32 ( & mut self ) -> u32 {
118
- self . reseed_if_necessary ( ) ;
119
- self . bytes_generated += 4 ;
120
- self . rng . next_u32 ( )
109
+ let value = self . rng . next_u32 ( ) ;
110
+ self . bytes_until_reseed -= 4 ;
111
+ if self . bytes_until_reseed <= 0 {
112
+ self . reseed ( ) ;
113
+ }
114
+ value
121
115
}
122
116
123
117
fn next_u64 ( & mut self ) -> u64 {
124
- self . reseed_if_necessary ( ) ;
125
- self . bytes_generated += 8 ;
126
- self . rng . next_u64 ( )
118
+ let value = self . rng . next_u64 ( ) ;
119
+ self . bytes_until_reseed -= 8 ;
120
+ if self . bytes_until_reseed <= 0 {
121
+ self . reseed ( ) ;
122
+ }
123
+ value
127
124
}
128
125
129
126
#[ cfg( feature = "i128_support" ) ]
130
127
fn next_u128 ( & mut self ) -> u128 {
131
- self . reseed_if_necessary ( ) ;
132
- self . bytes_generated += 16 ;
133
- self . rng . next_u128 ( )
128
+ let value = self . rng . next_u128 ( ) ;
129
+ self . bytes_until_reseed -= 16 ;
130
+ if self . bytes_until_reseed <= 0 {
131
+ self . reseed ( ) ;
132
+ }
133
+ value
134
134
}
135
135
136
136
fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
137
- self . reseed_if_necessary ( ) ;
138
- self . bytes_generated += dest. len ( ) as u64 ;
139
137
self . rng . fill_bytes ( dest) ;
138
+ self . bytes_until_reseed -= dest. len ( ) as i64 ;
139
+ if self . bytes_until_reseed <= 0 {
140
+ self . reseed ( ) ;
141
+ }
140
142
}
141
143
142
144
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)
145
+ self . rng . try_fill ( dest) ?;
146
+ self . bytes_until_reseed -= dest. len ( ) as i64 ;
147
+ if self . bytes_until_reseed <= 0 {
148
+ self . try_reseed ( ) ?;
149
+ }
150
+ Ok ( ( ) )
146
151
}
147
152
}
148
153
149
154
impl < R : SeedableRng , Rsdr : Reseeder < R > > ReseedingRng < R , Rsdr > {
150
155
/// Create a new `ReseedingRng` from the given reseeder and
151
- /// seed. This uses a default value for `generation_threshold `.
156
+ /// seed. This uses a default value for `threshold `.
152
157
pub fn from_reseeder ( rsdr : Rsdr , seed : <R as SeedableRng >:: Seed ) -> ReseedingRng < R , Rsdr > {
153
158
ReseedingRng {
154
159
rng : SeedableRng :: from_seed ( seed) ,
155
- generation_threshold : DEFAULT_GENERATION_THRESHOLD ,
156
- bytes_generated : 0 ,
160
+ threshold : DEFAULT_RESEEDING_THRESHOLD ,
161
+ bytes_until_reseed : DEFAULT_RESEEDING_THRESHOLD ,
157
162
reseeder : rsdr
158
163
}
159
164
}
0 commit comments