今天我想:好吧,即使对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("%xn", 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("%xn", 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("%llxn", 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吗?它有合法的用途吗?还是我们应该完全停止使用它?
正如另一个答案中所指出的,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至少被重新播种了2500000/511=4892次。
因此,RDRAND示例中至少有4892*128=626176比特的熵,而不是128比特的熵。
这比没有硬件支持的情况下0.361秒内获得的熵要多得多。如果你在做一些真正的随机性很重要的事情,这可能很重要。一个例子是沙米尔秘密共享大量数据——不确定是否还有其他数据。
总之,这不是为了速度,而是为了高度安全。当然,它是否被后门的问题很麻烦,但你总是可以将它与其他来源异或,至少不会伤害你。
RDRAND
不仅仅是一个PRNG。这是一个白化的TRNG,符合FIPS。不同之处在于,您可以依赖RDRAND
来包含大量直接从CPU检索到的实际熵。因此RDRAND
的主要用途是为操作系统/库/应用程序提供熵。
应用程序检索熵的唯一其他好方法通常是使用操作系统提供的熵源,如/dev/random
或/dev/urandom
(通常从/dev/random
中提取熵)。然而,该操作系统还需要在某个地方找到熵。通常,磁盘和网络访问时间的微小差异用于此(+其他半随机输入)。这些装置并不总是存在的,也不是设计为熵的来源;它们通常不是很好的来源,也不是很快。因此,在支持它的系统上,RDRAND
经常被用作操作系统的密码安全随机数生成器的熵源。
关于速度,特别是对于游戏,使用(非安全)PRNG是完全有效的。如果你想有一个合理的随机种子,那么用RDRAND
的结果来播种可能是个好主意,尽管从操作系统提供的RNG播种可能是一个更便携甚至更安全的选择(以防你不完全信任英特尔或美国)。
请注意,目前RDRAND是使用(AES)CTR_DRBG实现的,而不是为速度而创建的(分析不太好的)流密码,如Rabbit,因此Rabbit更快也就不足为奇了。更重要的是,在运行之前,它还必须从CPU内的熵源中检索熵。
英特尔的RDRAND有任何合法用途吗?
是的。
考虑蒙特卡洛模拟。它没有加密需求,所以它是否被美国国家安全局后门也没关系。
还是我们应该完全停止使用它?
我们无法回答这个问题。这是用例、需求和个人偏好的融合。
此外,我们至少有一个比RDRAND更快的软件CSPRNG,以及最广泛使用的体面的PRNG。。。"
Mersenne Twister在初始化后的某个时间对一个字可能会更快,并且没有Twists,因为它从状态数组返回一个字。但我怀疑它是否能像RDRAND那样快速地进行连续流。我知道RDRAND可以在连续流中达到基于总线宽度的理论极限。
根据英特尔的David Johnston(设计电路的人)的说法,这大约是800+MB/s。请参阅DJ在IvyBridge上RDRAND指令的延迟和吞吐量是多少?。
因此,我们有一种普遍的偏执狂,认为RDRAND是为了将NSA后门嵌入每个人的软件密码中。
偏执狂至少有两种选择。首先,他们可以放弃使用RDRAND和RDSEED。其次,他们可以使用RDRAND和RDSEED的输出为另一个生成器播种,然后使用第二个生成器的输出。我相信Linux内核采用了第二种方法。
这里有一篇天体物理学研究论文(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节包含了所有的细节。
真实随机性与伪随机性。
rdrand是真正熵的硬件来源,在这一点上,它是一个非常强大的来源(而且它不是英特尔独有的-AMD也提供同样的功能-你为什么要单独选择英特尔?好吧,我专注于英特尔的实现,因为它们提供了更多的信息,并且与Zen2[ryzen 3xxx]相比具有高得多的吞吐量)
忘记时钟吞吐量吧——这是一个误导性的指标,因为它并没有真正的相关性。吞吐量受到单个线程的往返延迟和以800Mhz运行的实际硬件实现的限制,具有固定的8个周期,并且每个事务可以传递64位随机值。仅从运行代码的线程所占用的时钟周期来看,这将在很大程度上取决于当前的时钟频率——在800 MHz下空转似乎比在4.8 Ghz下运行快6倍。但是核心和DRNG之间的延迟是核心间延迟的顺序,并且有两次,大约是80ns,结果大约是12MHz@8byte=>约100 MByte/s/线程,最大值为800 MB/s。
这样做的另一个好处是:它不会像大多数PRNG那样耗尽CPU资源,因此,虽然其他生成器可以有相当高的吞吐量(1-2个数量级),但它们也需要更多的资源。在需要大量随机数并且处于计算密集的循环中的情况下,rdrand实际上可能会提供更好的性能,但这当然在很大程度上取决于确切的场景和硬件。
如果你只是需要很多随机数来进行模拟,或者需要准随机数来玩游戏,那么rdrand可能不是最好的选择。如果你需要真正的安全随机数?如果你担心一些后门,可以使用它,并将它与其他熵源结合起来。
关于NSA后门的问题。我在设计DRNG逻辑时避开的后门是:
- 双EC DRNG。这显然是愚蠢的,甚至在斯诺登泄密之前。我使用了CTR-DRBG,它具有独立验证的安全特性,是最有效的,可以抵御定时攻击和侧信道攻击的安全性
- SP800-90A DF。它们很可能是后门。看看关键结构和提取比你能输入的更多熵的能力
- FIPS140-2 CRNGT。降低熵的后门。ISO将其从ISO/IEC 19790-2012中删除,即FIPS140的ISO版本
所以这是三个后门为一个的价格躲过的。然而,只有其中一个作为后门出现在公众意识中。不客气。