C ++,44014022/164607120
它是用C ++语言编写的,使用1 GB的内存,并花了大约45秒钟找到了第一对。找到所有时间后,我将更新时间。
下面的代码。它首先查找所有产生4个零的对,然后通过简单的试验将其归零(请参见check
方法)。它通过生成两个大数组来查找产生4个零的对,一个大数组包含state1生成器的前4个低阶字节,第二个数组包含state2生成器的前4个低阶字节的负数。然后对这些数组进行排序并搜索匹配项,该匹配项对应于整个生成器输出4个零开始的匹配。
数组太大而无法存储在内存中,因此它会按大小进行批量工作以适合内存。
看起来完整的运行大约需要12个小时。
编辑:改进了代码,因此只需要大约1个小时即可获得所有可能的种子。现在,它将表生成为256个不同的文件,每个输出的第一个字节一个。然后,我们可以独立处理每个文件,因此不必重新生成数据。
编辑:事实证明,您可以一次生成256个子表,而不是一次全部生成,因此不需要磁盘。使用256MB,运行时间可缩短至15分钟左右。
#include <stdio.h>
#include <stdint.h>
#include <algorithm>
using namespace std;
#define M1 65539
#define N1 4294967087
#define M2 65537
#define N2 4294965887
#define MATCHES 7
// M^-1 mod N
#define M1_INV 3027952124
#define M2_INV 1949206866
int npairs = 0;
void check(uint32_t seed1, uint32_t seed2) {
uint32_t s1 = seed1;
uint32_t s2 = seed2;
for (int i = 0; i < MATCHES; i++) {
s1 = (uint64_t)s1 * M1 % N1;
s2 = (uint64_t)s2 * M2 % N2;
if (((s1 + s2) & 0xff) != 0) return;
}
printf("%d %u %u\n", npairs++, seed1, seed2);
}
struct Record {
uint32_t signature; // 2nd through 5th generated bytes
uint32_t seed; // seed that generated them
};
// for sorting Records
bool operator<(const Record &a, const Record &b) {
return a.signature < b.signature;
}
int main(int argc, char *argv[]) {
Record *table1 = (Record*)malloc((N1/256+1)*sizeof(*table1));
Record *table2 = (Record*)malloc((N2/256+1)*sizeof(*table2));
for (int i = 0; i < 256; i++) { // iterate over first byte
printf("first byte %x\n", i);
// generate signatures (bytes 2 through 5) for all states of generator 1
// that generate i as the first byte.
Record *r = table1;
for (uint64_t k = i; k < N1; k += 256) {
uint32_t sig = 0;
uint32_t v = k;
for (int j = 0; j < 4; j++) {
v = (uint64_t)v * M1 % N1;
sig = (sig << 8) + (v & 0xff);
}
r->signature = sig;
r->seed = k;
r++;
}
Record *endtable1 = r;
// generate signatures (bytes 2 through 5) for all states of generator 2
// that generate -i as the first byte.
r = table2;
for (uint64_t k = (-i & 0xff); k < N2; k += 256) {
uint32_t sig = 0;
uint32_t v = k;
for (int j = 0; j < 4; j++) {
v = (uint64_t)v * M2 % N2;
sig = (sig << 8) + (-v & 0xff);
}
r->signature = sig;
r->seed = k;
r++;
}
Record *endtable2 = r;
sort(table1, endtable1);
sort(table2, endtable2);
// iterate through looking for matches
const Record *p1 = table1;
const Record *p2 = table2;
while (p1 < endtable1 && p2 < endtable2) {
if (p1->signature < p2->signature) p1++;
else if (p1->signature > p2->signature) p2++;
else {
check((uint64_t)p1->seed * M1_INV % N1, (uint64_t)p2->seed * M2_INV % N2);
// NOTE: may skip some potential matches, if p1->signature==(p1+1)->signature or p2->signature==(p2+1)->signature
p1++;
}
}
}
}