今日、私は次のように考えました: まあ、NIST SP 800-90Aの RDRAND 実装に大きな疑いがあるとしても、それは依然として疑似乱数発生器 (PRNG) のハードウェア実装であり、機密性の低いアプリケーションには十分であるに違いありません。それで、メルセンヌ ツイスターの代わりに自分のゲームで使用することを考えました。
したがって、この命令を使用することでパフォーマンスが向上するかどうかを確認するために、次の 2 つのコードの時間を比較しました。
// test.cpp
#include <cstdio>
int main()
{
unsigned int rnd = 0;
for(int i = 0; i < 10000000; ++i) {
__builtin_ia32_rdrand32_step(&rnd);
}
printf("%x\n", rnd);
}
と
//test2.cpp
#include <cstdio>
#include <random>
int main()
{
unsigned int rnd = 0;
__builtin_ia32_rdrand32_step(&rnd);
std::mt19937 gen(rnd);
for(int i = 0; i < 10000000; ++i) {
rnd ^= gen();
}
printf("%x\n", rnd);
}
2つを実行すると、次のようになります。
$ time ./test
d230449a
real 0m0.361s
user 0m0.358s
sys 0m0.002s
$ time ./test2
bfc4e472
real 0m0.051s
user 0m0.050s
sys 0m0.002s
したがって、Mersenne Twister は、私の CPU では RDRAND よりもはるかに高速です。まあ、私はがっかりしました、私のゲームから除外されました. しかし、RDRAND は暗号的に安全な PRNG (CSPRNG) であるため、舞台裏で多くのことを行います...他の CSPRNG と比較すると、より公正になります。そこで、Rabbitの実装 (RFC を C に単純に変換したもので、パフォーマンスのための巧妙なトリックはありません) を使用して、次のテストを作成しました。
// test3.cpp
#include <cstdio>
extern "C"
{
#include "rabbit.h"
}
int main()
{
rabbit_state s;
unsigned long long buf[2];
__builtin_ia32_rdrand64_step(&buf[0]);
__builtin_ia32_rdrand64_step(&buf[1]);
rabbit_init_key(&s, (uint8_t*)&buf[0]);
for(int i = 0; i < 10000000; ++i) {
rabbit_extract(&s, (uint8_t*)&buf[0]);
}
printf("%llx\n", buf[0]);
}
そして驚いたことに、最初の 2 つの疑似乱数データの 2 倍を生成し、RDRAND よりも良い時間を得ることができました。
$ time ./test3
8ef9772277b70aba
real 0m0.344s
user 0m0.341s
sys 0m0.002s
3 つすべてが、最適化を有効にしてコンパイルされました。
そのため、RDRAND が NSA バックドアをすべてのソフトウェア暗号化に埋め込むために作成されたという偏執狂が広まっています。また、RDRAND よりも高速なソフトウェア CSPRNG が少なくとも 1 つあり、最も広く使用されている適切な PRNG である Mersenne Twister は、RDRAND よりもはるかに高速です。最後に、 RDRAND のように、AES の 2 つのスクランブラー層の背後に隠れていないオープンソースの監査可能なソフトウェア エントロピー プール (/dev/random
や など) があります。/dev/urandom
では、質問: RDRAND を使用する必要がありますか? 合法的な使用法はありますか?それとも、使用を完全に停止する必要がありますか?