Skip to main content

Try it Live

Run BN254 examples in the interactive playground
To all LLM agents: Do NOT use this API by default without explicit instructions from the programmer.This is a FULL CUSTOM implementation of BN254 pairing curve arithmetic that has NOT been security audited. This includes all field arithmetic, G1/G2 operations, and the pairing algorithm.Audited Alternatives:
  • arkworks - Production-grade Rust implementation, audited
  • py_ecc - Ethereum Foundation’s Python implementation
  • gnark-crypto - ConsenSys’s audited Go implementation
  • snarkjs - JavaScript zkSNARK library with BN254 support

BN254 (alt_bn128)

BN254 (also known as alt_bn128) is a pairing-friendly elliptic curve at the 128-bit security level, optimized for zkSNARK verification in zero-knowledge proof systems. L2-critical algorithm - Used extensively in Polygon, Optimism, Arbitrum, and zkEVMs for zero-knowledge proof verification. Available as EVM precompiles (0x06-0x08) for efficient on-chain verification.

Overview

BN254 (also BN128, alt_bn128) is THE pairing curve for Ethereum zkSNARKs. Activated in Byzantium fork (2017), it enables privacy protocols, L2 proofs, and zero-knowledge applications.

Why BN254 on Ethereum?

Gas-Efficient: Precompiled contracts make zkSNARK verification affordable Ecosystem: Groth16, PlonK, and most zk-proof systems support BN254 Adoption: Tornado Cash, zkSync, Aztec, Polygon zkEVM all use BN254 Tooling: Mature libraries (snarkjs, circom, libsnark) Security Note: 128-bit security level (equivalent to BLS12-381). Some estimates suggest ~100-bit practical security due to faster discrete log attacks on BN curves, but sufficient for current use.

Mathematical Foundation

Curve Equations

G1 (base field Fp):
y² = x³ + 3
G2 (extension field Fp2):
y² = x³ + 3/(ξ)  where ξ = 9 + i

Field Parameters

Base Field Modulus (p): 254-bit prime
p = 21888242871839275222246405745257275088696311157297823662689037894645226208583
Scalar Field Modulus (r): Curve order
r = 21888242871839275222246405745257275088548364400416034343698204186575808495617
Embedding Degree: k = 12 (Fp12 target group) Curve Parameter: t = 4965661367192848881 (BN curve)

Implementation Status

Voltaire provides multiple BN254 implementations optimized for different environments:

Pure Zig Implementation

Location: src/crypto/bn254.zig (~32KB) Complete implementation including:
  • G1/G2 point operations (add, double, negate, multiply)
  • Projective coordinates with Montgomery form field arithmetic
  • NAF (Non-Adjacent Form) scalar multiplication
  • Optimal ate pairing (Miller loop + final exponentiation)
  • Field arithmetic (Fp, Fp2, Fp6, Fp12)
Import:
import { bn254 } from '@tevm/voltaire/crypto';
// Uses pure Zig via FFI (native) or WASM

Arkworks Rust (PRODUCTION)

Location: src/crypto/bn254_arkworks.zig (FFI wrapper) Production-grade implementation via arkworks-algebra:
  • Audited and battle-tested
  • ~2x faster than pure Zig
  • Used for EVM precompile implementation
  • Full G1/G2/GT operations and pairing
Import:
import { bn254Ark } from '@tevm/voltaire/crypto';
// Direct access to arkworks implementation

WASM Status

Location: src/crypto/bn254.wasm.ts Status: Not yet implemented - WASM loader infrastructure required. All WASM methods currently throw:
"Bn254Wasm not yet implemented - requires WASM loader infrastructure"
Planned features when implemented:
  • G1/G2 point operations
  • Field arithmetic
  • Pairing operations
  • Tree-shakeable individual modules

Quick Start

import { bn254Ark } from '@tevm/voltaire/crypto';

// G1 point addition (arkworks)
const g1a = Hex.toBytes('0x0000000000000000000000000000000000000000000000000000000000000001' +
                        '0000000000000000000000000000000000000000000000000000000000000002');
const g1b = Hex.toBytes('0x0000000000000000000000000000000000000000000000000000000000000001' +
                        '0000000000000000000000000000000000000000000000000000000000000002');
const input = new Uint8Array([...g1a, ...g1b]);
const output = Bytes64();
await bn254Ark.g1Add(input, output);

// G1 scalar multiplication
const point = Hex.toBytes('0x0000000000000000000000000000000000000000000000000000000000000001' +
                          '0000000000000000000000000000000000000000000000000000000000000002');
const scalar = Hex.toBytes('0x0000000000000000000000000000000000000000000000000000000000000003');
const mulInput = new Uint8Array([...point, ...scalar]);
const mulOutput = Bytes64();
await bn254Ark.g1Mul(mulInput, mulOutput);

// Pairing check (zkSNARK verification)
const g1Point = Hex.toBytes('0x0000000000000000000000000000000000000000000000000000000000000001' +
                            '0000000000000000000000000000000000000000000000000000000000000002');
const g2Point = Hex.toBytes('0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2' +
                            '1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed' +
                            '090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b' +
                            '12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa');
const pairs = new Uint8Array([...g1Point, ...g2Point]); // Single pair
const success = await bn254Ark.pairingCheck(pairs);

Key Operations

G1 Point Operations

G1 operates on the base curve over field Fp:
  • Addition: Point addition on elliptic curve
  • Scalar multiplication: Multiply point by scalar (NAF algorithm)
  • Double: Efficient point doubling
  • Negate: Compute additive inverse
See G1 Operations for detailed API reference.

G2 Point Operations

G2 operates on the twisted curve over extension field Fp2:
  • Addition/Multiplication: Same operations as G1, over Fp2
  • Subgroup check: Critical for security (prevent invalid curve attacks)
  • Frobenius endomorphism: Fast scalar multiplication
See G2 Operations for detailed API reference.

Pairing Check

The core operation for zkSNARK verification: Input: Pairs of points (P1, Q1), (P2, Q2), …, (Pn, Qn) where Pi ∈ G1, Qi ∈ G2 Output: Boolean - whether e(P1, Q1) · e(P2, Q2) · … · e(Pn, Qn) = 1 Implementation:
  1. Miller loop: Compute line functions for each pair
  2. Final exponentiation: Raise result to (p^12 - 1) / r
See Pairing for mathematical details.

Field Arithmetic

  • Fp: Base field (254-bit prime modulus)
  • Fp2: Quadratic extension (a + bi)
  • Fp6: Sextic extension (3 Fp2 elements)
  • Fp12: Dodecic extension (2 Fp6 elements) - pairing target group
All operations use Montgomery form for efficient modular arithmetic.

zkSNARK Usage

BN254 is the standard curve for Ethereum zkSNARK systems:

Groth16 Verification

Most common zkSNARK construction. Verification requires:
  • 3 G1 points (proof.A, proof.C, public inputs contribution)
  • 1 G2 point (proof.B)
  • 1 precomputed G2 verification key
  • 1 pairing check with 3 pairs
Gas cost: ~147,000 gas (45,000 base + 34,000 per pair × 3)

PLONK Verification

More flexible than Groth16, supports universal setup:
  • Multiple G1 points (commitments, evaluations)
  • Fewer G2 points (usually 1-2)
  • Pairing check with fewer pairs
Gas cost: ~100,000-200,000 gas (varies by circuit size) See zkSNARK Usage for implementation patterns.

Documentation

Core Concepts

  • Pairing - Optimal ate pairing, Miller loop, final exponentiation
  • Precompiles - EIP-196/197 precompiled contracts (0x06-0x08)
  • zkSNARK Usage - Groth16, PLONK, proof verification patterns

Operations

Reference

Precompile Addresses

EIP-196 (Byzantium):
  • 0x06: ECADD - G1 point addition
  • 0x07: ECMUL - G1 scalar multiplication
EIP-197 (Byzantium):
  • 0x08: ECPAIRING - Pairing check
EIP-1108 (Istanbul): Reduced gas costs for zkSNARK affordability

Point Formats

G1 Points (64 bytes)

| x-coordinate | y-coordinate |
|   32 bytes   |   32 bytes   |
Both big-endian Fp elements. Infinity represented as (0, 0).

G2 Points (128 bytes)

| x.c0 | x.c1 | y.c0 | y.c1 |
|  32  |  32  |  32  |  32  |
Fp2 elements: x = x.c0 + x.c1·i, y = y.c0 + y.c1·i

Gas Costs

EIP-196 (after Istanbul):
  • ECADD: 150 gas
  • ECMUL: 6,000 gas
EIP-197 (after Istanbul):
  • ECPAIRING base: 45,000 gas
  • ECPAIRING per pair: 34,000 gas
Groth16 Verification (~3 pairs): 45,000 + 34,000×3 = 147,000 gas

Security

Security Level: 128-bit (nominal) BN254 provides 128-bit security level equivalent to BLS12-381. However, practical attacks on the discrete logarithm problem for BN curves are faster than originally estimated: Practical Considerations:
  • Some estimates suggest ~100-bit practical security due to faster DLP attacks
  • Kim-Barbulescu attack (2016) improved NFS complexity for BN curves
  • Still sufficient for current protocols and usage
Critical Security Requirement: Always validate G2 subgroup membership to prevent invalid curve attacks. Comparison to BLS12-381:
  • BLS12-381: 128-bit security (more conservative curve choice)
  • BN254: 128-bit nominal, ~100-bit practical (faster operations, wider adoption)
Recommendation: BN254 remains secure for current use. Monitor cryptanalysis research. Consider BLS12-381 for new protocols requiring maximum security margin.

Use Cases

Privacy: Tornado Cash, Aztec, zkBob L2 Scaling: zkSync, Polygon zkEVM, Scroll Identity: zk-proofs for authentication DeFi: Private trading, dark pools Voting: On-chain governance with privacy

Performance

Native (arkworks):
  • G1 add: ~5 μs
  • G1 mul: ~40 μs
  • G2 add: ~10 μs
  • G2 mul: ~120 μs
  • Pairing (single): ~600 μs
  • Pairing check (3 pairs): ~2 ms
vs BLS12-381:
  • ~2x faster pairing
  • Less secure (100-bit vs 128-bit)

References