p = 243678574849421895808521345944938402807 q = 278451262698064898668334196027031252819 s = 172134561985710786674839705035313724070
c = 15084463560924811262750235394027264639346464192638172940901706702947534963652
defdecrypt(p, e, c): g = gcd(e, p-1) d = inverse_mod(e // g, p-1) m0 = pow(c, d, p) print(m0) print(g) m = Zmod(p)(m0).nth_root(g, all=True) print(m) assertpow(m[0], e, p) == c return m
mp = decrypt(p, s, c) mq = decrypt(q, s, c) for mpi, mqi in itertools.product(mp, mq): m = crt([ZZ(mpi), ZZ(mqi)], [p, q]) msg = long_to_bytes(int(m)) print(msg)
得到 flag 为:
1
CCTF{m1X!n9__3cC__&_R54_!}
关于为什么这样生成的曲线的阶满足 $\#E(\mathrm{F}_p) = p + 1$,可以看看 这篇 paper 的 3.2 节,之后也能看到类似的生成方法就不用验证也能一眼丁真(
classGao: def__init__(self): self.conn = remote('00.cr.yp.toc.tf', '31117') defdecompose(self, A, index_list, M): iflen(A) == 0: returnNone eliflen(A) == 1: if M != A[0]: returnNone else: return [index_list[0]] else: for i, Ai inenumerate(A): M_ = Ai^-1 * M try: 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 = self.decompose(A_, index_list_, M_) if res: return [index_list[i]] + res else: returnNone except: continue else: returnNone
defdecrypt(self, As, M): T = M # 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_ = Ai^-1 * T S = self.decompose(A_, index_list_, T_) if S: return [i] + S else: returnNone
defget_matrices(self, k, l): self.conn.sendlineafter('[Q]uit', 'G') matrices = [] for i inrange(l): mat = [] for i inrange(k): self.conn.recvuntil(b'[') row = self.conn.recvuntil(b']')[:-1].decode().split() mat.append(list(map(int, row))) matrices.append(matrix(ZZ, mat)) return matrices
classGao: def__init__(self): self.conn = remote('00.cr.yp.toc.tf', '31117') defdecompose(self, A, index_list, M): iflen(A) == 0: returnNone eliflen(A) == 1: if M != A[0]: returnNone else: return [index_list[0]] else: for i, Ai inenumerate(A): M_ = 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 = self.decompose(A_, index_list_, M_) if res: return [index_list[i]] + res else: returnNone else: returnNone
defdecrypt(self, As, M): T = M # 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_ = Ai^-1 * T S = self.decompose(A_, index_list_, T_) if S: return [i] + S else: returnNone
defget_matrices(self, k, l): self.conn.sendlineafter('[Q]uit', 'G') matrices = [] for i inrange(l): mat = [] for i inrange(k): self.conn.recvuntil(b'[') row = self.conn.recvuntil(b']')[:-1].decode().split() mat.append(list(map(int, row))) matrices.append(matrix(ZZ, mat)) return matrices
from Crypto.Util.number import * import itertools from tqdm import tqdm
pi = [3, 5, 379, 39719, 8959787, 891059823255825019255461632769683] ai = [1, 1 + 11954, 1, 1, 1, 1]
ri = [range(aii+1) for aii in ai] for ai_ in tqdm(itertools.product(*ri)): m = 1 for p, a inzip(pi, ai_): m *= p**a msg_ = long_to_bytes(m) ifall(32 <= x < 128for x in msg_): print('AOLIGEI!!!') print(msg_)