23

ランダム性の2つのソースを含むクラスがあります。

std::random_device rd;
std::mt19937 random_engine;

std::mt19937を呼び出してシードしstd::random_deviceます。番号を生成したいのに再現性を気にしない場合は、電話する必要がありますrd()random_engine()

私の特定のケースでは、パフォーマンスがそれほど重要ではなく、結果が特に敏感ではない一部のネットワーキングコードで呼び出されるため、両方とも問題なく機能すると確信しています。ただし、ハードウェアエントロピーをいつ使用するか、および疑似乱数をいつ使用するかについてのいくつかの「経験則」に興味があります。

現在、私はエンジンのstd::random_deviceシードにのみ使用してstd::mt19937おり、プログラムに必要な乱数の生成には、std::mt19937エンジンを使用しています。

編集:これは私がこの特定の例を使用している正確な説明です:

これはゲームプレイプログラム用です。この特定のゲームでは、ユーザーは対戦相手とのラウンドを開始する前に「チーム」をカスタマイズできます。戦闘の設定の一部には、サーバーにチームを送ることが含まれます。私のプログラムにはいくつかのチームがあり、乱数を使用してロードするチームを決定します。新しい戦いのたびstd::random_deviceに、疑似乱数ジェネレーターをシードするための呼び出しが行われます。ランダムに選択したこのチームと初期シードを含む、戦闘の初期状態をログに記録します。

この質問で私が質問している特定の乱数は、ランダムなチーム選択(対戦相手に、私が使用しているチームを事前に知らないことが有益であるが、ミッションクリティカルではない)のためのものですが、私はm本当に探しているのは経験則です。番号の再現性が必要ない場合は常に使用しstd::random_deviceても問題ありませんか、それとも収集できるよりも早くエントロピーを使い果たすリスクがありますか?

4

6 に答える 6

10

私の知る限り、標準的な方法は、コンピューターによって計算されない(ただし、外部の予測できないソースからの)数値を乱数ジェネレーターにシードすることです。これは、rd()関数の場合に当てはまります。それ以降、必要なすべての疑似乱数に対して疑似乱数ジェネレーター(PRNG)を呼び出します。

数値が十分にランダムでないことが心配な場合は、別のPRNGを選択する必要があります。エントロピーは希少で貴重な資源であり、そのように扱われるべきです。現在はそれほど多くの乱数を必要としないかもしれませんが、将来的には必要になるかもしれません。または他のアプリケーションがそれらを必要とする可能性があります。アプリケーションがエントロピーを要求するたびに、そのエントロピーを利用できるようにする必要があります。

あなたのアプリケーションにとって、メルセンヌツイスターはあなたのニーズにぴったり合うように思えます。あなたのゲームをプレイする人は、ロードされているチームがランダムではないと感じることはありません。

于 2012-08-06T03:00:05.083 に答える
8

暗号化に使用しない場合は、によってシードされたmt19937を繰り返し使用することをお勧めしrandom_engineます。

この回答の残りの部分では、ネットワークコードの暗号化に乱数を使用していると仮定します。つまり、mt19937はその用途には適していません。

http://en.wikipedia.org/wiki/Mersenne_twister#Disadvantages

攻撃者が乱数の予測を開始できるように、時間の経過とともに(おそらく間接的に)情報が漏洩する可能性があります。少なくとも理論的には、これがその目的です。ウィキペディアから


...この図は、将来の反復が生成される状態ベクトルのサイズであるため)、将来のすべての反復を予測することができます。

乱数生成情報がユーザーに漏洩するのを防ぐ簡単な方法は、一方向のハッシュ関数を使用することですが、それだけではありません。その目的のために設計された乱数ジェネレーターを使用する必要があります。

http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator

さまざまな例(コード付き)はここにありますhttp://xlinux.nist.gov/dads/HTML/pseudorandomNumberGen.html

于 2012-08-05T15:15:20.037 に答える
8

シミュレーションやゲームにランダム性が必要な場合は、それで問題ありません。ランダムデバイスを1回だけ呼び出し、ランダムにシードされた疑似RNGを使用して他のすべてを実行します。ボーナスとして、後で疑似ランダムシーケンスを再生できるように、シード値をログファイルに保存する必要があります。

auto const seed = std::random_device()();
// save "seed" to log file
std::mt19937 random_engine(seed);

(複数のスレッドの場合、メインスレッドでPRNGを使用して、生成されたスレッドでさらにPRNGのシードを生成します。)

暗号化の目的で多くの真のランダム性が必要な場合、PRNGは決して良い考えではありません。ただし、出力の長いシーケンスには真のランダム性よりもはるかに少ないランダム性が含まれるため、小さなサブセットからすべてを予測できます。真のランダム性が必要な場合は、予測できないソース(熱センサー、ユーザーのキーボード/マウスのアクティビティなど)から収集する必要があります。Unix/dev/randomはそのような「真のランダム性」のソースかもしれませんが、すぐにはいっぱいにならないかもしれません。

于 2012-08-05T15:18:50.433 に答える
3

http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmfulを見て、uniform_int_distributionを使用する理由と、random_device/mt19937の相対的な強みを説明することをお勧めします。

このビデオでは、Stephan T. Lavavejが、Visual C ++では、random_deviceを暗号化の目的で使用できると具体的に述べています。

于 2013-09-11T22:25:57.457 に答える
2

答えはプラットフォームに依存します。Visual C ++ 2010では、std::random_deviceが文書化されていない方法でmt19937にシードされていることを覚えているようです。

もちろん、乱数ジェネレーターに基づくアドホック暗号化スキームは非常に弱い可能性が高いことに気づきます。

于 2012-08-05T19:09:50.123 に答える
-2

これが暗号化の目的ではないと仮定すると、乱数の生成について覚えておくべき最も重要なことは、乱数の分布をどのようにしたいか、および期待する範囲を考えることです。

通常、ライブラリ内の標準の乱数ジェネレータは、均一に分布するように設計されています。したがって、数値は0からいくつかのRAND_MAXの範囲になります(たとえば、32ビットマシンでは2 ^ 31 -1です)。

ここで、疑似乱数ジェネレーターで覚えておくべきことがあります。それらのほとんどは、ランダムビットではなく乱数を生成するように設計されています。違いは微妙です。0から8までの数値が必要な場合、ほとんどのプログラマーはrand()%8と言います。アルゴリズムは32ビットをランダム化するためのものであるため、これは悪いことです。ただし、使用しているのは下位3ビットのみです。ダメ。これはあなたに均一な分布を与えません(それがあなたが探しているものであると仮定して)

8 *(rand()+ 1)/(RAND_MAX)を使用する必要があります。これにより、0から8までの一様乱数が得られます。

ハードウェア乱数ジェネレーターを使用すると、ランダムビットが生成される場合があります。それが実際に当てはまる場合は、各ビットが個別に生成されます。そうすると、それは同一の独立したランダムビットのセットのようなものになります。ここでのモデリングは少し異なる必要があります。特にシミュレーションでは、分布が重要になることに注意してください。

于 2012-08-05T15:32:35.170 に答える