通常のLCGのパラメータ
出力系列は
Truncated LCGでは(例えば)の下位半分がわからないときに、を求めたい
と書いて、が未知
まずb=0の場合
次のような等式を考えてみる
ベクトルをと置き、行列をと置いて:
を基底簡約してにして:
なので
もも小さいのでと近似して
これで以外がわかったので、
[* のとき]
とおいて
例題と回答
mod = random_prime(1<<64) a = randint(1, mod-1) c = randint(1, mod-1) seed = int.from_bytes(open("flag.txt","rb").read().strip(), "big") class LCG(): def __init__(self, a, c, mod, seed): self.a = a self.c = c self.mod = mod self.seed = seed def next(self): self.seed = (self.seed * self.a + self.c) % self.mod return self.seed lcg = LCG(a, c, mod, seed) outputs = [] for _ in range(10): r = lcg.next() half = r >> 32 outputs.append(half) print("a={}".format(a)) print("c={}".format(c)) print("mod={}".format(mod)) print("outputs={}".format(outputs))
def guess_state(xs, a, b, m): # s1 = a*s0 + b # s2 = a^2*s0 + ab + b # s3 = a^3*s0 + aab + ab + b # s4 = a^4*s0 + aaab + aab + ab + b n = len(xs) ks = [b] for i in range(1, n): ks.append(ks[i-1] + a^i * b) xxs = [(xs[i] << 32) - ks[i] for i in range(n)] L = matrix(ZZ, n, 1, [m] + [a^i for i in range(1, n)]) L = L.augment(matrix.identity(n)[:,1:] * -1) B = L.LLL() print(list(B)) xB = B * vector(xxs) k = [round(x/m) for x in xB] yys = B.solve_right(vector(k) * m - xB) print(yys) s1 = (xs[0] << 32) + yys[0] s0 = (s1 - b) * inverse_mod(a, m) % m return s0 a=4984204341965293659 c=812992498535670640 mod=12007620771585163889 outputs=[1603731004, 1981439462, 843976945, 95071464, 1700919759, 296270126, 952176344, 1205445753, 1258468465, 143557791] seed = guess_state(outputs, a, c, mod) print(bytes.fromhex(hex(seed)[2:]))