【问题标题】:using the hardware rng from python使用 python 中的硬件 rng
【发布时间】:2014-03-27 07:01:06
【问题描述】:

是否有任何现成的库,以便 numpy 程序可以使用 intel 硬件 prng (rdrand) 来填充随机数的缓冲区?

如果做不到这一点,有人可以为我可以适应或使用的一些 C 代码指明正确的方向(我使用 CPython 和 Cython 和 numpy,所以最小的包装器 shd 就足够了)。

我想要的随机生成器是 [0,1) 之间的统一随机数。

【问题讨论】:

    标签: python random numpy rdrand


    【解决方案1】:

    此代码将使用 /dev/urandom (Unix) 或 CryptGenRandom API (Windows)。使用哪种 RNG(硬件或软件)取决于操作系统。

    如果您想准确控制使用哪个生成器,您必须通过其硬件驱动程序或库来查询它。当您将随机位作为字符串时,您可以使用 np.fromstring 与此代码类似地进行操作。

    通常我们可以相信操作系统会为其加密服务使用最佳熵源,包括随机位生成器。如果有硬件 RNG,它可能会被使用,通常与其他熵源结合使用。

    import os
    import numpy as np
    
    def cryptorand(n):
        a = np.fromstring(os.urandom(n*4), dtype=np.uint32) >> 5
        b = np.fromstring(os.urandom(n*4), dtype=np.uint32) >> 6
        return (a * 67108864.0 + b) / 9007199254740992.0
    

    这是在 Mac OS X 上使用此方法生成的 1,000,000 个随机偏差的分布。您可以看到它在 [0,1) 上非常均匀:

    如果您需要非常强大的加密随机偏差,您可以使用 /dev/random 而不是 /dev/urandom。这仅适用于类 Unix 系统,不适用于 Windows:

    import numpy as np
    
    def cryptorand(n):
        with open('/dev/random','rb') as rnd:
            a = np.fromstring(rnd.read(n*4), dtype=np.uint32) >> 5
            b = np.fromstring(rnd.read(n*4), dtype=np.uint32) >> 6
            return (a * 67108864.0 + b) / 9007199254740992.0
    

    请注意,与使用 os.urandom 作为熵源的版本不同,此函数可能会阻塞。

    (Edit1:更新标准化以等同于 NumPy)

    编辑 2:cmets 表示问题的原因是速度,而不是加密强度。硬件RNG的目的不是速度而是强度,所以它使问题无效。然而,可以替代 Mersenne Twister 的快速且良好的 PRNG 是 George Marsaglia 的乘法与进位生成器。这是 Cython 中的一个简单实现:

    import numpy as np
    cimport numpy as cnp
    
    cdef cnp.uint32_t gw = 152315241 # any number except 0 or 0x464fffff
    cdef cnp.uint32_t gz = 273283728 # any number except 0 or 0x9068ffff
    
    def rand(cnp.intp_t n):
        """Generate n random numbers using George Marsaglia's 
        multiply-with-carry method."""
        global gw, gz
        cdef cnp.uint32_t w, z, a, b
        cdef cnp.intp_t i
        cdef cnp.ndarray x = cnp.PyArray_SimpleNew(1, &n, cnp.NPY_FLOAT64)
        cdef cnp.float64_t *r = <cnp.float64_t*> cnp.PyArray_DATA(x)
        w,z = gw,gz
        for i in range(n): 
            z = 36969 * (z & 65535) + (z >> 16)
            w = 18000 * (w & 65535) + (w >> 16)
            a = (z << 16) + w
            z = 36969 * (z & 65535) + (z >> 16)
            w = 18000 * (w & 65535) + (w >> 16)
            b = (z << 16) + w
            r[i] = (a * 67108864.0 + b) / 9007199254740992.0
        gw,gz = w,z
        return x
    

    请注意,Mersenne Twister 和乘法进位都没有加密强度。

    【讨论】:

    • hmm.. 我想试试看 rdrand 指令是否比 mersene twister 快,因为我有具有此功能的处理器。 /dev/urandom 设备对我来说有点慢(它的加密随机而不是我想要的沼泽标准模拟等级
    • 感谢关于制作统一 [0,1) 的指针。让我感到困惑的一件事是,如何将双精度数除以大于 64 位数字最大值的数字?
    【解决方案2】:

    【讨论】:

      【解决方案3】:

      这里有一篇论文 (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 和 RdSeed 指令访问。

      但作者似乎说你应该用 C/C++ 而不是 Python 来实现它。 rdrand python 模块的运行速度比 Python 默认随机数生成器慢约 100 倍,比 Numpy 中的慢约 1000 倍(论文第 5.2 节)。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-02-27
      • 1970-01-01
      • 2019-02-01
      • 2013-04-28
      • 1970-01-01
      • 2021-09-14
      • 1970-01-01
      相关资源
      最近更新 更多