# `EEVM.Precompiles.Bls12381.Curve`
[🔗](https://github.com/mw2000/eevm/blob/v0.1.0/lib/eevm/precompiles/bls12381/curve.ex#L1)

Arithmetic on the BLS12-381 curve, in pure Elixir, for the EIP-2537
precompiles (`0x0B`–`0x11`) and the EIP-4844 point-evaluation precompile
(`0x0A`).

Field elements are plain integers in `[0, p)`, kept canonical after every
operation. The extension fields form the usual tower:

- Fp2 = Fp[u] / (u² + 1), as `{a0, a1}` = a0 + a1·u
- Fp6 = Fp2[v] / (v³ − ξ) with ξ = 1 + u, as `{c0, c1, c2}`
- Fp12 = Fp6[w] / (w² − v), as `{c0, c1}`

G1 is the order-r subgroup of E: y² = x³ + 4 over Fp. G2 is the order-r
subgroup of the M-type sextic twist E': y² = x³ + 4(1 + u) over Fp2. A G1
point has integer coordinates and a G2 point Fp2 (tuple) coordinates, and
every point function here works on both: the field operations underneath
dispatch on the coordinate type, so the point formulas, scalar
multiplication, MSM, and map-to-curve are written once.

Affine points are `{x, y}` or `:infinity`. Internally points are in
Jacobian coordinates (x = X/Z², y = Y/Z³), so additions need no inversion.

The structure mirrors `EEVM.Precompiles.BN256.Curve`. The pairing follows
arkworks' `ark-ec` BLS12 model (M-type twist, x < 0), map-to-curve follows
RFC 9380, and the subgroup checks are Scott's endomorphism tests.

# `fp2`

```elixir
@type fp2() :: {fp(), fp()}
```

An element a0 + a1·u of Fp2.

# `fp`

```elixir
@type fp() :: non_neg_integer()
```

An element of Fp, in `[0, p)`.

# `g1`

```elixir
@type g1() :: {fp(), fp()} | :infinity
```

An affine G1 point (on E) or the point at infinity.

# `g2`

```elixir
@type g2() :: {fp2(), fp2()} | :infinity
```

An affine G2 point (on the twist E') or the point at infinity.

# `point`

```elixir
@type point() :: g1() | g2()
```

An affine point of either group.

# `add`

```elixir
@spec add(point(), point()) :: point()
```

Adds two affine points of the same group, both on the curve.

# `fp_modulus`

```elixir
@spec fp_modulus() :: pos_integer()
```

Returns the base field modulus p.

# `g1_decompress`

```elixir
@spec g1_decompress(binary()) :: {:ok, g1()} | :error
```

Decompresses a 48-byte G1 point in the ZCash serialization used by KZG
commitments and proofs (the consensus specs' `bytes_to_kzg_commitment`).

The top three bits are flags: compressed (must be set), infinity, and the
sign that picks the larger of y and p − y. The result is on the curve but
not checked to be in G1.

# `g1_generator`

```elixir
@spec g1_generator() :: g1()
```

Returns the standard generator of G1.

# `g2_generator`

```elixir
@spec g2_generator() :: g2()
```

Returns the standard generator of G2.

# `in_subgroup?`

```elixir
@spec in_subgroup?(point()) :: boolean()
```

Returns whether a point already known to be on its curve lies in the
order-r subgroup (G1 or G2).

Instead of computing r·P (255 doublings), this uses Scott's endomorphism
tests ("A note on group membership tests for G1, G2 and GT on BLS
pairing-friendly curves", eprint 2021/1130, §6 and §4), whose correctness
for BLS12-381 is proved in Dai, Lin, Zhao and Zhou, eprint 2022/352:

- G1: σ(P) = −[x²]P, with σ(x, y) = (β·x, y);
- G2: ψ(P) = [x]P.

Each needs one or two multiplications by the 64-bit |x|.

# `map_fp2_to_g2`

```elixir
@spec map_fp2_to_g2(fp2()) :: g2()
```

Maps an Fp2 element to a G2 point (EIP-2537 `MAP_FP2_TO_G2`): the
simplified SWU map onto E2', the 3-isogeny to E', and cofactor clearing
with the endomorphism ψ (RFC 9380, §8.8.2 and Appendix G.3).

# `map_fp_to_g1`

```elixir
@spec map_fp_to_g1(fp()) :: g1()
```

Maps an Fp element to a G1 point (EIP-2537 `MAP_FP_TO_G1`): the simplified
SWU map onto E1', the 11-isogeny to E, and cofactor clearing by
h_eff = 1 − x (RFC 9380, §6.6.2, §6.6.3 and §8.8.1).

# `msm`

```elixir
@spec msm([{point(), non_neg_integer()}]) :: point()
```

Returns the multi-scalar multiplication Σ kᵢ·Pᵢ over `{point, scalar}`
pairs of one group.

Every point must be in the order-r subgroup, so each scalar is first
reduced mod r. A single term uses a width-5 NAF; several use Pippenger's
bucket method.

# `neg`

```elixir
@spec neg(point()) :: point()
```

Negates an affine point.

# `on_curve?`

```elixir
@spec on_curve?(point()) :: boolean()
```

Returns whether an affine point lies on its curve: E (y² = x³ + 4) for a
G1 point, the twist E' (y² = x³ + 4(1 + u)) for a G2 point.

# `pairing_check`

```elixir
@spec pairing_check([{g1(), g2()}]) :: boolean()
```

Returns whether the product of e(P, Q) over `pairs` is 1 in GT.

Each pair is `{g1, g2}` of points already checked to be in G1 and G2.
Pairs with a point at infinity contribute 1. One Miller loop is shared by
every pair, followed by a single final exponentiation.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
