DF-5707 / minstd.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | /* * minstd.c - exact replica of sys/libkern/random.c krandom() Schrage stepping * plus utilities used by the DF-5707 evidence chain. * * step(s) : 16807*s mod (2^31-1) (valid for s in [1, 2^31-2]) * ainv(s) : multiply by modular inverse of 16807 (walk state backward) * * modes: * minstd step <state> <n> : print n successive states from state * minstd ainv <state> <n> : print n predecessors * minstd inv : print inverse of 16807 mod m * minstd backseed <state> <bootsec> <maxsteps> * : walk back up to maxsteps; report any s0 such that * (s0 ^ bootsec') < 1000000000 for bootsec' in {b-1,b,b+1}, * and forward-verify it reproduces <state> after t steps. * minstd igen <state> : print i_gen = t/2+1 for next 6 draws */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #define M 2147483647ULL #define A 16807ULL static uint64_t step(uint64_t s) { return (A * s) % M; } static uint64_t inv_mod(uint64_t a, uint64_t m) { int64_t t = 0, nt = 1, r = m, nr = a; while (nr) { int64_t q = r / nr, tmp; tmp = t - q * nt; t = nt; nt = tmp; tmp = r - q * nr; r = nr; nr = tmp; } if (r > 1) { fprintf(stderr, "not invertible\n"); exit(1); } if (t < 0) t += m; return (uint64_t)t; } int main(int argc, char **argv) { if (argc < 2) goto usage; if (!strcmp(argv[1], "inv")) { printf("%llu\n", (unsigned long long)inv_mod(A, M)); return 0; } if (argc >= 3 && !strcmp(argv[1], "igen")) { uint64_t s = strtoull(argv[2], NULL, 0); for (int i = 0; i < 6; i++) { s = step(s); printf("draw%u state=%llu igen=%llu (0x%llx)\n", i + 1, (unsigned long long)s, (unsigned long long)(s / 2 + 1), (unsigned long long)(s / 2 + 1)); } return 0; } if (argc >= 4 && !strcmp(argv[1], "dist")) { /* steps needed to go from state a to state b (forward, <= 64) */ uint64_t a = strtoull(argv[2], NULL, 0), b = strtoull(argv[3], NULL, 0); uint64_t s = a; for (long i = 1; i <= 8192; i++) { s = step(s); if (s == b) { printf("%ld\n", i); return 0; } } printf("-1\n"); return 0; } if (argc < 4) goto usage; if (!strcmp(argv[1], "step") || !strcmp(argv[1], "ainv")) { uint64_t s = strtoull(argv[2], NULL, 0); long n = atol(argv[3]); uint64_t k = !strcmp(argv[1], "step") ? A : inv_mod(A, M); for (long i = 0; i < n; i++) { s = (k * s) % M; printf("%llu\n", (unsigned long long)s); } return 0; } if (!strcmp(argv[1], "igen")) { uint64_t s = strtoull(argv[2], NULL, 0); for (int i = 0; i < 6; i++) { s = step(s); printf("draw%u state=%llu igen=%llu (0x%llx)\n", i + 1, (unsigned long long)s, (unsigned long long)(s / 2 + 1), (unsigned long long)(s / 2 + 1)); } return 0; } if (!strcmp(argv[1], "backseed2") && argc >= 6) { /* backseed2 <S_late> <S_early> <bootsec> <maxsteps> * S_early was observed D draws before S_late (D computed by forward * walk). For each t, candidate seed s0 = ainv^t(S_late) passes if * (s0 ^ bsec') < 1e9 for bsec' in [bsec-120, bsec+120] AND * step^(t-D)(s0) == S_early (independent landmark check). */ uint64_t s_late = strtoull(argv[2], NULL, 0); uint64_t s_early = strtoull(argv[3], NULL, 0); uint64_t bsec = strtoull(argv[4], NULL, 0); long maxsteps = atol(argv[5]); uint64_t ainv = inv_mod(A, M); long D = -1; { uint64_t w = s_early; for (long i = 1; i <= 2048; i++) { w = step(w); if (w == s_late) { D = i; break; } } } printf("landmark distance D=%ld\n", D); if (D < 0) { printf("landmarks not on same forward chain\n"); return 1; } uint64_t cur = s_late; for (long t = 1; t <= maxsteps; t++) { cur = (ainv * cur) % M; for (int d = -120; d <= 120; d++) { uint64_t ns = (uint64_t)((int64_t)cur ^ (int64_t)(bsec + d)); if (ns < 1000000000ULL && ns >= 1) { uint64_t f = ns; for (long j = 0; j < t - D; j++) f = step(f); if (f == s_early) printf("SEED-FOUND t=%ld seed=%llu nsec=%llu bootsec=%lld\n", t, (unsigned long long)ns, (unsigned long long)(ns ^ (uint64_t)((int64_t)bsec + d)), (long long)((int64_t)bsec + d)); } } } return 0; } usage: fprintf(stderr, "usage: minstd {inv|step S N|ainv S N|igen S|backseed S BSEC MAX}\n"); return 2; } |