Class: Crypt::ISAAC

Inherits:
Object
  • Object
show all
Defined in:
lib/crypt/isaac/pure.rb,
ext/crypt/isaac/isaac.c

Overview

ISAAC is a fast, cryptographically secure pseudo-random number generator. Details on the algorithm can be found here: burtleburtle.net/bob/rand/isaac.html This provides a consistent and capable algorithm for producing independent streams of quality random numbers.

Constant Summary collapse

DEFAULT =
ISAAC.new

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(args) ⇒ ISAAC

Returns a new instance of ISAAC.



84
85
86
87
88
# File 'ext/crypt/isaac/isaac.c', line 84

def initialize(seed = true)
  @mm = []

  self.srand( seed )
end

Instance Attribute Details

#aaObject

Returns the value of attribute aa.



12
13
14
# File 'lib/crypt/isaac/pure.rb', line 12

def aa
  @aa
end

#bbObject

Returns the value of attribute bb.



12
13
14
# File 'lib/crypt/isaac/pure.rb', line 12

def bb
  @bb
end

#ccObject

Returns the value of attribute cc.



12
13
14
# File 'lib/crypt/isaac/pure.rb', line 12

def cc
  @cc
end

#mmObject

Returns the value of attribute mm.



12
13
14
# File 'lib/crypt/isaac/pure.rb', line 12

def mm
  @mm
end

#randcntObject

Returns the value of attribute randcnt.



11
12
13
# File 'lib/crypt/isaac/pure.rb', line 11

def randcnt
  @randcnt
end

#randrslObject

Returns the value of attribute randrsl.



11
12
13
# File 'lib/crypt/isaac/pure.rb', line 11

def randrsl
  @randrsl
end

Class Method Details

.new_seed(args) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'ext/crypt/isaac/isaac.c', line 8

def self.new_seed( seed = true )
  seed_array = Array.new( 256,  0)
  rnd_source = nil
  rnd_source = seed ? '/dev/urandom' : '/dev/random' if ( ( seed == true ) || ( seed == false ) )
  if ( seed.respond_to?(:each) )
    ( seed.length > 255 ? 256 : seed.length ).times {|s| seed_array[s] = seed[s] }
  elsif rnd_source && ( FileTest.exist? rnd_source )
    File.open( rnd_source, 'r' ) do |r|
      256.times do |t|
        z = r.read(4)
        x = z.unpack('V')[0]
        seed_array[t] = x
      end
    end
  else
    seed = nil if rnd_source

    if seed.respond_to?( :rand )
      seed_prng = seed
    else
      seed_prng = Crypt::Xorshift64Star.new( seed )
    end

    256.times do |t|
      seed_array[t] = seed_prng.rand(4294967296)
    end
  end
  seed_array
end

.rand(args) ⇒ Object

When a Crypt::ISAAC object is created, it needs to be seeded for random number generation. If the system has a /dev/urandom file, that will be used to do the seeding by default. If false is explictly passed when creating the object, it will instead use /dev/random to generate its seeds. Be warned that this may make for SLOW initialization - if there isn’t enough entropy in the system, reads from /dev/random will block while waiting for more entropy, causing initialization to wait, as well. If the requested source (/dev/urandom or /dev/random) do not exist, the system will fall back to a simplistic initialization mechanism using a pseudo-random number generator. By default, it will use an xorshift* generator, but anything that responds to #rand can be passed as a seed.



28
29
30
# File 'lib/crypt/isaac/pure.rb', line 28

def self.rand( arg = nil )
  DEFAULT.rand( arg )
end

.srand(args) ⇒ Object



146
147
148
# File 'ext/crypt/isaac/isaac.c', line 146

def self.srand( seed = true )
  DEFAULT.srand( seed )
end

Instance Method Details

#==(v) ⇒ Object



240
241
242
# File 'ext/crypt/isaac/isaac.c', line 240

def ==(gen)
  self.state == gen.state
end

#bytes(count) ⇒ Object



250
251
252
253
254
255
256
257
258
259
# File 'ext/crypt/isaac/isaac.c', line 250

def bytes(size)
  buffer = ""
  ( size / 4 ).times { buffer << [rand(4294967295)].pack("L").unpack("aaaa").join }

  if size % 4 != 0
    buffer << [rand(4294967295)].pack("L").unpack("aaaa")[0..(size % 4 - 1)].join
  end

  buffer
end

#initialize_copy(from) ⇒ Object



98
99
100
101
102
103
104
105
106
107
# File 'ext/crypt/isaac/isaac.c', line 98

def initialize_copy( from )
  @aa = from.aa
  @bb = from.bb
  @cc = from.cc
  @mm = from.mm.dup
  @randcnt = from.randcnt
  @randrsl = from.randrsl.dup

  self
end

#isaacObject



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/crypt/isaac/pure.rb', line 139

def isaac
  i = 0
  x = 0
  y = 0

  @cc += 1
  @bb += @cc
  @bb = @bb & 0xffffffff

  while (i < 256) do
    x = @mm[i]
    @aa = (@mm[(i + 128) & 255] + (@aa^(@aa << 13)) ) & 0xffffffff
    @mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
    @randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
    i += 1

    x = @mm[i]
    @aa = (@mm[(i+128)&255] + (@aa^(0x03ffffff & (@aa >> 6))) ) & 0xffffffff
    @mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
    @randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
    i += 1

    x = @mm[i]
    @aa = (@mm[(i + 128)&255] + (@aa^(@aa << 2)) ) & 0xffffffff
    @mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
    @randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
    i += 1

    x = @mm[i]
    @aa = (@mm[(i+128)&255] + (@aa^(0x0000ffff & (@aa >> 16))) ) & 0xffffffff
    @mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
    @randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
    i += 1
  end
end

#rand(args) ⇒ Object

Works just like the standard rand() function. If called with an integer argument, rand() will return positive random number in the range of 0 to (argument - 1). If called without an integer argument, rand() returns a positive floating point number less than 1. If called with a Range, returns a number that is in the range.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/crypt/isaac/pure.rb', line 99

def rand(arg = nil)
  if (@randcnt == 1)
    isaac
    @randcnt = 256
  end
  @randcnt -= 1
  if arg.nil?
    ( @randrsl[@randcnt] / 536870912.0 ) % 1
  elsif Integer === arg
    @randrsl[@randcnt] % arg
  elsif Range === arg
    arg.min + @randrsl[@randcnt] % (arg.max - arg.min)
  else
    @randrsl[@randcnt] % arg.to_i
  end
end

#randinit(flag) ⇒ Object



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/crypt/isaac/pure.rb', line 175

def randinit(flag)
  i = 0
  a = 0
  b = 0
  c = 0
  d = 0
  e = 0
  f = 0
  g = 0
  @aa = @bb = @cc = 0
  a = b = c = d = e = f = g = h = 0x9e3779b9

  while (i < 4) do
    a ^= b<<1; d += a; b += c
    b ^= 0x3fffffff & (c>>2); e += b; c += d
    c ^= d << 8; f += c; d += e
    d ^= 0x0000ffff & (e >> 16); g += d; e += f
    e ^= f << 10; h += e; f += g
    f ^= 0x0fffffff & (g >> 4); a += f; g += h
    g ^= h << 8; b += g; h += a
    h ^= 0x007fffff & (a >> 9); c += h; a += b
    i += 1
  end

  i = 0
  while (i < 256) do
    if (flag)
      a+=@randrsl[i  ].to_i; b+=@randrsl[i+1].to_i;
      c+=@randrsl[i+2]; d+=@randrsl[i+3];
      e+=@randrsl[i+4]; f+=@randrsl[i+5];
      g+=@randrsl[i+6]; h+=@randrsl[i+7];
    end

    a^=b<<11; d+=a; b+=c;
    b^=0x3fffffff & (c>>2);  e+=b; c+=d;
    c^=d<<8;  f+=c; d+=e;
    d^=0x0000ffff & (e>>16); g+=d; e+=f;
    e^=f<<10; h+=e; f+=g;
    f^=0x0fffffff & (g>>4);  a+=f; g+=h;
    g^=h<<8;  b+=g; h+=a;
    h^=0x007fffff & (a>>9);  c+=h; a+=b;
    @mm[i]=a;@mm[i+1]=b; @mm[i+2]=c; @mm[i+3]=d;
    @mm[i+4]=e; @mm[i+5]=f; @mm[i+6]=g; @mm[i+7]=h;
    i += 8
  end

  if flag
    i = 0
    while (i < 256)
      a+=@mm[i  ]; b+=@mm[i+1]; c+=@mm[i+2]; d+=@mm[i+3];
      e+=@mm[i+4]; f+=@mm[i+5]; g+=@mm[i+6]; h+=@mm[i+7];
      a^=b<<11; d+=a; b+=c;
      b^=0x3fffffff & (c>>2);  e+=b; c+=d;
      c^=d<<8;  f+=c; d+=e;
      d^=0x0000ffff & (e>>16); g+=d; e+=f;
      e^=f<<10; h+=e; f+=g;
      f^=0x0fffffff & (g>>4);  a+=f; g+=h;
      g^=h<<8;  b+=g; h+=a;
      h^=0x007fffff & (a>>9);  c+=h; a+=b;
      @mm[i  ]=a; @mm[i+1]=b; @mm[i+2]=c; @mm[i+3]=d;
      @mm[i+4]=e; @mm[i+5]=f; @mm[i+6]=g; @mm[i+7]=h;
      i += 8
    end
  end

  isaac()
  @randcnt=256;        # /* prepare to use the first set of results */
end

#seedObject



226
227
228
# File 'ext/crypt/isaac/isaac.c', line 226

def seed
  @seed
end

#srand(args) ⇒ Object

If seeded with an integer, use that to seed a standard Ruby Mersenne Twister PRNG, and then use that to generate seed value for ISAAC. This is mostly useful for producing repeated, deterministic results, which may be needed for testing.



86
87
88
89
90
91
# File 'lib/crypt/isaac/pure.rb', line 86

def srand(seed = true)
  @randrsl = self.class.new_seed( seed )
  @seed = @randrsl.dup
  randinit(true)
  @seed
end

#stateObject



120
121
122
# File 'lib/crypt/isaac/pure.rb', line 120

def state
  @randrsl + [@randcnt]
end