Generate true random numbers in python
Question:
Python function that generates true random numbers?
By true random numbers it also means that what every time I run python the seed I generate is different. How do I do this?
Answers:
There are many ways of generating random numbers, with exactly 1 thing in common – they all require external input. Let’s say you use a simple RNG like games use. The RNG takes an input (usually the system time, in seconds or milliseconds), and performs various wonky mathematical operations to produce a random-looking output.
Let’s say, however, that your computer has hardware that can measure atmospheric noise – you could fairly easily do that with your built-in microphone on any laptop, or an external mic on a desktop… Or you can measure the randomness of the user’s input – humans are known to be good sources of entropy… Or you could measure the decay of a subatomic particle – quantum mechanics is as random as it gets.
If you could do any of those things – and you can actually do all of them (#3 requires special hardware) you could pass those through a cryptographic hash (ex. SHA-256) to create a truly random stream of bytes with equal probability for every possible state. If you use SHA-256 it would be a good idea to hash at least 512 bits (64 bytes) of data if you want the most randomness possible.
Also, most modern systems have TRNGs (true random number generators) built into their CPUs; hardware manufacturers started doing this to address the need for better RNGs in cryptography. As such, many systems will default to a TRNG if one is available (using the python secrets
module).
You can easily check if you have a TRNG on Linux by running cat /dev/random
. If it stops and waits after a few seconds you don’t and need to use another technique. If if keeps going the same as /dev/urandom
, you have a TRNG already and can make truly-random numbers easily!
Update:
The Python secrets
module documentation can be found here.
A quick example program:
import secrets
low = 10
high = 100
out = secrets.randbelow(high - low) + low # out = random number from range [low, high)
print(out) # Print your number
You can also use secrets
to create a hex string directly, or produce a stream of random bytes. You can see its docs to learn more.
Python has nothing that allows you to generate "truly random" numbers, in the sense that they are uniformly distributed and independent of everything else (especially the latter).
In any case, the distinction between "pseudorandom" and "truly random" numbers is not what applications care about (and you didn’t really specify what kind of application you have in mind). Instead, in general:
- Security applications care whether the numbers are hard to guess; in this case, only a cryptographic RNG can achieve this requirement (even one that relies on a pseudorandom number generator). A Python example is the
secrets
module or random.SystemRandom
.
- Scientific simulations care whether the numbers behave like independent uniform random numbers, and often care whether the numbers are reproducible at a later time. A Python example is
numpy.random.Generator
or random.Random
.
See also these questions:
There is a thing called true random numbers.
Check: www.random.org for more information.
Code example:
import requests
source = "https://www.random.org/integers/?num=1&min=1&max=100&col=5&base=10&format=plain&rnd=new"
number = requests.get(source)
number = int(number.text)
This will give you everything you need + how to set it & also how to get new seeds based on time:
def get_truly_random_seed_through_os(rand_size: int = 4) -> int:
"""
Usually the best random sample you could get in any programming language is generated through the operating system.
In Python, you can use the os module.
source: https://stackoverflow.com/questions/57416925/best-practices-for-generating-a-random-seeds-to-seed-pytorch/57416967#57416967
"""
random_data = os.urandom(
rand_size
) # Return a string of size random bytes suitable for cryptographic use.
random_seed: int = int.from_bytes(random_data, byteorder="big")
return int(random_seed)
def get_different_pseudo_random_seed_every_time_using_time() -> int:
""" Get a different pseudo random seed every time using time."""
import random
import time
# random.seed(int(time.time()))
seed: int = int(time.time())
return seed
def seed_everything(seed: int,
seed_torch: bool = True,
):
"""
https://stackoverflow.com/questions/57416925/best-practices-for-generating-a-random-seeds-to-seed-pytorch
"""
import random
import numpy as np
import os
random.seed(seed)
np.random.seed(seed)
os.environ["PYTHONHASHSEED"] = str(seed)
if seed_torch:
import torch
torch.manual_seed(seed)
# makes convs deterministic: https://stackoverflow.com/a/66647424/1601580, torch.backends.cudnn.deterministic=True only applies to CUDA convolution operations, and nothing else. Therefore, no, it will not guarantee that your training process is deterministic
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
# #torch.use_deterministic_algorithms(True) # do not uncomment
# fully_deterministic: bool = uutils.torch_uu.make_code_deterministic(args.seed)
as mentioned this is an excellent resource: Can I generate authentic random number with python?
Python function that generates true random numbers?
By true random numbers it also means that what every time I run python the seed I generate is different. How do I do this?
There are many ways of generating random numbers, with exactly 1 thing in common – they all require external input. Let’s say you use a simple RNG like games use. The RNG takes an input (usually the system time, in seconds or milliseconds), and performs various wonky mathematical operations to produce a random-looking output.
Let’s say, however, that your computer has hardware that can measure atmospheric noise – you could fairly easily do that with your built-in microphone on any laptop, or an external mic on a desktop… Or you can measure the randomness of the user’s input – humans are known to be good sources of entropy… Or you could measure the decay of a subatomic particle – quantum mechanics is as random as it gets.
If you could do any of those things – and you can actually do all of them (#3 requires special hardware) you could pass those through a cryptographic hash (ex. SHA-256) to create a truly random stream of bytes with equal probability for every possible state. If you use SHA-256 it would be a good idea to hash at least 512 bits (64 bytes) of data if you want the most randomness possible.
Also, most modern systems have TRNGs (true random number generators) built into their CPUs; hardware manufacturers started doing this to address the need for better RNGs in cryptography. As such, many systems will default to a TRNG if one is available (using the python secrets
module).
You can easily check if you have a TRNG on Linux by running cat /dev/random
. If it stops and waits after a few seconds you don’t and need to use another technique. If if keeps going the same as /dev/urandom
, you have a TRNG already and can make truly-random numbers easily!
Update:
The Python secrets
module documentation can be found here.
A quick example program:
import secrets
low = 10
high = 100
out = secrets.randbelow(high - low) + low # out = random number from range [low, high)
print(out) # Print your number
You can also use secrets
to create a hex string directly, or produce a stream of random bytes. You can see its docs to learn more.
Python has nothing that allows you to generate "truly random" numbers, in the sense that they are uniformly distributed and independent of everything else (especially the latter).
In any case, the distinction between "pseudorandom" and "truly random" numbers is not what applications care about (and you didn’t really specify what kind of application you have in mind). Instead, in general:
- Security applications care whether the numbers are hard to guess; in this case, only a cryptographic RNG can achieve this requirement (even one that relies on a pseudorandom number generator). A Python example is the
secrets
module orrandom.SystemRandom
. - Scientific simulations care whether the numbers behave like independent uniform random numbers, and often care whether the numbers are reproducible at a later time. A Python example is
numpy.random.Generator
orrandom.Random
.
See also these questions:
There is a thing called true random numbers.
Check: www.random.org for more information.
Code example:
import requests
source = "https://www.random.org/integers/?num=1&min=1&max=100&col=5&base=10&format=plain&rnd=new"
number = requests.get(source)
number = int(number.text)
This will give you everything you need + how to set it & also how to get new seeds based on time:
def get_truly_random_seed_through_os(rand_size: int = 4) -> int:
"""
Usually the best random sample you could get in any programming language is generated through the operating system.
In Python, you can use the os module.
source: https://stackoverflow.com/questions/57416925/best-practices-for-generating-a-random-seeds-to-seed-pytorch/57416967#57416967
"""
random_data = os.urandom(
rand_size
) # Return a string of size random bytes suitable for cryptographic use.
random_seed: int = int.from_bytes(random_data, byteorder="big")
return int(random_seed)
def get_different_pseudo_random_seed_every_time_using_time() -> int:
""" Get a different pseudo random seed every time using time."""
import random
import time
# random.seed(int(time.time()))
seed: int = int(time.time())
return seed
def seed_everything(seed: int,
seed_torch: bool = True,
):
"""
https://stackoverflow.com/questions/57416925/best-practices-for-generating-a-random-seeds-to-seed-pytorch
"""
import random
import numpy as np
import os
random.seed(seed)
np.random.seed(seed)
os.environ["PYTHONHASHSEED"] = str(seed)
if seed_torch:
import torch
torch.manual_seed(seed)
# makes convs deterministic: https://stackoverflow.com/a/66647424/1601580, torch.backends.cudnn.deterministic=True only applies to CUDA convolution operations, and nothing else. Therefore, no, it will not guarantee that your training process is deterministic
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
# #torch.use_deterministic_algorithms(True) # do not uncomment
# fully_deterministic: bool = uutils.torch_uu.make_code_deterministic(args.seed)
as mentioned this is an excellent resource: Can I generate authentic random number with python?