64 lines
1.4 KiB
Python
64 lines
1.4 KiB
Python
#!/usr/bin/env sage
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import re
|
|
import sys
|
|
|
|
|
|
def parse_task(path):
|
|
text = open(path, "r", encoding="utf-8").read()
|
|
|
|
def pick(name):
|
|
m = re.search(rf"^{name}\s*=\s*([0-9]+)\s*$", text, re.MULTILINE)
|
|
if not m:
|
|
raise RuntimeError(f"cannot find {name} in {path}")
|
|
return Integer(m.group(1))
|
|
|
|
N = pick("N")
|
|
e = pick("e")
|
|
c = pick("c")
|
|
p_revealed = pick("p_revealed")
|
|
return N, e, c, p_revealed
|
|
|
|
|
|
def main():
|
|
task_path = sys.argv[1] if len(sys.argv) > 1 else "public/task.txt"
|
|
N, e, c, p_revealed = parse_task(task_path)
|
|
|
|
# From src/chal.py
|
|
hidden_bits = 448
|
|
X = 2 ** hidden_bits
|
|
|
|
print(f"[*] N bits: {N.nbits()}")
|
|
print(f"[*] hidden bits: {hidden_bits}")
|
|
print("[*] running Coppersmith small_roots...")
|
|
|
|
R = Zmod(N)
|
|
P.<x> = PolynomialRing(R)
|
|
f = x + p_revealed
|
|
|
|
roots = f.small_roots(X=X, beta=0.4)
|
|
if not roots:
|
|
raise RuntimeError("small_roots found no solution")
|
|
|
|
x0 = Integer(roots[0])
|
|
p = Integer(p_revealed + x0)
|
|
if N % p != 0:
|
|
raise RuntimeError("candidate p does not divide N")
|
|
|
|
q = Integer(N // p)
|
|
phi = (p - 1) * (q - 1)
|
|
d = Integer(inverse_mod(e, phi))
|
|
m = Integer(power_mod(c, d, N))
|
|
m_int = int(m)
|
|
flag = m_int.to_bytes((m_int.bit_length() + 7) // 8, "big")
|
|
|
|
try:
|
|
print(flag.decode("utf-8"))
|
|
except Exception:
|
|
print(flag)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|