> ## Documentation Index
> Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# BN254 (BN128)

> Pairing-friendly elliptic curve for zkSNARK verification and Alt-BN128 precompiles

<Card title="Try it Live" icon="play" href="https://playground.tevm.sh?example=crypto/bn254.ts">
  Run BN254 examples in the interactive playground
</Card>

<Info>
  Source: [bn254.zig](https://github.com/evmts/voltaire/blob/main/src/crypto/bn254.zig) • [bn254.wasm.ts](https://github.com/evmts/voltaire/blob/main/src/crypto/bn254.wasm.ts)

  Tests: [bn254.test.ts](https://github.com/evmts/voltaire/blob/main/src/crypto/bn254.test.ts)
</Info>

# BN254 (BN128)

Pairing-friendly elliptic curve implementation for zkSNARK verification and Ethereum's Alt-BN128 precompiles (0x06-0x08).

## Overview

BN254 (also known as BN128 or Alt-BN128) is a Barreto-Naehrig pairing-friendly elliptic curve widely used in zero-knowledge proof systems. It provides efficient pairing operations essential for zkSNARK verification, privacy-preserving protocols, and cryptographic applications requiring bilinear pairings.

**Ethereum Use Cases:**

* **zkSNARKs**: Zero-knowledge proof verification (Zcash, Tornado Cash, zkSync)
* **EIP-196**: ECADD precompile (0x06) - G1 point addition
* **EIP-196**: ECMUL precompile (0x07) - G1 scalar multiplication
* **EIP-197**: ECPAIRING precompile (0x08) - Optimal ate pairing check
* **Privacy protocols**: Confidential transactions, private voting systems

## Quick Start

```typescript theme={null}
import * as BN254 from '@tevm/voltaire/crypto/bn254';

// G1 operations (base field)
const g1Gen = BN254.G1.generator();
const g1Doubled = BN254.G1.add(g1Gen, g1Gen);
const g1Scaled = BN254.G1.mul(g1Gen, 5n);

// G2 operations (extension field)
const g2Gen = BN254.G2.generator();
const g2Scaled = BN254.G2.mul(g2Gen, 3n);

// Pairing check (zkSNARK verification)
const isValid = BN254.Pairing.pairingCheck([
  [g1Scaled, g2Gen],
  [g1Gen, g2Scaled]
]);
```

## Elliptic Curve Pairing Basics

**Pairing-based cryptography** uses a special bilinear map `e: G1 × G2 → GT` that enables:

1. **Bilinearity**: `e(aP, bQ) = e(P, Q)^(ab)` - scalar multiplication distributes
2. **Non-degeneracy**: `e(G1, G2) ≠ 1` - generator pairing produces non-trivial result
3. **Computability**: Pairing computable in polynomial time (optimal ate pairing)

**Applications:**

* **Identity-based encryption**: Public keys derived from identities
* **Short signatures**: BLS signatures with signature aggregation
* **zkSNARKs**: Succinct non-interactive zero-knowledge proofs
* **Broadcast encryption**: Efficient one-to-many encryption

## API Reference

### Field Elements

BN254 operates over two finite fields:

#### Base Field (Fp)

```typescript theme={null}
import * as Fp from '@tevm/voltaire/crypto/bn254/Fp';

// Field modulus (254 bits)
const p = Fp.MOD; // 21888242871839275222246405745257275088696311157297823662689037894645226208583n

// Field arithmetic
const a = 123n;
const b = 456n;
const sum = Fp.add(a, b);
const prod = Fp.mul(a, b);
const inv = Fp.inv(a);
```

#### Scalar Field (Fr)

```typescript theme={null}
import * as Fr from '@tevm/voltaire/crypto/bn254/Fr';

// Scalar field modulus (curve order)
const r = Fr.MOD; // 21888242871839275222246405745257275088548364400416034343698204186575808495617n

// Scalar arithmetic
const s1 = Fr.mod(1234567890n);
const s2 = Fr.mod(9876543210n);
const product = Fr.mul(s1, s2);
```

#### Extension Field (Fp2)

```typescript theme={null}
import * as Fp2 from '@tevm/voltaire/crypto/bn254/Fp2';

// Quadratic extension Fp2 = Fp[u]/(u^2 + 1)
const elem = Fp2.create(123n, 456n); // 123 + 456u
const squared = Fp2.square(elem);
const conjugate = Fp2.conjugate(elem); // 123 - 456u
```

### Group Elements

#### G1 Points (Base Field)

```typescript theme={null}
import * as G1 from '@tevm/voltaire/crypto/bn254/G1';

// Generator point
const g = G1.generator(); // (1, 2)

// Point operations
const doubled = G1.double(g);
const sum = G1.add(g, doubled);
const scaled = G1.mul(g, 42n);
const negated = G1.negate(g);

// Point validation
const isOnCurve = G1.isOnCurve(g);
const isZero = G1.isZero(G1.infinity());

// Serialization (EIP-196 format)
const serialized = BN254.serializeG1(g); // 64 bytes: x || y
const deserialized = BN254.deserializeG1(serialized);
```

**Curve equation**: `y^2 = x^3 + 3` over Fp

#### G2 Points (Extension Field)

```typescript theme={null}
import * as G2 from '@tevm/voltaire/crypto/bn254/G2';

// Generator point (Fp2 coordinates)
const g2 = G2.generator();

// Point operations
const doubled = G2.double(g2);
const sum = G2.add(g2, doubled);
const scaled = G2.mul(g2, 7n);
const negated = G2.negate(g2);

// Subgroup check
const inSubgroup = G2.isInSubgroup(g2);

// Serialization (EIP-197 format)
const serialized = BN254.serializeG2(g2); // 128 bytes: x_c0 || x_c1 || y_c0 || y_c1
const deserialized = BN254.deserializeG2(serialized);
```

**Curve equation**: `y^2 = x^3 + 3/(9+u)` over Fp2

### Pairing Operations

#### Optimal Ate Pairing

```typescript theme={null}
import * as Pairing from '@tevm/voltaire/crypto/bn254/Pairing';

// Single pairing computation
const g1 = G1.generator();
const g2 = G2.generator();
const result = Pairing.pair(g1, g2); // Element in GT (Fp12)

// Check if pairing result equals 1
const isOne = Pairing.pairingResult.isOne(result);
```

#### Pairing Check (zkSNARK Verification)

```typescript theme={null}
// Verify pairing equation: e(P1, Q1) * e(P2, Q2) * ... = 1
const pairs = [
  [g1Point1, g2Point1],
  [g1Point2, g2Point2],
  [g1Point3, g2Point3]
];

const isValid = Pairing.pairingCheck(pairs);
```

**Common pattern** (Groth16 zkSNARK verification):

```typescript theme={null}
// Verify proof: e(-A, B) * e(alpha, beta) * e(C, delta) = 1
const isValidProof = Pairing.pairingCheck([
  [negatedA, proofB],
  [vkAlpha, vkBeta],
  [proofC, vkDelta]
]);
```

## Serialization

### G1 Point Format (64 bytes)

```typescript theme={null}
// EIP-196 format: x (32 bytes) || y (32 bytes)
const g1 = G1.generator();
const bytes = BN254.serializeG1(g1);
// bytes = [x_31, x_30, ..., x_0, y_31, y_30, ..., y_0]

// Point at infinity: (0, 0)
const infinity = G1.infinity();
const infinityBytes = BN254.serializeG1(infinity);
// infinityBytes = [0x00 * 64]
```

### G2 Point Format (128 bytes)

```typescript theme={null}
// EIP-197 format: x_c0 (32) || x_c1 (32) || y_c0 (32) || y_c1 (32)
const g2 = G2.generator();
const bytes = BN254.serializeG2(g2);
// Fp2 element x = x_c0 + x_c1*u
// Fp2 element y = y_c0 + y_c1*u
```

## Use Cases

### zkSNARK Verification

```typescript theme={null}
// Verify Groth16 proof
function verifyGroth16Proof(
  proof: { A: G1Point, B: G2Point, C: G1Point },
  vk: { alpha: G1Point, beta: G2Point, gamma: G2Point, delta: G2Point },
  publicInputs: bigint[]
): boolean {
  // Compute linear combination of public inputs
  const vkX = computePublicInputLinearCombination(vk, publicInputs);

  // Pairing check: e(-A, B) * e(alpha, beta) * e(vkX, gamma) * e(C, delta) = 1
  return BN254.Pairing.pairingCheck([
    [BN254.G1.negate(proof.A), proof.B],
    [vk.alpha, vk.beta],
    [vkX, vk.gamma],
    [proof.C, vk.delta]
  ]);
}
```

### EIP-196/197 Precompile Calls

```typescript theme={null}
// Direct precompile usage (via Zig/Rust)
import { bn254Add, bn254Mul, bn254Pairing } from '@tevm/voltaire/crypto/bn254';

// ECADD (0x06): Add two G1 points
const input1 = new Uint8Array(128); // p1_x || p1_y || p2_x || p2_y
const output1 = Bytes64();
bn254Add(input1, output1); // result_x || result_y

// ECMUL (0x07): Scalar multiply G1 point
const input2 = new Uint8Array(96); // p_x || p_y || scalar
const output2 = Bytes64();
bn254Mul(input2, output2);

// ECPAIRING (0x08): Pairing check
const input3 = new Uint8Array(192 * n); // n pairs of (g1_point || g2_point)
const isValid = bn254Pairing(input3); // boolean
```

## Implementation Details

#### Rust Implementation (Production - Arkworks)

* **Library**: arkworks (ark-bn254, ark-ec, ark-ff)
* **FFI**: `src/crypto/bn254_arkworks.zig`
* **Status**: Audited, production-ready
* **Performance**: 3-5x faster than Zig implementation
* **Use**: Recommended for production deployments

**Why arkworks?**

* Battle-tested in Ethereum ecosystem
* Constant-time operations (side-channel resistant)
* Extensive security audits
* Optimized assembly for critical paths

### TypeScript Implementation (Reference)

* **Location**: `src/crypto/bn254/` (`.js` files)
* **Purpose**: Pure TS reference, browser compatibility
* **Features**:
  * Fp, Fp2 field arithmetic
  * G1, G2 point operations
  * Pairing computation
  * Serialization utilities

### WASM Builds

**Zig fallback**: WASM builds use Zig implementation (arkworks unavailable in WASM). WASM performance is \~50% of native arkworks, but fully functional.

## Security Considerations

**Production Deployments**:

* Use arkworks (Rust) implementation for native builds
* Audited, constant-time operations
* Resistant to timing side-channels

**Development/Testing**:

* Zig implementation suitable for testing
* Pure implementation aids understanding
* No known vulnerabilities, but unaudited

**zkSNARK Security**:

* Verify trusted setup authenticity
* Validate proof inputs (prevent malleability)
* Check subgroup membership for G2 points
* Ensure scalar values in valid range \[1, r-1]

**Point Validation**:

```typescript theme={null}
import { Bn254InvalidPointError, Bn254SubgroupCheckError } from '@tevm/voltaire/crypto/bn254';

// Always validate deserialized points
const g1 = BN254.deserializeG1(bytes);
if (!G1.isOnCurve(g1)) {
  throw new Bn254InvalidPointError("Invalid G1 point", {
    context: { curve: "G1" },
    docsPath: "/crypto/bn254#point-validation"
  });
}

const g2 = BN254.deserializeG2(bytes);
if (!G2.isOnCurve(g2)) {
  throw new Bn254InvalidPointError("Invalid G2 point", {
    context: { curve: "G2" },
    docsPath: "/crypto/bn254#point-validation"
  });
}
if (!G2.isInSubgroup(g2)) {
  throw new Bn254SubgroupCheckError("G2 point not in subgroup", {
    context: { curve: "G2" },
    docsPath: "/crypto/bn254#subgroup-check"
  });
}
```

## Performance

**Native (Arkworks Rust)**:

* ECADD: \~0.02ms
* ECMUL: \~0.15ms
* Pairing: \~1.5ms
* Pairing check (2 pairs): \~2.5ms

**WASM (Zig)**:

* ECADD: \~0.05ms
* ECMUL: \~0.3ms
* Pairing: \~3ms
* Pairing check (2 pairs): \~5ms

## Constants

```typescript theme={null}
import { FP_MOD, FR_MOD, B_G1, G1_GENERATOR_X, G1_GENERATOR_Y } from '@tevm/voltaire/crypto/bn254';

// Field modulus (254 bits)
FP_MOD // 21888242871839275222246405745257275088696311157297823662689037894645226208583n

// Curve order (254 bits)
FR_MOD // 21888242871839275222246405745257275088548364400416034343698204186575808495617n

// G1 curve parameter: y^2 = x^3 + 3
B_G1 // 3n

// G1 generator point
G1_GENERATOR_X // 1n
G1_GENERATOR_Y // 2n
```

## Related

* [Precompiles: BN254 Add/Mul/Pairing](/evm/precompiles) - EIP-196/197 precompile implementations
* [BLS12-381](/crypto/bls12-381) - Alternative pairing curve for Eth2 consensus
* [KZG Commitments](/crypto/kzg) - Polynomial commitments using BLS12-381

## References

* [EIP-196: Precompiled contracts for addition and scalar multiplication on the elliptic curve alt\_bn128](https://eips.ethereum.org/EIPS/eip-196)
* [EIP-197: Precompiled contracts for optimal ate pairing check on the elliptic curve alt\_bn128](https://eips.ethereum.org/EIPS/eip-197)
* [Groth16: On the Size of Pairing-based Non-interactive Arguments](https://eprint.iacr.org/2016/260.pdf)
* [arkworks-rs/algebra](https://github.com/arkworks-rs/algebra) - Audited Rust implementation
