|
|
module Crypt
# ISAAC is a fast, strong random number generator. Details on the
# algorithm can be found here: http://burtleburtle.net/bob/rand/isaac.html
# This provides a consistent and capable algorithm for producing
# independent streams of quality random numbers.
class ISAAC
attr_accessor :randrsl, :randcnt
attr_accessor :mm, :aa, :bb, :cc
# 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. If it does not, the system
# will fall back to a simplistic initialization mechanism.
def initialize
@mm = []
@randrsl = []
# Best initialization of the generator would be by pulling
# numbers from /dev/random.
if (FileTest.exist? '/dev/urandom')
File.open('/dev/urandom','r') do |r|
256.times do |t|
z = r.read(4)
x = z.unpack('V')[0]
@randrsl[t] = x
end
end
else
# If urandom isn't available, the standard Ruby PRNG makes an
# adequate fallback.
256.times do |t|
@randrsl[t] = Kernel.rand(2147483647)
end
end
randinit(true)
nil
end
# 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.
def rand(*num)
if (@randcnt == 1)
isaac
@randcnt = 256
end
@randcnt -= 1
if num[0].to_i > 0
@randrsl[@randcnt].modulo(num[0])
else
".#{@randrsl[@randcnt]}".to_f
end
end
def isaac
i = 0
x = 0
y = 0
@cc += 1
@bb += @cc
@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
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
end
end
|