Files
ctf/2026/cscg/crypto/punkhash/crack.sage
2026-03-09 21:44:25 +01:00

70 lines
2.0 KiB
Python

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
# Given data
p = 161435094849208186723743776068899835990543
factors = [
156186292768571019331898663060909752711843,
109417470692453243484139400223645310959791,
93089433143062722427906401287402408530212,
28547969321924826217366869381297180095037,
8782064060721059630464173504550123514711,
102955100934149078143279795799942076169546,
6414672390685577718586273505396597123970,
104333325295219441337759136041049892760564,
112152969625868065689337753377527032666195,
73628881014191725621637709513252461493920,
55767305113105638821720350052172401226595,
151443380055257227298905238183594975661210,
154754427703287717852463872100570391036124,
109309350493404368756996675514019660378226,
72830920510645561848991903607768750782945,
140601680236381413682085702731572037454013
]
h = 55699848449950859593116400319282899455819
enc_flag = bytes.fromhex("62c4cc8d98f1cfbc92d0315fc939b464614c7c96cfc956b0c8a44eeda15e4856fcf87710f97b445b4c4986794666fa391eeaf70963ea8f522c5b3866b7e153b6")
n = len(factors)
W = 2**256
# --- THE FIX: Center the search space around 0 ---
OFFSET = 128
h_centered = (h - OFFSET * sum(factors)) % p
# Build an 18x18 Matrix
M = Matrix(ZZ, n + 2, n + 2)
for i in range(n):
M[i, i] = 1
M[i, n + 1] = factors[i] * W
M[n, n + 1] = p * W
M[n + 1, n] = 1
M[n + 1, n + 1] = -h_centered * W
# Run LLL Algorithm
L = M.LLL()
found = False
for row in L:
if row[n] in [1, -1]:
y_vals = list(row[:n])
# If flipped by LLL, flip it back
if row[n] == -1:
y_vals = [-y for y in y_vals]
preimage = [y + OFFSET for y in y_vals]
if all(0 <= x < 256 for x in preimage):
key = bytes(preimage)
cipher = AES.new(key, AES.MODE_ECB)
flag = unpad(cipher.decrypt(enc_flag), 16).decode()
print(flag)
found = True
break
if not found:
print(":/")