bound)结果中查找java.util.random种子

2w3rbyxf  于 2021-06-27  发布在  Java
关注(0)|答案(1)|浏览(325)

此问题已从加密堆栈交换迁移,因为它可以在堆栈溢出时得到回答。4天前迁移的。

背景

我一直在阅读并试图围绕各种与从java.util.random中查找seed相关的问题/答案,因为它的输出来自 nextInt() .
实施 nextInt(int bound) 是:

public int nextInt(int bound) {
   if (bound <= 0)
     throw new IllegalArgumentException("bound must be positive");

   if ((bound & -bound) == bound)  // i.e., bound is a power of 2
     return (int)((bound * (long)next(31)) >> 31);

   int bits, val;
   do {
       bits = next(31);
       val = bits % bound;
   } while (bits - val + (bound-1) < 0);
   return val;
 }

实施 next(int bits) 是:

protected int next(int bits) {
    long oldseed, nextseed;
    AtomicLong seed = this.seed;
    do {
        oldseed = seed.get();
        nextseed = (oldseed * multiplier + addend) & mask;
    } while (!seed.compareAndSet(oldseed, nextseed));
    return (int)(nextseed >>> (48 - bits));
}

乘数在哪里 0x5DEECE66DL ,加数是 0xBL ,面具是 (1L << 48) - 1 . 这些是十六进制值,其中l是java的约定 long 转换。
通过呼叫 nextInt() 如果没有绑定,则从 next(32) 而不是用 bits % bound .

问题

在没有完全穷尽全部248种可能性的情况下,我将如何在x次调用之后找到当前的种子 nextInt(n) (假设界不是2的幂)?例如,假设我想找到给定10个调用的种子 nextInt(344) [251, 331, 306, 322, 333, 283, 187, 54, 170, 331].
如何确定查找正确种子所需的数据量,而不仅仅是生成相同起始数据的另一个种子?
这会改变给定的奇偶边界吗?

7kjnsjlb

7kjnsjlb1#

在没有完全穷尽全部248种可能性的情况下,我将如何在x次调用之后找到当前的种子 nextInt(n) (假设界不是2的幂)?
让我们首先删除这里用于多线程、错误测试和 bound 二的幂。事情归结起来就是

public int nextInt_equivalent(int bound) {
   int bits, val;
   do {
       seed = (seed * multiplier + addend) & mask; // 48-bit LCG
       bits = seed >> 17;                          // keep the top 31 bits
       val = bits % bound;                         // build val in [0, bound)
   } while (bits - val + (bound-1) < 0);
   return val;
 }

接下来我们必须了解 while (bits - val + (bound-1) < 0) 是关于。它在这里使用 bits 只有在宽度为 bound ,从而确保 val . 这个间隔是[0,  (1L<<31)/bound*bound ).
while条件等价于 while (bits >= (1L<<31)/bound*bound) ,但执行速度更快。这种情况发生在 (1L<<31)%bound 最大值 bits 由于 1L<<31 . 什么时候 bound 为344,则8个值 bits 在231个国家中,约占3.7%。
这是如此罕见,一个合理的方法是假设它不会发生。另一种方法是希望它发生,并通过观察引起这种罕见事件的种子是否导致了一系列的基因突变来测试它是否(以及何时)发生 val 在吉文斯发现的。我们只有 ((1L<<31)%bound)<<17 (此处略高于一百万)的值 seed 进行测试,这是非常可行的。不管怎样,在剩下的部分,我假设这是排除的,并考虑发电机没有时间。
什么时候 bound 是偶数,或者更一般地说是2s的倍数,对于一些s>0,观察输出的低阶s位 val (我们可以找到)也是 bits ,从而将 seed . 种子的低17+s位完全独立于其他31-s位。什么时候 bound is 344=8×43,我们有s=3,因此我们可以攻击 seed 独立地。我们直接得到s=3位 seed 从一开始 val .
我们得到了 seed 通过消去:对于217个候选者中的每一个,给定我们知道的s=3位,那么17+s=20位 seed 导致一系列 val 哪个低阶s位与给定序列匹配?有了足够的值,我们就可以完全确定17+s位。我们需要⌈17/秒+1⌉ = 7 val 将数据的17+s低位缩小到一个值 seed 以这种方式。如果我们得到的更少,我们需要在下一步保留几个候选人。在这个问题上我们有足够的证据 val 缩小到一个单一的值,并确信我们得到了正确的结果。
当我们有17+s=20位 seed ,我们可以找到剩余的31-s=28,使用适度的暴力。我们可以测试228个未知位的值 seed 并检查哪个与已知的完全匹配 val . 但更好的是:我们知道 seed % (bound<<17) 没错,所以只需要测试231/ bound 价值观 seed (这里大约600万)。
如何确定查找正确种子所需的数据量?
对于除病理性lcg和许多其他prng之外的所有prng,一个可行的启发式方法是,您需要的信息与状态中的位(即48位)一样多。每个输出提供log2( bound )所以你需要⌈48/日志2( bound )⌉ 值,这里是6(这将需要跟踪低20位 seed 因此需要在第二阶段进行更多的工作)。额外的值给了我们恢复实际状态的信心,但是错误的猜测是不会发生的,除非 while 开始发挥作用。
这会改变给定的奇偶边界吗?
上述攻击策略对奇数攻击效果不佳 bound (我们不能单独猜测低位,需要搜索248/ bound 价值观 seed ). 然而,有更好的攻击与较少的猜测,适用于即使我们大大提高了国家位的数量,包括奇数 bound . 他们更难解释(阅读:我几乎无法让他们使用数学软件包,也无法解释如何使用;看这个问题)。

相关问题