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

时间:2012-01-20 04:53:19

标签: java random random-seed

例如,如果java生成伪随机序列: 9 3 2 5 6 通过使用 23 作为种子,我该如何做反向?即从 9 3 2 5 6 序列中 23

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

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

INSERT INTO SEQUENCE_TABLE VALUES (RANDOM_KEY, SEQUENCE)

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

5 个答案:

答案 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中对“随机”数字生成器进行逆向工程,那将会非常困难(我认为)。

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