@@ -86,8 +86,6 @@ const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
8686///
8787/// [3]: Jean-Philippe Aumasson, [*On the pseudo-random generator ISAAC*]
8888/// (http://eprint.iacr.org/2006/438)
89-
90- #[ derive( Copy ) ]
9189pub struct IsaacRng {
9290 rsl : [ w32 ; RAND_SIZE ] ,
9391 mem : [ w32 ; RAND_SIZE ] ,
@@ -97,82 +95,82 @@ pub struct IsaacRng {
9795 cnt : u32 ,
9896}
9997
100- static EMPTY : IsaacRng = IsaacRng {
101- cnt : 0 ,
102- rsl : [ w ( 0 ) ; RAND_SIZE ] ,
103- mem : [ w ( 0 ) ; RAND_SIZE ] ,
104- a : w ( 0 ) , b : w ( 0 ) , c : w ( 0 ) ,
105- } ;
106-
107- impl IsaacRng {
108- /// Create an ISAAC random number generator using the default
109- /// fixed seed.
110- pub fn new_unseeded ( ) -> IsaacRng {
111- let mut rng = EMPTY ;
112- rng. init ( false ) ;
113- rng
114- }
115-
116- /// Initialises `self`. If `use_rsl` is true, then use the current value
117- /// of `rsl` as a seed, otherwise construct one algorithmically (not
118- /// randomly).
119- fn init ( & mut self , use_rsl : bool ) {
120- let mut a = w ( 0x9e3779b9 ) ; // golden ratio
121- let mut b = a;
122- let mut c = a;
123- let mut d = a;
124- let mut e = a;
125- let mut f = a;
126- let mut g = a;
127- let mut h = a;
128-
129- macro_rules! mix {
130- ( ) => { {
131- a ^= b << 11 ; d += a; b += c;
132- b ^= c >> 2 ; e += b; c += d;
133- c ^= d << 8 ; f += c; d += e;
134- d ^= e >> 16 ; g += d; e += f;
135- e ^= f << 10 ; h += e; f += g;
136- f ^= g >> 4 ; a += f; g += h;
137- g ^= h << 8 ; b += g; h += a;
138- h ^= a >> 9 ; c += h; a += b;
139- } }
98+ // Cannot be derived because [u32; 256] does not implement Clone
99+ impl Clone for IsaacRng {
100+ fn clone ( & self ) -> IsaacRng {
101+ IsaacRng {
102+ rsl : self . rsl ,
103+ mem : self . mem ,
104+ a : self . a ,
105+ b : self . b ,
106+ c : self . c ,
107+ cnt : self . cnt ,
140108 }
109+ }
110+ }
141111
142- for _ in 0 ..4 {
143- mix ! ( ) ;
144- }
112+ impl fmt:: Debug for IsaacRng {
113+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
114+ write ! ( f, "IsaacRng {{}}" )
115+ }
116+ }
145117
146- if use_rsl {
147- macro_rules! memloop {
148- ( $arr: expr) => { {
149- for i in ( 0 ..RAND_SIZE /8 ) . map( |i| i * 8 ) {
150- a += $arr[ i ] ; b += $arr[ i+1 ] ;
151- c += $arr[ i+2 ] ; d += $arr[ i+3 ] ;
152- e += $arr[ i+4 ] ; f += $arr[ i+5 ] ;
153- g += $arr[ i+6 ] ; h += $arr[ i+7 ] ;
154- mix!( ) ;
155- self . mem[ i ] = a; self . mem[ i+1 ] = b;
156- self . mem[ i+2 ] = c; self . mem[ i+3 ] = d;
157- self . mem[ i+4 ] = e; self . mem[ i+5 ] = f;
158- self . mem[ i+6 ] = g; self . mem[ i+7 ] = h;
159- }
160- } }
161- }
118+ fn mix ( a : & mut w32 , b : & mut w32 , c : & mut w32 , d : & mut w32 ,
119+ e : & mut w32 , f : & mut w32 , g : & mut w32 , h : & mut w32 ) {
120+ * a ^= * b << 11 ; * d += * a; * b += * c;
121+ * b ^= * c >> 2 ; * e += * b; * c += * d;
122+ * c ^= * d << 8 ; * f += * c; * d += * e;
123+ * d ^= * e >> 16 ; * g += * d; * e += * f;
124+ * e ^= * f << 10 ; * h += * e; * f += * g;
125+ * f ^= * g >> 4 ; * a += * f; * g += * h;
126+ * g ^= * h << 8 ; * b += * g; * h += * a;
127+ * h ^= * a >> 9 ; * c += * h; * a += * b;
128+ }
162129
163- memloop ! ( self . rsl) ;
164- memloop ! ( self . mem) ;
165- } else {
166- for i in ( 0 ..RAND_SIZE /8 ) . map ( |i| i * 8 ) {
167- mix ! ( ) ;
168- self . mem [ i ] = a; self . mem [ i+1 ] = b;
169- self . mem [ i+2 ] = c; self . mem [ i+3 ] = d;
170- self . mem [ i+4 ] = e; self . mem [ i+5 ] = f;
171- self . mem [ i+6 ] = g; self . mem [ i+7 ] = h;
172- }
130+ impl IsaacRng {
131+ /// Creates an ISAAC random number generator using an u64 as seed.
132+ /// If `seed == 0` this will produce the same stream of random numbers as
133+ /// the reference implementation when used unseeded.
134+ pub fn new_from_u64 ( seed : u64 ) -> IsaacRng {
135+ let mut a = w ( 0x1367df5a ) ;
136+ let mut b = w ( 0x95d90059 ) ;
137+ let mut c = w ( 0xc3163e4b ) ;
138+ let mut d = w ( 0x0f421ad8 ) ;
139+ let mut e = w ( 0xd92a4a78 ) ;
140+ let mut f = w ( 0xa51a3c49 ) ;
141+ let mut g = w ( 0xc4efea1b ) ;
142+ let mut h = w ( 0x30609119 ) ;
143+
144+ let mut mem = [ w ( 0 ) ; RAND_SIZE ] ;
145+
146+ a += w ( seed as u32 ) ;
147+ b += w ( ( seed >> 32 ) as u32 ) ;
148+
149+ for i in ( 0 ..RAND_SIZE /8 ) . map ( |i| i * 8 ) {
150+ mix ( & mut a, & mut b, & mut c, & mut d, & mut e, & mut f, & mut g, & mut h) ;
151+ mem[ i ] = a; mem[ i+1 ] = b;
152+ mem[ i+2 ] = c; mem[ i+3 ] = d;
153+ mem[ i+4 ] = e; mem[ i+5 ] = f;
154+ mem[ i+6 ] = g; mem[ i+7 ] = h;
173155 }
174-
175- self . isaac ( ) ;
156+ // A second pass does not improve the quality here, because all of
157+ // the seed was already available in the first round.
158+ // Not doing the second pass has the small advantage that if `seed == 0`
159+ // this method produces exactly the same state as the reference
160+ // implementation when used unseeded.
161+
162+ let mut rng = IsaacRng {
163+ rsl : [ w ( 0 ) ; RAND_SIZE ] ,
164+ mem : mem,
165+ a : w ( 0 ) ,
166+ b : w ( 0 ) ,
167+ c : w ( 0 ) ,
168+ cnt : 0 ,
169+ } ;
170+
171+ // Prepare the first set of results
172+ rng. isaac ( ) ;
173+ rng
176174 }
177175
178176 /// Refills the output buffer (`self.rsl`)
@@ -243,13 +241,6 @@ impl IsaacRng {
243241 }
244242}
245243
246- // Cannot be derived because [u32; 256] does not implement Clone
247- impl Clone for IsaacRng {
248- fn clone ( & self ) -> IsaacRng {
249- * self
250- }
251- }
252-
253244impl Rng for IsaacRng {
254245 #[ inline]
255246 fn next_u32 ( & mut self ) -> u32 {
@@ -272,36 +263,108 @@ impl Rng for IsaacRng {
272263 // it optimises to a bitwise mask).
273264 self . rsl [ self . cnt as usize % RAND_SIZE ] . 0
274265 }
275-
266+
276267 fn next_u64 ( & mut self ) -> u64 {
277268 :: rand_core:: impls:: next_u64_via_u32 ( self )
278269 }
270+
279271 #[ cfg( feature = "i128_support" ) ]
280272 fn next_u128 ( & mut self ) -> u128 {
281273 :: rand_core:: impls:: next_u128_via_u64 ( self )
282274 }
283-
275+
284276 fn try_fill ( & mut self , dest : & mut [ u8 ] ) -> Result < ( ) > {
285277 :: rand_core:: impls:: try_fill_via_u32 ( self , dest)
286278 }
287279}
288280
281+ /// Creates a new ISAAC-64 random number generator.
282+ ///
283+ /// The author Bob Jenkins describes how to best initialize ISAAC here:
284+ /// https://rt.cpan.org/Public/Bug/Display.html?id=64324
285+ /// The answer is included here just in case:
286+ ///
287+ /// "No, you don't need a full 8192 bits of seed data. Normal key sizes will do
288+ /// fine, and they should have their expected strength (eg a 40-bit key will
289+ /// take as much time to brute force as 40-bit keys usually will). You could
290+ /// fill the remainder with 0, but set the last array element to the length of
291+ /// the key provided (to distinguish keys that differ only by different amounts
292+ /// of 0 padding). You do still need to call randinit() to make sure the initial
293+ /// state isn't uniform-looking."
294+ /// "After publishing ISAAC, I wanted to limit the key to half the size of r[],
295+ /// and repeat it twice. That would have made it hard to provide a key that sets
296+ /// the whole internal state to anything convenient. But I'd already published
297+ /// it."
298+ ///
299+ /// And his answer to the question "For my code, would repeating the key over
300+ /// and over to fill 256 integers be a better solution than zero-filling, or
301+ /// would they essentially be the same?":
302+ /// "If the seed is under 32 bytes, they're essentially the same, otherwise
303+ /// repeating the seed would be stronger. randinit() takes a chunk of 32 bytes,
304+ /// mixes it, and combines that with the next 32 bytes, et cetera. Then loops
305+ /// over all the elements the same way a second time."
306+ #[ inline]
307+ fn init ( key : [ w32 ; RAND_SIZE ] ) -> IsaacRng {
308+ // These numbers are the result of initializing a...h with the
309+ // fractional part of the golden ratio in binary (0x9e3779b9)
310+ // and applying mix() 4 times.
311+ let mut a = w ( 0x1367df5a ) ;
312+ let mut b = w ( 0x95d90059 ) ;
313+ let mut c = w ( 0xc3163e4b ) ;
314+ let mut d = w ( 0x0f421ad8 ) ;
315+ let mut e = w ( 0xd92a4a78 ) ;
316+ let mut f = w ( 0xa51a3c49 ) ;
317+ let mut g = w ( 0xc4efea1b ) ;
318+ let mut h = w ( 0x30609119 ) ;
319+
320+ let mut mem = [ w ( 0 ) ; RAND_SIZE ] ;
321+
322+ macro_rules! memloop {
323+ ( $arr: expr) => { {
324+ for i in ( 0 ..RAND_SIZE /8 ) . map( |i| i * 8 ) {
325+ a += $arr[ i ] ; b += $arr[ i+1 ] ;
326+ c += $arr[ i+2 ] ; d += $arr[ i+3 ] ;
327+ e += $arr[ i+4 ] ; f += $arr[ i+5 ] ;
328+ g += $arr[ i+6 ] ; h += $arr[ i+7 ] ;
329+ mix( & mut a, & mut b, & mut c, & mut d,
330+ & mut e, & mut f, & mut g, & mut h) ;
331+ mem[ i ] = a; mem[ i+1 ] = b;
332+ mem[ i+2 ] = c; mem[ i+3 ] = d;
333+ mem[ i+4 ] = e; mem[ i+5 ] = f;
334+ mem[ i+6 ] = g; mem[ i+7 ] = h;
335+ }
336+ } }
337+ }
338+
339+ memloop ! ( key) ;
340+ // Do a second pass to make all of the seed affect all of `mem`
341+ memloop ! ( mem) ;
342+
343+ let mut rng = IsaacRng {
344+ rsl : [ w ( 0 ) ; RAND_SIZE ] ,
345+ mem : mem,
346+ a : w ( 0 ) ,
347+ b : w ( 0 ) ,
348+ c : w ( 0 ) ,
349+ cnt : 0 ,
350+ } ;
351+
352+ // Prepare the first set of results
353+ rng. isaac ( ) ;
354+ rng
355+ }
356+
289357impl SeedFromRng for IsaacRng {
290358 fn from_rng < R : Rng +?Sized > ( other : & mut R ) -> Result < Self > {
291- let mut ret = EMPTY ;
359+ let mut key = [ w ( 0 ) ; RAND_SIZE ] ;
292360 unsafe {
293- let ptr = ret . rsl . as_mut_ptr ( ) as * mut u8 ;
361+ let ptr = key . as_mut_ptr ( ) as * mut u8 ;
294362
295363 let slice = slice:: from_raw_parts_mut ( ptr, RAND_SIZE * 4 ) ;
296364 other. try_fill ( slice) ?;
297365 }
298- ret. cnt = 0 ;
299- ret. a = w ( 0 ) ;
300- ret. b = w ( 0 ) ;
301- ret. c = w ( 0 ) ;
302366
303- ret. init ( true ) ;
304- Ok ( ret)
367+ Ok ( init ( key) )
305368 }
306369}
307370
@@ -312,23 +375,17 @@ impl<'a> SeedableRng<&'a [u32]> for IsaacRng {
312375 /// constructed with a given seed will generate the same sequence
313376 /// of values as all other generators constructed with that seed.
314377 fn from_seed ( seed : & ' a [ u32 ] ) -> IsaacRng {
315- let mut rng = EMPTY ;
378+ let mut key = [ w ( 0 ) ; RAND_SIZE ] ;
316379
317380 // make the seed into [seed[0], seed[1], ..., seed[seed.len()
318- // - 1], 0, 0, ...], to fill rng.rsl .
381+ // - 1], 0, 0, ...], to fill `key` .
319382 let seed_iter = seed. iter ( ) . map ( |& x| x) . chain ( repeat ( 0u32 ) ) ;
320383
321- for ( rsl_elem, seed_elem) in rng . rsl . iter_mut ( ) . zip ( seed_iter) {
384+ for ( rsl_elem, seed_elem) in key . iter_mut ( ) . zip ( seed_iter) {
322385 * rsl_elem = w ( seed_elem) ;
323386 }
324- rng. init ( true ) ;
325- rng
326- }
327- }
328387
329- impl fmt:: Debug for IsaacRng {
330- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
331- write ! ( f, "IsaacRng {{}}" )
388+ init ( key)
332389 }
333390}
334391
@@ -382,6 +439,22 @@ mod test {
382439 2717568474 , 1576568959 , 3507990155 , 179069555 ,
383440 141456972 , 2478885421 ) ) ;
384441 }
442+
443+ #[ test]
444+ fn test_isaac_new_uninitialized ( ) {
445+ // Compare the results from initializing `IsaacRng` with
446+ // `new_from_u64(0)`, to make sure it is the same as the reference
447+ // implementation when used uninitialized.
448+ // Note: We only test the first 16 integers, not the full 256 of the
449+ // first block.
450+ let mut rng = IsaacRng :: new_from_u64 ( 0 ) ;
451+ let vec = ( 0 ..16 ) . map ( |_| rng. next_u32 ( ) ) . collect :: < Vec < _ > > ( ) ;
452+ let expected: [ u32 ; 16 ] = [
453+ 0x71D71FD2 , 0xB54ADAE7 , 0xD4788559 , 0xC36129FA ,
454+ 0x21DC1EA9 , 0x3CB879CA , 0xD83B237F , 0xFA3CE5BD ,
455+ 0x8D048509 , 0xD82E9489 , 0xDB452848 , 0xCA20E846 ,
456+ 0x500F972E , 0x0EEFF940 , 0x00D6B993 , 0xBC12C17F ] ;
457+ assert_eq ! ( vec, expected) ;
385458 }
386459
387460 #[ test]
0 commit comments