2023-02-07 23:22:28 +00:00
# Deneb -- Polynomial Commitments
2022-06-22 12:13:41 +00:00
## Table of contents
<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE - RUN doctoc TO UPDATE -->
- [Introduction ](#introduction )
- [Custom types ](#custom-types )
- [Constants ](#constants )
- [Preset ](#preset )
2022-11-03 15:01:32 +00:00
- [Blob ](#blob )
- [Crypto ](#crypto )
2022-06-22 12:13:41 +00:00
- [Trusted setup ](#trusted-setup )
- [Helper functions ](#helper-functions )
2022-09-26 13:39:16 +00:00
- [Bit-reversal permutation ](#bit-reversal-permutation )
- [`is_power_of_two` ](#is_power_of_two )
- [`reverse_bits` ](#reverse_bits )
- [`bit_reversal_permutation` ](#bit_reversal_permutation )
2022-06-22 12:13:41 +00:00
- [BLS12-381 helpers ](#bls12-381-helpers )
2022-12-01 12:59:00 +00:00
- [`hash_to_bls_field` ](#hash_to_bls_field )
2022-09-26 15:57:00 +00:00
- [`bytes_to_bls_field` ](#bytes_to_bls_field )
2023-01-25 15:15:19 +00:00
- [`validate_kzg_g1` ](#validate_kzg_g1 )
- [`bytes_to_kzg_commitment` ](#bytes_to_kzg_commitment )
- [`bytes_to_kzg_proof` ](#bytes_to_kzg_proof )
2022-11-03 15:01:32 +00:00
- [`blob_to_polynomial` ](#blob_to_polynomial )
2023-01-29 13:05:02 +00:00
- [`compute_challenge` ](#compute_challenge )
2022-06-22 12:13:41 +00:00
- [`bls_modular_inverse` ](#bls_modular_inverse )
- [`div` ](#div )
2022-09-19 19:16:19 +00:00
- [`g1_lincomb` ](#g1_lincomb )
2022-11-03 15:01:32 +00:00
- [`compute_powers` ](#compute_powers )
- [Polynomials ](#polynomials )
- [`evaluate_polynomial_in_evaluation_form` ](#evaluate_polynomial_in_evaluation_form )
2022-06-22 12:13:41 +00:00
- [KZG ](#kzg )
2022-07-13 10:13:30 +00:00
- [`blob_to_kzg_commitment` ](#blob_to_kzg_commitment )
2022-06-22 12:13:41 +00:00
- [`verify_kzg_proof` ](#verify_kzg_proof )
2022-11-09 12:01:47 +00:00
- [`verify_kzg_proof_impl` ](#verify_kzg_proof_impl )
2023-02-14 21:21:46 +00:00
- [`verify_kzg_proof_batch` ](#verify_kzg_proof_batch )
2022-07-13 10:13:30 +00:00
- [`compute_kzg_proof` ](#compute_kzg_proof )
2023-02-15 18:23:04 +00:00
- [`compute_quotient_eval_within_domain` ](#compute_quotient_eval_within_domain )
2023-01-24 13:02:22 +00:00
- [`compute_kzg_proof_impl` ](#compute_kzg_proof_impl )
2023-01-29 13:05:02 +00:00
- [`compute_blob_kzg_proof` ](#compute_blob_kzg_proof )
- [`verify_blob_kzg_proof` ](#verify_blob_kzg_proof )
2023-02-14 21:21:46 +00:00
- [`verify_blob_kzg_proof_batch` ](#verify_blob_kzg_proof_batch )
2022-06-22 12:13:41 +00:00
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Introduction
2023-02-07 23:22:28 +00:00
This document specifies basic polynomial operations and KZG polynomial commitment operations as they are needed for the Deneb specification. The implementations are not optimized for performance, but readability. All practical implementations should optimize the polynomial operations.
2022-06-22 12:13:41 +00:00
2022-11-09 12:02:56 +00:00
Functions flagged as "Public method" MUST be provided by the underlying KZG library as public functions. All other functions are private functions used internally by the KZG library.
2023-01-25 15:15:19 +00:00
Public functions MUST accept raw bytes as input and perform the required cryptographic normalization before invoking any internal functions.
2022-06-22 12:13:41 +00:00
## Custom types
| Name | SSZ equivalent | Description |
| - | - | - |
2022-07-13 10:12:31 +00:00
| `G1Point` | `Bytes48` | |
| `G2Point` | `Bytes96` | |
2023-01-25 15:15:19 +00:00
| `BLSFieldElement` | `uint256` | Validation: `x < BLS_MODULUS` |
| `KZGCommitment` | `Bytes48` | Validation: Perform [BLS standard's ](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-04#section-2.5 ) "KeyValidate" check but do allow the identity point |
2022-06-22 12:13:41 +00:00
| `KZGProof` | `Bytes48` | Same as for `KZGCommitment` |
2023-01-24 14:14:25 +00:00
| `Polynomial` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | A polynomial in evaluation form |
2023-03-15 15:25:09 +00:00
| `Blob` | `ByteVector[BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB]` | A basic data blob |
2022-06-22 12:13:41 +00:00
## Constants
| Name | Value | Notes |
| - | - | - |
| `BLS_MODULUS` | `52435875175126190479447740508185965837690552500527637822603658699938581184513` | Scalar field modulus of BLS12-381 |
2023-03-07 21:56:55 +00:00
| `BYTES_PER_COMMITMENT` | `uint64(48)` | The number of bytes in a KZG commitment |
| `BYTES_PER_PROOF` | `uint64(48)` | The number of bytes in a KZG proof |
2022-11-03 15:01:32 +00:00
| `BYTES_PER_FIELD_ELEMENT` | `uint64(32)` | Bytes used to encode a BLS scalar field element |
2023-03-07 21:56:55 +00:00
| `BYTES_PER_BLOB` | `uint64(BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB)` | The number of bytes in a blob |
2023-01-25 15:15:19 +00:00
| `G1_POINT_AT_INFINITY` | `Bytes48(b'\xc0' + b'\x00' * 47)` | Serialized form of the point at infinity on the G1 group |
2022-06-22 12:13:41 +00:00
## Preset
2022-11-03 15:01:32 +00:00
### Blob
| Name | Value |
| - | - |
| `FIELD_ELEMENTS_PER_BLOB` | `uint64(4096)` |
| `FIAT_SHAMIR_PROTOCOL_DOMAIN` | `b'FSBLOBVERIFY_V1_'` |
2023-02-14 21:21:46 +00:00
| `RANDOM_CHALLENGE_KZG_BATCH_DOMAIN` | `b'RCKZGBATCH___V1_'` |
2022-11-03 15:01:32 +00:00
### Crypto
| Name | Value | Notes |
| - | - | - |
| `ROOTS_OF_UNITY` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | Roots of unity of order FIELD_ELEMENTS_PER_BLOB over the BLS12-381 field |
2022-06-22 12:13:41 +00:00
### 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 |
| - | - |
2022-12-13 10:13:22 +00:00
| `KZG_SETUP_G2_LENGTH` | `65` |
2022-07-13 10:12:31 +00:00
| `KZG_SETUP_G1` | `Vector[G1Point, FIELD_ELEMENTS_PER_BLOB]` , contents TBD |
2022-12-13 10:13:22 +00:00
| `KZG_SETUP_G2` | `Vector[G2Point, KZG_SETUP_G2_LENGTH]` , contents TBD |
2023-03-11 15:44:42 +00:00
| `KZG_SETUP_LAGRANGE` | `Vector[G1Point, FIELD_ELEMENTS_PER_BLOB]` , contents TBD |
2022-06-22 12:13:41 +00:00
## Helper functions
2022-09-26 13:39:16 +00:00
### Bit-reversal permutation
All polynomials (which are always given in Lagrange form) should be interpreted as being in
bit-reversal permutation. In practice, clients can implement this by storing the lists
`KZG_SETUP_LAGRANGE` and `ROOTS_OF_UNITY` in bit-reversal permutation, so these functions only
have to be called once at startup.
#### `is_power_of_two`
```python
def is_power_of_two(value: int) -> bool:
"""
Check if ``value`` is a power of two integer.
"""
return (value > 0) and (value & (value - 1) == 0)
```
#### `reverse_bits`
```python
def reverse_bits(n: int, order: int) -> int:
"""
2022-11-03 15:01:32 +00:00
Reverse the bit order of an integer ``n``.
2022-09-26 13:39:16 +00:00
"""
assert is_power_of_two(order)
# Convert n to binary with the same number of bits as "order" - 1, then reverse its bit order
return int(('{:0' + str(order.bit_length() - 1) + 'b}').format(n)[::-1], 2)
```
#### `bit_reversal_permutation`
```python
2022-09-28 04:22:53 +00:00
def bit_reversal_permutation(sequence: Sequence[T]) -> Sequence[T]:
2022-09-26 13:39:16 +00:00
"""
2022-09-27 11:13:56 +00:00
Return a copy with bit-reversed permutation. The permutation is an involution (inverts itself).
2022-09-26 13:39:16 +00:00
The input and output are a sequence of generic type ``T`` objects.
"""
2022-09-28 04:22:53 +00:00
return [sequence[reverse_bits(i, len(sequence))] for i in range(len(sequence))]
2022-09-26 13:39:16 +00:00
```
2022-06-22 12:13:41 +00:00
### BLS12-381 helpers
2022-12-01 12:59:00 +00:00
#### `hash_to_bls_field`
```python
def hash_to_bls_field(data: bytes) -> BLSFieldElement:
"""
Hash ``data`` and convert the output to a BLS scalar field element.
The output is not uniform over the BLS field.
"""
hashed_data = hash(data)
return BLSFieldElement(int.from_bytes(hashed_data, ENDIANNESS) % BLS_MODULUS)
```
2022-09-26 15:57:00 +00:00
#### `bytes_to_bls_field`
```python
def bytes_to_bls_field(b: Bytes32) -> BLSFieldElement:
"""
2023-01-25 15:15:19 +00:00
Convert untrusted bytes to a trusted and validated BLS scalar field element.
2022-12-01 12:59:00 +00:00
This function does not accept inputs greater than the BLS modulus.
2022-11-03 15:01:32 +00:00
"""
2022-12-01 12:59:00 +00:00
field_element = int.from_bytes(b, ENDIANNESS)
assert field_element < BLS_MODULUS
return BLSFieldElement(field_element)
2022-11-03 15:01:32 +00:00
```
2023-01-25 15:15:19 +00:00
#### `validate_kzg_g1`
```python
def validate_kzg_g1(b: Bytes48) -> None:
"""
Perform BLS validation required by the types `KZGProof` and `KZGCommitment` .
"""
if b == G1_POINT_AT_INFINITY:
return
assert bls.KeyValidate(b)
```
#### `bytes_to_kzg_commitment`
```python
def bytes_to_kzg_commitment(b: Bytes48) -> KZGCommitment:
"""
Convert untrusted bytes into a trusted and validated KZGCommitment.
"""
validate_kzg_g1(b)
return KZGCommitment(b)
```
#### `bytes_to_kzg_proof`
```python
def bytes_to_kzg_proof(b: Bytes48) -> KZGProof:
"""
Convert untrusted bytes into a trusted and validated KZGProof.
"""
validate_kzg_g1(b)
return KZGProof(b)
```
2022-11-03 15:01:32 +00:00
#### `blob_to_polynomial`
```python
def blob_to_polynomial(blob: Blob) -> Polynomial:
"""
Convert a blob to list of BLS field scalars.
"""
polynomial = Polynomial()
for i in range(FIELD_ELEMENTS_PER_BLOB):
2022-12-01 12:59:00 +00:00
value = bytes_to_bls_field(blob[i * BYTES_PER_FIELD_ELEMENT: (i + 1) * BYTES_PER_FIELD_ELEMENT])
2022-11-03 15:01:32 +00:00
polynomial[i] = value
return polynomial
```
2023-01-29 13:05:02 +00:00
#### `compute_challenge`
2022-11-03 15:01:32 +00:00
```python
2023-02-13 14:57:04 +00:00
def compute_challenge(blob: Blob,
2023-01-29 13:05:02 +00:00
commitment: KZGCommitment) -> BLSFieldElement:
2022-11-03 15:01:32 +00:00
"""
2023-02-14 21:10:09 +00:00
Return the Fiat-Shamir challenge required by the rest of the protocol.
2022-09-26 15:57:00 +00:00
"""
2023-01-29 13:05:02 +00:00
2023-02-15 19:48:58 +00:00
# Append the degree of the polynomial as a domain separator
degree_poly = int.to_bytes(FIELD_ELEMENTS_PER_BLOB, 16, ENDIANNESS)
data = FIAT_SHAMIR_PROTOCOL_DOMAIN + degree_poly
2022-11-03 15:01:32 +00:00
2023-02-13 14:57:04 +00:00
data += blob
2023-01-29 13:05:02 +00:00
data += commitment
2022-11-03 15:01:32 +00:00
2023-02-15 19:48:58 +00:00
# Transcript has been prepared: time to create the challenge
2023-02-14 20:17:25 +00:00
return hash_to_bls_field(data)
2022-09-26 15:57:00 +00:00
```
2022-06-22 12:13:41 +00:00
#### `bls_modular_inverse`
```python
def bls_modular_inverse(x: BLSFieldElement) -> BLSFieldElement:
"""
2023-03-16 13:49:40 +00:00
Compute the modular inverse of x (for x != 0)
i.e. return y such that x * y % BLS_MODULUS == 1
2022-06-22 12:13:41 +00:00
"""
2023-03-16 13:49:40 +00:00
assert (int(x) % BLS_MODULUS) != 0
return BLSFieldElement(pow(x, -1, BLS_MODULUS))
2022-06-22 12:13:41 +00:00
```
#### `div`
```python
2022-06-23 10:40:09 +00:00
def div(x: BLSFieldElement, y: BLSFieldElement) -> BLSFieldElement:
2022-11-03 15:01:32 +00:00
"""
Divide two field elements: ``x`` by `y` `.
"""
2022-11-28 12:16:18 +00:00
return BLSFieldElement((int(x) * int(bls_modular_inverse(y))) % BLS_MODULUS)
2022-06-22 12:13:41 +00:00
```
2022-09-19 19:16:19 +00:00
#### `g1_lincomb`
2022-06-22 12:13:41 +00:00
```python
2022-09-19 19:16:19 +00:00
def g1_lincomb(points: Sequence[KZGCommitment], scalars: Sequence[BLSFieldElement]) -> KZGCommitment:
2022-06-22 12:13:41 +00:00
"""
BLS multiscalar multiplication. This function can be optimized using Pippenger's algorithm and variants.
"""
2022-07-13 10:12:31 +00:00
assert len(points) == len(scalars)
2023-03-02 20:49:10 +00:00
result = bls.Z1()
2022-06-22 12:13:41 +00:00
for x, a in zip(points, scalars):
2022-07-13 10:12:31 +00:00
result = bls.add(result, bls.multiply(bls.bytes48_to_G1(x), a))
return KZGCommitment(bls.G1_to_bytes48(result))
```
2022-11-03 15:01:32 +00:00
#### `compute_powers`
```python
def compute_powers(x: BLSFieldElement, n: uint64) -> Sequence[BLSFieldElement]:
"""
2022-11-24 13:11:46 +00:00
Return ``x`` to power of [0, n-1], if n > 0. When n==0, an empty array is returned.
2022-11-03 15:01:32 +00:00
"""
current_power = 1
powers = []
for _ in range(n):
powers.append(BLSFieldElement(current_power))
current_power = current_power * int(x) % BLS_MODULUS
return powers
```
2022-11-23 14:52:47 +00:00
2022-11-03 15:01:32 +00:00
### Polynomials
#### `evaluate_polynomial_in_evaluation_form`
```python
def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial,
z: BLSFieldElement) -> BLSFieldElement:
"""
2023-03-04 19:20:01 +00:00
Evaluate a polynomial (in evaluation form) at an arbitrary point ``z``.
- When ``z`` is in the domain, the evaluation can be found by indexing the polynomial at the
position that ``z`` is in the domain.
- When ``z`` is not in the domain, the barycentric formula is used:
2022-11-03 15:01:32 +00:00
f(z) = (z**WIDTH - 1) / WIDTH * sum_(i=0)^WIDTH (f(DOMAIN[i]) * DOMAIN[i]) / (z - DOMAIN[i])
"""
width = len(polynomial)
assert width == FIELD_ELEMENTS_PER_BLOB
2022-11-28 12:16:18 +00:00
inverse_width = bls_modular_inverse(BLSFieldElement(width))
2022-11-03 15:01:32 +00:00
roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY)
2023-01-16 13:57:35 +00:00
# If we are asked to evaluate within the domain, we already know the answer
if z in roots_of_unity_brp:
eval_index = roots_of_unity_brp.index(z)
return BLSFieldElement(polynomial[eval_index])
2022-11-03 15:01:32 +00:00
result = 0
for i in range(width):
2022-11-28 12:16:18 +00:00
a = BLSFieldElement(int(polynomial[i]) * int(roots_of_unity_brp[i]) % BLS_MODULUS)
b = BLSFieldElement((int(BLS_MODULUS) + int(z) - int(roots_of_unity_brp[i])) % BLS_MODULUS)
result += int(div(a, b) % BLS_MODULUS)
2023-03-02 20:49:10 +00:00
result = result * int(BLS_MODULUS + pow(z, width, BLS_MODULUS) - 1) * int(inverse_width)
2022-11-28 12:16:18 +00:00
return BLSFieldElement(result % BLS_MODULUS)
2022-11-03 15:01:32 +00:00
```
2022-06-22 12:13:41 +00:00
### KZG
2023-02-07 23:22:28 +00:00
KZG core functions. These are also defined in Deneb execution specs.
2022-06-22 12:13:41 +00:00
2022-07-13 10:12:31 +00:00
#### `blob_to_kzg_commitment`
2022-06-22 12:13:41 +00:00
```python
2022-07-13 10:12:31 +00:00
def blob_to_kzg_commitment(blob: Blob) -> KZGCommitment:
2022-11-09 12:02:56 +00:00
"""
Public method.
"""
2023-03-07 21:56:55 +00:00
assert len(blob) == BYTES_PER_BLOB
2022-11-03 15:01:32 +00:00
return g1_lincomb(bit_reversal_permutation(KZG_SETUP_LAGRANGE), blob_to_polynomial(blob))
2022-06-22 12:13:41 +00:00
```
#### `verify_kzg_proof`
```python
2023-01-25 15:15:19 +00:00
def verify_kzg_proof(commitment_bytes: Bytes48,
2023-03-07 21:56:55 +00:00
z_bytes: Bytes32,
y_bytes: Bytes32,
2023-01-25 15:15:19 +00:00
proof_bytes: Bytes48) -> bool:
2022-06-23 10:40:09 +00:00
"""
2022-07-13 10:12:31 +00:00
Verify KZG proof that ``p(z) == y`` where ``p(z)`` is the polynomial represented by ``polynomial_kzg``.
2022-11-09 12:01:47 +00:00
Receives inputs as bytes.
Public method.
"""
2023-03-07 21:56:55 +00:00
assert len(commitment_bytes) == BYTES_PER_COMMITMENT
assert len(z_bytes) == BYTES_PER_FIELD_ELEMENT
assert len(y_bytes) == BYTES_PER_FIELD_ELEMENT
assert len(proof_bytes) == BYTES_PER_PROOF
2023-01-25 15:15:19 +00:00
return verify_kzg_proof_impl(bytes_to_kzg_commitment(commitment_bytes),
2023-03-07 21:56:55 +00:00
bytes_to_bls_field(z_bytes),
bytes_to_bls_field(y_bytes),
2023-01-25 15:15:19 +00:00
bytes_to_kzg_proof(proof_bytes))
2022-11-09 12:01:47 +00:00
```
#### `verify_kzg_proof_impl`
```python
2023-01-25 15:15:19 +00:00
def verify_kzg_proof_impl(commitment: KZGCommitment,
2022-11-09 12:01:47 +00:00
z: BLSFieldElement,
y: BLSFieldElement,
2023-01-25 15:15:19 +00:00
proof: KZGProof) -> bool:
2022-11-09 12:01:47 +00:00
"""
Verify KZG proof that ``p(z) == y`` where ``p(z)`` is the polynomial represented by ``polynomial_kzg``.
2022-06-23 10:40:09 +00:00
"""
2022-07-13 10:12:31 +00:00
# Verify: P - y = Q * (X - z)
2023-03-02 20:49:10 +00:00
X_minus_z = bls.add(bls.bytes96_to_G2(KZG_SETUP_G2[1]), bls.multiply(bls.G2(), (BLS_MODULUS - z) % BLS_MODULUS))
P_minus_y = bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1(), (BLS_MODULUS - y) % BLS_MODULUS))
2022-06-22 12:13:41 +00:00
return bls.pairing_check([
2023-03-02 20:49:10 +00:00
[P_minus_y, bls.neg(bls.G2())],
2023-01-25 15:15:19 +00:00
[bls.bytes48_to_G1(proof), X_minus_z]
2022-06-22 12:13:41 +00:00
])
```
2023-02-14 21:21:46 +00:00
#### `verify_kzg_proof_batch`
2023-01-27 14:23:38 +00:00
```python
2023-02-14 21:21:46 +00:00
def verify_kzg_proof_batch(commitments: Sequence[KZGCommitment],
2023-01-27 14:23:38 +00:00
zs: Sequence[BLSFieldElement],
ys: Sequence[BLSFieldElement],
proofs: Sequence[KZGProof]) -> bool:
"""
Verify multiple KZG proofs efficiently.
"""
assert len(commitments) == len(zs) == len(ys) == len(proofs)
# Compute a random challenge. Note that it does not have to be computed from a hash,
# r just has to be random.
degree_poly = int.to_bytes(FIELD_ELEMENTS_PER_BLOB, 8, ENDIANNESS)
num_commitments = int.to_bytes(len(commitments), 8, ENDIANNESS)
2023-02-14 21:21:46 +00:00
data = RANDOM_CHALLENGE_KZG_BATCH_DOMAIN + degree_poly + num_commitments
2023-01-27 14:23:38 +00:00
2023-02-14 20:00:58 +00:00
# Append all inputs to the transcript before we hash
2023-01-27 14:23:38 +00:00
for commitment, z, y, proof in zip(commitments, zs, ys, proofs):
data += commitment \
+ int.to_bytes(z, BYTES_PER_FIELD_ELEMENT, ENDIANNESS) \
+ int.to_bytes(y, BYTES_PER_FIELD_ELEMENT, ENDIANNESS) \
+ proof
2023-02-14 20:17:25 +00:00
r = hash_to_bls_field(data)
2023-01-27 14:23:38 +00:00
r_powers = compute_powers(r, len(commitments))
# Verify: e(sum r^i proof_i, [s]) ==
# e(sum r^i (commitment_i - [y_i]) + sum r^i z_i proof_i, [1])
proof_lincomb = g1_lincomb(proofs, r_powers)
2023-02-16 14:09:57 +00:00
proof_z_lincomb = g1_lincomb(
proofs,
[BLSFieldElement((int(z) * int(r_power)) % BLS_MODULUS) for z, r_power in zip(zs, r_powers)],
)
2023-03-02 20:49:10 +00:00
C_minus_ys = [bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1(), (BLS_MODULUS - y) % BLS_MODULUS))
2023-01-27 14:23:38 +00:00
for commitment, y in zip(commitments, ys)]
2023-02-14 20:59:24 +00:00
C_minus_y_as_KZGCommitments = [KZGCommitment(bls.G1_to_bytes48(x)) for x in C_minus_ys]
2023-01-27 14:23:38 +00:00
C_minus_y_lincomb = g1_lincomb(C_minus_y_as_KZGCommitments, r_powers)
return bls.pairing_check([
2023-02-16 14:09:57 +00:00
[bls.bytes48_to_G1(proof_lincomb), bls.neg(bls.bytes96_to_G2(KZG_SETUP_G2[1]))],
2023-03-02 20:49:10 +00:00
[bls.add(bls.bytes48_to_G1(C_minus_y_lincomb), bls.bytes48_to_G1(proof_z_lincomb)), bls.G2()]
2023-01-27 14:23:38 +00:00
])
```
2022-07-13 10:12:31 +00:00
#### `compute_kzg_proof`
```python
2023-03-07 21:56:55 +00:00
def compute_kzg_proof(blob: Blob, z_bytes: Bytes32) -> Tuple[KZGProof, Bytes32]:
2022-09-26 13:39:16 +00:00
"""
2023-01-24 13:02:22 +00:00
Compute KZG proof at point `z` for the polynomial represented by `blob` .
2022-12-17 17:14:48 +00:00
Do this by computing the quotient polynomial in evaluation form: q(x) = (p(x) - p(z)) / (x - z).
Public method.
2022-09-26 13:39:16 +00:00
"""
2023-03-07 21:56:55 +00:00
assert len(blob) == BYTES_PER_BLOB
assert len(z_bytes) == BYTES_PER_FIELD_ELEMENT
2023-01-24 13:02:22 +00:00
polynomial = blob_to_polynomial(blob)
2023-03-07 21:56:55 +00:00
proof, y = compute_kzg_proof_impl(polynomial, bytes_to_bls_field(z_bytes))
2023-03-07 17:50:56 +00:00
return proof, y.to_bytes(BYTES_PER_FIELD_ELEMENT, ENDIANNESS)
2023-01-24 13:02:22 +00:00
```
2023-02-14 12:50:44 +00:00
#### `compute_quotient_eval_within_domain`
```python
def compute_quotient_eval_within_domain(z: BLSFieldElement,
polynomial: Polynomial,
y: BLSFieldElement
) -> BLSFieldElement:
"""
Given `y == p(z)` for a polynomial `p(x)` , compute `q(z)` : the KZG quotient polynomial evaluated at `z` for the
special case where `z` is in `ROOTS_OF_UNITY` .
For more details, read https://dankradfeist.de/ethereum/2021/06/18/pcs-multiproofs.html section "Dividing
when one of the points is zero". The code below computes q(x_m) for the roots of unity special case.
"""
roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY)
result = 0
for i, omega_i in enumerate(roots_of_unity_brp):
if omega_i == z: # skip the evaluation point in the sum
continue
f_i = int(BLS_MODULUS) + int(polynomial[i]) - int(y) % BLS_MODULUS
numerator = f_i * int(omega_i) % BLS_MODULUS
denominator = int(z) * (int(BLS_MODULUS) + int(z) - int(omega_i)) % BLS_MODULUS
2023-02-16 17:22:11 +00:00
result += int(div(BLSFieldElement(numerator), BLSFieldElement(denominator)))
2023-02-14 12:50:44 +00:00
return BLSFieldElement(result % BLS_MODULUS)
```
2023-01-24 13:02:22 +00:00
#### `compute_kzg_proof_impl`
```python
2023-03-07 17:50:56 +00:00
def compute_kzg_proof_impl(polynomial: Polynomial, z: BLSFieldElement) -> Tuple[KZGProof, BLSFieldElement]:
2023-01-24 13:02:22 +00:00
"""
2023-02-20 10:54:16 +00:00
Helper function for `compute_kzg_proof()` and `compute_blob_kzg_proof()` .
2023-01-24 13:02:22 +00:00
"""
2023-02-14 12:50:44 +00:00
roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY)
# For all x_i, compute p(x_i) - p(z)
2022-07-13 10:12:31 +00:00
y = evaluate_polynomial_in_evaluation_form(polynomial, z)
2022-11-28 12:16:18 +00:00
polynomial_shifted = [BLSFieldElement((int(p) - int(y)) % BLS_MODULUS) for p in polynomial]
2022-07-13 10:12:31 +00:00
2023-02-14 12:50:44 +00:00
# For all x_i, compute (x_i - z)
2022-11-28 12:16:18 +00:00
denominator_poly = [BLSFieldElement((int(x) - int(z)) % BLS_MODULUS)
2023-02-20 10:57:39 +00:00
for x in roots_of_unity_brp]
2022-07-13 10:12:31 +00:00
2023-02-14 12:50:44 +00:00
# Compute the quotient polynomial directly in evaluation form
quotient_polynomial = [BLSFieldElement(0)] * FIELD_ELEMENTS_PER_BLOB
for i, (a, b) in enumerate(zip(polynomial_shifted, denominator_poly)):
if b == 0:
# The denominator is zero hence `z` is a root of unity: we must handle it as a special case
quotient_polynomial[i] = compute_quotient_eval_within_domain(roots_of_unity_brp[i], polynomial, y)
else:
# Compute: q(x_i) = (p(x_i) - p(z)) / (x_i - z).
quotient_polynomial[i] = div(a, b)
2023-03-07 17:50:56 +00:00
return KZGProof(g1_lincomb(bit_reversal_permutation(KZG_SETUP_LAGRANGE), quotient_polynomial)), y
2022-07-13 10:12:31 +00:00
```
2023-01-29 13:05:02 +00:00
#### `compute_blob_kzg_proof`
2022-06-22 12:13:41 +00:00
```python
2023-03-07 17:50:56 +00:00
def compute_blob_kzg_proof(blob: Blob, commitment_bytes: Bytes48) -> KZGProof:
2022-06-22 12:13:41 +00:00
"""
2023-01-29 13:05:02 +00:00
Given a blob, return the KZG proof that is used to verify it against the commitment.
2023-03-07 17:50:56 +00:00
This method does not verify that the commitment is correct with respect to `blob` .
2022-11-09 12:02:56 +00:00
Public method.
"""
2023-03-07 21:56:55 +00:00
assert len(blob) == BYTES_PER_BLOB
assert len(commitment_bytes) == BYTES_PER_COMMITMENT
2023-03-07 17:50:56 +00:00
commitment = bytes_to_kzg_commitment(commitment_bytes)
2023-01-29 13:05:02 +00:00
polynomial = blob_to_polynomial(blob)
2023-02-13 14:57:04 +00:00
evaluation_challenge = compute_challenge(blob, commitment)
2023-03-07 17:50:56 +00:00
proof, _ = compute_kzg_proof_impl(polynomial, evaluation_challenge)
return proof
2022-06-22 12:13:41 +00:00
```
2022-07-13 10:12:31 +00:00
2023-01-29 13:05:02 +00:00
#### `verify_blob_kzg_proof`
2022-11-03 15:01:32 +00:00
```python
2023-01-29 13:05:02 +00:00
def verify_blob_kzg_proof(blob: Blob,
commitment_bytes: Bytes48,
proof_bytes: Bytes48) -> bool:
2022-11-09 12:02:56 +00:00
"""
2023-01-29 13:05:02 +00:00
Given a blob and a KZG proof, verify that the blob data corresponds to the provided commitment.
2022-12-01 12:59:00 +00:00
2022-11-09 12:02:56 +00:00
Public method.
"""
2023-03-07 21:56:55 +00:00
assert len(blob) == BYTES_PER_BLOB
assert len(commitment_bytes) == BYTES_PER_COMMITMENT
assert len(proof_bytes) == BYTES_PER_PROOF
2023-01-29 13:05:02 +00:00
commitment = bytes_to_kzg_commitment(commitment_bytes)
2023-01-27 14:23:38 +00:00
2023-01-29 13:05:02 +00:00
polynomial = blob_to_polynomial(blob)
2023-02-13 14:57:04 +00:00
evaluation_challenge = compute_challenge(blob, commitment)
2023-01-27 14:23:38 +00:00
2023-02-14 20:59:41 +00:00
# Evaluate polynomial at `evaluation_challenge`
2023-01-29 13:05:02 +00:00
y = evaluate_polynomial_in_evaluation_form(polynomial, evaluation_challenge)
2023-01-27 14:23:38 +00:00
2023-01-29 13:05:02 +00:00
# Verify proof
proof = bytes_to_kzg_proof(proof_bytes)
return verify_kzg_proof_impl(commitment, evaluation_challenge, y, proof)
2022-11-03 15:01:32 +00:00
```
2023-01-27 14:23:38 +00:00
2023-02-14 21:21:46 +00:00
#### `verify_blob_kzg_proof_batch`
2023-01-27 14:23:38 +00:00
```python
2023-02-14 21:21:46 +00:00
def verify_blob_kzg_proof_batch(blobs: Sequence[Blob],
2023-01-29 13:05:02 +00:00
commitments_bytes: Sequence[Bytes48],
proofs_bytes: Sequence[Bytes48]) -> bool:
2023-01-27 14:23:38 +00:00
"""
2023-01-29 13:05:02 +00:00
Given a list of blobs and blob KZG proofs, verify that they correspond to the provided commitments.
2023-01-27 14:23:38 +00:00
Public method.
"""
2023-02-14 21:10:09 +00:00
assert len(blobs) == len(commitments_bytes) == len(proofs_bytes)
2023-01-27 14:23:38 +00:00
2023-01-29 13:05:02 +00:00
commitments, evaluation_challenges, ys, proofs = [], [], [], []
for blob, commitment_bytes, proof_bytes in zip(blobs, commitments_bytes, proofs_bytes):
2023-03-07 21:56:55 +00:00
assert len(blob) == BYTES_PER_BLOB
assert len(commitment_bytes) == BYTES_PER_COMMITMENT
assert len(proof_bytes) == BYTES_PER_PROOF
2023-01-29 13:05:02 +00:00
commitment = bytes_to_kzg_commitment(commitment_bytes)
commitments.append(commitment)
polynomial = blob_to_polynomial(blob)
2023-02-13 14:57:04 +00:00
evaluation_challenge = compute_challenge(blob, commitment)
2023-02-13 14:32:50 +00:00
evaluation_challenges.append(evaluation_challenge)
2023-01-29 13:05:02 +00:00
ys.append(evaluate_polynomial_in_evaluation_form(polynomial, evaluation_challenge))
proofs.append(bytes_to_kzg_proof(proof_bytes))
2023-01-27 14:23:38 +00:00
2023-02-14 21:21:46 +00:00
return verify_kzg_proof_batch(commitments, evaluation_challenges, ys, proofs)
2023-01-27 14:23:38 +00:00
```
2023-03-02 20:49:10 +00:00