I did not manage to solve this challenge. The private key is composed by some $f, g$, both smaller than $\sqrt{\frac{q}{2}}$, with the relation that $fh - g = 0 \mod q$
This means that there exists a $k$ such that $fh = qk + g$, since $h$ is about the same size of $q$, we have that $k$ is the same size of $f$.
We have the observation that $f \cdot (h, 1) + (-k) \cdot (q, 1) = (g, f - k)$, where both components of the result are small (g is around the square root of $\frac{q}{2}$, and $f$ is approximately $k$). Also note that $f > k$, hence $f - k > 0$.
We can use Gauss reduction to find the lattice generated by $(h, 1), (q, 1)$ has a chance to give us $g$.
Sage Implementation: (kudos to Drago
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
from Crypto.Util.number import long_to_bytes
def decrypt(q, h, f, g, e):
a = (f*e) % q
m = (a*inverse_mod(f, g)) % g
return m
def gauss(v1, v2):
while True:
if v2.norm() < v1.norm():
v1, v2 = v2, v1
m = round(v1*v2/(v1*v1))
if m == 0:
return v1, v2
v2 = v2-m*v1
h, q = (2163268902194560093843693572170199707501787797497998463462129592239973581462651622978282637513865274199374452805292639586264791317439029535926401109074800, 7638232120454925879231554234011842347641017888219021175304217358715878636183252433454896490677496516149889316745664606749499241420160898019203925115292257)
enc_flag = 5605696495253720664142881956908624307570671858477482119657436163663663844731169035682344974286379049123733356009125671924280312532755241162267269123486523
g = gauss(vector([q,1]),vector([h,1]))[0][0]
F = IntegerModRing(q)
f = int(g / F(h))
print(long_to_bytes(decrypt(q,h,f,g,enc_flag)))
|