Challenge Files


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)}