例如,如果java生成伪随机序列: 9 3 2 5 6 通过使用 23 作为种子,我该如何做反向?即从 9 3 2 5 6 序列中 23 。
或者如何为特定序列分配种子?
如果有数据库则很容易 - 只需为序列分配一个随机密钥
INSERT INTO SEQUENCE_TABLE VALUES (RANDOM_KEY, SEQUENCE)
但是,如果我不被允许使用数据库,是否有公式可以做这样的事情?
答案 0 :(得分:6)
随机数生成器的点是不可能的。 SecureRandom的设计特别cryptographically strong,但一般来说,如果你正在编写一个随机数生成器,这是可能的或简单的,那你做错了。
也就是说,使用Java内置的Random类可能不是不可能。 (SecureRandom是另一个故事。)但它需要数量惊人的数学。
更具体一点:如果存在多项式时间算法来做你想要的,对于某些特定的伪随机数生成器,那么根据定义它将失败链接的维基百科文章中描述的“下一位测试”,因为你可以预测下一个要生成的元素。
答案 1 :(得分:5)
是的,对设计不良的伪随机数生成器的数字流进行逆向工程非常容易,例如Java编程语言(java.util.Random
)中的线性同余PRNG实现。
实际上,只要该特定生成器的 TWO 值少,以及值出现顺序的信息,就可以预测整个流。
Random random = new Random();
long v1 = random.nextInt();
long v2 = random.nextInt();
for (int i = 0; i < 65536; i++) {
long seed = v1 * 65536 + i;
if (((seed * multiplier + addend) & mask) >>> 16) == v2) {
System.out.println("Seed found: " + seed);
break;
}
}
这正是使用加密安全随机数生成器的关键所在,这些生成器已被社区审查为需要安全性的实现。
有关逆向工程PRNG的更多信息,包括java.util.Random
here。 ...
答案 2 :(得分:4)
当然可以恢复java.util.Random使用的种子。 This post描述了Random的线性同余公式背后的数学,这里是一个从nextInt()返回的最后两个整数中发现当前种子的函数。
public static long getCurrentSeed(int i1, int i2) {
final long multiplier = 0x5DEECE66DL;
final long inv_mult = 0xDFE05BCB1365L;
final long increment = 0xBL;
final long mask = ((1L << 48) - 1);
long suffix = 0L;
long lastSeed;
long currSeed;
int lastInt;
for (long i=0; i < (1<<16); i++) {
suffix = i;
currSeed = ((long)i2 << 16) | suffix;
lastSeed = ((currSeed - increment) * inv_mult) & mask;
lastInt = (int)(lastSeed >>> 16);
if (lastInt == i1) {
/* We've found the current seed, need to roll back 2 seeds */
currSeed = lastSeed;
lastSeed = ((currSeed - increment) * inv_mult) & mask;
return lastSeed ^ multiplier;
}
}
/* Error, current seed not found */
System.err.println("current seed not found");
return 0;
}
此函数返回一个值,该值可与rand.setSeed()一起使用,以生成以i1和i2开头的伪随机数字序列。
答案 3 :(得分:2)
您想要获取任意数字序列,然后确定一个短(固定长度?)键,这将允许您重新生成该数字序列,而不存储原始数据?不幸的是,你想要的在技术上是不可能的。原因如下:
这是压缩的特例。您有一长串数据,您希望能够从较小的信息中无损地重建这些数据。如果您要求的是可能的,那么我将能够将整个堆栈溢出压缩为一个整数(因为整个网站可以序列化为一系列数字,虽然很长!)
不幸的是,数学并不是那样的。任何给定的序列都具有特定的熵度量 - 该序列中的平均复杂度。为了无损地再现该序列,您必须能够编码至少足够的信息来表示其熵。
对于某些序列,实际上可能存在能够生成长的特定序列的种子,但这仅仅是因为存在硬编码的数学函数,其接收该种子并产生特定的数字序列。但是,要获取任意值的序列并生成这样的种子,您需要种子和能够从该种子生成该序列的函数。为了对这两件事进行编码,您会发现自己拥有的数据远远超出预期!
答案 4 :(得分:1)
如果你可以使用String
作为种子,可以使用:
String seed = "9 3 2 5 6";
然后你的发电机看起来像:
String[] numbers = seed.split(" ");
如果你真的想在java中对“随机”数字生成器进行逆向工程,那将会非常困难(我认为)。
如果可以,最好以相反的方式进行:从种子开始,生成序列,然后从那里开始。