「乱数」の版間の差分
(同じ利用者による、間の5版が非表示) | |||
行1: | 行1: | ||
− | [[乱数]] (random number)とは、ランダムな数列である[[乱数列]] | + | [[乱数]] (random number)とは、ランダムな数列である[[乱数列]]の各要素のことです。C言語などでは、rand()関数を呼び出すことで乱数を得られます。[[OpenSSL]]コマンドで乱数データを生成したり、Unixでは、デバイスファイル random/urandom を読み出すことでも乱数データを得られます。 |
'''読み方''' | '''読み方''' | ||
行9: | 行9: | ||
[[乱数]]とは、出現する値に規則性のない数です。 | [[乱数]]とは、出現する値に規則性のない数です。 | ||
コンピューターでは、必要な範囲内で[[乱数]]とみなす[[擬似乱数]]を用います。 | コンピューターでは、必要な範囲内で[[乱数]]とみなす[[擬似乱数]]を用います。 | ||
+ | |||
+ | [[乱数]]は、[[秘密鍵]]([[プライベート鍵]])の作成に利用されます。 | ||
+ | == 真の乱数 == | ||
+ | 「真の乱数」は、「サイコロを振った値」です。 | ||
+ | |||
+ | 「真の乱数」は、以下の条件が必要です。 | ||
+ | * 偏りがない | ||
+ | * 規則性がない | ||
+ | * 再現性がない | ||
+ | |||
+ | 一般的なサイコロは、1の目は大きな穴があいているなど、偏りが発生します。つまり「弱い乱数」です。カジノで使われる精密ダイス(プレシジョンダイス, Precision Dice)は、出目が限りなく均一で、重心が限りなく中央にあり、重さも均一になっています。 | ||
+ | |||
== プログラミングにおける乱数 == | == プログラミングにおける乱数 == | ||
* C言語では、標準関数 rand() 関数を用いて乱数を生成できます。 | * C言語では、標準関数 rand() 関数を用いて乱数を生成できます。 | ||
* C++言語では、標準関数 rand() 関数を用いて乱数を生成できます。 | * C++言語では、標準関数 rand() 関数を用いて乱数を生成できます。 | ||
+ | * PHPは、メルセンヌツイスター法のmt_srand(), mt_rand()を使用します。srand(),rand()は、すでにレガシーです。 | ||
+ | * PHPで暗号のための安全な乱数が必要であれば、openssl_random_pseudo_bytes()を使用します。 | ||
* UNIXでは、/dev/random, /dev/urandom のデバイスを読むこと乱数を得られます。 | * UNIXでは、/dev/random, /dev/urandom のデバイスを読むこと乱数を得られます。 | ||
− | * [[OpenSSL]]コマンドを使用して乱数を生成できます。<syntaxhighlight lang="bash"> | + | * [[OpenSSL]]コマンドを使用して乱数を生成できます。 |
+ | * Rでは、randomパッケージを使用します。大気のノイズを観測して乱数を生成します。 | ||
+ | ** http://cran.stat.ucla.edu/web/packages/random/ | ||
+ | ** http://random.org/ | ||
+ | ** 擬似乱数を生成する runif() もあります。 | ||
+ | === C言語 === | ||
+ | ==== rand() ==== | ||
+ | <syntaxhighlight lang="c"> | ||
+ | /* | ||
+ | * 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; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | ==== /dev/urandom ==== | ||
+ | /dev/urandomを/dev/randomに変更すれば、/dev/randomから読み出します。 | ||
+ | <syntaxhighlight lang="c"> | ||
+ | #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); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | === PHP === | ||
+ | ==== mt_rand ==== | ||
+ | rand()ではなく、mt_rand()を使用します。mt_rand()は、乱数生成器 Mersenne Twister を使用します。平均してlibcのrand()よりも4倍以上高速に乱数を生成できます。 | ||
+ | srand()は、seedが必要でしたが、PHP4.2.0以降は、ランダム数生成器にシードが与える必要がなくなりました。 | ||
+ | <syntaxhighlight lang="php"> | ||
+ | <?php | ||
+ | mt_srand(); | ||
+ | echo mt_rand() , PHP_EOL; | ||
+ | ?> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | 5から15まで(両端を含む)の[[乱数]]を得るには、範囲を指定します。 | ||
+ | <syntaxhighlight lang="php"> | ||
+ | <?php | ||
+ | echo mt_rand(5, 15), PHP_EOL; | ||
+ | ?> | ||
+ | </syntaxhighlight> | ||
+ | ==== PHP+OpenSSLモジュール ==== | ||
+ | [[暗号]]のために安全な乱数データが欲しい場合には、openssl_random_pseudo_bytes()を使用します。PHPのopensslモジュールが必要になります。 | ||
+ | |||
+ | 10バイトの乱数が得たい場合、以下のコードになります。 | ||
+ | <syntaxhighlight lang="php"> | ||
+ | <?php | ||
+ | $data = openssl_random_pseudo_bytes(10); | ||
+ | ?> | ||
+ | </syntaxhighlight> | ||
+ | openssl_random_pseudo_bytes()は、バイト列を返すので、画面にエコーしたいなら16進数にします。 | ||
+ | <syntaxhighlight lang="php"> | ||
+ | <?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; | ||
+ | ?> | ||
+ | </syntaxhighlight> | ||
+ | 上記のコードを実行すると、このようになります。 | ||
+ | <syntaxhighlight lang="bash"> | ||
+ | $ php openssl_random_pseudo_bytes.php | ||
+ | b5b9801a5f00cd0f322e59268169982867a944ed | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | 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()のコードは、以下の通りです。 | ||
+ | <syntaxhighlight lang="php"> | ||
+ | <?php | ||
+ | srand(); | ||
+ | echo rand() , PHP_EOL; | ||
+ | echo rand(5, 15), PHP_EOL; | ||
+ | ?> | ||
+ | </syntaxhighlight> | ||
+ | === OpenSSL コマンドによる乱数データの生成 === | ||
+ | [[OpenSSL]]コマンドを用いて、100バイトのデータを生成する例です。 | ||
+ | <syntaxhighlight lang="bash"> | ||
openssl rand 100 -out /tmp/rand.100 | openssl rand 100 -out /tmp/rand.100 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | === dd コマンドとrandomデバイスによる乱数データの生成 === | ||
+ | 1MBのファイルを作成する例です。 | ||
+ | <syntaxhighlight lang="bash"> | ||
+ | $ dd if=/dev/random of=urandom.dat count=1024 bs=1024 | ||
+ | </syntaxhighlight> | ||
+ | urandomの場合は、/dev/urandomを指定します。 | ||
+ | <syntaxhighlight lang="bash"> | ||
+ | $ dd if=/dev/urandom of=urandom.dat count=1024 bs=1024 | ||
+ | </syntaxhighlight> | ||
+ | == 擬似乱数生成アルゴリズム == | ||
+ | * メルセンヌツイスター(mersenne twister) | ||
+ | * カオス乱数 | ||
== 関連項目 == | == 関連項目 == | ||
* [[擬似乱数]] | * [[擬似乱数]] |
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)
- カオス乱数