Kernel :: srand是否有最大输入值?

时间:2011-03-11 23:31:42

标签: ruby

我正在尝试使用哈希的输出为随机数生成器播种。目前我正在计算SHA-1哈希,将其转换为一个巨大的整数,然后将其提供给srand以初始化RNG。这样我就可以得到一组可预测的随机数,用于一组无限的笛卡尔坐标(我正在对坐标进行散列)。

我想知道Kernel :: srand是否实际上具有它将采用的最大值,之后它会以某种方式截断它。文档并没有真正证明这一点 - 他们只是说“一个数字”。

我会试着弄清楚自己,但我假设有人已经遇到过这个问题。

1 个答案:

答案 0 :(得分:4)

知道程序员是什么样的,它可能只是调用libc的srand()。无论哪种方式,它可能限于2 ^ 32-1,2 ^ 31-1,2 ^ 16-1或2 ^ 15-1。

当从biginteger转换为C int / long时,还有一个危险是该值被修剪,而不是仅采用低位。

一个简单的测试是使用1播种并获取第一个输出。然后,在[1..64]左右为i种子2 i +1,取每个的第一个输出,并进行比较。如果你得到一些i=n和所有更大i的匹配,那么它可能是算术模2 n

请注意,无论如何,随机数生成器几乎肯定限制在32或48位熵,因此用巨大的值来播种它几乎没有什么意义,攻击者可以合理地轻松预测过去输出的未来输出(以及“攻击者” “可能只是公共nethack服务器上的玩家。”

编辑:所以我错了。

根据Kernel :: rand()的文档,

  

Ruby目前使用经过修改的Mersenne Twister,周期为2 ** 19937-1。

这意味着它不仅仅是对libc的rand()的调用。 Mersenne Twister在统计上更优越(但不具有加密安全性)。但无论如何。

使用Kernel::srand(0); Kernel::sprintf("%x",Kernel::rand(2**32))测试各种输出尺寸(2 * 16,2 * 32,2 * 36,2 * 60,2 * 64,2 * 32 + 1,2 * 35,2 * 34 + 1),有一些事情是显而易见的:

  1. 它计算出它需要多少位(max-1中的位数)。
  2. 它以32位为一组产生输出,最高有效位优先,然后丢弃最高位(即0x [r0] [r1] [r2] [r3] [r4],顶部位被屏蔽掉)
  3. 如果它不小于max,它会进行某种重试。从输出中得到的结果并不明显。
  4. 如果小于max,则输出结果。
  5. 我不确定为什么2 * 32 + 1和2 * 64 + 1是特殊的(它们从Kernel::rand(2**1024)产生相同的输出,所以可能具有完全相同的状态) - 我没有发现另一次碰撞。

    好消息是它不会简单地剪切到某个任意最大值(即传递大量数字不等于传入2 ** 31-1),这是最明显的可能出错的事情。 Kernel :: srand()也返回前一个种子,看起来是128位,所以传入大的东西似乎是安全的。

    编辑2:当然,不能保证输出在不同的Ruby版本之间可以重现(文档只是说它“当前使用”;显然这最初是在2002年提交的)。 Java有几个可移植的确定性PRNG(SecureRandom.getInstance("SHA1PRNG","SUN"),虽然很慢);我不知道Ruby的相似之处。