Reputation: 2886
I'm dd
'ing from /dev/urandom
in order to create files with random contents. This works well, but I would like to be able to reproduce the file contents at some later point by running the PRNG again with the same seed. Is there any seedable PRNG which exposes a character device?
I'm using recent Linux 3.X kernels.
Upvotes: 5
Views: 5807
Reputation: 384124
Python 3.9 random.randbytes
+ random.seed
I've learnt to stop fighting what Bash can't do and just go with the flow:
randbytes() (
python -c 'import random;import sys;random.seed(int(sys.argv[1]));sys.stdout.buffer.write(random.randbytes(int(sys.argv[2])))' "$@"
)
Usage:
randbytes <seed> <nbytes>
e.g.:
randbytes 0 8 | hd
always outputs 8 identical pseudo-random bytes with seed 0:
00000000 cd 07 2c d8 be 6f 9f 62 |..,..o.b|
00000008
Readable multiline version at: Generating random string of seedable data
On my Lenovo ThinkPad P51, I can dump 100 million bytes in ramfs in 0.5s. however, if I try to dump 1 billion it blows up with:
Python int too large to convert to C int
so it is something to keep in mind.
For comparison:
time sudo dd if=/dev/urandom of=ramfs/test bs=4k count=24414
took 2.5s, so it is slower, which is not surprising as it is a more random source, while the Python generator is deterministic and appears to be written in C.
Tested on Ubuntu 20.10, Linux kernel 5.8.0.
Upvotes: 2
Reputation: 8030
Check out the ISO C rand() and srand() functions:
http://man7.org/linux/man-pages/man3/rand.3.html
Upvotes: 0
Reputation: 1950
If you want your files to be random but reproductible given a seed, you are using the wrong tool. /dev/urandom gets its randomness from the environment (timing of incoming and outgoing network packets, disk accesses, etc.) so even if you start with the same seed, it's very highly unlikely that you will get the same sequence of random numbers two times in a row.
You want a conventional (aka software-only) pseudo-random number generator. The Mersenne Twister is a good one. It should have an implementation in the language you're using. Or just use whatever pseudo-random number generator comes with your language.
Upvotes: 0
Reputation: 51910
/dev/*random do not use a seed, because they're not pseudo-random number generators. They provide randomness from the environment (using even hardware as a source, like keyboard, interrupts, network, etc.) In the case of /dev/urandom, a seed and an RNG is only used when the pool is exhausted. But it's still unpredictable when that happens.
So, do not read random numbers from /dev/*random. Instead, use the bash facilities to generate random numbers:
#! /bin/bash # Seed the RNG RANDOM = 1234 # Print 10 random numbers for i in {1..10} do echo $RANDOM done
The above script will print the same sequence of numbers every time, because the seed is constant.
If you want to generate bytes, meaning values in the range of 0 to 255, then use printf
instead of echo
and cycle the random number you get to that range:
printf "\\x$(printf "%x" $(($RANDOM % 256)))"
If you now run the script and redirect output to a file, it will contain 10 "random" bytes.
Upvotes: 1
Reputation: 25676
/dev/urandom
is designed to be as unpredictable as possible. It sounds like you want a more conventional seeded pseudorandom number generator.
Here's one I just wrote in C:
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char *endptr;
unsigned long int seed;
if (argc != 2 || *argv[1] == '\0') {
fprintf(stderr, "usage: %s seed\n", argv[0]);
return EXIT_FAILURE;
}
errno = 0;
seed = strtoul(argv[1], &endptr, 0);
if (errno != 0 || *endptr != '\0' || seed > UINT_MAX) {
fprintf(stderr, "%s: invalid seed\n", argv[0]);
return EXIT_FAILURE;
}
srandom((unsigned int) seed);
while (1) {
int i;
long int randomnum = random();
for (i = 0; i < sizeof randomnum; i++) {
if (putchar((randomnum >> (i * CHAR_BIT)) & UCHAR_MAX) == EOF) {
return EXIT_SUCCESS;
}
}
}
}
This is a program, not a device file, but its output is the same format as you'd get from /dev/urandom
. You can pipe the output from it into dd
and omit if
.
If you need to come up with a truly random seed to supply to the program, you can get one in bash from /dev/urandom
like this:
seed=$(od -vAn -N4 -tu4 </dev/urandom)
Replace 4 with whatever sizeof(unsigned int)
is on your machine (it's probably 4).
Upvotes: 2
Reputation: 4188
taken from urandom documentation
When a Linux system starts up without much operator interaction, the entropy pool may be in a fairly predictable state. This reduces the actual amount of noise in the entropy pool below the estimate. In order to counteract this effect, it helps to carry entropy pool information across shut-downs and start-ups. To do this, add the following lines to an appropriate script which is run during the Linux system start-up sequence:
echo "Initializing kernel random number generator..." # Initialize kernel random number generator with random seed # from last shut-down (or start-up) to this start-up. Load and # then save 512 bytes, which is the size of the entropy pool. if [ -f /var/random-seed ]; then cat /var/random-seed >/dev/urandom fi dd if=/dev/urandom of=/var/random-seed count=1
Upvotes: 1