14

今天我想:好吧,即使对NIST SP 800-90A的 RDRAND 实现有很大的怀疑,它仍然是伪随机数生成器 (PRNG) 的硬件实现,对于非敏感应用程序来说必须足够好。所以我想在我的游戏中使用它而不是 Mersenne Twister。

因此,为了查看使用该指令是否有任何性能提升,我比较了以下两个代码的时间:

// 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);
}

通过运行这两个我得到:

$ 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]);
}

令我惊讶的是,生成的伪随机数据是前两个的两倍,我得到了比 RDRAND 更好的时间:

$ time ./test3 
8ef9772277b70aba

real    0m0.344s
user    0m0.341s
sys     0m0.002s

这三个都是在启用优化的情况下编译的。

因此,我们普遍怀疑 RDRAND 是为了将 NSA 后门嵌入到每个人的软件密码学中。此外,我们至少有一个软件 CSPRNG 比 RDRAND 快,并且使用最广泛的体面 PRNG Mersenne Twister比 RDRAND快得多。最后,我们有开源的可审计软件熵池,比如/dev/random/dev/urandom,它们没有隐藏在 AES 的双重加扰器层之后,比如 RDRAND。

那么问题来了:人们应该使用 RDRAND 吗?它有什么合法用途吗?还是我们应该完全停止使用它?

4

5 回答 5

25

正如另一个答案中所指出的,RDRAND 以真正的随机性为种子。特别是,它经常使用 128 位硬件生成的随机性为其内部 CSPRNG 重新播种,保证每 511 * 128 位至少重新播种一次。请参阅本文档的第 4.2.5 节:

https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide

因此,在您的示例中,您使用单个 128 位种子从 rabbit_extract 生成 1000 万次随机抽取。在 RDRAND 版本中,相当于 250 万次 128 位绘制,这意味着 CSPRING 至少重新播种 2,500,000/511 = 4,892 次

因此,不是 128 位熵进入您的兔子示例,而是至少 4,892*128 = 626,176 位熵进入 RDRAND 示例。

这比在没有硬件支持的情况下在 0.361 秒内获得的熵要多得多。如果您正在做很多真正随机性很重要的事情,那可能很重要。一个例子是 Shamir 秘密共享大量数据——不确定是否还有其他数据。

所以总而言之——这不是为了速度,而是为了高安全性。当然,它是否是后门的问题令人不安,但你总是可以将它与其他来源进行异或,至少它不会伤害你。

于 2014-12-06T00:22:29.663 回答
10

RDRAND不仅仅是一个 PRNG。它是符合 FIPS 标准的增白 TRNG。不同之处在于,您可以依赖RDRAND包含大量直接从 CPU 检索的实际熵。所以主要用途RDRAND是为操作系统/库/应用程序提供熵。

应用程序检索熵的唯一其他好方法通常是使用操作系统提供的熵源,例如/dev/randomor /dev/urandom(通常从 中提取熵/dev/random)。但是,该操作系统还需要在某处找到熵。通常磁盘和网络访问时间的微小差异用于此(+其他半随机输入)。这些设备并不总是存在,也不是设计为熵的来源;它们通常不是很好的来源,也不是很快。所以在支持它的系统上,它RDRAND经常被用作操作系统的加密安全随机数生成器的熵源。

关于速度,特别是对于游戏,使用(非安全)PRNG 是完全有效的。如果你想有一个合理的随机种子,那么用结果播种它RDRAND可能是一个好主意,尽管从操作系统提供的 RNG 播种它可能是一个更便携甚至更安全的选择(如果你不完全信任英特尔或美国)。


请注意,目前 RDRAND 是使用 (AES) CTR_DRBG 实现的,而不是为速度而创建的(分析较少的)流密码,例如 Rabbit,因此 Rabbit 更快也就不足为奇了。更重要的是,它还必须在运行之前从 CPU 内的熵源中检索熵。

于 2014-11-06T14:30:03.137 回答
3

英特尔的 RDRAND 有任何合法用途吗?

是的。

考虑蒙特卡罗模拟。它没有加密需求,因此它是否被 NSA 后门并不重要。


还是我们应该完全停止使用它?

我们无法回答。这是一个融合用例、需求和个人偏好。


...此外,我们至少有一个软件 CSPRNG 比 RDRAND 更快,以及使用最广泛的体面 PRNG...”

Mersenne Twister 可能会在初始化之后的某个时间和没有 Twists 的情况下更快地处理一个单词,因为它会从状态数组中返回一个单词。但我怀疑它是否像 RDRAND 一样快连续流。我知道 RDRAND 可以根据连续流中的总线宽度达到理论极限。

根据英特尔的大卫约翰斯顿(设计电路)的说法,这大约是 800+ MB/s。请参阅 DJ在 Ivy Bridge 上 RDRAND 指令的延迟和吞吐量是多少?.


因此,我们普遍怀疑 RDRAND 是为了将 NSA 后门嵌入到每个人的软件密码学中。

偏执狂的人至少有两种选择。首先,他们可以放弃使用 RDRAND 和 RDSEED。其次,他们可以使用 RDRAND 和 RDSEED 的输出来播种另一个生成器,然后使用第二个生成器的输出。我相信Linux内核采用第二种方法。

于 2015-10-12T20:54:35.647 回答
1

这里有一篇天体物理学研究论文(http://iopscience.iop.org/article/10.3847/1538-4357/aa7ede/meta;jsessionid=A9DA9DDB925E6522D058F3CEEC7D0B21.ip-10-40-2-120),(非付费墙)此处的版本 ( https://arxiv.org/abs/1707.02212 ) 为 RdRand 提供了合法用途。

正如之前的一篇文章所建议的那样,它检查了 RdRand 对蒙特卡洛模拟器的影响。但作者并没有发现使用或不使用 RdRand 的结果有任何统计学差异。从性能的角度来看,Mersenne Twister 看起来要快得多。我认为第 2.2.1 节和第 5 节包含所有细节。

于 2017-11-13T22:18:21.630 回答
1

真随机与伪随机。

rdrand 是真正熵的硬件源,并且是一个非常强大的源(它也不是英特尔独有的 - AMD 提供相同的 - 那你为什么要挑出英特尔?好吧,我专注于实现与 Zen2 [ryzen 3xxx] 相比,英特尔提供了更多信息并具有更高的吞吐量)

忘记clockcyle-throughput - 这是一个误导性的指标,因为它并不真正相关。吞吐量受到单个线程的往返延迟和以 800 Mhz 运行的实际硬件实现的限制,具有固定的 8 个周期,并且可以为每个事务提供 64 位随机值。仅查看运行代码的线程所采用的时钟周期将在很大程度上取决于当前的时钟速率 - 在 800 MHz 空闲时,它似乎比以 4.8 Ghz 运行快 6 倍。但是核心和 DRNG 之间的延迟是核心间延迟的顺序,你有两次,所以大约 80ns - 结果大约为 12MHz@8byte => ~100 MByte/s/Thread,最大值为 800 MB/秒。

这样做的另一个好处:它不会像大多数 PRNG 那样耗尽您的 CPU 资源,因此虽然其他生成器可以具有相当高的吞吐量(1-2 个数量级),但它们也需要更多资源。在需要大量随机数并且处于计算量很大的紧凑循环中的情况下,rdrand 实际上可能会提供更好的性能,但这当然很大程度上取决于确切的场景和硬件。

如果您只是需要大量随机数进行某些模拟或需要准随机数进行游戏,那么 rdrand 可能不是最佳选择。如果您需要真正的安全随机数?如果您担心某些后门,请使用它 - 并将其与其他熵源结合使用。

于 2019-09-12T12:09:34.260 回答