Javaで乱数を生成する(2)

Javaで乱数を生成する」というタイトルだが、生成できるのは疑似乱数だ。今日は「Javaで乱数を生成する(1)」で説明した「疑似乱数生成器がどのように疑似乱数を生成するのか」について、Javaではどのように実装すればよいか説明する。


Javaでは、疑似乱数生成器として“java.util.Random”と“java.security.SecureRandom”が用意されている(SecureRandomクラスはRandomクラスのサブクラス)。
Randomクラスは、線形合同法*1を用いており、出力された値から内部状態が推測可能(次に出力される値が推測可能)な疑似乱数生成器である。なので、セキュリティ用途では使えない。
SecureRandomクラスは、内部でハッシュ演算を行っており、出力された値から内部状態が推測困難な疑似乱数生成器である。セキュリティ用途では、こちらを用いなければならない。


後は、推測困難なシードを用いて、疑似乱数生成器を初期化すればよい。
例えば、128バイトの疑似乱数を“2つだけ”得たい場合には、次のように実装すればよい。

    // 推測困難なシードを用意する。
    byte[] seed = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        /* (途中略) */
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
    };
    // シードを用いて、疑似乱数生成器を初期化する。
    Random prng = new SecureRandom(seed);
    
    // 疑似乱数を生成する。
    byte[] results1 = new byte[128];
    prng.nextBytes(results1);
    
    // 疑似乱数を生成する。
    byte[] results2 = new byte[128];
    prng.nextBytes(results2);

なるほど。
しかし、このプログラムは、全くもって実用的ではない。このプログラムを2回実行すると、2回とも同じ疑似乱数が得られるからだ*2。では、実際には、どのように疑似乱数を生成すればよいのだろうか?
私は、難しいことはわからないので、Apache Tomcatに教えてもらおうと思う。
(つづく)

*1:n番目の疑似乱数 x(n) を“x(n) = { a*x(n-1) + b } mod c”により求める方法(a、b、cは定数)。要は、ax + b を c で割った余りを求めるだけ。

*2:科学計算などでは、わざと同じ疑似乱数列を生成させたいことがあるかもしれないが。