有没有办法从一系列数字中生成种子?

例如,如果java通过使用23作为种子产生伪随机序列: 9 3 2 5 6 ,我该如何进行反演? 即从序列中获得23 个3 3 2 5 6

或者我如何为特定序列分配种子?

如果有数据库则很容易 – 只需为序列分配一个随机密钥

INSERT INTO SEQUENCE_TABLE VALUES (RANDOM_KEY, SEQUENCE) 

但是,如果我不被允许使用数据库,是否有一个公式来做这样的事情?

随机数生成器的要点是这是不可能的。 SecureRandom的设计特别强大 ,但一般来说,如果你正在编写一个随机数生成器,这是可能的或简单的,那你做错了。

也就是说,Java内置的Random类可能并非不可能 。 (然而,SecureRandom是另一个故事。)但它需要数量惊人的数学。

更具体一点:如果存在多项式时间算法来做你想要的,对于某些特定的伪随机数生成器,那么根据定义它将失败链接的维基百科文章中描述的“下一位测试”,因为你可以预测将生成的下一个元素。

是的,对设计不良的伪随机数生成器的数字流进行逆向工程是非常容易的,例如Java编程语言( java.util.Random )中的线性同余PRNG实现。

事实上,只要该特定生成器的两个值,以及值出现顺序的信息,就可以预测整个流。

 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 。 …

当然可以恢复java.util.Random使用的种子。 这篇文章描述了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开头的伪随机数字序列。

您想要获取任意数字序列,然后确定一个短(固定长度?)键,这将允许您重新生成该序列的数字,而不存储原始数据? 不幸的是,你想要的在技术上是不可能的。 原因如下:

这是压缩的特殊情况。 您有一长串数据,您希望能够从较小的信息中无损地重建这些数据。 如果您要求的是可能的,那么我将能够将整个堆栈溢出压缩为一个整数(因为整个网站可以序列化为一系列数字,虽然很长!)

不幸的是,数学并不是那样的。 任何给定的序列都有一个特定的熵度量 – 该序列中的平均复杂度。 为了无损地再现该序列,您必须能够编码至少足够的信息来表示其熵。

对于某些序列,事实上可能存在能够产生长的特定序列的种子,但这仅仅是因为存在硬编码的数学函数,其取得该种子并产生特定的数字序列。 但是,要获取任意值的序列并生成这样的种子,您需要种子和能够从该种子生成该序列的函数。 为了对这两件事进行编码,您会发现您拥有的数据远远超出您的期望!

如果你可以使用String作为种子,你可以使用:

 String seed = "9 3 2 5 6"; 

然后你的发电机看起来像:

 String[] numbers = seed.split(" "); 

如果你真的想要在java中对“随机”数字生成器进行逆向工程,那将会非常困难(我认为)。

如果可以的话,最好以相反的方式做到:从种子开始,生成序列,然后从那里开始。