These Walls - Codegate 2025
from secret import P, s, o, wrong, flag
from Crypto.Cipher import AES
import random, os, math
assert P * o == P.curve()(0)
assert all(math.gcd(o, w) == 1 for w in wrong + [s])
assert all(P * s != P * w for w in wrong)
key = os.urandom(32)
enc_flag = AES.new(key, AES.MODE_CTR, nonce=bytes(12)).encrypt(flag.encode())
print(f"{enc_flag.hex() = }\n{o = }")
key = int.from_bytes(key)
for i in range(32 * 8):
P *= [random.choice(wrong), s][(key >> i) & 1]
print(P.xy())
Solve:
Author’s writeup: https://github.com/soon-haari/my-ctf-challenges/tree/main/2025-codegate/crypto-thesewalls
1. Getting curve parameters
You can do something like this: https://hackropole.fr/en/writeups/fcsc2021-crypto-lost-curve/984a2038-3039-42c2-af1b-8d671c8d5cb0/
wget https://raw.githubusercontent.com/soon-haari/my-ctf-challenges/refs/heads/main/2025-codegate/crypto-thesewalls/prob/for_organizer/output.txt
points = [[int(i) for i in line.strip()[1:-1].split(', ')] for line in open('output.txt').readlines()[2:]]
PR.<a, b> = PolynomialRing(ZZ)
eqs = []
for x, y in points:
eqs.append(x^3 + a * x + b - y^2)
for eq in Ideal(eqs).groebner_basis():
print(eq)
modulus = 102426836944425277819174256940128868455066517869185115488781035394164877927042198980921397582250905694209313963017944880679709788694772632564808279062807699845761214703586660326307989151472431126842544189892251409194318824261554131269698538462346988910692541060196190265045309883144365795763912362099350625483
a = -42437997016440510106912234059113681926759694788505021671714484006715784960406807326337661210536581463443414294141888675487947253004723175974512262085287744401565107056353588589043894055035481272184124372125833792185916608297835874449349134631410453080264719245505015377542883012707703282190702361267129303085
b = -459126200632887849752040227678358886031820038366770963884159263686486524398810848612517185164748716420888346292004054958933940038260166360595786900336024132100453336182502034941923082615662562466591523855797071255915619970830634702916789796993677327554098916574862778060640867963470961569155246282541122528
print(a % modulus)
print(b % modulus)
So:
modulus = 102426836944425277819174256940128868455066517869185115488781035394164877927042198980921397582250905694209313963017944880679709788694772632564808279062807699845761214703586660326307989151472431126842544189892251409194318824261554131269698538462346988910692541060196190265045309883144365795763912362099350625483
a = 59988839927984767712262022881015186528306823080680093817066551387449092966635391654583736371714324230765899668876056205191762535690049456590296016977519955444196107647233071737264095096436949854658419817766417617008402215963718256820349403830936535830427821814691174887502426870436662513573210000832221322398
b = 101967710743792389969422216712450509569034697830818344524896876130478391402643388132308880397086156977788425616725940825720775848656512466204212492162471675713660761367404158291366066068856768564375952666036454337938403204290723496566781748665353311583138442143621327486984669015180894834194757115816809502955
2. Factor the modulus
You can check the author’s code how to do it, the result is:
modulus = 102426836944425277819174256940128868455066517869185115488781035394164877927042198980921397582250905694209313963017944880679709788694772632564808279062807699845761214703586660326307989151472431126842544189892251409194318824261554131269698538462346988910692541060196190265045309883144365795763912362099350625483
p1 = 3562548874780288796769030192977
p2 = 3692983360407686094702508373879
p3 = 2717597692908121319788497985451
p4 = 324094280281900209908870811008292068290746348301400744740589987
assert modulus == p1 * p2**2 * p3**3 * p4**2
Now we’ll split this into 4 different curves with the different primes.
3. p1 - singular curve (elliptic node)
same as https://connor-mccartney.github.io/cryptography/ecc/Backdoor-IRONCTF2024
from collections import namedtuple
Point = namedtuple("Point", "x y")
O = 'Origin'
def point_inverse(P):
if P == O:
return P
return Point(P.x, -P.y % p)
def point_addition(P, Q):
if P == O:
return Q
elif Q == O:
return P
elif Q == point_inverse(P):
return O
else:
if P == Q:
lam = (3*P.x**2 + a)*pow(2*P.y, -1, p)
lam %= p
else:
lam = (Q.y - P.y) * pow((Q.x - P.x), -1, p)
lam %= p
Rx = (lam**2 - P.x - Q.x) % p
Ry = (lam*(P.x - Rx) - P.y) % p
R = Point(Rx, Ry)
return R
def mul(P, n):
Q = P
R = O
while n > 0:
if n % 2 == 1:
R = point_addition(R, Q)
Q = point_addition(Q, Q)
n = n // 2
return R.x
def node_log(p, a, b, qx, qy, sx, sy):
PR.<x> = PolynomialRing(GF(p))
f = x^3 + a*x + b
double_root = [r for r, e in f.roots() if e==2][0]
qx -= double_root
sx -= double_root
f2 = f.subs(x=x+double_root)
c = f2.factor()[0][0].coefficients()[0]
sqrt_c = GF(p)(c).sqrt()
def mapping(x, y, sqrt_c):
return (y + x*sqrt_c) * pow(y - x*sqrt_c, -1, p)
return mapping(sx, sy, sqrt_c).log(mapping(qx, qy, sqrt_c))
points = [[int(i) for i in line.strip()[1:-1].split(', ')] for line in open('output.txt').readlines()[2:]]
p = 3562548874780288796769030192977
a = 59988839927984767712262022881015186528306823080680093817066551387449092966635391654583736371714324230765899668876056205191762535690049456590296016977519955444196107647233071737264095096436949854658419817766417617008402215963718256820349403830936535830427821814691174887502426870436662513573210000832221322398
b = 101967710743792389969422216712450509569034697830818344524896876130478391402643388132308880397086156977788425616725940825720775848656512466204212492162471675713660761367404158291366066068856768564375952666036454337938403204290723496566781748665353311583138442143621327486984669015180894834194757115816809502955
cache = set()
#cache = set([2419208789977833651231607199477, 2583035536321228815355660114783, 1296865482336368230445011996195, 501301829518150467387924489803, 1596507685543054568030561590627, 1189472469521133536636628876539, 1688818121111580066310934554129, 3127040603798222765320841880913, 1313812976397865456124720849605, 2450964906071836807094736013303])
for i in range(255):
P1 = Point(points[i][0], points[i][1])
P2 = Point(points[i+1][0], points[i+1][1])
log = None
for l in cache:
if mul(P1, l) == P2.x % p:
log = l
break
if log is None:
log = node_log(p, a, b, P1.x,P1.y, P2.x, P2.y)
cache.add(log)
print(log)
[1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1596507685543054568030561590627, 3127040603798222765320841880913, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2450964906071836807094736013303, 1688818121111580066310934554129, 1296865482336368230445011996195, 1688818121111580066310934554129, 1688818121111580066310934554129, 1189472469521133536636628876539, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1189472469521133536636628876539, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2419208789977833651231607199477, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 3127040603798222765320841880913, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 501301829518150467387924489803, 1688818121111580066310934554129, 2419208789977833651231607199477, 1296865482336368230445011996195, 1688818121111580066310934554129, 3127040603798222765320841880913, 2419208789977833651231607199477, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1296865482336368230445011996195, 1688818121111580066310934554129, 1688818121111580066310934554129, 2419208789977833651231607199477, 1688818121111580066310934554129, 1688818121111580066310934554129, 1189472469521133536636628876539, 1296865482336368230445011996195, 1688818121111580066310934554129, 501301829518150467387924489803, 1688818121111580066310934554129, 1688818121111580066310934554129, 3127040603798222765320841880913, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2450964906071836807094736013303, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1596507685543054568030561590627, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1596507685543054568030561590627, 1688818121111580066310934554129, 2583035536321228815355660114783, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2419208789977833651231607199477, 1688818121111580066310934554129, 1313812976397865456124720849605, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1296865482336368230445011996195, 1688818121111580066310934554129, 1688818121111580066310934554129, 1313812976397865456124720849605, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1596507685543054568030561590627, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2450964906071836807094736013303, 1688818121111580066310934554129, 1688818121111580066310934554129, 501301829518150467387924489803, 1688818121111580066310934554129, 3127040603798222765320841880913, 1688818121111580066310934554129, 1688818121111580066310934554129, 3127040603798222765320841880913, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2419208789977833651231607199477, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1189472469521133536636628876539, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2450964906071836807094736013303, 2450964906071836807094736013303, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1596507685543054568030561590627, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 3127040603798222765320841880913, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2419208789977833651231607199477, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1596507685543054568030561590627, 1688818121111580066310934554129, 1313812976397865456124720849605, 2450964906071836807094736013303, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1189472469521133536636628876539, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1296865482336368230445011996195, 3127040603798222765320841880913, 501301829518150467387924489803, 1688818121111580066310934554129, 1189472469521133536636628876539, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1296865482336368230445011996195, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2583035536321228815355660114783, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2419208789977833651231607199477, 1688818121111580066310934554129, 1313812976397865456124720849605, 2419208789977833651231607199477, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129]
4. p2 - supersingular curve (MOV attack)
p2 = 3692983360407686094702508373879
a = 59988839927984767712262022881015186528306823080680093817066551387449092966635391654583736371714324230765899668876056205191762535690049456590296016977519955444196107647233071737264095096436949854658419817766417617008402215963718256820349403830936535830427821814691174887502426870436662513573210000832221322398
b = 101967710743792389969422216712450509569034697830818344524896876130478391402643388132308880397086156977788425616725940825720775848656512466204212492162471675713660761367404158291366066068856768564375952666036454337938403204290723496566781748665353311583138442143621327486984669015180894834194757115816809502955
E = EllipticCurve(GF(p2), [a, b])
# embedding degree
k = 1
while (p2**k - 1) % E.order() != 0:
k += 1
print(k)
The embedding degree is 2.
You have about a 50% change of getting the correct s and not one of the wrong ones.
Index 2 happens to be correct.
points = [[int(i) for i in line.strip()[1:-1].split(', ')] for line in open('output.txt').readlines()[2:]]
p2 = 3692983360407686094702508373879
a = 59988839927984767712262022881015186528306823080680093817066551387449092966635391654583736371714324230765899668876056205191762535690049456590296016977519955444196107647233071737264095096436949854658419817766417617008402215963718256820349403830936535830427821814691174887502426870436662513573210000832221322398
b = 101967710743792389969422216712450509569034697830818344524896876130478391402643388132308880397086156977788425616725940825720775848656512466204212492162471675713660761367404158291366066068856768564375952666036454337938403204290723496566781748665353311583138442143621327486984669015180894834194757115816809502955
E = EllipticCurve(GF(p2), [a, b])
def MOV_attack(E, G, A, k):
E2 = EllipticCurve(GF(p2**k), [a,b])
T = E2.random_point()
M = T.order()
N = G.order()
T1 = (M//gcd(M, N)) * T
_G = E2(G).weil_pairing(T1, N)
_A = E2(A).weil_pairing(T1, N)
nA = _A.log(_G)
return nA
i = 2
P1 = E(points[i][0], points[i][1])
P2 = E(points[i+1][0], points[i+1][1])
log = MOV_attack(E, P1, P2, k=2)
print(log)
$ time sage x.sage
860437940168965817900625942259
real 29m14.353s
5. p3 - supersingular curve, with a=0
For p3, and p4, technically MOV attack could work again but it’s very slow.
But p3 has a=0 and p4 has b=0, this allows for a better idea: distortion maps
This is where the challenge name becomes a hint - (wall -> weil pairing)
We don’t actually compute any logs, just check if the pairings match.
from tqdm import trange
points = [[int(i) for i in line.strip()[1:-1].split(', ')] for line in open('output.txt').readlines()[2:]]
correct_idx = 2
p3 = 2717597692908121319788497985451
a = 59988839927984767712262022881015186528306823080680093817066551387449092966635391654583736371714324230765899668876056205191762535690049456590296016977519955444196107647233071737264095096436949854658419817766417617008402215963718256820349403830936535830427821814691174887502426870436662513573210000832221322398
b = 101967710743792389969422216712450509569034697830818344524896876130478391402643388132308880397086156977788425616725940825720775848656512466204212492162471675713660761367404158291366066068856768564375952666036454337938403204290723496566781748665353311583138442143621327486984669015180894834194757115816809502955
E = EllipticCurve(GF(p3), [a, b])
o = E.order()
assert E.is_supersingular()
assert E.a4() == 0
assert o == p3 + 1
def dlog_power(P, Q, p, o, E):
EQp = E.change_ring(Qp(p))
Pmul = EQp(P) * o
Qmul = EQp(Q) * o
return ZZ((Qmul[0] / Qmul[1]) / (Pmul[0] / Pmul[1]))
Fp2 = GF(p3^2)
z = Fp2(1).nth_root(3)
assert z != 1
E = EllipticCurve(Fp2, [a, b])
def distorsion_map(P):
x, y = P.xy()
return E(x * z, y)
dat_p3 = [E(P) for P in points]
assert dat_p3[0].order() == o
dat_p3_distorsion = [distorsion_map(P) for P in dat_p3]
res_p3 = [ dat_p3[correct_idx].weil_pairing(dat_p3_distorsion[i + 1], p3 + 1)
== dat_p3[correct_idx + 1].weil_pairing(dat_p3_distorsion[i], p3 + 1)
for i in trange(255)]
print(f'{res_p3 = }')
E = EllipticCurve(Zmod(p3^3), [a, b])
dat_p3 = [E(P) for P in points]
dlog_correct = dlog_power(dat_p3[correct_idx + 1], dat_p3[correct_idx], p3, o, E)
res_p3_power = [dlog_power(dat_p3[i + 1], dat_p3[i], p3, o, E) == dlog_correct for i in trange(255)]
print(f'{res_p3_power = }')
res_p3 = [True, False, True, True, True, False, False, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, True, True, True, True, False, True, False, True, True, True, False, True, True, True, True, True, True, True, True, False, True, False, False, True, True, False, True, True, True, False, False, True, True, True, False, True, True, True, False, True, True, True, False, True, True, True, False, True, True, True, True, False, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, False, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, True, False, True, False, True, True, False, True, False, False, True, True, True, False, False, True, True, True, True, True, False, False, False, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, False, True, True, True, False, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, False, True, True, False, True, False, True, True, True, True, False, True, True, True, True, True, False, True, True, True, True, True, True, False, True, False, True, True, True, True, True, True, False, True, True, True, True, True, True, True, False, True, True, False, True, False, True, True, True, True, True, False, True]
res_p3_power = [False, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, True, True, True, False, True, True, False, True, True, True, False, True, False, False, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, False, True, False, True, True, False, True, True, True, True, False, False, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, False, True, True, True, True, True, True, False, False, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True]
6. p4 - supersingular curve, with b=0
from tqdm import trange
points = [[int(i) for i in line.strip()[1:-1].split(', ')] for line in open('output.txt').readlines()[2:]]
correct_idx = 2
p4 = 324094280281900209908870811008292068290746348301400744740589987
a = 59988839927984767712262022881015186528306823080680093817066551387449092966635391654583736371714324230765899668876056205191762535690049456590296016977519955444196107647233071737264095096436949854658419817766417617008402215963718256820349403830936535830427821814691174887502426870436662513573210000832221322398
b = 101967710743792389969422216712450509569034697830818344524896876130478391402643388132308880397086156977788425616725940825720775848656512466204212492162471675713660761367404158291366066068856768564375952666036454337938403204290723496566781748665353311583138442143621327486984669015180894834194757115816809502955
E = EllipticCurve(GF(p4), [a, b])
o = E.order()
assert E.is_supersingular()
assert o == p4 + 1
def dlog_power(P, Q, p, o, E):
EQp = E.change_ring(Qp(p))
Pmul = EQp(P) * o
Qmul = EQp(Q) * o
return ZZ((Qmul[0] / Qmul[1]) / (Pmul[0] / Pmul[1]))
Fp2 = GF(p4^2)
z = Fp2(-1).nth_root(2)
E = EllipticCurve(Fp2, [a, b])
def distorsion_map(P):
x, y = P.xy()
return E(-x, y * z)
dat_p4 = [E(P) for P in points]
assert dat_p4[0].order() == o
dat_p4_distorsion = [distorsion_map(P) for P in dat_p4]
res_p4 = [ dat_p4[correct_idx].weil_pairing(dat_p4_distorsion[i + 1], p4 + 1)
== dat_p4[correct_idx + 1].weil_pairing(dat_p4_distorsion[i], p4 + 1)
for i in trange(255)]
print(f'{res_p4 = }')
E = EllipticCurve(Zmod(p4^2), [a, b])
dat_p4 = [E(P) for P in points]
dlog_correct = dlog_power(dat_p4[correct_idx + 1], dat_p4[correct_idx], p4, o, E)
res_p4_power = [dlog_power(dat_p4[i + 1], dat_p4[i], p4, o, E) == dlog_correct for i in trange(255)]
print(f'{res_p4_power = }')
res_p4 = [True, True, True, True, True, True, False, True, True, True, True, True, True, True, False, True, True, False, True, True, True, True, False, True, True, True, True, True, True, False, True, True, False, True, False, True, True, True, True, True, True, True, True, False, True, False, True, False, True, False, True, True, True, True, True, True, True, True, False, True, True, False, True, True, False, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, True, True, True, True, True, True, True, True, False, True, False, True, True, True, True, True, True, False, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, False, False, True, True, True, True, True, False, True, True, False, True, False, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, False, True, True, True, True, True, True, True, False, True, True, True, True, False, True, False, True, True, False, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, True, True, False, True, True, True, True, True, True]
res_p4_power = [True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, True, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, False, False, False, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, False, True, True, True, True, True, False, True, False, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True]
7. Combining everything
from Crypto.Cipher import AES
p1_logs = [1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1596507685543054568030561590627, 3127040603798222765320841880913, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2450964906071836807094736013303, 1688818121111580066310934554129, 1296865482336368230445011996195, 1688818121111580066310934554129, 1688818121111580066310934554129, 1189472469521133536636628876539, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1189472469521133536636628876539, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2419208789977833651231607199477, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 3127040603798222765320841880913, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 501301829518150467387924489803, 1688818121111580066310934554129, 2419208789977833651231607199477, 1296865482336368230445011996195, 1688818121111580066310934554129, 3127040603798222765320841880913, 2419208789977833651231607199477, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1296865482336368230445011996195, 1688818121111580066310934554129, 1688818121111580066310934554129, 2419208789977833651231607199477, 1688818121111580066310934554129, 1688818121111580066310934554129, 1189472469521133536636628876539, 1296865482336368230445011996195, 1688818121111580066310934554129, 501301829518150467387924489803, 1688818121111580066310934554129, 1688818121111580066310934554129, 3127040603798222765320841880913, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2450964906071836807094736013303, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1596507685543054568030561590627, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1596507685543054568030561590627, 1688818121111580066310934554129, 2583035536321228815355660114783, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2419208789977833651231607199477, 1688818121111580066310934554129, 1313812976397865456124720849605, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1296865482336368230445011996195, 1688818121111580066310934554129, 1688818121111580066310934554129, 1313812976397865456124720849605, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1596507685543054568030561590627, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2450964906071836807094736013303, 1688818121111580066310934554129, 1688818121111580066310934554129, 501301829518150467387924489803, 1688818121111580066310934554129, 3127040603798222765320841880913, 1688818121111580066310934554129, 1688818121111580066310934554129, 3127040603798222765320841880913, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2419208789977833651231607199477, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1189472469521133536636628876539, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2450964906071836807094736013303, 2450964906071836807094736013303, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1596507685543054568030561590627, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 3127040603798222765320841880913, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2419208789977833651231607199477, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1596507685543054568030561590627, 1688818121111580066310934554129, 1313812976397865456124720849605, 2450964906071836807094736013303, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1189472469521133536636628876539, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1296865482336368230445011996195, 3127040603798222765320841880913, 501301829518150467387924489803, 1688818121111580066310934554129, 1189472469521133536636628876539, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1296865482336368230445011996195, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2583035536321228815355660114783, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 2419208789977833651231607199477, 1688818121111580066310934554129, 1313812976397865456124720849605, 2419208789977833651231607199477, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129, 1688818121111580066310934554129]
res_p1 = [x==p1_logs[2] for x in p1_logs]
p2_log = 860437940168965817900625942259
points = [[int(i) for i in line.strip()[1:-1].split(', ')] for line in open('output.txt').readlines()[2:]]
p2 = 3692983360407686094702508373879
a = 59988839927984767712262022881015186528306823080680093817066551387449092966635391654583736371714324230765899668876056205191762535690049456590296016977519955444196107647233071737264095096436949854658419817766417617008402215963718256820349403830936535830427821814691174887502426870436662513573210000832221322398
b = 101967710743792389969422216712450509569034697830818344524896876130478391402643388132308880397086156977788425616725940825720775848656512466204212492162471675713660761367404158291366066068856768564375952666036454337938403204290723496566781748665353311583138442143621327486984669015180894834194757115816809502955
E = EllipticCurve(GF(p2), [a, b])
p2_dat = [E(x, y) for x, y in points]
res_p2 = [p2_dat[i] * p2_log == p2_dat[i+1] for i in range(255)]
res_p2_power = [True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, False, True, False, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, True, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, False, True, True, True, False, True, True, True, True, False, False, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True]
res_p3 = [True, False, True, True, True, False, False, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, True, True, True, True, False, True, False, True, True, True, False, True, True, True, True, True, True, True, True, False, True, False, False, True, True, False, True, True, True, False, False, True, True, True, False, True, True, True, False, True, True, True, False, True, True, True, False, True, True, True, True, False, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, False, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, True, False, True, False, True, True, False, True, False, False, True, True, True, False, False, True, True, True, True, True, False, False, False, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, False, True, True, True, False, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, False, True, True, False, True, False, True, True, True, True, False, True, True, True, True, True, False, True, True, True, True, True, True, False, True, False, True, True, True, True, True, True, False, True, True, True, True, True, True, True, False, True, True, False, True, False, True, True, True, True, True, False, True]
res_p3_power = [False, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, True, True, True, False, True, True, False, True, True, True, False, True, False, False, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, False, True, False, True, True, False, True, True, True, True, False, False, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, False, True, True, True, True, True, True, False, False, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True]
res_p4 = [True, True, True, True, True, True, False, True, True, True, True, True, True, True, False, True, True, False, True, True, True, True, False, True, True, True, True, True, True, False, True, True, False, True, False, True, True, True, True, True, True, True, True, False, True, False, True, False, True, False, True, True, True, True, True, True, True, True, False, True, True, False, True, True, False, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, True, True, True, True, True, True, True, True, False, True, False, True, True, True, True, True, True, False, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, False, False, True, True, True, True, True, False, True, True, False, True, False, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, False, True, True, True, True, True, True, True, False, True, True, True, True, False, True, False, True, True, False, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, True, True, False, True, True, True, True, True, True]
res_p4_power = [True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, True, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, False, True, True, True, False, False, False, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, False, True, True, True, True, True, False, True, False, True, True, True, True, True, True, True, True, True, True, True, True, False, True, True, False, True, True, True, True, True, True, True, True, True]
res_list = [res_p1, res_p2, res_p2_power, res_p3, res_p3_power, res_p4, res_p4_power]
res = [all(r[i] for r in res_list) for i in range(255)]
enc_flag = bytes.fromhex('5ade26f7b0461ec24e2f6a328be00be8e49e7707b5533c8da3b42bbb41a2aeb4ec8a63c2d625f891b6cce1c6842bda77a31957351aa90525385df3d80431db3c9c73183207267adccf016cbda326cf872c365903d63e20fab0f31bb2ef19b31ea151db097514b49f3fdbc05b8a26ae02')
for front in range(2):
key = 0
keybits = [front] + res
for i in range(256):
key += keybits[i] << i
key = int(key).to_bytes(32)
flag = AES.new(key, AES.MODE_CTR, nonce=bytes(12)).decrypt(enc_flag)
try:
print(flag.decode())
except:
pass
# codegate2025{If_these_weils_could_talk_(I_can_feel_your_reign_when_it_cries_supersingular_curves_inside_of_you)}