p = q = o = p^3 * q^5 * (p^2+p+1)*(q^2+q+1)*(p-1)*(q-1) n = p^4 * q^6 pubkey = enc = n_, e = pubkey assert n == n_
defadd(P, Q, c, n): # Add two points P and Q on curve x^3 + c*y^3 + c^2*z^3 - 3*c*x*y*z = 1 in Zmod(n) (x1, y1, z1) = P (x2, y2, z2) = Q x3 = (x1*x2 + c*(y2*z1 + y1*z2)) % n y3 = (x2*y1 + x1*y2 + c*z1*z2) % n z3 = (y1*y2 + x2*z1 + x1*z2) % n return (x3, y3, z3)
defmul(P, g, c, n): # Scalar multiplication on curve (x1, y1, z1) = P (x2, y2, z2) = (1, 0, 0) for b inbin(g)[2:]: (x2, y2, z2) = add((x2, y2, z2), (x2, y2, z2), c, n) if b == '1': (x2, y2, z2) = add((x2, y2, z2), (x1, y1, z1), c, n) return (x2, y2, z2)
deflift(f, p, k, previous): result = [] df = diff(f) for lower_solution in previous: dfr = Integer(df(lower_solution)) fr = Integer(f(lower_solution)) if dfr % p != 0: t = ZZ((-(xgcd(dfr, p)[1]) * int(fr // p ** (k - 1))) % p) x_ = lower_solution + t * p ** (k - 1) result.append(x_) if dfr % p == 0: if fr % p ** k == 0: for t inrange(0, p): x_ = lower_solution + t * p ** (k - 1) result.append(x_) return result
defhensel_lifting(f, p, k, base_solution): solution = base_solution for i inrange(2, k + 1): solution = lift(f, p, i, solution) return solution
defget_c(P, p, k): x, y, z = P PR.<c> = PolynomialRing(Zmod(p)) f = x^3 + c*y^3 + c^2*z^3 - 3*c*x*y*z - 1 c_list = [ZZ(x) for x, rep in f.roots()] PR.<c> = PolynomialRing(Zmod(p^k)) f = x^3 + c*y^3 + c^2*z^3 - 3*c*x*y*z - 1 c_list = hensel_lifting(f, p, k, c_list) c = ZZ(c_list[0]) return c_list
cp_list = get_c(enc, p, 4) cq_list = get_c(enc, q, 6)
d = inverse_mod(e, o) for cp, cq in itertools.product(cp_list, cq_list): c = crt([ZZ(cp), ZZ(cq)], [p^4, q^6]) m = mul(enc, d, c, n) x, y, z = m msg = long_to_bytes(int(m[0])) + long_to_bytes(int(m[1])) print(msg)
defget_matrix(x): x_ = x.replace('[', '').replace(']', '') xlines = x_.splitlines() ret = [[int(xij) for xij in xline.strip().split()] for xline in xlines] return matrix(ZZ, ret)
mat_list = list(map(get_matrix, mat_list))
nbit = 256 k, l, _B = 5, 19, 63 M, As, Ep = mat_list[:l], mat_list[l:2*l], mat_list[-1]
defgao_one(i): Mi, Asi = M[i], As[i] wtf = Asi^-1 * Ep^-1 * Mi * Ep a = wtf[0, 0] return a
plist = [] for i inrange(1, l): pi = gao_one(0) - gao_one(i) plist.append(pi.numerator()) p = gcd(plist) Zp = Zmod(p) M = [A.change_ring(Zp) for A in M] As = [A.change_ring(Zp) for A in As] Ep = Ep.change_ring(Zp) Ds = As[0]^-1 * Ep^-1 * M[0] * Ep
C = '\n'.join(s[157:162])[4:] C = get_matrix(C) C = C.change_ring(Zp)
defdecompose(A, index_list, M, Ds): iflen(A) == 0: returnNone eliflen(A) == 1: if M != A[0]: returnNone else: return [index_list[0]] else: for i, Ai inenumerate(A): M_ = Ds^-1 * Ai^-1 * M MZ = M.change_ring(ZZ).list() MZ_ = M_.change_ring(ZZ).list() if (all(MZi_ < MZi for MZi, MZi_ inzip(MZ, MZ_))): A_ = A[:i] + A[i+1:] index_list_ = index_list[:i] + index_list[i+1:] res = decompose(A_, index_list_, M_, Ds) if res: return [index_list[i]] + res else: returnNone else: returnNone
defdecrypt(C, M, As, Ep, Ds): T = Ep^-1 * C * Ep * Ds^-1 # CAONIMA, exceed index_list = list(range(len(As))) for i, Ai inenumerate(As): A_ = As[:i] + As[i+1:] index_list_ = index_list[:i] + index_list[i+1:] T_ = Ds^-1 * Ai^-1 * T S = decompose(A_, index_list_, T_, Ds) if S: return [i] + S else: returnNone
my_order = decrypt(C, M, As, Ep, Ds)
from string import printable as prn flag = 'CCTF{' + ''.join([prn[10 + my_order[_]] for _ inrange(l)]) + '}' print(f'{flag = }')