eth2.0-specs/specs/eip4844/polynomial-commitments.md

4.6 KiB

EIP-4844 -- Polynomial Commitments

Table of contents

Introduction

This document specifies basic polynomial operations and KZG polynomial commitment operations as they are needed for the EIP-4844 specification. The implementations are not optimized for performance, but readability. All practical implementations should optimize the polynomial operations.

Custom types

Name SSZ equivalent Description
BLSFieldElement uint256 x < BLS_MODULUS
KZGCommitment Bytes48 Same as BLS standard "is valid pubkey" check but also allows 0x00..00 for point-at-infinity
KZGProof Bytes48 Same as for KZGCommitment

Constants

Name Value Notes
BLS_MODULUS 52435875175126190479447740508185965837690552500527637822603658699938581184513 Scalar field modulus of BLS12-381
ROOTS_OF_UNITY Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB] Roots of unity of order FIELD_ELEMENTS_PER_BLOB over the BLS12-381 field

Preset

Trusted setup

The trusted setup is part of the preset: during testing a minimal insecure variant may be used, but reusing the mainnet settings in public networks is a critical security requirement.

Name Value
KZG_SETUP_G2 Vector[G2Point, FIELD_ELEMENTS_PER_BLOB], contents TBD
KZG_SETUP_LAGRANGE Vector[KZGCommitment, FIELD_ELEMENTS_PER_BLOB], contents TBD

Helper functions

BLS12-381 helpers

bls_modular_inverse

def bls_modular_inverse(x: BLSFieldElement) -> BLSFieldElement:
    """
    Compute the modular inverse of x
    i.e. return y such that x * y % BLS_MODULUS == 1 and return 0 for x == 0
    """
    return pow(x, -1, BLS_MODULUS) if x != 0 else 0

div

def div(x: BLSFieldElement, y: BLSFieldElement) -> BLSFieldElement:
    """Divide two field elements: `x` by `y`"""
    return x * bls_modular_inverse(y) % BLS_MODULUS

lincomb

def lincomb(points: List[KZGCommitment], scalars: List[BLSFieldElement]) -> KZGCommitment:
    """
    BLS multiscalar multiplication. This function can be optimized using Pippenger's algorithm and variants.
    """
    r = bls.Z1
    for x, a in zip(points, scalars):
        r = bls.add(r, bls.multiply(x, a))
    return r

KZG

KZG core functions. These are also defined in EIP-4844 execution specs.

blob_to_kzg

def blob_to_kzg(blob: Blob) -> KZGCommitment:
    return lincomb(KZG_SETUP_LAGRANGE, blob)

verify_kzg_proof

def verify_kzg_proof(polynomial_kzg: KZGCommitment,
                     x: BLSFieldElement,
                     y: BLSFieldElement,
                     quotient_kzg: KZGProof) -> bool:
    """
    Verify KZG proof that ``p(x) == y`` where ``p(x)`` is the polynomial represented by ``polynomial_kzg``.
    """
    # Verify: P - y = Q * (X - x)
    X_minus_x = bls.add(KZG_SETUP_G2[1], bls.multiply(bls.G2, BLS_MODULUS - x))
    P_minus_y = bls.add(polynomial_kzg, bls.multiply(bls.G1, BLS_MODULUS - y))
    return bls.pairing_check([
        [P_minus_y, bls.neg(bls.G2)],
        [quotient_kzg, X_minus_x]
    ])

Polynomials

evaluate_polynomial_in_evaluation_form

def evaluate_polynomial_in_evaluation_form(poly: List[BLSFieldElement], x: BLSFieldElement) -> BLSFieldElement:
    """
    Evaluate a polynomial (in evaluation form) at an arbitrary point `x`
    Uses the barycentric formula:
       f(x) = (1 - x**WIDTH) / WIDTH  *  sum_(i=0)^WIDTH  (f(DOMAIN[i]) * DOMAIN[i]) / (x - DOMAIN[i])
    """
    width = len(poly)
    assert width == FIELD_ELEMENTS_PER_BLOB
    inverse_width = bls_modular_inverse(width)

    for i in range(width):
        r += div(poly[i] * ROOTS_OF_UNITY[i], (x - ROOTS_OF_UNITY[i]))
    r = r * (pow(x, width, BLS_MODULUS) - 1) * inverse_width % BLS_MODULUS

    return r