【问题标题】:Linear congruential generator: How important is setting seed?线性同余生成器:设置种子有多重要?
【发布时间】:2010-10-07 09:34:57
【问题描述】:

我正在学习算法和数据结构课程中的linear congruential generator。在考虑了我们一直在使用的 RNG 实现(a=429493445,c=907633385,mod=4294967296,X 是 _uint32)之后,我想到了一件事:程序有设置种子的功能。

该函数在 C 和 C++ 中的重要性如何?

这是我的思路:一旦程序启动,操作系统就会为所有使用的变量分配地址。给种子的内存位置中的数据可以解释为一个数字。

我了解在小型计算机中,操作系统(如果有的话)可能会为种子分配多次相同的地址,但该地址中包含的数据不会每次都不同吗?除非系统在每次启动后将所有空闲 RAM 设置为某个值,否则 RAM 中包含的数据本身几乎是随机的,并且提供了足够好的种子。

即使给种子的空间中包含的数据被另一个程序使用,我看不出这会对生成器本身产生什么影响。

【问题讨论】:

  • “随机数的生成太重要了,不能靠运气”——Robert R. Coveyou
  • @pmg 对不起,我不明白你的意思。
  • @pmg:“任何考虑产生随机数字的算术方法的人当然都处于罪恶状态。” ——约翰·冯·诺依曼
  • Robert R. Coveyou 的意思是,我认为,生成个随机数是困难的,而且机会可能仅限于计算机算法,并不是一种有效的方法。跨度>
  • @AndrejaKo:Coveyou 的俏皮话(适用于本示例)是您正在使用一些您不知道如何预测的数据,但您也不知道它到底有多随机。也许在某些系统上它实际上是非常可预测的。即使在不小的计算机上,通过虚拟寻址,您也会发现程序中的几乎所有内容每次都出现在相同的(虚拟)位置。所以,不要依靠你不完善的知识来“听天由命”——仅仅因为你个人目前无法找到预测它的方法并不意味着它是可靠的随机的。

标签: c++ c random


【解决方案1】:

虽然不认真地玩 RNG,但使用“记忆中的垃圾”播种可能会正常工作。但这确实是一种糟糕的做事方式:您无法保证内存中的数据随机的,即使可以。在安全应用程序中(我想这与这里无关,因为您使用的是线性同余生成器),您不希望不受您控制的环境部分(RAM)充当种子。在其他应用程序中,例如科学计算,您希望您的结果是可重现的。然后您所做的通常是让用户为自己选择一个种子,并提供一个选项来对种子的 OS RNG 进行采样(类 UNIX 系统上的 /dev/random)。

底线是:如果您想要随机种子,请从良好的随机性来源中获取。您的操作系统提供的几乎所有易于访问的资源都比“嘿,今天这个位置的 RAM 中有什么?”更好。例如,从 /dev/urandom 进行采样并不比对 RAM 进行采样更困难,而且这是正确的做法(当然,对于非安全敏感的事情)。

编辑:以下是使用 C 在 GNU/Linux 上对 /dev/urandom 进行采样的方法:

int seed;
FILE* urandom = fopen("/dev/urandom", "r");
fread(&seed, sizeof(int), 1, urandom);
fclose(urandom);

现在seed 保存了一个整数,可以用作 PRNG 的种子(您可能需要不同的数据类型)。

维基百科有some nice information on /dev/random and /dev/urandom

【讨论】:

  • 我在哪里可以找到一些关于当今流行操作系统(Windows、GNU/Linux)提供的易于访问的随机源的信息?还是我应该将其作为单独的问题发布?
  • @AndrejaKo:添加了一篇不错的维基百科文章和代码示例的链接。
【解决方案2】:

OpenSSL 确实使用未初始化的内存来生成其随机初始化的一部分。 2年前Debian did remove this的时候有一些噪音,认为使用未初始化的变量是一个错误。

请注意,这不是 OpenSSL 中熵的唯一来源

所以是的,未初始化的内存可以用作随机性的来源。但要小心真正了解你在做什么!

【讨论】:

  • 我想补充最后一句话:并清楚地记录您在做什么以及您是故意这样做的。否则,您可以轻松地让维护程序员消除您的随机性来源。
  • Debian 认为这是一个错误是正确的。它具有 undefined (不是未指定)行为,并且未来的编译器和库版本将完全免费使其崩溃程序。操作系统提供了获取熵的正确方法;使用它们。把手指给西奥。
【解决方案3】:

关于 PRNG 的一件事是,当您知道它们的参数并设置初始种子时,它们会提供可重现的序列。所以在这方面,在 API 中公开这个“特性”是很自然的。许多应用程序都需要这种形式的确定性,而真正的 RNG 设备无法提供。

编辑:要回答您的实际问题,假设堆栈变量中的数据是随机的是错误的,几乎所有 unix 系统都会清除堆栈和堆(用 0 初始化)作为安全措施,假设您可以读取密码上一个进程留在内存中的字符串。

【讨论】:

  • 我没想到。如果您需要调试与伪随机数相关的应用程序的一部分,那么提前知道 PRNG 将为应用程序提供什么肯定会很有用。
【解决方案4】:

随机内存可以用作种子。但是,由于操作系统中的内存分配算法不是随机的,并且其他程序生成的数据通常也遵循某种模式,因此我认为它不是一个完美的种子。这取决于您的应用程序的目的——例如,我绝对不会在银行系统中使用它。 如果您想要更多随机性,您可以将其用作种子的一部分,然后将其与来自不同来源的其他随机种子相乘。

【讨论】:

    【解决方案5】:

    不要将种子设置为。由/dev/urandom 初始化将是最好的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-20
      • 2015-08-22
      • 2013-10-09
      • 1970-01-01
      • 1970-01-01
      • 2019-11-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多