乱数と 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)をすると、サブプロセスで乱数系列がすべておなじになってしまうので注意がひつようである。
参考文献:
- http://wellington.pm.org/archive/200704/randomness/index.html#slide0
- Perl_seed()@util.c, pp_rand()@pp.c
【追記】
セキュリティ的なアレだったらだまって 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 でかくにんできる