# pure division - zer0pts ctf 2021
## challenge
It’s just a division, so it is "pure". We are given the following code and outputs.
Anyway, we have to solve the ECDLP. In general, ECDLP is hard. But in this case, the curve is over quotient ring $F_p = \mathbb{Z}/p^3\mathbb{Z}$, so we can get the flag. (note: This "$F_p$" is not $\mathbb{F}_p$. It indicates the name of variable in the code.)
``` python
# task.sage
from Crypto.Util.number import *
from flag import flag
assert len(flag) == 40
p = 74894047922780452080480621188147614680859459381887703650502711169525598419741
a1 = 22457563127094032648529052905270083323161530718333104214029365341184039143821
a2 = 82792468191695528560800352263039950790995753333968972067250646020461455719312
Fp = Zmod(p^3)
E = EllipticCurve(Fp, [a1, a2])
m = bytes_to_long(flag)
S = E(201395103510950985196528886887600944697931024970644444173327129750000389064102542826357168547230875812115987973230106228243893553395960867041978131850021580112077013996963515239128729448812815223970675917812499157323530103467271226, 217465854493032911836659600850860977113580889059985393999460199722148747745817726547235063418161407320876958474804964632767671151534736727858801825385939645586103320316229199221863893919847277366752070948157424716070737997662741835)
T = m * S
with open("output.txt", "w") as f:
f.write("T: {}".format(T))
```
```
# output.txt
T: (49376632602749543055345783411902198690599351794957124343389298933965298693663616388441379424236401744560279599744281594405742089477317921152802669021421009909184865835968088427615238677007575776072993333868804852765473010336459028 : 342987792080103175522504176026047089398654876852013925736156942540831035248585067987750805770826115548602899760190394686399806864247192767745458016875262322097116857255158318478943025083293316585095725393024663165264177646858125759 : 1)
```
## solution
$\mathbb{Z}/p^n\mathbb{Z}$ can be seen as a set of numbers with $n$ digits of precision in $\mathbb{Q}_p$. Since the flag is 320 bits and $p^3$ is large enough, it is no problem to solve the ECDLP over $\mathbb{Q}_p$. The main part of the solution was meant to be here. In this section, one of the solution methods which is similar to SSSA Attack is introduced.
Let $E$ be an elliptic curve over $\mathbb{Q}_p$ and let $E_f$ be the reduction curve of $E$ over $\mathbb{F}_p$. For simplicity, we assume $E_f$ is not singular.
Let $\pi : \mathbb{P}^2(\mathbb{Q}_p) \longrightarrow \mathbb{P}^2(\mathbb{F}_p)$ be a reduction map and we equate $(x,y,1) \in \mathbb{P}^2(\mathbb{Q})$ with $(x,y) \in \mathbb{A}^2$. Then let $\mathcal{E}$ be a formal group associated $E$, the isomorphism is constructed as follows
$$\ker \pi \overset{\phi}{\longrightarrow} \mathcal{E}(p\mathbb{Z}_p) \overset{\log_\mathcal{E}}\longrightarrow p\mathbb{Z}_p$$
where $\phi:\ker \pi \ni (x,y,z) \longmapsto -x/y \in \mathcal{E}(p\mathbb{Z}_p)$
Also, let $N$ be $N = \sharp E_f(\mathbb{F}_p)$. Obviously, $NP \in \ker \pi$ is holded for $P \in E(\mathbb{Q}_p)$.
Thus we can construct a isomorphism as follows
$$E(\mathbb{Q}_p) \longrightarrow \ker \pi \longrightarrow p\mathbb{Z}_p$$
Since $p\mathbb{Z}_p \simeq \mathbb{F}_p^+$, the ECDLP is solvable.
## implementation
In implementation, p-adic expansion is useful. Using the p-adic valuation $v_p$, we consider subsets $E_n(\mathbb{Q}_p) = \left\{ P \in E(\mathbb{Q}_p) \mid v_p(P_x) \leq -2n \right\} \cup \left\{O\right\}$ of $E(\mathbb{Q}_p)$. Then $E_n(\mathbb{Q}_p) \simeq \mathcal{E}(p^n\mathbb{Z}_p)$.
By using identity map, the following holds.
$$\mathcal{E}(p^n\mathbb{Z}_p)/\mathcal{E}(p^{n+1}\mathbb{Z}_p) \simeq p^n\mathbb{Z}_p / p^{n+1}\mathbb{Z}_p \simeq \mathbb{F}_p^+$$
By this result, we can sequentially find each coefficient $a_i$ of the p-adic expansion $\sum a_i p^i$ of require value.
Anyway, look at this solver.
```python=
from Crypto.Util.number import *
p = 74894047922780452080480621188147614680859459381887703650502711169525598419741
a1 = 22457563127094032648529052905270083323161530718333104214029365341184039143821
a2 = 82792468191695528560800352263039950790995753333968972067250646020461455719312
Fp = Zmod(p^3)
E = EllipticCurve(Fp, [a1, a2])
S = E(201395103510950985196528886887600944697931024970644444173327129750000389064102542826357168547230875812115987973230106228243893553395960867041978131850021580112077013996963515239128729448812815223970675917812499157323530103467271226, 217465854493032911836659600850860977113580889059985393999460199722148747745817726547235063418161407320876958474804964632767671151534736727858801825385939645586103320316229199221863893919847277366752070948157424716070737997662741835)
T = E(49376632602749543055345783411902198690599351794957124343389298933965298693663616388441379424236401744560279599744281594405742089477317921152802669021421009909184865835968088427615238677007575776072993333868804852765473010336459028, 342987792080103175522504176026047089398654876852013925736156942540831035248585067987750805770826115548602899760190394686399806864247192767745458016875262322097116857255158318478943025083293316585095725393024663165264177646858125759)
# --------------- solve -----------------
prec = 3
Qp = pAdicField(p, prec)
E = EllipticCurve(Qp, [a1, a2])
Fp = GF(p)
Ef = EllipticCurve(Fp, [a1, a2])
N = Ef.order()
S = E(S[0], S[1])
T = E(T[0], T[1])
NS = N * S
a = Fp(-NS[0] / (p * NS[1]))
n = 0
l = 1
Sp = S
Tp = T
ds = []
while Tp != 0:
NTp = N*Tp
w = -NTp[0] / NTp[1]
b = w / p^l
d = Fp(Integer(b)/a)
ds.append(Integer(d))
Tp = Tp - Integer(d)*Sp
Sp = p*Sp
n += 1
l += 1
if n > prec:
break
solve = 0
for i in range(len(ds)):
solve += ds[i] * p^i
print(long_to_bytes(solve))
```
Here is the flag ```zer0pts{elliptic_curve_over_p-adic!yey!}```