EEVM.Precompiles.BN256.Curve (eevm v0.1.0)

Copy Markdown View Source

Arithmetic on the BN254 (alt_bn128) curve for the ecAdd, ecMul, and ecPairing precompiles (EIP-196, EIP-197): G1 point addition and scalar multiplication, G2 curve and subgroup checks, and the optimal ate pairing.

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

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

G1 is the curve E: y² = x³ + 3 over Fp, of prime order n. G2 lives on the D-type sextic twist E': y² = x³ + 3/ξ over Fp2, which maps into E(Fp12) by (x, y) ↦ (x·w², y·w³).

pairing_check/1 runs one Miller loop shared by every pair over the NAF of 6u + 2, then a single final exponentiation, and compares the product with 1. The structure follows arkworks' ark-ec BN model and the final exponentiation follows go-ethereum's crypto/bn256/cloudflare.

Summary

Types

An element a0 + a1·i of Fp2.

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

An affine G1 point (not the point at infinity).

An affine G1 point or the point at infinity.

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

Functions

Adds two G1 points (ecAdd), both on the curve.

Multiplies a G1 point on the curve by a scalar (ecMul).

Returns whether point lies on E: y² = x³ + 3.

Returns whether a point on the twist lies in G2, the order-n subgroup.

Returns whether point lies on the twist E': y² = x³ + 3/ξ.

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

Types

fp2()

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

An element a0 + a1·i of Fp2.

fp()

@type fp() :: non_neg_integer()

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

g1()

@type g1() :: {fp(), fp()}

An affine G1 point (not the point at infinity).

g1_or_infinity()

@type g1_or_infinity() :: g1() | :infinity

An affine G1 point or the point at infinity.

g2()

@type g2() :: {fp2(), fp2()}

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

Functions

g1_add(p, q)

@spec g1_add(g1_or_infinity(), g1_or_infinity()) :: g1_or_infinity()

Adds two G1 points (ecAdd), both on the curve.

g1_mul(point, scalar)

Multiplies a G1 point on the curve by a scalar (ecMul).

E(Fp) has prime order n, so k·P = (k mod n)·P for every point on the curve, and the scalar is reduced first. The product uses a width-5 NAF over a table of odd multiples of P, all in Jacobian coordinates, with one inversion at the end to return an affine point.

g1_on_curve?(arg)

@spec g1_on_curve?(g1()) :: boolean()

Returns whether point lies on E: y² = x³ + 3.

g2_in_subgroup?(point)

@spec g2_in_subgroup?(g2()) :: boolean()

Returns whether a point on the twist lies in G2, the order-n subgroup.

EIP-197 requires it; unlike G1, the twist also has points of other orders. Instead of computing n·Q (254 doublings), this uses the endomorphism test from Dai, Lin, Zhao and Zhou, "Fast subgroup membership testings for G1, G2 and GT on pairing-friendly curves" (eprint 2022/348, §3 and §5.1), also used by gnark-crypto: Q ∈ G2 ⟺ [u + 1]Q + ψ([u]Q) + ψ²([u]Q) = ψ³([2u]Q). That needs one 63-bit multiplication by u.

The test accepts exactly the kernel of a group endomorphism. G2 is in the kernel; the rest of the twist group is cyclic of square-free order h = 2p − n = 10069 · 5864401 · 1875725156269 · q₄ (q₄ prime), so the test is sound if it rejects one point of each of those prime orders. The unit tests check exactly that.

g2_on_curve?(arg)

@spec g2_on_curve?(g2()) :: boolean()

Returns whether point lies on the twist E': y² = x³ + 3/ξ.

pairing_check(pairs)

@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}: an affine point of G1 and an affine point of G2, both already validated. Pairs with a point at infinity contribute 1, so callers leave them out.