owned this note
owned this note
Published
Linked with GitHub
# Curve isomorphisms explainer
Let $\mathbb{F}_q$ be a finite field with characteristic different from 2 and 3, meaning $q = p^f$ for some prime $p \geq 5$ and integer $f \geq 1$. We consider elliptic curves $E$ over $\mathbb{F}_q$ given by the short Weierstraß equation:
\begin{equation}\tag{1}
y^2 = x^3 + A x + B
\end{equation}
where $A$ and $B$ are constants satisfying $4A^3 + 27B^2 \neq 0$.^[This condition ensures the curve is **non-singular**; if it were violated, the equation would define a singular point lacking a well-defined tangent, making it impossible to perform meaningful self-addition. In such cases, the object is not technically an elliptic curve.]
## Curve Isomorphisms
Two elliptic curves are considered **isomorphic**^[To exploit the vulnerabilities described here, we really want **isomorphic** curves, not just **isogenous** curves.] if they can be related by an affine change of variables. Such transformations preserve the group structure and ensure that point addition remains consistent. It can be shown that the only possible transformations between two curves in short Weierstraß form take the shape:
\begin{equation}\tag{2}
(x, y) \mapsto (e^2 x, e^3 y)
\end{equation}
for some nonzero $e \in \mathbb{F}_q$. Applying this transformation to the curve equation results in:
\begin{equation}\tag{3}
y^2 = x^3 + A e^{4} x + B e^{6}
\end{equation}
### The $j$-Invariant
The **$j$-invariant** of a curve is defined as:
\begin{equation}\tag{4}
j = 1728 \frac{4A^3}{4A^3 + 27B^2}
\end{equation}
Every element of $\mathbb{F}_q$ can be a possible $j$-invariant.^[Both BLS and BN curves have a j-invariant equal to 0, which is **really special**.] When two elliptic curves share the same $j$-invariant, they are either **isomorphic** (in the sense described above) or they are **twists** of each other^[We omit the discussion about twists here, as they are not relevant to this case.]
# Finding isomorphic curves for j-invatiant 0 curves
If we want to do this in a black-box way, the easiest approach is to change the $B$ value in the Weierstraß equation (1) and stop when the cardinality^[This is just a fancy way to indicate the total number of points on the elliptic curve, including the point at infinity.] of the new curve matches the cardinality of the first one (as shown in the following Sage snippet):
```sage=
q = 0x1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB # base field order
h = 0x396c8c005555e1568c00aaab0000aaab # cofactor of BLS12-381 curve
r = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001 # order of the subgroup
Fq = GF(q) # base field
E1 = EllipticCurve(Fq, (0, 4)) # BLS12-381 curve
Et = EllipticCurve(Fq, (0, 24)) # Some other curve
assert E1.cardinality() == Et.cardinality()
```
then having a malicious point in the isomorphic curve is just a matter of
`Pt = Et.random_point() * h`
## More theory (only for the brave)
Let's check equations (2) and (3) using the value derived in the previous section:
```sage=
iso = E1.isomorphism_to(Et)
e2 = list(iso.rational_maps()[0].numerator().dict().items())[0][1] // e^2 in (2)
e3 = list(iso.rational_maps()[1].numerator().dict().items())[0][1] // e^3 in (2)
e = Fq(e2).sqrt()
assert e^3 == e3
assert e^6* E1.a6() == Et.a6()
```
## Even more theory (only for the Jedi Masters)
This simple method works reasonably well for finding an isomorphic curve in $G_1$ and exploiting the vulnerability discovered in BLS12-381 by [Alex Filippov](https://x.com/alexfilippov314/status/1920421052401750474), but it will likely fail to find an isomorphic curve for the [BN254 $G_2$ case](https://blog.ethereum.org/2025/05/07/the-curious-case).
Here's what we can do using a bit of isogeny theory. First, some observations:
1. BN254 has a $j$-invariant equal to 0 (so does BLS12-381, by the way). This makes it a special curve—the class number of the discriminant is 1, which also means the crater of the isogeny volcano is just a single vertex/point.
2. If we find a horizontal $\ell$-isogeny, we can easily find an isomorphic curve.
3. Testing whether an $\ell$-isogeny can be horizontal is just a matter of checking a Legendre symbol.
Armed with the observations above we use a 3-isogeny to find an isomorphic curve, here we go:
```sage=
p = 21888242871839275222246405745257275088696311157297823662689037894645226208583
Fp = GF(p)
Fpx.<x> = Fp[]
Fp2.<i> = GF(p^2, modulus=x^2+1)
E2 = EllipticCurve(Fp2, [0, 3/(i+9)]) # BN-254 curve
assert E2.j_invariant() == 0
Et = E2.isogenies_prime_degree(3)[0].codomain() # isomorphic curve
assert Et.j_invariant() == 0
assert E2 != Et
```
[^1]:
[^2]:
[^3]:
[^4]:
[^5]: