Elliptic curve crypto in python including secp256k1, alt_bn128, and bls12_381
—
Reference implementation of BN128 (also known as alt_bn128) elliptic curve operations used in Ethereum's precompiled contracts. This curve provides efficient pairing operations and is used in various Ethereum applications including zkSNARKs and other zero-knowledge proof systems.
# Generator points
G1 # Generator point on G1 (base curve)
G2 # Generator point on G2 (twist curve)
G12 # Identity element in GT (target group)
# Points at infinity
Z1 # Point at infinity for G1
Z2 # Point at infinity for G2
# Curve parameters
b: int # Curve coefficient for G1: y^2 = x^3 + b
b2 # Curve coefficient for G2 (quadratic extension)
b12 # Curve coefficient for G12 (degree 12 extension)
curve_order: int # Order of the curve
field_modulus: int # Prime modulus of the base field
twist # Twist parameter for G2Basic elliptic curve point operations for both G1 and G2 groups.
def add(p1, p2):
"""
Add two elliptic curve points.
Args:
p1: First point (G1 or G2)
p2: Second point (G1 or G2, same type as p1)
Returns:
Point of same type as inputs representing p1 + p2
"""
def double(p):
"""
Double an elliptic curve point.
Args:
p: Point to double (G1 or G2)
Returns:
Point of same type representing 2 * p
"""
def multiply(p, n):
"""
Multiply a point by a scalar.
Args:
p: Point to multiply (G1 or G2)
n (int): Scalar multiplier
Returns:
Point of same type representing n * p
"""
def neg(p):
"""
Negate a point.
Args:
p: Point to negate (G1 or G2)
Returns:
Point of same type representing -p
"""Functions to check point properties and validate curve membership.
def eq(p1, p2) -> bool:
"""
Test if two points are equal.
Args:
p1: First point
p2: Second point
Returns:
bool: True if points are equal, False otherwise
"""
def is_inf(p) -> bool:
"""
Check if a point is the point at infinity.
Args:
p: Point to check
Returns:
bool: True if point is at infinity, False otherwise
"""
def is_on_curve(p) -> bool:
"""
Verify that a point lies on the curve.
Args:
p: Point to validate
Returns:
bool: True if point is on curve, False otherwise
"""Pairing functions that map pairs of points to elements in the target group GT.
def pairing(p1, p2):
"""
Compute the bilinear pairing e(p1, p2).
Args:
p1: Point in G1
p2: Point in G2
Returns:
Element in GT (degree 12 extension field)
"""
def final_exponentiate(p):
"""
Perform the final exponentiation step of pairing computation.
Args:
p: Element from the Miller loop computation
Returns:
Final pairing result in GT
"""The BN128 curve operations work with various field elements:
# Field element types (imported from py_ecc.fields)
FQ # Base field element (Fp)
FQ2 # Quadratic extension field element (Fp2)
FQ12 # Degree 12 extension field element (Fp12, target group GT)
FQP # General polynomial field elementfrom py_ecc.bn128 import G1, G2, multiply, add, is_on_curve, eq
# Scalar multiplication
point1 = multiply(G1, 123)
point2 = multiply(G1, 456)
# Point addition
sum_point = add(point1, point2)
# Verify points are on curve
assert is_on_curve(point1)
assert is_on_curve(point2)
assert is_on_curve(sum_point)
# This should equal (123 + 456) * G1
expected = multiply(G1, 123 + 456)
assert eq(sum_point, expected)from py_ecc.bn128 import G1, G2, multiply, pairing
# Create some points
p1 = multiply(G1, 123)
q1 = multiply(G2, 456)
p2 = multiply(G1, 789)
q2 = multiply(G2, 321)
# Compute pairings
pairing1 = pairing(p1, q1)
pairing2 = pairing(p2, q2)
# Pairing is bilinear: e(a*P, Q) = e(P, a*Q) = e(P, Q)^a
a = 42
pa_q = pairing(multiply(p1, a), q1)
p_aq = pairing(p1, multiply(q1, a))
p_q_a = pairing1 ** a
print("Bilinearity verified")from py_ecc.bn128 import G1, G2, multiply, add, pairing
# Example compatible with Ethereum's bn256Add precompile
def bn256_add_example():
"""Example usage compatible with Ethereum's bn256Add precompile."""
# Points represented as (x, y) coordinates
p1 = multiply(G1, 123)
p2 = multiply(G1, 456)
# Addition (compatible with precompile format)
result = add(p1, p2)
return result
# Example compatible with Ethereum's bn256ScalarMul precompile
def bn256_scalar_mul_example():
"""Example usage compatible with Ethereum's bn256ScalarMul precompile."""
point = G1
scalar = 12345
# Scalar multiplication
result = multiply(point, scalar)
return result
# Example compatible with Ethereum's bn256Pairing precompile
def bn256_pairing_example():
"""Example usage compatible with Ethereum's bn256Pairing precompile."""
# Multiple pairing check: e(p1, q1) * e(p2, q2) = 1
p1 = multiply(G1, 123)
q1 = multiply(G2, 456)
p2 = multiply(G1, 789)
q2 = neg(multiply(G2, 321)) # Negative for pairing check
# Compute product of pairings
pairing1 = pairing(p1, q1)
pairing2 = pairing(p2, q2)
product = pairing1 * pairing2
# Check if product equals 1 (identity in GT)
from py_ecc.fields import bn128_FQ12 as FQ12
return product == FQ12.one()from py_ecc.bn128 import G1, G2, multiply, pairing, add
def groth16_pairing_example():
"""Example pairing computation similar to Groth16 verification."""
# Simulated proof elements (in practice these come from the proof)
proof_a = multiply(G1, 123)
proof_b = multiply(G2, 456)
proof_c = multiply(G1, 789)
# Simulated verification key elements
vk_alpha = multiply(G1, 111)
vk_beta = multiply(G2, 222)
vk_gamma = multiply(G2, 333)
vk_delta = multiply(G2, 444)
# Groth16 pairing equation: e(A, B) = e(α, β) * e(C, γ) * ...
# (This is a simplified example)
lhs = pairing(proof_a, proof_b)
rhs_1 = pairing(vk_alpha, vk_beta)
rhs_2 = pairing(proof_c, vk_gamma)
print("zkSNARK-style pairing computation completed")
return lhs, rhs_1, rhs_2from py_ecc.bn128 import G1, G2, is_on_curve, is_inf, multiply
# Validate generator points
assert is_on_curve(G1)
assert is_on_curve(G2)
assert not is_inf(G1)
assert not is_inf(G2)
# Create and validate random points
random_point = multiply(G1, 12345)
assert is_on_curve(random_point)
assert not is_inf(random_point)
# Check point at infinity
zero_point = multiply(G1, 0) # Should be point at infinity
assert is_inf(zero_point)
print("Point validation complete")from py_ecc.fields import bn128_FQ as FQ, bn128_FQ2 as FQ2
# Work with field elements directly
a = FQ(123)
b = FQ(456)
c = a + b
d = a * b
e = a ** 3
# Quadratic extension field
f = FQ2([1, 2]) # 1 + 2*i where i^2 = -1
g = FQ2([3, 4]) # 3 + 4*i
h = f * g
print(f"Field arithmetic results: {c}, {d}, {e}")
print(f"Extension field result: {h}")from typing import Optional, Tuple
from py_ecc.fields import bn128_FQ, bn128_FQ2, bn128_FQ12
# Point types (None represents point at infinity)
Point2D = Optional[Tuple[bn128_FQ, bn128_FQ]]
Point2D_FQ2 = Optional[Tuple[bn128_FQ2, bn128_FQ2]] # For G2 points
# Field element types
Field = bn128_FQ
ExtensionField2 = bn128_FQ2
ExtensionField12 = bn128_FQ12BN128 operations may raise various exceptions:
from py_ecc.bn128 import is_on_curve, pairing, multiply, G1, G2
try:
# Validate points before pairing
p1 = multiply(G1, some_scalar)
p2 = multiply(G2, some_other_scalar)
if is_on_curve(p1) and is_on_curve(p2):
result = pairing(p1, p2)
else:
raise ValueError("Invalid curve points")
except Exception as e:
print(f"Curve operation error: {e}")The BN128 curve is specifically designed for compatibility with Ethereum's precompiled contracts:
These precompiles use specific encoding formats for points and scalars. When integrating with Ethereum smart contracts, ensure proper encoding/decoding of curve points and field elements.
Install with Tessl CLI
npx tessl i tessl/pypi-py-ecc