kuboon
3/27/2019 - 5:03 PM

sakai_csprng.rb

require "set"

N=32
srand ARGV[0]&.to_i

class P < Array
  def self.rand
    new(N.times.to_a.shuffle)
  end
  def *(o)
    case o
    when Array
      P.new(self.map{|a| o[a]})
    when Integer
      o_bin = "%0#{N}b" % o
      (self * o_bin.chars).join.to_i(2)
    end
  end
  def !
    @inv ||= P.new(self.map.with_index.sort_by{|i,v| i}.map{|i,v| v})
  end
end

def bytes(r)
  (N/8).times.map do
    r,a = [r>>8, r & 0xff]
    a.chr
  end
end

def prng
  x = P.rand
  y = P.rand
  r = rand(2**N)
  Enumerator.new do |out|
    loop do
      out << r ^= y * r
      y = x*y*!x
    end
  end
end

s=Set.new
open("rand.dat", "wb") do |f|
  prng.lazy.take(100).each do |r|
    if s && !s.add?(r)
      puts s.length
      s = nil
    end
    f.write bytes(r)
  end
end