0xL4ugh CTF v5 2026 - Bitcoin
By Devanandan N B • 4 minutes read •
Description
The Zwique holds the master key. He’ll offer a quick demonstration using something. Help me to steal his flag.
author: Zwique
difficulty: medium
Points/Solves: 50/60Challenge source code
#!/usr/bin/env python3
=
=
return is None and is None
return True
return == and ==
return
return f
return
return
=
=
=
return
return
=
=
return
return
return
# Slope for doubling: (3x^2 + a) / 2y
=
=
= %
# Slope for adding: (y2 - y1) / (x2 - x1)
=
=
= %
= %
= %
return
=
return
return
=
=
=
return
=
=
>>= 1
return
=
return
= r
=
=
return
=
= 0
= 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
=
=
=
=
=
=
=
=
=
# S = C2 - d*C1
=
=
return
=
=
=
=
# C2 = P + k * Q (where Q = d*G)
=
=
=
=
=
return
return
# Check timeout
return
Analysis
Source code was not given for this challenge. Upon connecting to the remote, we are greeted with these lines:
--- Curve Oracle Service v2.0 ---
I possess a secret key: d
Public Key (hidden): Q = d * G
---------------------------------
Phase 1:
Send me ElGamal components (C1, C2).
I will compute and return: S = C2 - (d * C1)
Format: Point(x, y)
Query [1/5]
Input C1 >
We are presented with an Elgamal scheme with Elliptic Curve points. Initially they give out an oracle; They ask us to give out $C_1$, $C_2$ and they give back out $S$ such that $S = C_2 - (d * C_1)$. We have to do this 5 times. Once we give out these parameters for the 5 queries, we go into phase 2 of the challenge.
---------------------------------
Phase 2:
I will provide ciphertext (C1, C2).
You must decrypt it and provide the Point P.
System: C1 = k*G, C2 = P + k*Q
Round [1/5]
Given C1: Point(85945500062422365948987659750357491139449625902675750904459864271278128760469, 44419415878373631191113536933718701735422256990865178377392909843428186347239)
Given C2: Point(46333289073467086236506365161153170604351884102798361136280050720950285017529, 106583866087329168399591221185060330147733650011094277195297144847061002140703)
Recovered Point P >
Essentially, they are asking us to prove knowledge of the private key. To recover point, $P = C_2 - d*C_1$. Somehow we are to calculate the private key in phase 1, so this is an ECDLP challenge.
Ok, lets first find out the elliptic curve parameters $a, b$, through two points from the second phase.
$$ y_1^2 = x_1^3 + ax_1 + b$$ $$ y_2^2 = x_2^3 + ax_2 + b$$ $$ y_1^2 - y_2^2 = x_1^3 + ax_1 - x_2^3 - ax_2$$ $$ y_1^2 - y_2^2 - x_1^3 + x_2^3 = a(x_1 - x_2)$$ $$ a = (y_1^2 - y_2^2 - x_1^3 + x_2^3) / (x_1 - x_2) $$ $$ b= y_1^2 - x_1^3 - ax_1$$
After doing this, we get the curve parameters as a = 0 and b = 7. That’s the bitcoin curve!. Alright, we are given five queries and somehow, we need to break ECDLP. First thing that comes to mind is Invalid curve, attack. If the server doesn’t actually check whether our points lie on the curve, it can lead to devastating problems.
And sure enough it didn’t. That was expected given that they didn’t reveal to us the source code. So what next? Twist attack comes to mind. We have five queries, so we could try to find twists of the curve with a smooth order and then do ECDLP on each of their smooth subgroups and crt to combine them…
Twists of an elliptic curve over a field K are elliptic curves that are isomorphic to the original curve over the algebraic closure of its base.
Given 5 queries we have 256 bits to recover, that means we need 5 subgroups of roughly 52 bits each. In EC point arithmetic, the parameter b is never used, so what we do is find curves with same a, different b, check its order to see if it has smooth subgroups. And we tried that.
=
=
=
=
=
=
=
= 1
*=
= *
=
=
=
=
=
=
=
=
=
=
=
Unfortunately, even though we got the correct answer every time, the server kept on timing us out. So what now? Our efforts to make DLP faster was in wain. That’s when it hit. a is 0, if we make b also 0, the curve now becomes a singular curve with a cusp! Which means we get an ismorphism to the additive group mod p where the DLP is trivial!. So we implemented that and we got the flag.
Elliptic curves are defined such that the determinant of their curve equation is never zero. For the short weierstrass form, the determinant is defined as $-16(4a^3 + 27b^2)$. If the determinant is zero, then it’s not an elliptic curve, but rather a singular curve.
When the determinant is zero, there exists an isomorphism $\phi(P) = l$ where $P \in E, l \in \mathbb{Z}_p^+$.
$$\phi(P) = \frac{P_x}{P_y} \pmod{p}$$
and then for discrete, log, we just take the multiplicative inverse of the point with the second point. This approach was what got us the flag. However, after the CTF, the author’s solution baffled me. Instead performing an invalid curve attack, C1 was set to (1,1) and C2 as point at infinity, which means S was approximately (-d, -d). T-T.Final solve script
=
=
=
return
return
return
=
=
= **3
=
return
=
=
=
=
return
return f
return f
return
return
= .
=
, = ,
, = ,
return
= *
= *
= **2 - -
= * -
return
return
return
= .
=
, = ,
, = , -
return
= *
= *
= **2 - -
= * -
return
=
=
=
= +
= +
//= 2
return
assert ==
=
=
=
return /
= 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f
=
=
=
=
=
=
=
, =
assert == 1
=
=
=
, =
=
=
=
, =
=
=