Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EIP4844: Update cryptography API and Fiat-Shamir logic #3038

Merged
merged 35 commits into from
Nov 3, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
429e597
4844: Start moving cryptography functions to polynomial-commitments
asn-d6 Oct 14, 2022
22a4dcd
4844: hash_to_bls_field() doesn't use SSZ and does domain separation
asn-d6 Oct 14, 2022
b5959a1
4844: Refactor aggregation and move to polynomial-commitments
asn-d6 Oct 14, 2022
642f138
4844: Fix ToC
asn-d6 Oct 14, 2022
ff528a2
Merge branch 'dev' into pr3038
hwwhww Oct 15, 2022
91476fe
Fix linter error
hwwhww Oct 15, 2022
090dc7e
Blobs as flat ByteVector
dankrad Oct 20, 2022
30d19a3
Move is_data_available from validator to beacon_chain
dankrad Oct 21, 2022
0eb82cf
Set domain separators to empty string
dankrad Oct 21, 2022
7631c18
Add placeholder domain separators for two protocols; add old transcri…
dankrad Oct 21, 2022
fe7af4b
Remove duplicate hash in
dankrad Oct 22, 2022
46b6b24
Fix typo
dankrad Oct 22, 2022
889deff
Fix doctoc
dankrad Oct 22, 2022
83ca385
Fix typo
dankrad Oct 22, 2022
cbc170b
Fix tests
dankrad Oct 22, 2022
89d4ae0
Fix doctoc
dankrad Oct 22, 2022
b9dfdaf
Happy linter
dankrad Oct 22, 2022
033567b
Use Polynomial type consistently, vector_lincomb to poly_lincomb
dankrad Oct 22, 2022
e81d54c
Small fixes
dankrad Oct 22, 2022
463948e
Fix get_sample_blob
dankrad Oct 22, 2022
a33a423
Make `blob_to_field_elements` return `Polynomial` and fix tests
hwwhww Oct 23, 2022
31ad8a5
Rearrange presets
hwwhww Oct 24, 2022
0174521
Proofread
hwwhww Oct 24, 2022
dfcf33c
By kev: Removes domain separators as constants, Removes second call t…
dankrad Oct 27, 2022
d98c103
Add name for Fiat-Shamir protocol
dankrad Oct 30, 2022
80d4d09
Improve comments in polynomial-commitments.md
asn-d6 Nov 1, 2022
c8b8b53
Fix description of BLS_MODULUS
asn-d6 Nov 1, 2022
5354a96
blob_to_field_elements() -> blob_to_polynomial()
asn-d6 Nov 1, 2022
0e2e477
Use modular multiplication in compute_aggregated_poly_and_commitment
asn-d6 Nov 1, 2022
db619e2
Satisfy executable spec tests
asn-d6 Nov 1, 2022
cb46b11
Improve code that deals with the evaluation challenge
asn-d6 Nov 2, 2022
af48987
Minor spec improvements (after review by hww)
asn-d6 Nov 2, 2022
1c9a8db
Remove extra space
dankrad Nov 3, 2022
186a2eb
Move `BYTES_PER_FIELD_ELEMENT` from presets to constants
hwwhww Nov 3, 2022
c130995
Clarify BYTES_PER_FIELD_ELEMENT comment a bit more
asn-d6 Nov 3, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 104 additions & 1 deletion specs/eip4844/polynomial-commitments.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,19 @@
- [`bit_reversal_permutation`](#bit_reversal_permutation)
- [BLS12-381 helpers](#bls12-381-helpers)
- [`bytes_to_bls_field`](#bytes_to_bls_field)
- [`hash_to_bls_field`](#hash_to_bls_field)
- [`bls_modular_inverse`](#bls_modular_inverse)
- [`div`](#div)
- [`g1_lincomb`](#g1_lincomb)
- [`vector_lincomb`](#vector_lincomb)
- [`compute_powers`](#compute_powers)
- [KZG](#kzg)
- [`blob_to_kzg_commitment`](#blob_to_kzg_commitment)
- [`verify_kzg_proof`](#verify_kzg_proof)
- [`compute_kzg_proof`](#compute_kzg_proof)
- [`compute_aggregated_poly_and_commitment`](#compute_aggregated_poly_and_commitment)
- [`compute_aggregate_kzg_proof`](#compute_aggregate_kzg_proof)
- [`verify_aggregate_kzg_proof`](#verify_aggregate_kzg_proof)
- [Polynomials](#polynomials)
- [`evaluate_polynomial_in_evaluation_form`](#evaluate_polynomial_in_evaluation_form)

Expand All @@ -46,13 +51,18 @@ This document specifies basic polynomial operations and KZG polynomial commitmen
| `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` |
| `Polynomial` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | a polynomial in evaluation form |
asn-d6 marked this conversation as resolved.
Show resolved Hide resolved

## 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 |
| `DOMAIN_SEPARATOR_FIELD_ELEMENT` | `b"FIELD_ELEMENT"` | Fiat-Shamir domain separator for field elements |
asn-d6 marked this conversation as resolved.
Show resolved Hide resolved
| `DOMAIN_SEPARATOR_POINT` | `b"POINT"` | Fiat-Shamir domain separator for G1 points |
| `DOMAIN_SEPARATOR_SQUEEZE` | `b"SQUEEZE"` | Fiat-Shamir domain separator before hashing |


## Preset

Expand Down Expand Up @@ -122,6 +132,32 @@ def bytes_to_bls_field(b: Bytes32) -> BLSFieldElement:
return int.from_bytes(b, "little") % BLS_MODULUS
```

#### `hash_to_bls_field`

```python
def hash_to_bls_field(polys: Sequence[Polynomial], comms: Sequence[KZGCommitment]) -> BLSFieldElement:
"""
Compute 32-byte hash of serialised polynomials and commitments concatenated.
This hash is then converted to a BLS field element.
The output is not uniform over the BLS field.
"""
data = bytes()

# Append each polynomial which is composed by field elements
for poly in polys:
for field_element in poly:
data += DOMAIN_SEPARATOR_FIELD_ELEMENT
data += int.to_bytes(field_element, 32, ENDIANNESS)
hwwhww marked this conversation as resolved.
Show resolved Hide resolved

# Append serialised G1 points
hwwhww marked this conversation as resolved.
Show resolved Hide resolved
for commitment in comms:
data += DOMAIN_SEPARATOR_POINT
data += commitment

data += DOMAIN_SEPARATOR_SQUEEZE
return bytes_to_bls_field(hash(data))
```

#### `bls_modular_inverse`

```python
Expand Down Expand Up @@ -171,6 +207,21 @@ def vector_lincomb(vectors: Sequence[Sequence[BLSFieldElement]],
return [BLSFieldElement(x) for x in result]
```

#### `compute_powers`

```python
def compute_powers(x: BLSFieldElement, n: uint64) -> Sequence[BLSFieldElement]:
"""
Return ``x`` to power of [0, n-1].
"""
current_power = 1
powers = []
for _ in range(n):
powers.append(BLSFieldElement(current_power))
current_power = current_power * int(x) % BLS_MODULUS
return powers
```

### KZG

KZG core functions. These are also defined in EIP-4844 execution specs.
Expand Down Expand Up @@ -226,12 +277,64 @@ def compute_kzg_proof(polynomial: Sequence[BLSFieldElement], z: BLSFieldElement)
return KZGProof(g1_lincomb(bit_reversal_permutation(KZG_SETUP_LAGRANGE), quotient_polynomial))
```

#### `compute_aggregated_poly_and_commitment`

```python
def compute_aggregated_poly_and_commitment(
blobs: Sequence[Blob],
kzg_commitments: Sequence[KZGCommitment]) -> Tuple[Polynomial, KZGCommitment]:
"""
Return the aggregated polynomial and aggregated KZG commitment.
"""
# Generate random linear combination challenges
r = hash_to_bls_field(blobs, kzg_commitments)
asn-d6 marked this conversation as resolved.
Show resolved Hide resolved
r_powers = compute_powers(r, len(kzg_commitments))

# Create aggregated polynomial in evaluation form
aggregated_poly = Polynomial(vector_lincomb(blobs, r_powers))

# Compute commitment to aggregated polynomial
aggregated_poly_commitment = KZGCommitment(g1_lincomb(kzg_commitments, r_powers))

return aggregated_poly, aggregated_poly_commitment
```

#### `compute_aggregate_kzg_proof`

```python
def compute_aggregate_kzg_proof(blobs: Sequence[Blob]) -> KZGProof:
commitments = [blob_to_kzg_commitment(blob) for blob in blobs]
aggregated_poly, aggregated_poly_commitment = compute_aggregated_poly_and_commitment(blobs, commitments)
x = hash_to_bls_field([aggregated_poly],[aggregated_poly_commitment])
asn-d6 marked this conversation as resolved.
Show resolved Hide resolved
return compute_kzg_proof(aggregated_poly, x)
```

#### `verify_aggregate_kzg_proof`

```python
def verify_aggregate_kzg_proof(blobs: Sequence[Blob],
expected_kzg_commitments: Sequence[KZGCommitment],
kzg_aggregated_proof : KZGCommitment) -> bool:
aggregated_poly, aggregated_poly_commitment = compute_aggregated_poly_and_commitment(
blobs,
expected_kzg_commitments,
)

# Generate challenge `x` and evaluate the aggregated polynomial at `x`
x = hash_to_bls_field([aggregated_poly], [aggregated_poly_commitment])
# Evaluate aggregated polynomial at `x` (evaluation function checks for div-by-zero)
y = evaluate_polynomial_in_evaluation_form(aggregated_poly, x)

# Verify aggregated proof
return verify_kzg_proof(aggregated_poly_commitment, x, y, kzg_aggregated_proof)
```

### Polynomials

#### `evaluate_polynomial_in_evaluation_form`

```python
def evaluate_polynomial_in_evaluation_form(polynomial: Sequence[BLSFieldElement],
def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial,
asn-d6 marked this conversation as resolved.
Show resolved Hide resolved
z: BLSFieldElement) -> BLSFieldElement:
"""
Evaluate a polynomial (in evaluation form) at an arbitrary point `z`
Expand Down
110 changes: 2 additions & 108 deletions specs/eip4844/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,9 @@

- [Introduction](#introduction)
- [Prerequisites](#prerequisites)
- [Custom types](#custom-types)
- [Containers](#containers)
- [`BlobsAndCommitments`](#blobsandcommitments)
- [`PolynomialAndCommitment`](#polynomialandcommitment)
- [Helpers](#helpers)
- [`is_data_available`](#is_data_available)
- [`hash_to_bls_field`](#hash_to_bls_field)
- [`compute_powers`](#compute_powers)
- [`compute_aggregated_poly_and_commitment`](#compute_aggregated_poly_and_commitment)
- [`validate_blobs_sidecar`](#validate_blobs_sidecar)
- [`compute_proof_from_blobs`](#compute_proof_from_blobs)
- [`get_blobs_and_kzg_commitments`](#get_blobs_and_kzg_commitments)
- [Beacon chain responsibilities](#beacon-chain-responsibilities)
- [Block proposal](#block-proposal)
Expand All @@ -43,31 +35,6 @@ All behaviors and definitions defined in this document, and documents it extends
All terminology, constants, functions, and protocol mechanics defined in the updated [Beacon Chain doc of EIP4844](./beacon-chain.md) are requisite for this document and used throughout.
Please see related Beacon Chain doc before continuing and use them as a reference throughout.

## Custom types

| Name | SSZ equivalent | Description |
| - | - | - |
| `Polynomial` | `List[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | a polynomial in evaluation form |

## Containers

### `BlobsAndCommitments`

```python
class BlobsAndCommitments(Container):
blobs: List[Blob, MAX_BLOBS_PER_BLOCK]
kzg_commitments: List[KZGCommitment, MAX_BLOBS_PER_BLOCK]
```

### `PolynomialAndCommitment`

```python
class PolynomialAndCommitment(Container):
polynomial: Polynomial
kzg_commitment: KZGCommitment
```


## Helpers

### `is_data_available`
Expand All @@ -88,53 +55,6 @@ def is_data_available(slot: Slot, beacon_block_root: Root, blob_kzg_commitments:
return True
```

### `hash_to_bls_field`

```python
def hash_to_bls_field(x: Container) -> BLSFieldElement:
"""
Compute 32-byte hash of serialized container and convert it to BLS field.
The output is not uniform over the BLS field.
"""
return bytes_to_bls_field(hash(ssz_serialize(x)))
```

### `compute_powers`
```python
def compute_powers(x: BLSFieldElement, n: uint64) -> Sequence[BLSFieldElement]:
"""
Return ``x`` to power of [0, n-1].
"""
current_power = 1
powers = []
for _ in range(n):
powers.append(BLSFieldElement(current_power))
current_power = current_power * int(x) % BLS_MODULUS
return powers
```

### `compute_aggregated_poly_and_commitment`

```python
def compute_aggregated_poly_and_commitment(
blobs: Sequence[Blob],
kzg_commitments: Sequence[KZGCommitment]) -> Tuple[Polynomial, KZGCommitment]:
"""
Return the aggregated polynomial and aggregated KZG commitment.
"""
# Generate random linear combination challenges
r = hash_to_bls_field(BlobsAndCommitments(blobs=blobs, kzg_commitments=kzg_commitments))
r_powers = compute_powers(r, len(kzg_commitments))

# Create aggregated polynomial in evaluation form
aggregated_poly = Polynomial(vector_lincomb(blobs, r_powers))

# Compute commitment to aggregated polynomial
aggregated_poly_commitment = KZGCommitment(g1_lincomb(kzg_commitments, r_powers))

return aggregated_poly, aggregated_poly_commitment
```

### `validate_blobs_sidecar`

```python
Expand All @@ -148,33 +68,7 @@ def validate_blobs_sidecar(slot: Slot,
kzg_aggregated_proof = blobs_sidecar.kzg_aggregated_proof
assert len(expected_kzg_commitments) == len(blobs)

aggregated_poly, aggregated_poly_commitment = compute_aggregated_poly_and_commitment(
blobs,
expected_kzg_commitments,
)

# Generate challenge `x` and evaluate the aggregated polynomial at `x`
x = hash_to_bls_field(
PolynomialAndCommitment(polynomial=aggregated_poly, kzg_commitment=aggregated_poly_commitment)
)
# Evaluate aggregated polynomial at `x` (evaluation function checks for div-by-zero)
y = evaluate_polynomial_in_evaluation_form(aggregated_poly, x)

# Verify aggregated proof
assert verify_kzg_proof(aggregated_poly_commitment, x, y, kzg_aggregated_proof)
```

### `compute_proof_from_blobs`

```python
def compute_proof_from_blobs(blobs: Sequence[Blob]) -> KZGProof:
commitments = [blob_to_kzg_commitment(blob) for blob in blobs]
aggregated_poly, aggregated_poly_commitment = compute_aggregated_poly_and_commitment(blobs, commitments)
x = hash_to_bls_field(PolynomialAndCommitment(
polynomial=aggregated_poly,
kzg_commitment=aggregated_poly_commitment,
))
return compute_kzg_proof(aggregated_poly, x)
assert verify_aggregate_kzg_proof(blobs, expected_kzg_commitments, kzg_aggregated_proof)
```

### `get_blobs_and_kzg_commitments`
Expand Down Expand Up @@ -231,7 +125,7 @@ def get_blobs_sidecar(block: BeaconBlock, blobs: Sequence[Blob]) -> BlobsSidecar
beacon_block_root=hash_tree_root(block),
beacon_block_slot=block.slot,
blobs=blobs,
kzg_aggregated_proof=compute_proof_from_blobs(blobs),
kzg_aggregated_proof=compute_aggregate_kzg_proof(blobs),
)
```

Expand Down