【问题标题】:True random numbers with C++11 and RDRAND使用 C++11 和 RDRAND 的真随机数
【发布时间】:2013-07-11 02:48:24
【问题描述】:

我看到英特尔似乎包含了一个新的汇编函数来获取从硬件中获取的真实随机数。该指令的名称是RdRand,但在互联网上似乎只能找到少量细节:http://en.wikipedia.org/wiki/RdRand

我对这条新指令及其在 C++11 中的使用的问题如下:

  1. RdRand生成的随机数真的是随机的吗? (每个比特都是由不相关的白噪声或量子过程产生的?)

  2. 它是 Ivy Bridge 处理器的一个特殊功能吗,英特尔会在下一代 cpu 中继续实现这个功能吗?

  3. 如何通过C++11使用?也许使用std::random_device,但如果指令可用,编译器是否已经调用RdRand

  4. 编译程序时如何判断RdRand是否真的被调用?

【问题讨论】:

  • 我会查看Intel Manual,这是他们CPU接口的权威文档。
  • 它还在 Haswell 中 - 到目前为止,它看起来好像还在。
  • 也许你应该接受大卫约翰斯顿的回答?

标签: c++ assembly c++11 random rdrand


【解决方案1】:
  1. 这当然取决于你对宇宙决定论的看法,所以这更像是一个哲学问题,但许多人认为它是随机的。
  2. 只有 Intel 知道,但既然有添加它的需求,它可能会有保留它的需求
  3. std::random_device 不需要是硬件驱动的,即使是,也不需要使用rdrand。你可以询问它的double entropy() const noexcept 成员函数是否是硬件驱动的。使用rdrand 是一个 QoI 问题,但我希望每个理智的实现都可以这样做(我已经看到例如 gcc 这样做)。如果不确定,您可以随时检查组装,但其他硬件随机性方法也应该足够好(还有其他可用的专用硬件)。
  4. 见上,如果你对它是否只有硬件感兴趣,使用entropy,如果对rdrand感兴趣,扫描生成的机器码。

【讨论】:

  • libc++ 对random_device 的实现默认使用/dev/urandom,或者用户指定的其他文件。 VS2012 的实现使用了 Window 的加密服务。
【解决方案2】:
  1. 我认为它们“据说”是随机的...因为它是用于加密的。我不会太担心随机数的质量。
  2. 我认为英特尔会继续这样做,因为他们始终认为向后兼容性很重要,即使这条指令将来可能无用。
  3. 很抱歉我无法回答这个问题,因为我不使用 C++11。
  4. 如果您不想深入研究汇编代码,可以尝试 librdrand.a。英特尔在其网站上提供了免费下载的库。我测试过,挺方便的,有报错机制(因为随机数生成器生成随机数失败的概率很小)。所以如果你使用这个库,你只需要检查librdrand中函数的返回值

如果我的回复有任何问题,请告诉我。谢谢

祝你好运

向皮赛MM

【讨论】:

  • "既然是加密的,我不会太担心随机数的质量。" -- 什么??
【解决方案3】:

我设计了为 RdRand 指令提供随机数的随机数生成器。所以换个方式,我真的知道答案。

1) 随机数由符合 SP800-90 AES-CTR DRBG 的 PRNG 生成。 AES 使用 128 位密钥,因此这些数字具有高达 128 位的乘法预测阻力和超过 128 位的加法预测阻力。

但是,PRNG 经常从全熵源重新播种。对于孤立的 RdRand 指令,它将重新播种。对于 4 个内核上的 8 个线程以尽可能快的速度拉动,它的重新播种总是比每 14 个 RdRands 一次更频繁。

种子来自真正的随机数生成器。这涉及使用 AES-CBC-MAC 将 2.5Gbps 熵源输入到 3:1 压缩比熵提取器中。

所以它实际上是一个 TRNG,但在负载重时,它会回退到短序列的加密安全 PRNG 的属性。

这正是 Linux 上 /dev/random 和 /dev/urandom 之间的语义差异,只是快了很多。

熵最终是从一个量子过程中收集的,因为这是我们在自然界中所知道的唯一基本随机过程。在 DRNG 中,特别是 4 个晶体管栅极中的热噪声驱动亚稳态锁存器的分辨率状态,每秒 25 亿次。

熵源和调节器旨在符合 SP800-90B 和 SP800-90C,但这些规范仍处于草案形式。

2) RdRand 是标准 intel 指令集的一部分。未来所有CPU产品都会支持。

3) 您要么需要使用内联汇编,要么需要使用 RdRand 的库(如 openssl)。如果您使用库,则该库正在实现您可以直接实现的内联汇编器。英特尔在其网站上提供了代码示例。

其他人提到了 librdrand.a。我是这么写的。这很简单。

4) 只需在二进制文件中查找 RdRand 操作码。

【讨论】:

    【解决方案4】:

    自从 PRISM 和斯诺登爆料以来,我会非常小心地在有安全问题的应用程序中使用硬件随机生成器或依赖一个单一的库。我更喜欢使用独立的开源密码随机生成器的组合。通过组合,我的意思是例如: 让我们rarbrc 是三个独立的密码随机生成器,r 是返回给应用程序的随机值。 让我们sasbsc 成为他们的种子、tatbtc,重新播种周期,例如重新播种rbtb 抽奖。 By independant:尽可能属于独立的库,依赖不同的密码或算法。

    伪代码:

    // init
    seed std rand with time (at least millisec, preferably microsec)
    sa = std rand xor time // of course, not the same time evaluation
    // loop
    sb = ra every tb
    sc = rb every tc
    r = rb xor rc
    sa = rc every ta
    

    当然,每次抽奖只能使用一次。

    可能有两个来源就足够了:

    // init
    seed std rand with time (at least millisec, preferably microsec)
    sa = std rand xor time // of course, not the same time evaluation
    // loop
    sb = ra every tb
    sa = rb every ta
    r = rb xor ra
    

    为 ta、tb、tc 选择不同的值。它们的范围取决于您使用的随机源的强度。

    编辑:我为此目的启动了新库ABaDooRand

    【讨论】:

    • 关于 PRISM 和使用多个来源的优点。然而,std::rand 是垃圾,没有人应该再使用它(参见channel9.msdn.com/Events/GoingNative/2013/…)。其他一些建议:将 rdrand 与 /dev/random(在 Linux 上)和应用程序级别的高分辨率时间戳(或只是它们的低位)结合起来,例如用于进程启动、用户输入、网络流量等。处理器的性能计数器也可能是有用。如果您需要大量数据,请使用前面提到的值以增量方式播种具有此能力的加密强度 PRNG。¢>
    【解决方案5】:

    1) 不,来自 RdRand 的数字并不是真正随机的,因为它们来自加密安全的伪随机数生成器。但是,RdRand、RdSeed 和英特尔安全密钥技术可能是您能找到的最接近真正随机的技术。

    2) 是的,从您提到的 Ivy Bridge 处理器开始,所有出现在笔记本电脑、台式机和服务器中的 Intel 处理器都提供该功能。如今,这些功能也在 AMD 芯片中实现。

    3 和 4) 英特尔软件开发指南是寻找这些答案的地方。这里 (http://iopscience.iop.org/article/10.3847/1538-4357/aa7ede/meta;jsessionid=A9DA9DDB925E6522D058F3CEEC7D0B21.ip-10-40-2-120) 和非付费版本 (https://arxiv.org/abs/1707.02212) 对英特尔安全密钥如何应用于天体物理问题进行了有趣的讨论。本文描述了该技术的工作原理、实现方式以及性能(第 2.2.1 节和第 5 节)。不得不在课堂上阅读它。

    【讨论】:

    猜你喜欢
    • 2013-11-09
    • 2012-12-10
    • 2014-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-25
    • 1970-01-01
    相关资源
    最近更新 更多