I'm trying to write a python script to test the randomness of /dev/random, but I can't get it to give me any number. My code looks like this
with open("/dev/random", 'rb') as file:
print f.read(10)
which I believe is supposed to print out 10 bytes from /dev/random, but instead of numbers, it prints out weird characters (non-standard letters and no numbers). Any idea what I'm doing wrong?
Python has a builtin function for this (which will also use the appropriate method on other OS's as well)...
import os
print os.urandom(10)
# '\xf1\x11xJOl\xab\xcc\xf0\xfd'
From the docs at http://docs.python.org/2/library/os.html#os.urandom
This function returns random bytes from an OS-specific randomness source. The returned data should be unpredictable enough for cryptographic applications, though its exact quality depends on the OS implementation. On a UNIX-like system this will query /dev/urandom, and on Windows it will use CryptGenRandom. If a randomness source is not found, NotImplementedError will be raised.
If you then wanted those bytes to be a number, you can do so by converting as such:
>>> rand = os.urandom(10)
>>> int(binascii.hexlify(rand), 16)
1138412584848598544216317L
Or using Python 2:
>>> int(rand.encode('hex'), 16)
1138412584848598544216317L
Although, /dev/random
and /dev/urandom
are slightly different, so you can use your existing .read()
op and just do the int
conversion if the difference is significant to you.
In Python 3.2 and higher, the following is shorter and probably faster than the solutions in the older answers:
with open("/dev/random", 'rb') as f:
print(int.from_bytes(f.read(10), 'big'))
This prints a single 80-bit number (range 0 to 2^80-1 inclusive).
You are getting 10 bytes. Python won't automatically turn them into numbers.
I recommend you grab the bytes in multiples of 4, then turn them into 32-bit unsigned integers, then scale them to whatever you need.
EDIT: the old code showed the idea but was poorly divided into functions. Here is the same basic idea but now conveniently packaged into functions.
import os
import struct
_random_source = open("/dev/random", "rb")
def random_bytes(len):
return _random_source.read(len)
def unpack_uint32(bytes):
tup = struct.unpack("I", bytes)
return tup[0]
UINT32_MAX = 0xffffffff
def randint(low, high):
"""
Return a random integer in the range [low, high], including
both endpoints.
"""
n = (high - low) + 1
assert n >= 1
scale_factor = n / float(UINT32_MAX + 1)
random_uint32 = unpack_uint32(random_bytes(4))
result = int(scale_factor * random_uint32) + low
return result
def randint_gen(low, high, count):
"""
Generator that yields random integers in the range [low, high],
including both endpoints.
"""
n = (high - low) + 1
assert n >= 1
scale_factor = n / float(UINT32_MAX + 1)
for _ in range(count):
random_uint32 = unpack_uint32(random_bytes(4))
result = int(scale_factor * random_uint32) + low
yield result
if __name__ == "__main__":
# roll 3 dice individually with randint()
result = [randint(1, 6) for _ in range(3)]
print(result)
# roll 3 dice more efficiently with randint_gen()
print(list(randint_gen(1, 6, 3)))
It's printing random characters, so just convert them to ints using the ord()
function. Something like:
with open("/dev/random", 'rb') as file: print [ord(x) for x in file.read(10)]
This will print a list of 10 random ints from 0 to 255. (I got: [117, 211, 225, 24, 134, 145, 51, 234, 153, 89]
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With