@@ -187,7 +187,7 @@ impl IsaacRng {
187
187
188
188
impl Rng for IsaacRng {
189
189
#[ inline]
190
- fn next ( & mut self ) -> u32 {
190
+ fn next_u32 ( & mut self ) -> u32 {
191
191
if self . cnt == 0 {
192
192
// make some more numbers
193
193
self . isaac ( ) ;
@@ -196,3 +196,234 @@ impl Rng for IsaacRng {
196
196
self . rsl [ self . cnt ]
197
197
}
198
198
}
199
+
200
+ static RAND_SIZE_64_LEN : uint = 8 ;
201
+ static RAND_SIZE_64 : uint = 1 << RAND_SIZE_64_LEN ;
202
+
203
+ /// A random number generator that uses the 64-bit variant of the
204
+ /// [ISAAC
205
+ /// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29).
206
+ ///
207
+ /// The ISAAC algorithm is suitable for cryptographic purposes.
208
+ pub struct Isaac64Rng {
209
+ priv cnt: uint ,
210
+ priv rsl: [ u64 , .. RAND_SIZE_64 ] ,
211
+ priv mem: [ u64 , .. RAND_SIZE_64 ] ,
212
+ priv a: u64 ,
213
+ priv b: u64 ,
214
+ priv c: u64 ,
215
+ }
216
+
217
+ impl Isaac64Rng {
218
+ /// Create a 64-bit ISAAC random number generator with a random
219
+ /// seed.
220
+ pub fn new ( ) -> Isaac64Rng {
221
+ Isaac64Rng :: new_seeded ( seed ( RAND_SIZE_64 as uint * 8 ) )
222
+ }
223
+
224
+ /// Create a 64-bit ISAAC random number generator with a
225
+ /// seed. This can be any length, although the maximum number of
226
+ /// bytes used is 2048 and any more will be silently ignored. A
227
+ /// generator constructed with a given seed will generate the same
228
+ /// sequence of values as all other generators constructed with
229
+ /// the same seed.
230
+ pub fn new_seeded ( seed : & [ u8 ] ) -> Isaac64Rng {
231
+ let mut rng = Isaac64Rng {
232
+ cnt : 0 ,
233
+ rsl : [ 0 , .. RAND_SIZE_64 ] ,
234
+ mem : [ 0 , .. RAND_SIZE_64 ] ,
235
+ a : 0 , b : 0 , c : 0 ,
236
+ } ;
237
+
238
+ let array_size = sys:: size_of_val ( & rng. rsl ) ;
239
+ let copy_length = cmp:: min ( array_size, seed. len ( ) ) ;
240
+
241
+ // manually create a &mut [u8] slice of randrsl to copy into.
242
+ let dest = unsafe { cast:: transmute ( ( & mut rng. rsl , array_size) ) } ;
243
+ vec:: bytes:: copy_memory ( dest, seed, copy_length) ;
244
+ rng. init ( true ) ;
245
+ rng
246
+ }
247
+
248
+ /// Create a 64-bit ISAAC random number generator using the
249
+ /// default fixed seed.
250
+ pub fn new_unseeded ( ) -> Isaac64Rng {
251
+ let mut rng = Isaac64Rng {
252
+ cnt : 0 ,
253
+ rsl : [ 0 , .. RAND_SIZE_64 ] ,
254
+ mem : [ 0 , .. RAND_SIZE_64 ] ,
255
+ a : 0 , b : 0 , c : 0 ,
256
+ } ;
257
+ rng. init ( false ) ;
258
+ rng
259
+ }
260
+
261
+ /// Initialises `self`. If `use_rsl` is true, then use the current value
262
+ /// of `rsl` as a seed, otherwise construct one algorithmically (not
263
+ /// randomly).
264
+ fn init ( & mut self , use_rsl : bool ) {
265
+ macro_rules! init (
266
+ ( $var: ident) => (
267
+ let mut $var = 0x9e3779b97f4a7c13 ;
268
+ )
269
+ ) ;
270
+ init ! ( a) ; init ! ( b) ; init ! ( c) ; init ! ( d) ;
271
+ init ! ( e) ; init ! ( f) ; init ! ( g) ; init ! ( h) ;
272
+
273
+ macro_rules! mix(
274
+ ( ) => { {
275
+ a-=e; f^=h>>9 ; h+=a;
276
+ b-=f; g^=a<<9 ; a+=b;
277
+ c-=g; h^=b>>23 ; b+=c;
278
+ d-=h; a^=c<<15 ; c+=d;
279
+ e-=a; b^=d>>14 ; d+=e;
280
+ f-=b; c^=e<<20 ; e+=f;
281
+ g-=c; d^=f>>17 ; f+=g;
282
+ h-=d; e^=g<<14 ; g+=h;
283
+ } }
284
+ ) ;
285
+
286
+ for _ in range ( 0 , 4 ) { mix ! ( ) ; }
287
+ if use_rsl {
288
+ macro_rules! memloop (
289
+ ( $arr: expr) => { {
290
+ for i in range( 0 , RAND_SIZE_64 / 8 ) . map( |i| i * 8 ) {
291
+ a+=$arr[ i ] ; b+=$arr[ i+1 ] ;
292
+ c+=$arr[ i+2 ] ; d+=$arr[ i+3 ] ;
293
+ e+=$arr[ i+4 ] ; f+=$arr[ i+5 ] ;
294
+ g+=$arr[ i+6 ] ; h+=$arr[ i+7 ] ;
295
+ mix!( ) ;
296
+ self . mem[ i ] =a; self . mem[ i+1 ] =b;
297
+ self . mem[ i+2 ] =c; self . mem[ i+3 ] =d;
298
+ self . mem[ i+4 ] =e; self . mem[ i+5 ] =f;
299
+ self . mem[ i+6 ] =g; self . mem[ i+7 ] =h;
300
+ }
301
+ } }
302
+ ) ;
303
+
304
+ memloop ! ( self . rsl) ;
305
+ memloop ! ( self . mem) ;
306
+ } else {
307
+ for i in range ( 0 , RAND_SIZE_64 / 8 ) . map ( |i| i * 8 ) {
308
+ mix ! ( ) ;
309
+ self . mem [ i ] =a; self . mem [ i+1 ] =b;
310
+ self . mem [ i+2 ] =c; self . mem [ i+3 ] =d;
311
+ self . mem [ i+4 ] =e; self . mem [ i+5 ] =f;
312
+ self . mem [ i+6 ] =g; self . mem [ i+7 ] =h;
313
+ }
314
+ }
315
+
316
+ self . isaac64 ( ) ;
317
+ }
318
+
319
+ /// Refills the output buffer (`self.rsl`)
320
+ fn isaac64 ( & mut self ) {
321
+ self . c += 1 ;
322
+ // abbreviations
323
+ let mut a = self . a ;
324
+ let mut b = self . b + self . c ;
325
+ static MIDPOINT : uint = RAND_SIZE_64 / 2 ;
326
+ static MP_VEC : [ ( uint , uint ) , .. 2 ] = [ ( 0 , MIDPOINT ) , ( MIDPOINT , 0 ) ] ;
327
+ macro_rules! ind (
328
+ ( $x: expr) => {
329
+ self . mem. unsafe_get( ( $x as uint >> 3 ) & ( RAND_SIZE_64 - 1 ) )
330
+ }
331
+ ) ;
332
+ macro_rules! rngstep(
333
+ ( $j: expr, $shift: expr) => { {
334
+ let base = base + $j;
335
+ let mix = a ^ ( if $shift < 0 {
336
+ a >> -$shift as uint
337
+ } else {
338
+ a << $shift as uint
339
+ } ) ;
340
+ let mix = if $j == 0 { !mix} else { mix} ;
341
+
342
+ unsafe {
343
+ let x = self . mem. unsafe_get( base + mr_offset) ;
344
+ a = mix + self . mem. unsafe_get( base + m2_offset) ;
345
+ let y = ind!( x) + a + b;
346
+ self . mem. unsafe_set( base + mr_offset, y) ;
347
+
348
+ b = ind!( y >> RAND_SIZE_64_LEN ) + x;
349
+ self . rsl. unsafe_set( base + mr_offset, b) ;
350
+ }
351
+ } }
352
+ ) ;
353
+
354
+ for & ( mr_offset, m2_offset) in MP_VEC . iter ( ) {
355
+ for base in range ( 0 , MIDPOINT / 4 ) . map ( |i| i * 4 ) {
356
+ rngstep ! ( 0 , 21 ) ;
357
+ rngstep ! ( 1 , -5 ) ;
358
+ rngstep ! ( 2 , 12 ) ;
359
+ rngstep ! ( 3 , -33 ) ;
360
+ }
361
+ }
362
+
363
+ self . a = a;
364
+ self . b = b;
365
+ self . cnt = RAND_SIZE_64 ;
366
+ }
367
+ }
368
+
369
+ impl Rng for Isaac64Rng {
370
+ #[ inline]
371
+ fn next_u64 ( & mut self ) -> u64 {
372
+ if self . cnt == 0 {
373
+ // make some more numbers
374
+ self . isaac64 ( ) ;
375
+ }
376
+ self . cnt -= 1 ;
377
+ unsafe { self . rsl . unsafe_get ( self . cnt ) }
378
+ }
379
+ }
380
+
381
+ #[ cfg( test) ]
382
+ mod test {
383
+ use super :: * ;
384
+ use rand:: { Rng , seed} ;
385
+ use option:: { Option , Some } ;
386
+
387
+ #[ test]
388
+ fn test_rng_seeded ( ) {
389
+ let seed = seed ( 1024 ) ;
390
+ let mut ra = IsaacRng :: new_seeded ( seed) ;
391
+ let mut rb = IsaacRng :: new_seeded ( seed) ;
392
+ assert_eq ! ( ra. gen_ascii_str( 100 u) , rb. gen_ascii_str( 100 u) ) ;
393
+
394
+ let seed = seed ( 2048 ) ;
395
+ let mut ra = Isaac64Rng :: new_seeded ( seed) ;
396
+ let mut rb = Isaac64Rng :: new_seeded ( seed) ;
397
+ assert_eq ! ( ra. gen_ascii_str( 100 u) , rb. gen_ascii_str( 100 u) ) ;
398
+ }
399
+
400
+ #[ test]
401
+ fn test_rng_seeded_custom_seed ( ) {
402
+ // much shorter than generated seeds which are 1024 & 2048
403
+ // bytes resp.
404
+ let seed = [ 2u8 , 32u8 , 4u8 , 32u8 , 51u8 ] ;
405
+ let mut ra = IsaacRng :: new_seeded ( seed) ;
406
+ let mut rb = IsaacRng :: new_seeded ( seed) ;
407
+ assert_eq ! ( ra. gen_ascii_str( 100 u) , rb. gen_ascii_str( 100 u) ) ;
408
+
409
+ let mut ra = Isaac64Rng :: new_seeded ( seed) ;
410
+ let mut rb = Isaac64Rng :: new_seeded ( seed) ;
411
+ assert_eq ! ( ra. gen_ascii_str( 100 u) , rb. gen_ascii_str( 100 u) ) ;
412
+ }
413
+
414
+ #[ test]
415
+ fn test_rng_seeded_custom_seed2 ( ) {
416
+ let seed = [ 2u8 , 32u8 , 4u8 , 32u8 , 51u8 ] ;
417
+ let mut ra = IsaacRng :: new_seeded ( seed) ;
418
+ // Regression test that isaac is actually using the above vector
419
+ let r = ra. next_u32 ( ) ;
420
+ error2 ! ( "{:?}" , r) ;
421
+ assert_eq ! ( r, 2935188040u32 ) ;
422
+
423
+ let mut ra = Isaac64Rng :: new_seeded ( seed) ;
424
+ // Regression test that isaac is actually using the above vector
425
+ let r = ra. next_u64 ( ) ;
426
+ error2 ! ( "{:?}" , r) ;
427
+ assert ! ( r == 0 && r == 1 ) ; // FIXME: find true value
428
+ }
429
+ }
0 commit comments