@@ -15,6 +15,8 @@ use core::iter::repeat;
15
15
use core:: num:: Wrapping as w;
16
16
use core:: fmt;
17
17
18
+ use rand_core:: impls;
19
+
18
20
use { Rng , SeedFromRng , SeedableRng , Error } ;
19
21
20
22
#[ allow( non_camel_case_types) ]
@@ -87,12 +89,12 @@ const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
87
89
/// [3]: Jean-Philippe Aumasson, [*On the pseudo-random generator ISAAC*]
88
90
/// (http://eprint.iacr.org/2006/438)
89
91
pub struct IsaacRng {
90
- rsl : [ w32 ; RAND_SIZE ] ,
92
+ rsl : [ u32 ; RAND_SIZE ] ,
91
93
mem : [ w32 ; RAND_SIZE ] ,
92
94
a : w32 ,
93
95
b : w32 ,
94
96
c : w32 ,
95
- cnt : u32 ,
97
+ index : u32 ,
96
98
}
97
99
98
100
// Cannot be derived because [u32; 256] does not implement Clone
@@ -105,7 +107,7 @@ impl Clone for IsaacRng {
105
107
a : self . a ,
106
108
b : self . b ,
107
109
c : self . c ,
108
- cnt : self . cnt ,
110
+ index : self . index ,
109
111
}
110
112
}
111
113
}
@@ -149,20 +151,23 @@ impl IsaacRng {
149
151
/// - We maintain one index `i` and add `m` or `m2` as base (m2 for the
150
152
/// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer
151
153
/// arithmetic.
154
+ /// - We fill `rsl` backwards. The reference implementation reads values
155
+ /// from `rsl` in reverse. We read them in the normal direction, to make
156
+ /// `fill_bytes` a memcopy. To maintain compatibility we fill in reverse.
152
157
fn isaac ( & mut self ) {
153
158
self . c += w ( 1 ) ;
154
159
// abbreviations
155
160
let mut a = self . a ;
156
161
let mut b = self . b + self . c ;
157
162
const MIDPOINT : usize = RAND_SIZE / 2 ;
158
163
159
- #[ inline( always ) ]
164
+ #[ inline]
160
165
fn ind ( mem : & [ w32 ; RAND_SIZE ] , v : w32 , amount : usize ) -> w32 {
161
166
let index = ( v >> amount) . 0 as usize % RAND_SIZE ;
162
167
mem[ index]
163
168
}
164
169
165
- #[ inline( always ) ]
170
+ #[ inline]
166
171
fn rngstep ( ctx : & mut IsaacRng ,
167
172
mix : w32 ,
168
173
a : & mut w32 ,
@@ -175,7 +180,7 @@ impl IsaacRng {
175
180
let y = * a + * b + ind ( & ctx. mem , x, 2 ) ;
176
181
ctx. mem [ base + m] = y;
177
182
* b = x + ind ( & ctx. mem , y, 2 + RAND_SIZE_LEN ) ;
178
- ctx. rsl [ base + m] = * b ;
183
+ ctx. rsl [ RAND_SIZE - 1 - base - m] = ( * b ) . 0 ;
179
184
}
180
185
181
186
let mut m = 0 ;
@@ -198,44 +203,50 @@ impl IsaacRng {
198
203
199
204
self . a = a;
200
205
self . b = b;
201
- self . cnt = RAND_SIZE as u32 ;
206
+ self . index = 0 ;
202
207
}
203
208
}
204
209
205
210
impl Rng for IsaacRng {
206
211
#[ inline]
207
212
fn next_u32 ( & mut self ) -> u32 {
208
- if self . cnt == 0 {
209
- // make some more numbers
213
+ // Using a local variable for `index`, and checking the size avoids a
214
+ // bounds check later on.
215
+ let mut index = self . index as usize ;
216
+ if index >= RAND_SIZE {
210
217
self . isaac ( ) ;
218
+ index = 0 ;
211
219
}
212
- self . cnt -= 1 ;
213
-
214
- // self.cnt is at most RAND_SIZE, but that is before the
215
- // subtraction above. We want to index without bounds
216
- // checking, but this could lead to incorrect code if someone
217
- // misrefactors, so we check, sometimes.
218
- //
219
- // (Changes here should be reflected in Isaac64Rng.next_u64.)
220
- debug_assert ! ( ( self . cnt as usize ) < RAND_SIZE ) ;
221
-
222
- // (the % is cheaply telling the optimiser that we're always
223
- // in bounds, without unsafe. NB. this is a power of two, so
224
- // it optimises to a bitwise mask).
225
- self . rsl [ self . cnt as usize % RAND_SIZE ] . 0
220
+
221
+ let value = self . rsl [ index] ;
222
+ self . index += 1 ;
223
+ value
226
224
}
227
225
226
+ #[ inline]
228
227
fn next_u64 ( & mut self ) -> u64 {
229
- :: rand_core :: impls:: next_u64_via_u32 ( self )
228
+ impls:: next_u64_via_u32 ( self )
230
229
}
231
230
232
231
#[ cfg( feature = "i128_support" ) ]
233
232
fn next_u128 ( & mut self ) -> u128 {
234
- :: rand_core :: impls:: next_u128_via_u64 ( self )
233
+ impls:: next_u128_via_u64 ( self )
235
234
}
236
235
237
236
fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
238
- :: rand_core:: impls:: fill_bytes_via_u32 ( self , dest) ;
237
+ let mut read_len = 0 ;
238
+ while read_len < dest. len ( ) {
239
+ if self . index as usize >= RAND_SIZE {
240
+ self . isaac ( ) ;
241
+ }
242
+
243
+ let ( consumed_u32, filled_u8) =
244
+ impls:: fill_via_u32_chunks ( & mut self . rsl [ ( self . index as usize ) ..] ,
245
+ & mut dest[ read_len..] ) ;
246
+
247
+ self . index += consumed_u32 as u32 ;
248
+ read_len += filled_u8;
249
+ }
239
250
}
240
251
241
252
fn try_fill ( & mut self , dest : & mut [ u8 ] ) -> Result < ( ) , Error > {
@@ -300,12 +311,12 @@ fn init(mut mem: [w32; RAND_SIZE], rounds: u32) -> IsaacRng {
300
311
}
301
312
302
313
let mut rng = IsaacRng {
303
- rsl : [ w ( 0 ) ; RAND_SIZE ] ,
314
+ rsl : [ 0 ; RAND_SIZE ] ,
304
315
mem : mem,
305
316
a : w ( 0 ) ,
306
317
b : w ( 0 ) ,
307
318
c : w ( 0 ) ,
308
- cnt : 0 ,
319
+ index : 0 ,
309
320
} ;
310
321
311
322
// Prepare the first set of results
0 commit comments