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.
Try it Live Run Blob examples in the interactive playground
KZG (Kate-Zaverucha-Goldberg) commitments provide cryptographic binding between blob data and commitments. This page explains the mathematics and implementation.
Overview
KZG commitments enable:
Binding - Cannot create two different blobs with same commitment
Hiding - Commitment doesn’t reveal blob contents
Succinct - 48-byte commitment for 131,072-byte blob
Verifiable - Prove blob matches commitment without revealing data
Mathematical Foundation
Polynomial Commitment Scheme
Blob as Polynomial
Blob contains 4,096 field elements
Treat as polynomial coefficients: f(x) = a₀ + a₁x + a₂x² + ... + a₄₀₉₅x⁴⁰⁹⁵
Trusted Setup
Generate powers of secret: [G₁, sG₁, s²G₁, ..., s⁴⁰⁹⁵G₁] where G₁ is BLS12-381 generator
Secret s destroyed after ceremony
Commitment
Evaluate polynomial at secret: C = f(s)G₁ = Σ(aᵢ · sⁱG₁)
Result is 48-byte G₁ point (commitment)
Proof
Prove evaluation at challenge point z: f(z) = y
Generate proof π that verifies: e(C - yG₁, G₂) = e(π, (s - z)G₂)
BLS12-381 Curve
KZG uses BLS12-381 pairing-friendly curve:
// Field modulus (scalar field)
const MODULUS =
52435875175126190479447740508185965837690552500527637822603658699938581184513 n ;
// G1 point size: 48 bytes (compressed)
// G2 point size: 96 bytes (compressed)
// Each blob field element must be < MODULUS
Implementation
Computing Commitments
import { Kzg , Blob } from 'tevm' ;
const blob = Blob . fromData ( data );
// Compute commitment (requires c-kzg-4844 library)
const commitment = Kzg . Commitment ( blob );
console . log ( commitment . length ); // 48 bytes
console . log ( commitment instanceof Uint8Array ); // true
Internal Process
// Conceptual implementation (actual uses c-kzg-4844)
function computeKZGCommitment ( blob : Uint8Array ) : Uint8Array {
// 1. Parse blob as 4,096 field elements
const fieldElements = parseFieldElements ( blob );
// 2. Load trusted setup (powers of tau)
const setup = loadTrustedSetup ();
// 3. Compute commitment: C = Σ(aᵢ · sⁱG₁)
let commitment = G1 . identity ();
for ( let i = 0 ; i < fieldElements . length ; i ++ ) {
commitment = commitment . add (
setup . g1Powers [ i ]. mul ( fieldElements [ i ])
);
}
// 4. Serialize to 48 bytes
return commitment . toBytes ();
}
Generating Proofs
import { Kzg , Blob } from 'tevm' ;
const blob = Blob . fromData ( data );
const commitment = Kzg . Commitment ( blob );
// Generate KZG proof
const proof = Kzg . Proof ( blob );
console . log ( proof . length ); // 48 bytes
// Verify proof
const isValid = Kzg . verify ( blob , commitment , proof );
console . log ( isValid ); // true
Trusted Setup
KZG Ceremony
EIP-4844 uses trusted setup from ceremony.ethereum.org :
// Trusted setup parameters
const SETUP_SIZE = 4096 ; // Powers of tau
const PARTICIPANTS = 4000 + ; // Contributors
// Security guarantee:
// Safe if at least 1 participant honest and destroyed secret
Powers of Tau
// Trusted setup contains:
// G1 powers: [G₁, sG₁, s²G₁, ..., s⁴⁰⁹⁵G₁]
// G2 powers: [G₂, sG₂]
// Where s is secret, destroyed after ceremony
// Used for:
// - Computing commitments (G1 powers)
// - Verifying proofs (G2 powers, pairings)
Loading Setup
// c-kzg-4844 loads trusted setup
import { loadTrustedSetup } from 'c-kzg' ;
// Mainnet setup
const setup = loadTrustedSetup ( 'mainnet.txt' );
// Or load from file
const setupData = readFileSync ( 'trusted_setup.txt' );
loadTrustedSetup ( setupData );
Verification
Proof Verification
import { Kzg , Blob } from 'tevm' ;
// Create blob and proof
const blob = Blob . fromData ( data );
const commitment = Kzg . Commitment ( blob );
const proof = Kzg . Proof ( blob );
// Verify (uses pairing check)
const isValid = Kzg . verify ( blob , commitment , proof );
console . log ( isValid ); // true
Pairing Equation
Verification uses BLS12-381 pairing:
e(commitment, G₂) = e(proof, challenge_G₂)
Where:
- e() is pairing function
- commitment is 48-byte G₁ point
- proof is 48-byte G₁ point
- G₂ is generator
- challenge_G₂ is challenge point in G₂
Batch Verification
More efficient for multiple blobs:
import { Kzg , Blob } from 'tevm' ;
const blobs = [ blob1 , blob2 , blob3 ];
const commitments = blobs . map ( b => Kzg . Commitment ( b ));
const proofs = blobs . map ( b => Kzg . Proof ( b ));
// Batch verify (single pairing check)
const allValid = Kzg . verifyBatch ( blobs , commitments , proofs );
console . log ( allValid ); // true
Security Properties
Computational Binding
Cannot find two different blobs with same commitment:
import { Kzg , Blob } from 'tevm' ;
const blob1 = Blob . fromData ( data1 );
const blob2 = Blob . fromData ( data2 ); // Different data
const commitment1 = Kzg . Commitment ( blob1 );
const commitment2 = Kzg . Commitment ( blob2 );
// Commitments differ (except with negligible probability)
console . log ( Blob . equals ( commitment1 , commitment2 )); // false
// Cannot create valid proof for wrong blob
const proof1 = Kzg . Proof ( blob1 );
console . log ( Kzg . verify ( blob1 , commitment1 , proof1 )); // true
console . log ( Kzg . verify ( blob2 , commitment1 , proof1 )); // false
Hiding (Partial)
Commitment doesn’t directly reveal blob contents, but:
Not fully hiding (deterministic)
Same data = same commitment
Use versioned hash (SHA256) for additional hiding
import { Kzg , Blob } from 'tevm' ;
const blob = Blob . fromData ( data );
const commitment = Kzg . Commitment ( blob );
// Commitment doesn't reveal data (48 bytes for 131 KB)
console . log ( `Blob: ${ blob . length } bytes` );
console . log ( `Commitment: ${ commitment . length } bytes` );
// But versioned hash adds additional hiding
const versionedHash = Blob . toVersionedHash ( commitment );
console . log ( `Versioned hash: ${ versionedHash . length } bytes` );
Soundness
Valid proofs always verify:
import { Kzg , Blob } from 'tevm' ;
const blob = Blob . fromData ( data );
const commitment = Kzg . Commitment ( blob );
const proof = Kzg . Proof ( blob );
// Always verifies for correctly generated proof
console . log ( Kzg . verify ( blob , commitment , proof )); // true (always)
// Cannot create fake proof
const fakeProof = new Uint8Array ( 48 );
console . log ( Kzg . verify ( blob , commitment , fakeProof )); // false (except negligible probability)
Field Element Validation
Modulus Check
Each 32-byte element must be < BLS12-381 modulus:
const BLS_MODULUS =
52435875175126190479447740508185965837690552500527637822603658699938581184513 n ;
// Valid field element
const validElement = Bytes32 ();
validElement [ 31 ] = 0x01 ; // Small value
// OK: 1 < BLS_MODULUS
// Invalid field element
const invalidElement = Bytes32 ();
invalidElement . fill ( 0xff ); // Large value
// Error: 0xfff...fff > BLS_MODULUS
Automatic Validation
Tevm’s fromData() ensures valid field elements:
import { Blob } from 'tevm' ;
// Automatic field element validation
const blob = Blob . fromData ( data );
// All field elements guaranteed < BLS_MODULUS
const isValid = Blob . isValid ( blob );
console . log ( isValid ); // true
Implementation Notes
c-kzg-4844 Library
Tevm uses c-kzg-4844 :
// Native bindings to C library
import * as kzg from 'c-kzg' ;
// Load trusted setup
kzg . loadTrustedSetup ( 'trusted_setup.txt' );
// Compute commitment
const commitment = kzg . blobToKzgCommitment ( blob );
// Compute proof
const proof = kzg . computeBlobKzgProof ( blob , commitment );
// Verify
const isValid = kzg . verifyBlobKzgProof ( blob , commitment , proof );
WASM Support
WASM builds stub KZG operations (not yet supported):
// In WASM environment
try {
const commitment = Kzg . Commitment ( blob );
} catch ( e ) {
console . error ( e ); // "Not implemented: requires c-kzg-4844 library"
}
// Use native builds for KZG operations
Operation Costs
Approximate timing (single-threaded):
Operation Time Notes Commitment ~10ms FFT + MSM Proof ~10ms Similar to commitment Verify ~5ms Pairing check Batch Verify (6) ~15ms Single pairing
Optimization
import { Kzg } from 'tevm' ;
// Individual verification (slower)
console . time ( 'individual' );
for ( const [ blob , commitment , proof ] of items ) {
Kzg . verify ( blob , commitment , proof );
}
console . timeEnd ( 'individual' ); // ~30ms
// Batch verification (faster)
console . time ( 'batch' );
Kzg . verifyBatch ( blobs , commitments , proofs );
console . timeEnd ( 'batch' ); // ~15ms
Resources
See Also