コンテンツにスキップ

Top

乱数生成時に使うシードを日時以外から取得する

乱数を発生させるrand関数のseedを設定するsrandには大抵の場合日時(time(NULL))とかを設定していると思うが、時間を保持しないエンベデッド機器などでは毎回同じ秒数(起動してから実行されるまでいつも同じ時間)になる場合が多いので、問題が生じる場合もある。

そんなとき、Linux系のOSだったら/dev/randomを使うことによって回避することができる。

(もっと確実に安全な乱数を作りたい場合、CSPRNGとかあるけどそんなの使うような仕事してないのでパス〜)

/dev/random

/dev/random は 主にハードウェアに発生するエントロピーを利用してランダムな値を生成する疑似デバイスである。

以下のようなシェルで値を取得できる。

1
2
$ od -An -tu2 -N2 /dev/random
 12963

上記は/dev/randomから2バイト分のデータをodコマンドで取得し10進数で表示したものである。見やすいようにアドレスを消している(-An)。

これでほぼ問題なく一意なシードを取得できるわけだが1点問題があり、/dev/randomはエントロピーが枯渇すると乱数を生成しなくなるのだ。

具体的には以下のシェルを動かしてみたらわかる。

1
2
3
4
5
while :
do
    od -An -tu2 -N2 /dev/random
    cat /proc/sys/kernel/random/entropy_avail
done

ばーっと乱数が出ていたのに途中から止まったり、スピードが遅くなったはずだ。
エントロピーがなくなったので乱数が作れなくなったのだ。

しかしながら、これを解決するために、 /dev/urandom という疑似デバイスがある。
urandomのuはunlock のuとのこと。

こちらはエントロピーを再利用する代わりに固まったりしない。
が、言い換えれば使いまわしている分、乱数の衝突が発生しやすい、ということだ。

どっちを使うかはケースバイケースと言える。

なお、上記でしれっと使った、

1
cat /proc/sys/kernel/random/entropy_avail

はエントロピープールの残量を示している。
これが0になると/dev/randomでは乱数を生成できなくなる。
ほっとくと勝手に増えるのだが(ハードウェア、例えばCPUなど、のノイズなどで増えていくので)
意図的に増やしたい場合は、 Haveged というデーモンプログラムがあるのでこれをインストールしてサービスとして動かしておけばエントロピーが増えやすくなる。

あと、エントロピープールの上限は、デフォルトで4096の場合が多い。

1
2
$ cat /proc/sys/kernel/random/poolsize
4096

増やしたりもできるみたいだがどちらにせよ使えば減るわけで、足りなくなって困るような使い方をするなら根本的に別の方法を検討したほうが良いかもしれない。

以上。