Skip to main content
This page is a placeholder. All examples on this page are currently AI-generated and are not correct. This documentation will be completed in the future with accurate, tested examples.

Overview

Address: 0x0000000000000000000000000000000000000008 Introduced: Byzantium (EIP-197) EIP: EIP-197, EIP-1108 The BN254 Pairing precompile performs a pairing check on the BN254 (alt_bn128) elliptic curve. It verifies whether a product of pairings equals the identity element: e(A1,B1) * e(A2,B2) * ... * e(Ak,Bk) = 1. This is the fundamental cryptographic operation for Groth16 zkSNARK verification, enabling zero-knowledge proofs on Ethereum. A pairing is a special bilinear map that takes two elliptic curve points (one from group G1, one from group G2) and produces a value in a third group GT. The bilinear property means e(aP, bQ) = e(P, Q)^(ab), which is what makes zero-knowledge proofs mathematically possible. Think of it as a one-way function that lets you verify relationships between encrypted values without decrypting them. EIP-1108 (Istanbul hardfork) reduced gas costs by 56-57%, making zkSNARK verification practical for production applications like Tornado Cash and zk-rollups.

Gas Cost

Formula: 45000 + 34000 * k where k = number of point pairs Examples:
  • Empty input (k=0): 45,000 gas
  • 1 pair: 79,000 gas
  • 2 pairs: 113,000 gas
  • 4 pairs: 181,000 gas
Pre-Istanbul: 100,000 + 80,000*k (much more expensive)

Input Format

Input must be a multiple of 192 bytes. Each pair consists of:
Each 192-byte chunk represents one (G1, G2) pair.
  • k pairs = 192 * k bytes
  • Empty input (0 bytes) is valid and returns success (empty product = 1)
G2 point encoding: G2 points have coordinates in Fp2 = Fp[i]/(i²+1):
  • x = x1 + x2*i (offset 64: x1, offset 96: x2)
  • y = y1 + y2*i (offset 128: y1, offset 160: y2)

Output Format

Total output length: 32 bytes (single word)
  • Success: 0x0000…0001 (last byte = 1)
  • Failure: 0x0000…0000 (all zeros)

Usage Example

Error Conditions

  • Out of gas
  • Input length not multiple of 192
  • G1 point not on curve
  • G2 point not on curve
  • Coordinate >= field modulus
  • Invalid G2 point encoding
Failures return error (not false). Only valid inputs that fail the pairing check return false (32 zero bytes).

Use Cases

Production Applications:
  • Tornado Cash: Privacy-preserving Ethereum transactions using Groth16 proofs. Each withdrawal verifies a pairing check proving knowledge of a deposit without revealing which one (181,000 gas).
  • zk-Rollups: Layer 2 scaling solutions verify validity proofs on L1:
    • zkSync Era: Uses PLONK (different proof system, but same curve)
    • Polygon zkEVM: Groth16 verification for batches of thousands of transactions
    • Scroll: zkEVM using different proof systems but BN254 pairing primitives
  • Semaphore: Anonymous signaling and voting. Proves “I’m in this group” without revealing identity. Used by privacy protocols and DAO voting systems.
  • Aztec Protocol: Privacy-preserving smart contracts on Ethereum. Each private transaction includes zkSNARK proof verified via pairing.
Why Pairing Instead of Pure Software? Computing a BN254 pairing in EVM bytecode would cost millions of gas. The precompile uses optimized native code (via arkworks-rs) and reduces cost by 99%+. Without this precompile, zkSNARKs on Ethereum would be economically infeasible. BLS Signatures (Historical): Early BLS signature schemes used BN254, but modern implementations prefer BLS12-381 (see precompiles 0x0a-0x0d) for better security margins.

Implementation Details

  • Zig: Uses arkworks-rs via Rust FFI for optimal pairing performance
  • TypeScript: Wraps BN254 crypto module pairing implementation
  • Integration: Most complex of BN254 operations, uses Miller loop + final exponentiation
  • Algorithm: Optimal Ate pairing on BN254
  • Optimization: Multi-pairing optimization (Miller loop shared across pairs)

Mathematical Background

What is a Pairing? A pairing is a bilinear map: e: G1 × G2 → GT Key properties:
  • Bilinearity: e(aP, bQ) = e(P, Q)^(ab) = e(bP, aQ) for all scalars a, b
  • Non-degeneracy: e(G1_generator, G2_generator) ≠ 1
  • Computability: Efficiently computable (using Miller loop + final exponentiation)
Why This Enables zkSNARKs: The bilinear property lets verifiers check polynomial equations without knowing the polynomial coefficients:
  • Prover commits to polynomial: C = p(τ) * G1 (where τ is trusted setup secret)
  • Verifier checks relationships: e(C, G2) = e(proof, verifier_key)
  • If equation holds, proof is valid - but verifier never learns τ or polynomial coefficients
This is why a trusted setup is needed: someone generates τ and computes powers of τ, then deletes τ. As long as one person in the ceremony is honest, the system is secure. BN254 Curve Details:
  • Prime field: 254-bit prime p = 21888242871839275222246405745257275088696311157297823662689037894645226208583
  • Embedding degree: 12 (pairing uses degree-12 extension field)
  • Security: ~100-bit security level (approximately equivalent to 2048-bit RSA)
  • Groups: G1 over Fp, G2 over Fp2, GT in Fp12

Groth16 zkSNARK Verification

Groth16 is the most widely used zkSNARK system. A typical proof consists of three G1 points (A, B, C), and verification checks:
Rearranging for implementation (using negation to avoid inversions):
Verification key elements:
  • alpha, beta, delta, gamma: Points from trusted setup
  • public_inputs: Derived from circuit public inputs and verification key
Gas cost for Groth16: 45000 + 34000*4 = 181,000 gas Real-world example: Tornado Cash uses Groth16 to prove “I know a secret that was deposited” without revealing which deposit. The circuit has ~2,000 constraints, proving knowledge of a Merkle path in the deposit tree.

Gas Cost Comparison

Test Vectors

From official Ethereum test suite: