Blog

乱数と Perl5 にかんする蘊蓄の話

Perlの乱数についてIRCで盛り上がったのでまとめておく。

結論からいうと、srand()はPerl5組み込みのものでよい。乱数の生成はMath::Random::MTがよいとおもう。
Perlのrand()の実装はConfigure時に選べるようだが*1、ふつうはdrand48()がつかわれる。これは下位ビットがまったくランダムでないことで知られるrand(3)よりはましだが、しょせん線形合同法なのでセッションIDなどを作るのには安全ではない。安全な乱数を作るためにtime()やSHA1を混ぜ込んだりするほうほうもよくつかわれるが、そのくらいならはじめからM::R::MTを使ったほうがいいとおもう。
なお、srand()はあれば/dev/urandomを読むので、自前でsrand(time)などとするのはよくない。また、最初にrand()を呼ぶときに自動的に呼ばれるので、ふつうは明示的によぶひつようすらない。ただし、どこかでrand()してからfork(2)をすると、サブプロセスで乱数系列がすべておなじになってしまうので注意がひつようである。

id:kazuho++ id:sfujiwara++

参考文献:

【追記】
セキュリティ的なアレだったらだまって openssl の prng つかっとけや!というお話。

あと、akr さんのこのエントリもおもしろい。
https://www.codeblog.org/blog/akr/20060127.html

13:45 tokuhirom: なんでこんなことやってるかというと
13:45 tokuhirom: Math::Random::MT を僕もつかってるからです!
13:45 gfx: ほー。
13:45 gfx: どういうときに使うの?
13:45 tokuhirom: 乱数をつくりたいとき
13:46 gfx: nrhd
13:46 gfx: ってそれくらいわかるよ!(>_<)
13:46 kazuho____: wwwwww
13:46 tokuhirom: www
13:46 lestrrat: ふいた
13:46 tokuhirom: rand() って
13:46 tokuhirom: あんまり良質じゃないから
13:46 tokuhirom: MT の方がいいよねーという
13:47 tokuhirom: おはなし
13:47 gfx: いや、そうなんだろけど、そこまでクリティカルな乱数がひつよなケースって何かなーと。
13:47 gfx: NDAくさいね!
13:47 tokuhirom: いや、たとえば
13:47 tokuhirom: ゲームとかだったら MT をとりあえずつかっとけや
13:47 tokuhirom: ってじいちゃんがいってた
13:47 gfx: あーなるほど。
13:48 gfx: ふむー。
13:48 kazuho____: MT と openssl の prng があれば後はいらないなー
13:49 tokuhirom: rand(3) は下位ビットが
13:49 tokuhirom: 1 と 0 が交互にでる
13:49 tokuhirom: とかなんとか
13:49 tokuhirom: random(3) だったかもw
13:50 gfx: あ、3はman pageの3か。
13:50 tokuhirom: w
13:50 kazuho____: random(3) はもうちょっとマトモだったような
13:50 kazuho____: rand(3) がひどい
13:50 gfx: でも今のPerlはrand(3)じゃないですよね?
13:52 kazuho____: http://wellington.pm.org/archive/200704/randomness/index.html#slide0
13:52 tokuhirom: drand48 かな
13:52 tokuhirom: ていうか乱数生成ルーチンはさしかえ可能だった
13:53 tokuhirom: ./Configure で random() と rand() と drand48() が
13:53 tokuhirom: えらべる
13:53 gfx: あとで読む!
13:54 kazuho____: > By default perl's rand is defined in C as: sub rand { my $top = shift || 1.0; $top * (libc_rand() & 32767) / 32768; } perl carefully discards the good bits.
13:54 kazuho____: コーヒーフイタ
13:54 gfx: えーw
13:54 gfx: いつのPerlですかw
13:54 kazuho____: これ2007年の資料だよ
13:54 tokuhirom: 嘘だとおもうけど
13:54 gfx: そんな変な実装じゃなかったと思うけど
13:55 tokuhirom: drand48() を
13:55 tokuhirom: よんでるだけですよ
13:55 gfx: うん。
13:55 kazuho____: drand48 の話も出て来る
13:55 gfx: ってかalgorithm変えられるのしらなかった。drand48()とあるから。
13:56 kazuho____: まあいずれにせよ LCG だからうんぬん、って話ですよね
13:58 tokuhirom: > ある乱数が得られたら、 次に現れる乱数が限られてしまうこと
13:58 tokuhirom: が最大の問題なのかな
13:58 tokuhirom: drand48() は、ある値がでたら、次の値が確実にわかるらしい
13:58 gfx: へー!
13:58 gfx: それはおそろしい。
13:59 tokuhirom: セキュリティ的な用途につかう乱数とかだと問題になるのかな
13:59 tokuhirom: しらんけど
13:59 gfx: いや擬似乱数はむしろそのほうがいいのかな。
13:59 kazuho____: http://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E5%90%88%E5%90%8C%E6%B3%95 のあたり読むといいよ
13:59 tokuhirom: セキュリティ的なやつは openssl のやつつかっとけばいいんだろうけど
14:00 kazuho____: セキュリティ的にはありえないすねー
14:00 gfx: hm
14:00 kazuho____: いったん暗号通信やったら、次の鍵が予測できるとかw
14:00 tokuhirom: www
14:01 kazuho____: 俺の次に発行されるセッションIDが予測できるとか
14:01 gfx: w
14:01 tokuhirom: w
14:02 tokuhirom: たいがいのウェブアプリケーションはくみこみの rand() つかってるけど
14:02 tokuhirom: time() くっつけて sha1 かけるとかやってる
14:02 kazuho____: Time::HiRes とか使ってればまだいいんだけど...
14:03 kazuho____: 数年前の LAMPP がやばかった記憶
14:03 gfx: そんなことするくらいなら最初からMT使えよって話か
14:03 tokuhirom: HTTP::Session は sha1_hex(rand() . Time::HiRes::gettimeofday())
14:03 tokuhirom: だった
14:03 tokuhirom: で、まあ rand() なり drand48() なり random() なりには
14:04 tokuhirom: それぞれいろいろ問題があるので
14:04 tokuhirom: それぞれどれがどうだったかおぼえたりするのだるいから
14:04 kazuho____: srand 系の問題もありますしね
14:04 tokuhirom: 馬鹿の一つおぼえで MT つかっとく!
14:04 kazuho____: それか /dev/srandom 読む。
14:04 tokuhirom: ah
14:05 tokuhirom: /dev/srandom って移植性がひくいから
14:06 tokuhirom: という理由でつかったことがないすな
14:06 kazuho____: じゃあ seeding どうしてるの?
14:06 tokuhirom: seeding は
14:06 tokuhirom: てきとうです!
14:06 kazuho____: CGI で使えねーw
14:06 tokuhirom: time() くわせてるのかな。たぶん
14:07 kazuho____: if (-e '/dev/urandom') { ... } とかが Math::Random::MT に入ってるとみんなハッピーになるんじゃないか
14:09 tokuhirom: ah
14:09 tokuhirom: なんかそこまでいくと
14:09 tokuhirom: Math::Random::MT じゃなくて
14:09 tokuhirom: Math::Random::Seed とか
14:10 tokuhirom: そういうかんじ
14:10 kazuho____: www
14:11 kazuho____: なんかそこまで言うなら seeder = rng だから seed ですらないよねみたいなw
14:11 tokuhirom: ちなみに
14:11 tokuhirom: perl5 の srand() は
14:12 tokuhirom: /dev/urandom よんでますね
14:12 kazuho____: oo
14:12 tokuhirom: だから srand(time()) とかかく必要ないし
14:12 kazuho____: あーそういう議論ありましたね
14:12 tokuhirom: srand(time()) とかよぶとかえってよくないw
14:13 tokuhirom: rand() を初回よぶときに自動で srand() よばれるし
14:13 tokuhirom: という話っぽい

*1:perl -V:randfunc でかくにんできる