乱数ジェネレーター

任意の範囲で暗号的に強力なランダム数を生成します。

このジェネレーターについて

コンピュータは決定論的な機械なので、「ランダム性」を生成するのは奇妙です。コンピュータ上の擬似乱数生成器(PRNG)の歴史は、John von Neumann の1946年のミドルスクエア法から始まります、前の数値を二乗、中間の桁を新しい値として取得、繰り返し。von Neumann 自身、ミドルスクエアには明らかな失敗モード(ゼロにロックされたサイクル、短い周期)があるので、完全に理解せずに乱数生成器を使うことを「罪深い状態」と特徴付けました。Lehmer の線形合同法生成器(LCG、1951)、x_(n+1) = (a × x_n + c) mod m、は妥当な統計特性を持つ最初の PRNG ファミリーです、C 標準ライブラリの rand() は依然として通常 LCG 変種を使用します。Mersenne Twister(Matsumoto と Nishimura、1997-1998)は周期 219937−1(はい、6,000 桁の数)と優れた統計特性を持つ生成器を私たちに与えました、Python、R、MATLAB、PHP、その他多くの言語のデフォルトになりました。Marsaglia のxorshift ファミリー(2003)はより高速でハードウェアレジスタに収まるほど小さい、現代の V8(Chrome の JavaScript エンジン)は Math.random() に xorshift128+ 変種を使用します。Melissa O'Neill のPCG(Permuted Congruential Generator)(2014)は非暗号 PRNG の現在の統計の最先端で、低コストで優れた統計特性のために LCG スタイルの状態前進と出力順列を組み合わせます。

暗号的に安全な PRNG(CSPRNG)は別の獣です。定義特性:攻撃者が生成器によって生成されたすべての過去の出力を知っていても、無視できる利点より良く次の出力を予測できません。Linux の getrandom() システムコール(カーネル 3.17、2014年10月で追加)と基礎の /dev/urandom はハードウェアエントロピーソース(RDRAND、割り込みタイミング、音声ノイズ)からシードされた ChaCha20 ベースの生成器を使用します。Windows の BCryptGenRandom は複数のエントロピーソースからシードされた AES-CTR-DRBG 構築(NIST SP 800-90A)を使用します。macOS / iOS は Fortuna から派生した CSPRNG を使用します。PRNG と CSPRNG の違いは大きく重要です:PRNG はゲームランダム性、A/B テストバケッティング、シミュレーションに適しています、攻撃者が予測しようとするかもしれないあらゆるもの(セッショントークン、パスワード生成、セキュリティ識別子)には、CSPRNG のみが安全です。

JavaScript の 2 つのランダム API

Math.random() は古いシンプルな API で、[0, 1) でほぼ均一に分布する浮動小数点数を返します。ECMAScript 仕様は基礎となるアルゴリズムを意図的に未指定のままにしました("approximately uniform distribution between 0 and 1, exclusive")、エンジンは何年もの間使用するものを変更してきました。V8(Chrome)は2015年まで Park-Miller LCG を使用、その後より良い統計特性のために xorshift128+ に切り替えました。SpiderMonkey(Firefox)と JavaScriptCore(Safari)は同様の高速非暗号生成器を使用します。Math.random() はゲームメカニクス、シミュレーション、予測不可能性がセキュリティ要件ではないあらゆるアプリケーションに十分高速で均一です。暗号的に安全ではありません、周期は実装定義、状態は少数の出力から復元可能、シーケンスはパスワード生成やセキュリティ機微なユースケースには安全ではありません。crypto.getRandomValues() は Web Crypto API の CSPRNG です。OS の CSPRNG(TLS セッションキーのために TLS が使用するのと同じソース)から引き出された暗号的に安全なランダムバイトで型付き配列を埋めます。約2014年からすべての現代のブラウザで利用可能、単一呼び出しの最大バッファサイズは 65,536 バイト。重要なあらゆる乱数の正しい選択、トークン生成、セキュリティ識別子、パスワード生成、攻撃者が予測しようとするかもしれないあらゆるもの。

モジュロバイアスの罠

CSPRNG から特定の範囲で均一な整数を生成するのは見た目より難しいです。素朴なアプローチ、サイコロロールの crypto.getRandomValues(new Uint8Array(1))[0] % 6、はバイアスのかかった分布を生成します、256 が 6 で均等に割れないからです。値 0-3 は範囲 0-255 でそれぞれ 43 回現れます、値 4-5 は 42 回現れます。バイアスは小さい範囲で小さいですが実際で、長い実行で検出可能です。標準的な修正はリジェクションサンプリングです:ランダムバイトを生成、それが範囲のフィットする最大の倍数(ここでは 252 = 42 × 6)に入るかをテスト、入るなら使用、入らないなら捨ててリトライ。リジェクションレートは(範囲 / 次の 2 のべき乗)で制限されます、つまり「1-6」では約 1.5 % のバイトを浪費します、32 ビットのランダム整数に対する「1-1000000」では約 0.02 % を浪費します。あらゆる本格的なランダムライブラリはリジェクションサンプリングを実装します、Math.random() ベースの Math.floor(Math.random() * (max - min + 1)) + min はバイアスを避けます、Math.random() の精度が十分に高い(53 ビット仮数)ので、合理的な範囲でバイアスは人間が検出可能なレベル以下です。この生成器はリジェクションサンプリングで CSPRNG 出力を使用します、要求された任意の整数範囲で均一な出力。

ユースケースとそれぞれに必要なランダム性レベル

RANDOM.ORG と真のランダム性の区別

RANDOM.ORG は1998年に Trinity College Dublin の Mads Haahr によってローンチされ、オンラインの「真のランダム性」のリファレンスのままです。すべての CSPRNG が最終的にハードウェアシードされた状態のアルゴリズム的変換からビットを派生する(攻撃者にとって予測不可能でも、決定論的プロセス)のに対し、RANDOM.ORG はラジオ受信機によって取得された大気ノイズを測定し、そのアナログノイズを直接ビットに変換します。これにより擬似乱数生成器ではなく真の乱数生成器(TRNG)になります、ビットは決定論的アルゴリズムではなく真の非決定論的物理プロセスから来ます。RANDOM.ORG は宝くじオペレーター、二重盲検研究を実施する学術研究者、検証可能なランダム性が重要なゲームによって使用されます。トレードオフ:リクエストごとのネットワークラウンドトリップ、無料層の毎日のクォータ、RANDOM.ORG の主張するエントロピーソースをローカル CSPRNG より信頼するかという哲学的質問。ほとんどの使用には、ローカル CSPRNG で十分です、第三者がランダム性を独立して検証する必要があるケース(規制された宝くじ、二重盲検科学研究)には、RANDOM.ORG は有料サービスとして署名されたランダム性証明書を提供します。

置換なしのサンプリング、Fisher-Yates シャッフル

範囲内でN 個の一意の数が必要なとき、宝くじの 1 〜 49 の 6 つの数字を引く、1,000 のエントリーから 10 人の勝者を選択する、素朴な「生成して重複なら拒否」は小さな N で機能しますが、N が範囲のサイズに近づくとひどく劣化します(プールが縮むにつれて新しい数字を引く可能性が下がる)。標準アルゴリズムはFisher-Yates シャッフルです、Fisher と Yates の1938年の統計表から発信され、1969年に Donald Knuth によってコンピュータサイエンスの現代的な形(時には Knuth シャッフルと呼ばれる)に置かれました。アルゴリズムは非常にシンプルです:数 1 〜 N を配列に書く、i を N-1 から 1 まで、要素 i をインデックス 0 〜 i(包含的)のランダム要素と交換、配列は今や均一にシャッフルされています。K 個のユニークなランダム数のために最初の K 要素を取ります。重要な詳細:ランダムインデックスは [0, i] 包含的でなければなりません、[0, i-1] を使用すると、暗号コミュニティが特徴づけるのに何年もかかった微妙なバイアス(Sattolo 変種、時には真の Fisher-Yates の代わりに誤って使用される)が導入されます。すべての N 値の配列を割り当てることが実用的でない非常に大きな範囲(例えば 1 と 109 の間で 100 のユニーク値を選ぶ)には、リザーバーサンプリング(Vitter、1985)が単一パスで境界付きメモリでストリーミングまたは無境界入力を処理します。

サイコロロール慣習

乱数生成器は変装したサイコロです。D6(6 面サイコロ)はボードゲームの普遍的なデフォルト、範囲 1-6。D20(20 面サイコロ)は能力チェック、攻撃ロール、セービングスローに使用される Dungeons & Dragons の象徴的なサイコロ、D&D の修飾子システムは、単一の D20 ロールにスタットボーナスを加えたものがほとんどのアクションの結果を決定することを意味します。D100(パーセンタイル、1-100)は Call of Cthulhu、Warhammer Roleplay、多くのクリティカルチャンスシステムでパーセンテージロールに使用されます。記法 NdM は「M 面サイコロを N 個振って合計」を意味します、NdM+B はボーナスを加えます。3d6 は 3 つの 6 面サイコロを振って合計します(範囲 3-18、古典的な D&D 能力スコア範囲、10-11 周辺の三角分布)。公平なシミュレーションのために、各サイコロに [1, M] の均一整数を生成して合計するのは物理サイコロを振るのと正確に同等です、基礎となる CSPRNG 分布は購入できるあらゆる物理サイコロより均一です。カジノと規制されたゲームは、規制当局に均一性を証明するために統計バッテリー(TestU01 の BigCrush、NIST SP 800-22)に対してテストされた認証された RNG を使用します、同じ標準が宝くじ RNG に適用されます。

シードと再現性

PRNG の微妙だが重要な特性:与えられたシードに対して決定論的です。シードを既知の値に固定すると、「ランダム」数のシーケンスは正確に再現可能です。これはテストに非常に貴重です(ランダムデータを使用する単体テストは失敗を再現可能にするためにシードを固定すべき)、検証可能な抽選にも(抽選前にシードを公開、その後誰でも結果を検証できる)。Python の random モジュールにはこのために random.seed(value) があります、Java の Random はコンストラクタでシードを取ります。JavaScript の Math.random() は意図的にシード API を公開しません、エンジンはシードを内部状態として扱います、しかしいくつかの純粋 JS ライブラリ(seedrandom、pcg-random)はシード可能な PRNG を提供します。CSPRNG は設計により異なります:意味全体が予測不可能性なのでシードを公開しません。再現性が必要なら、明示的なシードで PRNG を使用してください、セキュリティが必要なら、CSPRNG を使用しその後シーケンスを再現できないことを受け入れてください。

プライバシー、なぜ乱数のためでもブラウザのみか

乱数自体はめったに機微情報を含みません、では純粋なブラウザアーキテクチャがなぜ重要か? 2 つの理由。第一に、乱数がセッショントークン、冪等性キー、認証チャレンジ、その他の秘密のような値として使用されるとき、第三者サーバーで生成することはそのサーバーが使用前に値を見たことを意味します、小さいが実際の露出。第二に、「暗号的なランダム性」を約束するサーバー側生成器はユーザーが検証できません、バグのあるまたは悪意のあるサーバーは見かけ上ランダムだが非ランダムまたはバイアスされた値を返す可能性があり、大規模サンプリングなしにバイアスを検出する方法がありません。ブラウザのみの生成器はアプリケーションがサーバー側で実行するのと同じ crypto.getRandomValues() 呼び出しを実行します、エントロピーは同じ OS ソース(Linux getrandom()、Windows BCryptGenRandom、macOS)から来ます、第三者は出力を見ません。Generate をクリックする間に DevTools の Network タブを開いて確認できます、発信リクエストはありません。ロード後にページをオフライン(機内モード)にしても生成器はまだ動作します。

よくある質問

これらの数値は暗号的に安全ですか?

はい。生成器はリジェクションサンプリングで Web Crypto API の crypto.getRandomValues() を使用して任意の範囲で均一な整数を生成します。エントロピーは OS の CSPRNG から来ます、Linux getrandom()、Windows BCryptGenRandom、macOS、TLS セッションキーのために TLS が使用するのと同じソース。セキュリティ機微な使用に適しています:宝くじ抽選、セッショントークン、冪等性キー、パスワード生成。

なぜ単に Math.random() を使わないのか?

ゲームメカニクス、シミュレーション、A/B テストバケッティング、または予測不可能性がセキュリティ要件ではないあらゆるものには、Math.random() で十分、高速、十分に均一、どこでも利用可能。攻撃者が予測しようとするかもしれないあらゆるもの、セッショントークン、パスワード生成、セキュリティ識別子、宝くじ抽選には、Math.random() は危険です。状態は少数の出力から復元可能、シーケンスは任意の出発点から再現可能、周期(現代のエンジンでは大きいが)は実装定義で暗号的とは宣伝されていません。crypto.getRandomValues() に切り替えるコストは現代のハードウェアで本質的にゼロです、回答が重要なときは常にデフォルトにしてください。

重複なしで生成できますか?

はい、「Unique only」オプションを有効にしてください。それは Fisher-Yates シャッフル(Fisher と Yates 1938 以来の標準アルゴリズム、Knuth が1969年にコンピュータサイエンスの現代的な形に置いた)を使用して、範囲からN個のユニーク値をバイアスなしで引き出します。範囲サイズに対して小さい N には、コストは無視できます、範囲サイズに近い N には、アルゴリズムは O(N) で実行されます。古典的なケースは宝くじスタイルの抽選(1 と 49 の間の 6 つのユニーク数)で、重複は無効です。

RANDOM.ORG との違いはありますか?

はい。RANDOM.ORG(Mads Haahr、Trinity College Dublin、1998)は真の乱数生成器(TRNG)です、そのビットはラジオ受信機によって測定された大気ノイズから来ます、真の非決定論的物理プロセス。この生成器は暗号的に安全な擬似乱数生成器(CSPRNG)です、そのビットは与えられた OS エントロピー状態に対して決定論的ですが、その状態へのアクセスを持たないあらゆる攻撃者には予測不可能です。ほとんどの使用には、CSPRNG は TRNG と区別がつきません、第三者がランダム性を独立して検証する必要があるケース(規制された宝くじ、二重盲検科学研究)には、RANDOM.ORG の署名付きランダム性証明書はゴールドスタンダードです、ネットワークラウンドトリップと毎日のクォータの代償で。

なぜ他で「モジュロバイアス」警告を見るかもしれないのか?

ランダムバイト(0-255)をサイコロロール(1-6)に素朴にマップする方法が小さなバイアスを導入するからです:byte % 6 は 256 が 6 で均等に割れないので、値 0-3 を値 4-5 より約 0.4 % より頻繁に与えます。修正はリジェクションサンプリングです:バイト ≥ 252(6 ≤ 256 の最大倍数)を捨ててリトライします。この生成器はすべての整数範囲にリジェクションサンプリングを使用するので、出力は検出可能なバイアスなしに均一です。バイアスは、バイアスされた出力に対する統計的攻撃が鍵素材を回復できる暗号アプリケーションに最も重要です、ゲームメカニクスには見えません。

数字はどこかに送信されますか?

いいえ。各乱数は Web Crypto API を介してブラウザでローカルに生成されます。生成器は決してネットワークリクエストを行いません、Generate をクリックする間に DevTools の Network タブを確認するか、ロード後にページをオフラインにしてもツールがまだ動作することを確認してください。第三者が使用前に値を見ることを望まないセッショントークン、宝くじ抽選、セキュリティ識別子、または任意の数値の生成に安全です。

関連ツール