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: 0x000000000000000000000000000000000000000f
Introduced: Prague (EIP-2537)
EIP: EIP-2537
The BLS12-381 G2 Mul precompile performs scalar multiplication on the BLS12-381 curve’s G2 group. It multiplies a G2 point by a scalar, computing scalar * point. This operation is fundamental for BLS signature schemes, zero-knowledge proofs, and cryptographic protocols requiring operations over extension fields.
BLS12-381 provides 128 bits of security and is the foundation of Ethereum 2.0’s consensus layer signature scheme.
Gas Cost
Fixed: 45000 gas
G2 vs G1
G2 scalar multiplication operates on points over the Fp2 extension field:
- G1 points: 128 bytes (2 Fp coordinates)
- G2 points: 256 bytes (2 Fp2 coordinates)
- G1 mul gas: 12,000
- G2 mul gas: 45,000 (3.75x more expensive)
- Cost driver: Extension field arithmetic is significantly more complex
Offset | Length | Description
-------|--------|-------------
0 | 64 | x.c0 (point x-coordinate c0 component, big-endian)
64 | 64 | x.c1 (point x-coordinate c1 component, big-endian)
128 | 64 | y.c0 (point y-coordinate c0 component, big-endian)
192 | 64 | y.c1 (point y-coordinate c1 component, big-endian)
256 | 32 | scalar (multiplier, big-endian)
Total input length: 288 bytes (256 bytes G2 point + 32 bytes scalar)
G2 point must satisfy curve equation: y^2 = x^3 + 4(1 + u) over Fp2.
Scalar can be any 256-bit value (automatically reduced modulo curve order).
Offset | Length | Description
-------|--------|-------------
0 | 64 | x.c0 (result point x-coordinate c0 component, big-endian)
64 | 64 | x.c1 (result point x-coordinate c1 component, big-endian)
128 | 64 | y.c0 (result point y-coordinate c0 component, big-endian)
192 | 64 | y.c1 (result point y-coordinate c1 component, big-endian)
Total output length: 256 bytes
Usage Example
TypeScript
import { execute, PrecompileAddress } from '@tevm/voltaire/precompiles';
import { Hardfork } from '@tevm/voltaire/primitives/Hardfork';
// Multiply G2 point by scalar
// Using point at infinity (valid edge case: O * k = O)
const point = new Uint8Array(256); // All zeros = point at infinity
const scalar = Bytes32('0x0000000000000000000000000000000000000000000000000000000000000005'); // multiply by 5
const input = new Uint8Array(288);
input.set(point, 0);
input.set(scalar, 256);
const result = execute(
PrecompileAddress.BLS12_G2_MUL,
input,
50000n,
Hardfork.PRAGUE
);
if (result.success) {
const resultPoint = result.output; // 256 bytes
const xc0 = result.output.slice(0, 64);
const xc1 = result.output.slice(64, 128);
const yc0 = result.output.slice(128, 192);
const yc1 = result.output.slice(192, 256);
console.log('Result G2 point:', { xc0, xc1, yc0, yc1 });
console.log('Gas used:', result.gasUsed); // 45000
} else {
console.error('Error:', result.error);
}
Zig
const std = @import("std");
const precompiles = @import("precompiles");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Create input: G2 point (256 bytes) + scalar (32 bytes)
var input = [_]u8{0} ** 288;
// ... populate G2 point coordinates
input[287] = 5; // scalar = 5
// Execute G2 multiplication
const result = try precompiles.bls12_g2_mul.execute(
allocator,
&input,
100000
);
defer result.deinit(allocator);
std.debug.print("Gas used: {}\n", .{result.gas_used}); // 45000
std.debug.print("Output length: {}\n", .{result.output.len}); // 256
}
Error Conditions
- Out of gas: gasLimit < 45,000
- Invalid input length: input.len != 288
- Point not on curve: coordinates don’t satisfy G2 curve equation
- Invalid field element: coordinate component >= field modulus
- Invalid point: point not in correct subgroup
Use Cases
- BLS signature verification: Key derivation and signature operations
- Threshold signatures: Generate signature shares
- Key generation: Derive public keys from private scalars
- Commitment schemes: Pedersen-like commitments over G2
- Zero-knowledge proofs: zkSNARKs and zkSTARKs on BLS12-381
- Ethereum 2.0: Validator key operations
Implementation Details
- Zig: Uses BLST library optimized for BLS12-381
- TypeScript: Wraps @noble/curves bls12-381 G2 operations
- Algorithm: Windowed scalar multiplication for efficiency
- Security: Constant-time execution prevents timing attacks
- Optimization: Double-and-add with precomputed tables
Special Cases
- Scalar = 0: Returns point at infinity (256 bytes of zeros)
- Scalar = 1: Returns input point unchanged
- Scalar = group order: Returns point at infinity (r*P = O)
- Point at infinity input: Returns point at infinity regardless of scalar
- Scalar > group order: Automatically reduced modulo group order
Scalar Arithmetic
Scalars are elements of F_r where r is the curve order:
- Group order (r): Same as BLS12-381 scalar field order
- Modular reduction: Scalars wrap around modulo r
- Zero scalar: Always produces point at infinity
- Negative scalars: Equivalent to positive via modular arithmetic
Extension Field Operations
G2 scalar multiplication involves Fp2 arithmetic:
- Field elements:
a = a.c0 + a.c1*u where u^2 + 1 = 0
- Point doubling: Requires Fp2 squaring and multiplication
- Point addition: Complex formula over extension field
- Cost: Each Fp2 operation is ~3-4x more expensive than Fp
This complexity explains why G2 mul is 3.75x more expensive than G1 mul.
Gas Comparison
| Operation | G1 Gas | G2 Gas | Ratio |
|---|
| Addition | 500 | 800 | 1.6x |
| Multiplication | 12,000 | 45,000 | 3.75x |
| MSM (base) | 12,000 | 45,000 | 3.75x |
The multiplication cost ratio reflects the increased complexity of extension field arithmetic.
- Expensive operation: 45,000 gas is substantial
- Batch with MSM: For multiple scalar muls, use G2 MSM with discount
- Precomputation: Cache commonly used multiples when possible
- G1 vs G2 choice: Use G1 operations when either group works
- Signature verification: Typically requires 1-2 G2 muls
Test Vectors
// Generator * 0 = Identity
const scalar = 0n;
const result = bls12G2Mul(G2_GENERATOR, scalar);
// result = point at infinity (256 bytes of zeros)
// Generator * 1 = Generator
const result = bls12G2Mul(G2_GENERATOR, 1n);
// result = G2_GENERATOR
// Point * group_order = Identity
const result = bls12G2Mul(somePoint, groupOrder);
// result = point at infinity
BLS Signature Context
In BLS signature schemes:
- Public keys: Often G2 points derived via scalar multiplication
- Signature verification: Requires G2 scalar operations
- Key aggregation: Combine public keys via G2 addition
- Threshold schemes: Generate key shares with G2 mul
Security Considerations
- 128-bit security: BLS12-381 provides quantum-resistant classical security
- Side-channel resistance: Constant-time implementation prevents timing attacks
- Subgroup checks: Implementation validates points are in correct subgroup
- Field validation: Coordinates must be valid field elements
Gas Cost Justification
The 45,000 gas cost reflects:
- Extension field arithmetic: Fp2 operations are computationally intensive
- Security overhead: Subgroup and validity checks
- Scalar multiplication: Requires ~255 point operations on average
- Memory operations: 256-byte point representation
Compared to BN254 mul (6,000 gas), the higher cost accounts for stronger security and extension field complexity.