此代码将使用/ 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
Run Code Online (Sandbox Code Playgroud)
以下是在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
Run Code Online (Sandbox Code Playgroud)
请注意,与使用os.urandom作为熵源的版本不同,此函数可能会阻塞.
(Edit1:更新了标准化以等同于NumPy的标准化)
编辑2:评论表明问题的原因是速度,而不是加密强度.硬件RNG的目的不是速度而是强度,因此它使问题无效.然而,一个快速和良好的PRNG可以替代Mersenne Twister是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
Run Code Online (Sandbox Code Playgroud)
请注意,Mersenne Twister和multiply-with-carry都没有加密强度.