「乱数」の版間の差分
行145: | 行145: | ||
openssl_random_pseudo_bytes () の実態は、 '''RAND_pseudo_bytes''' () です。 | openssl_random_pseudo_bytes () の実態は、 '''RAND_pseudo_bytes''' () です。 | ||
RAND_pseudo_bytes() は、 OpenSSL の crypto/rand/rand_lib.c で実装されています。 RAND_pseudo_bytes は、 RAND_get_rand_method() でランダム関数を取得して、呼び出します。内部では、 ENGINE_get_default_RAND()とENGINE_get_RAND() でデフォルトの関数を取得します。デフォルトがなければ、 RAND_SSLeay()が使用されます。 | RAND_pseudo_bytes() は、 OpenSSL の crypto/rand/rand_lib.c で実装されています。 RAND_pseudo_bytes は、 RAND_get_rand_method() でランダム関数を取得して、呼び出します。内部では、 ENGINE_get_default_RAND()とENGINE_get_RAND() でデフォルトの関数を取得します。デフォルトがなければ、 RAND_SSLeay()が使用されます。 | ||
− | + | ENGINE_get_default_RANDは engine_table_selectで rand_tableからポインタを返します。 | |
==== rand ==== | ==== rand ==== | ||
レガシーな rand()のコードは、以下の通りです。 | レガシーな rand()のコードは、以下の通りです。 |
2018年3月14日 (水) 23:13時点における最新版
乱数 (random number)とは、ランダムな数列である乱数列の各要素のことです。C言語などでは、rand()関数を呼び出すことで乱数を得られます。OpenSSLコマンドで乱数データを生成したり、Unixでは、デバイスファイル random/urandom を読み出すことでも乱数データを得られます。
読み方
- 乱数
- らんすう
- random number
- らんだむ なんばー
目次
概要
乱数とは、出現する値に規則性のない数です。 コンピューターでは、必要な範囲内で乱数とみなす擬似乱数を用います。
真の乱数
「真の乱数」は、「サイコロを振った値」です。
「真の乱数」は、以下の条件が必要です。
- 偏りがない
- 規則性がない
- 再現性がない
一般的なサイコロは、1の目は大きな穴があいているなど、偏りが発生します。つまり「弱い乱数」です。カジノで使われる精密ダイス(プレシジョンダイス, Precision Dice)は、出目が限りなく均一で、重心が限りなく中央にあり、重さも均一になっています。
プログラミングにおける乱数
- C言語では、標準関数 rand() 関数を用いて乱数を生成できます。
- C++言語では、標準関数 rand() 関数を用いて乱数を生成できます。
- PHPは、メルセンヌツイスター法のmt_srand(), mt_rand()を使用します。srand(),rand()は、すでにレガシーです。
- PHPで暗号のための安全な乱数が必要であれば、openssl_random_pseudo_bytes()を使用します。
- UNIXでは、/dev/random, /dev/urandom のデバイスを読むこと乱数を得られます。
- OpenSSLコマンドを使用して乱数を生成できます。
- Rでは、randomパッケージを使用します。大気のノイズを観測して乱数を生成します。
- http://cran.stat.ucla.edu/web/packages/random/
- http://random.org/
- 擬似乱数を生成する runif() もあります。
C言語
rand()
/* * rand.c * Copyright (C) 2014 kaoru <kaoru@bsd> */ #include <stdio.h> #include <stdlib.h> #include <time.h> int main(int argc, char *argv[]) { srand( time(NULL) ); int r = rand (); printf ("%d\n", r); return 0; }
/dev/urandom
/dev/urandomを/dev/randomに変更すれば、/dev/randomから読み出します。
#include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <err.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <fcntl.h> #define DEV_RANDOM "/dev/urandom" #define BUF 256 int get_random (char * const buf, const int buflen, const int len) { if (len > buflen) { warnx ("buffer size is small (%d / %d)", buflen, len); return (-1); } int fd = open(DEV_RANDOM, O_RDONLY); if (fd == -1) { warn ("can not open %s", DEV_RANDOM); return (-1); } int r = read (fd, buf, len); if (r < 0) { warn ("can not read"); return (-1); } if (r != len) { warnx ("can not read(%d != %d)", r, len); return (-1); } (void) close (fd); return (0); }
PHP
mt_rand
rand()ではなく、mt_rand()を使用します。mt_rand()は、乱数生成器 Mersenne Twister を使用します。平均してlibcのrand()よりも4倍以上高速に乱数を生成できます。 srand()は、seedが必要でしたが、PHP4.2.0以降は、ランダム数生成器にシードが与える必要がなくなりました。
<?php mt_srand(); echo mt_rand() , PHP_EOL; ?>
5から15まで(両端を含む)の乱数を得るには、範囲を指定します。
<?php echo mt_rand(5, 15), PHP_EOL; ?>
PHP+OpenSSLモジュール
暗号のために安全な乱数データが欲しい場合には、openssl_random_pseudo_bytes()を使用します。PHPのopensslモジュールが必要になります。
10バイトの乱数が得たい場合、以下のコードになります。
<?php $data = openssl_random_pseudo_bytes(10); ?>
openssl_random_pseudo_bytes()は、バイト列を返すので、画面にエコーしたいなら16進数にします。
<?php /** * Short description for openssl_random_pseudo_bytes.php * * @package openssl_random_pseudo_bytes * @author kaoru <kaoru@bsd> * @copyright (C) 2014 kaoru <kaoru@bsd> */ $data = openssl_random_pseudo_bytes(20); echo bin2hex($data),PHP_EOL; ?>
上記のコードを実行すると、このようになります。
$ php openssl_random_pseudo_bytes.php b5b9801a5f00cd0f322e59268169982867a944ed
openssl_random_pseudo_bytes は PHP のソースコードの ext/openssl/openssl.c で実装されています。 openssl_random_pseudo_bytes () の実態は、 RAND_pseudo_bytes () です。 RAND_pseudo_bytes() は、 OpenSSL の crypto/rand/rand_lib.c で実装されています。 RAND_pseudo_bytes は、 RAND_get_rand_method() でランダム関数を取得して、呼び出します。内部では、 ENGINE_get_default_RAND()とENGINE_get_RAND() でデフォルトの関数を取得します。デフォルトがなければ、 RAND_SSLeay()が使用されます。 ENGINE_get_default_RANDは engine_table_selectで rand_tableからポインタを返します。
rand
レガシーな rand()のコードは、以下の通りです。
<?php srand(); echo rand() , PHP_EOL; echo rand(5, 15), PHP_EOL; ?>
OpenSSL コマンドによる乱数データの生成
OpenSSLコマンドを用いて、100バイトのデータを生成する例です。
openssl rand 100 -out /tmp/rand.100
dd コマンドとrandomデバイスによる乱数データの生成
1MBのファイルを作成する例です。
$ dd if=/dev/random of=urandom.dat count=1024 bs=1024
urandomの場合は、/dev/urandomを指定します。
$ dd if=/dev/urandom of=urandom.dat count=1024 bs=1024
擬似乱数生成アルゴリズム
- メルセンヌツイスター(mersenne twister)
- カオス乱数