Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using the hardware rng from python

Are there any ready made libraries so that the intel hardware prng (rdrand) can be used by numpy programs to fill buffers of random numbers?

Failing this can someone point me in the right direction for some C code that I could adapt or use (I use CPython and Cython with numpy so the bare minimum wrapper shd be enough).

The random generators I want are uniform random numbers between [0,1).

like image 842
staticd Avatar asked Mar 27 '14 07:03

staticd


People also ask

How does hardware RNG work?

Random number generators or RNGS are hardware devices or software programs which take non-deterministic inputs in the form of physical measurements of temperature or phase noise or clock signals etc and generate unpredictable numbers as its output.

How does Python RNG work?

The random module in python contains two interfaces(classes) of pseudorandom number generators(PRNGs). You can view it as two ways to generate random numbers. SystemRandom uses either the /dev/urandom file on POSIX systems or the CryptGenRandom() function on Windows NT systems. Both are Cryptographically secure PRNGs.

Is computer RNG really random?

Typically, that means it starts with a common 'seed' number and then follows a pattern.” The results may be sufficiently complex to make the pattern difficult to identify, but because it is ruled by a carefully defined and consistently repeated algorithm, the numbers it produces are not truly random.


1 Answers

This code will use /dev/urandom (Unix) or CryptGenRandom APIs (Windows). Which RNG is used, hardware or software, is dependent on the operating system.

If you want to control exactly which generator is used, you must query it through its hardware driver or library. When you have the random bits as a string, you proceeed similarly to this code, using np.fromstring.

Normally we can trust the operating system to use the best entropy sources for its cryptographic services, including the random bit generator. If there is a hardware RNG it is likely to be used, usually combination with other entropy sources.

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

Here is the distribution of 1,000,000 random deviates generated with this method on Mac OS X. As you can see it is quite uniform on [0,1):

enter image description here

If you need really strong cryptographic random deviates, you can use /dev/random instead of /dev/urandom. This applies only to Unix-like systems, not 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

Note that this function might block, unlike the version that uses os.urandom as entropy source.

(Edit1: Updated normalization to equate that of NumPy)

Edit 2: The comments indicates the reason for the question was speed, not cryptographic strength. The purpose of hardware RNG is not speed but strength, so it makes the question invalid. However, a fast and good PRNG which can be an alternative to the Mersenne Twister is George Marsaglia's multiply-with-carry generator. Here is a simple implementation in 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

Beware that neither Mersenne Twister nor multiply-with-carry have cryptographic strength.

like image 81
12 revs Avatar answered Oct 21 '22 20:10

12 revs