此问题已从加密堆栈交换迁移,因为它可以在堆栈溢出时得到回答。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].
如何确定查找正确种子所需的数据量,而不仅仅是生成相同起始数据的另一个种子?
这会改变给定的奇偶边界吗?
1条答案
按热度按时间7kjnsjlb1#
在没有完全穷尽全部248种可能性的情况下,我将如何在x次调用之后找到当前的种子
nextInt(n)
(假设界不是2的幂)?让我们首先删除这里用于多线程、错误测试和
bound
二的幂。事情归结起来就是接下来我们必须了解
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⌉ = 7val
将数据的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
. 他们更难解释(阅读:我几乎无法让他们使用数学软件包,也无法解释如何使用;看这个问题)。