Cedric found a mysterious box made of pure copper in the old archive. He is convinced that it contains the secrets he is looking for, but he is unable to penetrate the metal case. Can you help?
Challenge
import secrets
p = 0x31337313373133731337313373133731337313373133731337313373133732ad
a = 0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef
b = 0xdeadc0dedeadc0dedeadc0dedeadc0dedeadc0dedeadc0dedeadc0dedeadc0de
def lcg(x, a, b):
while True:
yield (x := a*x + b)
x = int.from_bytes(flag + secrets.token_bytes(30-len(flag)), 'big')
gen = lcg(x, a, b)
h1 = next(gen) * pow(next(gen), -1, p) % p
h2 = next(gen) * pow(next(gen), -1, p) % p
with open('output.txt', 'w') as o:
trunc = 48
# oops, i forgot the last part
o.write(f'hint1 = {h1 >> trunc}\n')
o.write(f'hint2 = {h2 >> trunc}\n')
This looks like a Truncated LCG question, and the challenge name hints at us to use Coppersmith's method.
The hints that are given to us are not directly truncated outputs, rather a pair of the product of the state and inverse of the next state.
To find the flag, we need to find the seed of the LCG, first we need to see the equations given. Let si denote the states, then
The hints given to us are f(x)=x∗e2piiξxh1>>48 and h2>> 48, since h1 and h2 are given modulus p, we can recover h1 and h2 using Coppersmith's method. Let's try forming the equations
We need to form an equation with h1 and h2 such that it is 0 mod p.
One approach that we can try is trying to find an approximation to x from h1 and substituting it in h2.
The problem here is that Coppersmith's method doesn't take inverse polynomials. Even if it did, we need to calculate (a2h1−a)−1, which is a problem, because inverse calculation needs to precise, even a small change can cause a large change in the inverse, which virtually gives us no information about the approximation of x, even though we have an approximation of h1.
We can consider another approach which doesn't use x . To do this, we need to find some relation between h1 and h2. We can do this using Groebner basis.
R.<a,b,x,h1,h2> = PolynomialRing(ZZ)
gen = lcg(x, a, b)
f = next(gen) - h1*next(gen)
g = next(gen) - h2*next(gen)
I = Ideal(f,g)
I.elimination_ideal(x)
#Ideal (a^2*b*h1*h2 - a^2*b*h2 + a*b*h1*h2 - a*b*h1 - a*b*h2 + a*b - b*h2 + b) of Multivariate Polynomial Ring in a, b, x, h1, h2 over Integer Ring
Let l1 and l2 be the 48-bits of LSB of h1 and h2