5

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.

4

6 回答 6

2

/dev/urandom被设计为尽可能不可预测。听起来您想要一个更传统的种子伪随机数生成器。

这是我刚刚用 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;
            }
        }
    }
}

这是一个程序,而不是设备文件,但它的输出格式与您从/dev/urandom. 您可以将其输出通过管道传输到dd并省略if.

如果您需要提供一个真正随机的种子来提供给程序,您可以从 bash 中获得一个,/dev/urandom如下所示:

seed=$(od -vAn -N4 -tu4 </dev/urandom)

将 4 替换sizeof(unsigned int)为您机器上的任何内容(可能是 4)。

于 2013-07-26T15:44:00.093 回答
2

Python 3.9 random.randbytes+random.seed

我已经学会了停止与 Bash 做不到的事情作斗争,顺其自然:

randbytes() (
  python -c 'import random;import sys;random.seed(int(sys.argv[1]));sys.stdout.buffer.write(random.randbytes(int(sys.argv[2])))' "$@"
)

用法:

randbytes <seed> <nbytes>

例如:

randbytes 0 8 | hd

总是输出 8 个相同的伪随机字节,种子为 0:

00000000  cd 07 2c d8 be 6f 9f 62                           |..,..o.b|
00000008

可读的多行版本:生成可种子数据的随机字符串

在我的联想 ThinkPad P51 上,我可以在 0.5 秒内将 1 亿字节转储到 ramfs 中。但是,如果我尝试倾销 10 亿,它会爆炸:

Python int too large to convert to C int

所以要记住这一点。

为了比较:

time sudo dd if=/dev/urandom of=ramfs/test bs=4k count=24414

耗时 2.5 秒,因此速度较慢,这并不奇怪,因为它是一个更随机的源,而 Python 生成器是确定性的,并且似乎是用 C 编写的。

在 Ubuntu 20.10、Linux 内核 5.8.0 上测试。

于 2021-02-02T22:02:07.090 回答
1

取自 urandom文档

当 Linux 系统在没有太多操作员交互的情况下启动时,熵池可能处于相当可预测的状态。这将熵池中的实际噪声量减少到低于估计值。为了抵消这种影响,它有助于在关闭和启动过程中携带熵池信息。为此,请将以下几行添加到在 Linux 系统启动序列期间运行的适当脚本中:

    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
于 2013-07-25T14:49:22.430 回答
1

/dev/*random 不使用种子,因为它们不是伪随机数生成器。它们提供来自环境的随机性(甚至使用硬件作为源,如键盘、中断、网络等)。在 /dev/urandom 的情况下,仅当池耗尽时才使用种子和 RNG。但是当这种情况发生时,它仍然是不可预测的。

所以,不要从 /dev/*random 中读取随机数。相反,使用 bash 工具生成随机数:

#!/bin/bash

# 播种 RNG
随机 = 1234

# 打印 10 个随机数
对于我在 {1..10}
做
    回声$随机
完毕

上面的脚本每次都会打印相同的数字序列,因为种子是恒定的。

如果要生成字节,即 0 到 255 范围内的值,请使用printf而不是echo循环获取该范围的随机数:

printf "\\x$(printf "%x" $(($RANDOM % 256)))"

如果您现在运行脚本并将输出重定向到一个文件,它将包含 10 个“随机”字节。

于 2013-07-26T15:53:51.540 回答
0

如果您希望您的文件是随机的但给定种子可复制,那么您使用了错误的工具。/dev/urandom 从环境中获取随机性(传入和传出网络数据包的时间、磁盘访问等),因此即使您从相同的种子开始,也极不可能获得相同的随机数序列二连续几次。

您需要一个传统的(也称为纯软件)伪随机数生成器。Mersenne Twister是一款不错的产品。它应该具有您正在使用的语言的实现。或者只是使用您的语言附带的任何伪随机数生成器。

于 2013-07-26T17:45:48.637 回答
0

查看 ISO C rand() 和 srand() 函数:

http://man7.org/linux/man-pages/man3/rand.3.html

于 2013-07-26T18:06:08.707 回答