# Elliptic Curves over Goldilocks
> **TL;DR:** The two elliptic curves implementation can be found [here](https://github.com/0xPolygonHermez/pil2-proofman/pull/202/commits/4ee3a2a9e728bdf2fef7d3ccd8a7f928e704d2f2).
We aim to construct an elliptic curve satisfying the following criteria:
- Prime order.
- Efficient group operations.
- Deterministc and efficient hash-to-curve encoding.
- Security level of **128 bits**.
## Extension Field Selection
To achieve the target security level, we adopt an approach similar to [EcGFp5](https://eprint.iacr.org/2022/274.pdf). Specifically, we define the extension field $\mathbb{F}_{p^5} = \mathbb{F}_p[z] / (z^5 - 3)$ over $p = 2^{64} - 2^{32} + 1$
We select the polynomial $f(z) = z^5 - 3$ because:
- It has the minimal Hamming weight among irreducible polynomials.
- It uses nonzero coefficients as close to $\pm 1$ as possible.
- A polynomial of the form $z^k - c$ minimizes the computational cost of the Frobenius operator.
The following Sage script verifies that the previous claims about $z^5 - 3$ are true:
```sage
# Define Fp
p = 2**64 - 2**32 + 1
F = GF(p)
# Define Fp[z]
R.<z> = PolynomialRing(F)
# Polynomials of the form z⁵±c for c ∈ [0,2] are not irreducible
for i in range(3):
assert(R(z^5+i).is_irreducible() == R(z^5-i).is_irreducible() == False)
# The polynomial z^5-3 is irreducible
assert(R(z^5-3).is_irreducible())
```
### Quadratic Residuosity
To check whether an element $a \in \mathbb{F}_{p^{5}}$ is a quadratic residue, we use [Euler's criterion](https://en.wikipedia.org/wiki/Euler%27s_criterion), raising $a$ to the power $(p^{5}-1)/2$.
This exponentiation can be optimized by noting that:
$$
p^5 - 1 = (p^4 + p^3 + p^2 + p + 1) \cdot (p-1)
$$
which follows from the [cyclotomic polynomial](https://en.wikipedia.org/wiki/Cyclotomic_polynomial) decomposition.
To compute $a$ to the power over $p^4 + p^3 + p^2 + p + 1$, we need to efficiently compute the first and second **Frobenius operator**. Moreover, notice that when this exponentation is done, we get an element $b \in \mathbb{F}_{p^5}$ such that $b^{p-1} = 1$ and this can only happen when $b \in \mathbb{F}_p$; so the second exponentiation is over $\mathbb{F}_p$ instead.
Exponentiation by $(p-1)/2$ is done by observing that:
$$
\frac{p-1}{2} = 2^{63} - 2^{31},
$$
and using repeated squaring.
### Frobenius Operator
As we have shown in the previous section, we must be able compute the first and second Frobenius operator over an element in $\mathbb{F}_{p^{5}}$ efficiently. A naive implementation would take $O(\log p) = O(64)$ $\mathbb{F}_{p^{5}}$-operations, but we will do it much better.
Write $a$ as $a_0 + a_1z + a_2z^2 + a_3z^3 + a_4z^4$, with $a_i \in \mathbb{F}_{p}$. Then, we can compute the frobenius operators as follows:
\begin{align}
a^{p} = a_0 + a_1\gamma_{1,1}z + a_2\gamma_{1,2}z^2 + a_3\gamma_{1,3}z^3 + a_4\gamma_{1,4}z^4, \\
a^{p^2} = a_0 + a_1\gamma_{2,1}z + a_2\gamma_{2,2}z^2 + a_3\gamma_{2,3}z^3 + a_4\gamma_{2,4}z^4,
\end{align}
with $\gamma_{1,i} = 3^{i\frac{p-1}{5}}$ and $\gamma_{2,i} = 3^{i\frac{p^2-1}{5}} = \gamma_{1,i}^2$. Hence, assuming the precomputation of $\gamma_{1,i},\gamma_{2,i}$ for $i \in [4]$, we can compute $a^p$ and $a^{p^2}$ by four multiplications each.
:::spoiler Expand to see the proof
**Proof**:
On the one hand, using [Fermat's little theorem](https://en.wikipedia.org/wiki/Fermat%27s_little_theorem) we have that $a_j^{p^i} = a_j$.
On the other hand, notice $z^p = (z^5)^{\frac{p-1}{5}}z = 3^{\frac{p-1}{5}}z$ and therefore $(z^{i})^p = \gamma_{1,i} \cdot z^i$, where $\gamma_{1,i} = 3^{i\frac{p-1}{5}}$.
Using the previous observations, we have:
\begin{align}
a^p &= (a_0 + a_1z + a_2z^2 + a_3z^3 + a_4z^4)^p = a_0 + a_1z^p + a_2z^{2p} + a_3z^{3p} + a_4z^{4p} \\
&= a_0 + a_1\gamma_{1,1}z + a_2\gamma_{1,2}z^2 + a_3\gamma_{1,3}z^3 + a_4\gamma_{1,4}z^4,
\end{align}
which can be computed using a few multiplications.
Similarly, notice $z^{p^2} = 3^{\frac{p^2-1}{5}}z = (\gamma_{1,1})^{p+1}z = \gamma_{1,1}^2 \cdot z$ and therefore $(z^{i})^{p^2} = \gamma_{2,i}z^i$, where $\gamma_{2,i} = \gamma_{1,i}^2$.
**TODO**: Develop on $\gamma_{1,i} = 3^{i\frac{p-1}{5}}$ generating a subgroup of order $5$.
:::
Playing a little bit, we can refine exponentiation by $p^4 + p^3 + p^2 + p + 1$:
\begin{align}
t_0 &:= a^{p} \cdot a^{p^2}, \\
t_1 &:= t_0^{p^2}, \\
t_2 &:= t_0 \cdot t_1, \\
t_3 &:= a \cdot t_2 = a_0 \cdot b_0 + 3 \cdot (a_1 \cdot b_4 + a_2 \cdot b_3 + a_3 \cdot b_2 + a_4 \cdot b_1),
\end{align}
where $b := t_2$ is viewed as a $\mathbb{F}_{p^5}$-element.
### Square Roots
To compute the square root of an element $b \in \mathbb{F}_{p^{5}}$ we will use in our favour the fact that to check its quadratic residuosity we have to raise it to $p^4 + p^3 + p^2 + p + 1$.
After a bit of algebra, we get the following identity:
$$
\frac{1}{2} + \frac{p^4 + p^3 + p^2 + p + 1}{2} = \left(\frac{p+1}{2}\right)p^3 + \left(\frac{p+1}{2}\right)p + 1,
$$
so we can compute the squaring by:
- Compute the square of $b^{-(p^4 + p^3 + p^2 + p + 1)}$ by using any squaring algorithms over the base field (recall that when an element is raised to $p^4 + p^3 + p^2 + p + 1$ it gets mapped to the base field).
- Compute the exponentiation of $b$ by the RHS of the identity.
- Multiply both results.
## EcGFp5
### Definition
Found by [Thomas Pornin](https://eprint.iacr.org/2022/274.pdf), the EcGFp5 curve is defined by the equation:
$$
E/\mathbb{F}_{p^5} : y^2 = x^3 + ax + b
$$
with constants:
\begin{align}
a &= 6148914689804861439 + 263z, \\
b &= 15713893096167979237 + 6148914689804861265z
\end{align}
and order $2n$ for the $319$-bit prime:
```
n = 0x7ffffffd800000077ffffff1000000167fffffe6cfb80639e8885c39d724a09ce80fd996948bffe1
```
Since $n$ is odd, the points belonging to the subgroup of order $n$ are precisely the $n$-torsion $E[n]$ of the curve.
### Hashing to the Curve
We follow the [RFC 9380: Hashing to Elliptic Curves](https://www.rfc-editor.org/rfc/rfc9380.html) to get a deterministic mapping.
```
hash_to_curve(msg)
Input: msg, an arbitrary-length byte string.
Output: P, a point in G.
Steps:
1. u = hash_to_field(msg, 2)
2. Q0 = map_to_curve_simple_swu(u[0])
3. Q1 = map_to_curve_simple_swu(u[1])
4. R = Q0 + Q1
5. P = R + R # clear_cofactor(R)
6. return P
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
map_to_curve_simple_swu(u)
Input: u, an element in Fp5.
Output: P, a point in E.
Steps:
1. tv1 = inv0(Z^2 * u^4 + Z * u^2)
2. x1 = (-B / A) * (1 + tv1)
3. If tv1 == 0, set x1 = B / (Z * A)
4. gx1 = x1^3 + A * x1 + B
5. x2 = Z * u^2 * x1
6. gx2 = x2^3 + A * x2 + B
7. If is_square(gx1), set x = x1 and y = sqrt(gx1)
8. Else set x = x2 and y = sqrt(gx2)
9. If sgn0(u) != sgn0(y), set y = -y
10. return (x, y)
```
## EcMasFp5
### Definition
We choose the short Weierstrass equation:
$$
y^2 = x^3 + Ax + B
$$
because assuming that $A \in \mathbb{F}_p^*$ and that the cost of addition, subtraction, multiplication and division over the field is the same (something true in SNARK settings), point addition costs $10$ field operations and point doubling costs $12$ field operations.
Setting $A \in \mathbb{F}_p^*$ also restricts $B$ to be from the extension field, rather from the prime field; otherwise the curve could not be of primer order.
Since $B$ has no impact in group operations, we perform a linear search:
```sage
# Define Fp⁵
K.<z> = GF(p^5, modulus=z^5-3)
# Perform a linear search
def find_ec_over_gfp5(initial_a = 0, initial_c = 1, attempts = 50, pol_degree = K.degree(), verbose = True):
A = initial_a
c = initial_c
if verbose:
print("· Attempting with A =", A)
while True:
for i in range(1, pol_degree):
B = c * z**i
E = EllipticCurve(K, (A, B))
if verbose:
print(" -",E)
if is_prime(E.order(algorithm="pari")):
print(f"Elliptic curve found with A = {E.a4()} and B = {E.a6()}")
return E
else:
c += 1
# If no prime order was found, reset `c` and update `A`
if c == attempts:
c = initial_c
A += 1
if verbose:
print("· Attempting with A =", A)
continue
break
E = find_ec_over_gfp5()
```
The first elliptic curve found was:
$$
E/\mathbb{F}_{p^5}: y^2 = x^3 + 3x + 8z^4,
$$
with a $320$-bit prime order:
```
n = 0xfffffffb0000000effffffe20000002cffffffcc2c13f5f892042da0dfcde3fc8f4b2caf22360ee3
```
The name for this curve was chosen to be **EcMasFp5** (**E**lliptic **C**urve for **M**aximum **A**ggregation **S**peed over $\mathbb{F}_{p^5}$).
### Security of the Curve
> Thanks to [Robin Salen](https://github.com/Nashtare) for help and discussion.
We follow the criteria in [Safe Curves](https://safecurves.cr.yp.to/index.html).
#### Summary
```
Curve prime order `n`: 0xfffffffb0000000effffffe20000002cffffffcc2c13f5f892042da0dfcde3fc8f4b2caf22360ee3 (320 bits)
Curve cofactor: 1
Curve embedding degree: n-1 (320 bits)
Curve CM discriminant `D`: -0x350910d76c19ff80472df1f236bda8f251edc59a20563b4f1bcb88ad47f9892d334755425f4369e43 (323 bits)
Curve security (Pollard-Rho): 159.83 bits
Twist prime order `nt`: 0x128ad28934008b50864257bbff0983af9688b4f04ff3f024f86f (205 bits)
Twist cofactor: 0xdce68ed7aef21329a0ac97d33d76f (116 bits)
Twist embedding degree: (nt-1)/15 (201 bits)
Twist CM discriminant: D (323 bits)
Twist security (Pollard-Rho): 101.93 bits
```
More details are given below.
#### Field
Since the extension field is the same as the one in [EcGFp5](https://eprint.iacr.org/2022/274.pdf), we inherit by default its security. In particular, this field selection approximately achieves a $142$-bit security level, well beyond the target one.
#### Embedding Degree
We use the following code to find the embedding degree $e$:
```sage
def embedding_degree(q,n):
F = GF(n)
return F(q).multiplicative_order()
```
Finding that $e = n-1$, as large as it can possibly be, avoiding MOV-type attacks.
#### CM Discriminant
The CM Discriminant $D = t^2-4q$ was found to be a $323$-bit integer:
```
D = -0x350910d76c19ff80472df1f236bda8f251edc59a20563b4f1bcb88ad47f9892d334755425f4369e43
```
#### Twist
The number $q+1+t$ factorizes as:
```
0x128ad28934008b50864257bbff0983af9688b4f04ff3f024f86f*0xdce68ed7aef21329a0ac97d33d76f
```
### Hashing to the Curve
It is the same as the one for EcFp5 with the exception that this one does not need to clean the cofactor.
## Resources
- [EcGFp5: a Specialized Elliptic Curve](https://eprint.iacr.org/2022/274.pdf) - Thomas Pornin (2022/274).
- [SP1 Turbo Memory Argument](https://github.com/succinctlabs/sp1/blob/dev/book/static/SP1_Turbo_Memory_Argument.pdf).
- [Safe Curves](https://safecurves.cr.yp.to/index.html).
- [How to Hash into Elliptic Curves](https://eprint.iacr.org/2009/226.pdf) - Thomas Icart (2009/226).
- [RFC 9380: Hashing to Elliptic Curves](ttps://www.rfc-editor.org/rfc/rfc9380.html).