mirror of
https://github.com/status-im/eth2.0-specs.git
synced 2025-01-20 15:38:55 +00:00
Merge branch 'dev' into pr3244
This commit is contained in:
commit
c2315c90a3
6
Makefile
6
Makefile
@ -27,10 +27,10 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/phase0/*.md) \
|
||||
$(wildcard $(SPEC_DIR)/altair/*.md) $(wildcard $(SPEC_DIR)/altair/**/*.md) \
|
||||
$(wildcard $(SPEC_DIR)/bellatrix/*.md) \
|
||||
$(wildcard $(SPEC_DIR)/capella/*.md) $(wildcard $(SPEC_DIR)/capella/**/*.md) \
|
||||
$(wildcard $(SPEC_DIR)/custody/*.md) \
|
||||
$(wildcard $(SPEC_DIR)/das/*.md) \
|
||||
$(wildcard $(SPEC_DIR)/sharding/*.md) \
|
||||
$(wildcard $(SPEC_DIR)/deneb/*.md) $(wildcard $(SPEC_DIR)/deneb/**/*.md) \
|
||||
$(wildcard $(SPEC_DIR)/_features/custody/*.md) \
|
||||
$(wildcard $(SPEC_DIR)/_features/das/*.md) \
|
||||
$(wildcard $(SPEC_DIR)/_features/sharding/*.md) \
|
||||
$(wildcard $(SSZ_DIR)/*.md)
|
||||
|
||||
COV_HTML_OUT=.htmlcov
|
||||
|
@ -26,9 +26,9 @@ Features are researched and developed in parallel, and then consolidated into se
|
||||
| - | - | - |
|
||||
| Capella (tentative) | <ul><li>Core</li><ul><li>[Beacon chain changes](specs/capella/beacon-chain.md)</li><li>[Capella fork](specs/capella/fork.md)</li></ul><li>Additions</li><ul><li>[Light client sync protocol changes](specs/capella/light-client/sync-protocol.md) ([fork](specs/capella/light-client/fork.md), [full node](specs/capella/light-client/full-node.md), [networking](specs/capella/light-client/p2p-interface.md))</li></ul><ul><li>[Validator additions](specs/capella/validator.md)</li><li>[P2P networking](specs/capella/p2p-interface.md)</li></ul></ul> |
|
||||
| Deneb (tentative) | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/deneb/beacon-chain.md)</li><li>[Deneb fork](specs/deneb/fork.md)</li><li>[Polynomial commitments](specs/deneb/polynomial-commitments.md)</li><li>[Fork choice changes](specs/deneb/fork-choice.md)</li></ul><li>Additions</li><ul><li>[Light client sync protocol changes](specs/deneb/light-client/sync-protocol.md) ([fork](specs/deneb/light-client/fork.md), [full node](specs/deneb/light-client/full-node.md), [networking](specs/deneb/light-client/p2p-interface.md))</li></ul><ul><li>[Honest validator guide changes](specs/deneb/validator.md)</li><li>[P2P networking](specs/deneb/p2p-interface.md)</li></ul></ul> |
|
||||
| Sharding (outdated) | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/sharding/beacon-chain.md)</li></ul><li>Additions</li><ul><li>[P2P networking](specs/sharding/p2p-interface.md)</li></ul></ul> |
|
||||
| Custody Game (outdated) | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/custody_game/beacon-chain.md)</li></ul><li>Additions</li><ul><li>[Honest validator guide changes](specs/custody_game/validator.md)</li></ul></ul> | Dependent on sharding |
|
||||
| Data Availability Sampling (outdated) | <ul><li>Core</li><ul><li>[Core types and functions](specs/das/das-core.md)</li><li>[Fork choice changes](specs/das/fork-choice.md)</li></ul><li>Additions</li><ul><li>[P2P Networking](specs/das/p2p-interface.md)</li><li>[Sampling process](specs/das/sampling.md)</li></ul></ul> | <ul><li> Dependent on sharding</li><li>[Technical explainer](https://hackmd.io/@HWeNw8hNRimMm2m2GH56Cw/B1YJPGkpD)</li></ul> |
|
||||
| Sharding (outdated) | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/_features/sharding/beacon-chain.md)</li></ul><li>Additions</li><ul><li>[P2P networking](specs/_features/sharding/p2p-interface.md)</li></ul></ul> |
|
||||
| Custody Game (outdated) | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/_features/custody_game/beacon-chain.md)</li></ul><li>Additions</li><ul><li>[Honest validator guide changes](specs/_features/custody_game/validator.md)</li></ul></ul> | Dependent on sharding |
|
||||
| Data Availability Sampling (outdated) | <ul><li>Core</li><ul><li>[Core types and functions](specs/_features/das/das-core.md)</li><li>[Fork choice changes](specs/_features/das/fork-choice.md)</li></ul><li>Additions</li><ul><li>[P2P Networking](specs/_features/das/p2p-interface.md)</li><li>[Sampling process](specs/_features/das/sampling.md)</li></ul></ul> | <ul><li> Dependent on sharding</li><li>[Technical explainer](https://hackmd.io/@HWeNw8hNRimMm2m2GH56Cw/B1YJPGkpD)</li></ul> |
|
||||
|
||||
### Accompanying documents can be found in [specs](specs) and include:
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Mainnet preset - Phase0
|
||||
# Mainnet preset - Deneb
|
||||
|
||||
# Misc
|
||||
# ---------------------------------------------------------------
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Minimal preset - Phase0
|
||||
# Minimal preset - Deneb
|
||||
|
||||
# Misc
|
||||
# ---------------------------------------------------------------
|
||||
|
2
setup.py
2
setup.py
@ -1169,7 +1169,7 @@ setup(
|
||||
"pycryptodome==3.15.0",
|
||||
"py_ecc==6.0.0",
|
||||
"milagro_bls_binding==1.9.0",
|
||||
"remerkleable==0.1.25",
|
||||
"remerkleable==0.1.27",
|
||||
"trie==2.0.2",
|
||||
RUAMEL_YAML_VERSION,
|
||||
"lru-dict==1.1.8",
|
||||
|
@ -36,11 +36,11 @@ docs are requisite for this document and used throughout. Please see the Custody
|
||||
|
||||
## Becoming a validator
|
||||
|
||||
Becoming a validator in Custody Game is unchanged from Phase 0. See the [Phase 0 validator guide](../phase0/validator.md#becoming-a-validator) for details.
|
||||
Becoming a validator in Custody Game is unchanged from Phase 0. See the [Phase 0 validator guide](../../phase0/validator.md#becoming-a-validator) for details.
|
||||
|
||||
## Beacon chain validator assignments
|
||||
|
||||
Beacon chain validator assignments to beacon committees and beacon block proposal are unchanged from Phase 0. See the [Phase 0 validator guide](../phase0/validator.md#validator-assignments) for details.
|
||||
Beacon chain validator assignments to beacon committees and beacon block proposal are unchanged from Phase 0. See the [Phase 0 validator guide](../../phase0/validator.md#validator-assignments) for details.
|
||||
|
||||
##### Custody slashings
|
||||
|
@ -143,7 +143,7 @@ If the node does not already have connected peers on the topic it needs to sampl
|
||||
|
||||
### Topics and messages
|
||||
|
||||
Following the same scheme as the [Phase0 gossip topics](../phase0/p2p-interface.md#topics-and-messages), names and payload types are:
|
||||
Following the same scheme as the [Phase0 gossip topics](../../phase0/p2p-interface.md#topics-and-messages), names and payload types are:
|
||||
| Name | Message Type |
|
||||
|----------------------------------|---------------------------|
|
||||
| `das_sample_{subnet_index}` | `DASSample` |
|
||||
@ -192,7 +192,7 @@ This is to serve other peers that may have missed it.
|
||||
|
||||
To pull samples from nodes, in case of network instability when samples are unavailable, a new query method is added to the Req-Resp domain.
|
||||
|
||||
This builds on top of the protocol identification and encoding spec which was introduced in [the Phase0 network spec](../phase0/p2p-interface.md).
|
||||
This builds on top of the protocol identification and encoding spec which was introduced in [the Phase0 network spec](../../phase0/p2p-interface.md).
|
||||
|
||||
Note that DAS networking uses a different protocol prefix: `/eth2/das/req`
|
||||
|
@ -39,7 +39,7 @@ The adjustments and additions for Shards are outlined in this document.
|
||||
|
||||
### Topics and messages
|
||||
|
||||
Following the same scheme as the [Phase0 gossip topics](../phase0/p2p-interface.md#topics-and-messages), names and payload types are:
|
||||
Following the same scheme as the [Phase0 gossip topics](../../phase0/p2p-interface.md#topics-and-messages), names and payload types are:
|
||||
|
||||
| Name | Message Type |
|
||||
|---------------------------------|--------------------------|
|
@ -33,7 +33,7 @@ This document represents the changes to be made in the code of an "honest valida
|
||||
|
||||
## Prerequisites
|
||||
|
||||
This document is an extension of the [Bellatrix -- Honest Validator](../bellatrix/validator.md) guide.
|
||||
This document is an extension of the [Bellatrix -- Honest Validator](../../bellatrix/validator.md) guide.
|
||||
All behaviors and definitions defined in this document, and documents it extends, carry over unless explicitly noted or overridden.
|
||||
|
||||
All terminology, constants, functions, and protocol mechanics defined in the updated Beacon Chain doc of [Sharding](./beacon-chain.md) are requisite for this document and used throughout.
|
@ -242,7 +242,7 @@ class BeaconState(Container):
|
||||
current_sync_committee: SyncCommittee
|
||||
next_sync_committee: SyncCommittee
|
||||
# Execution
|
||||
latest_execution_payload_header: ExecutionPayloadHeader
|
||||
latest_execution_payload_header: ExecutionPayloadHeader # [Modified in Capella]
|
||||
# Withdrawals
|
||||
next_withdrawal_index: WithdrawalIndex # [New in Capella]
|
||||
next_withdrawal_validator_index: ValidatorIndex # [New in Capella]
|
||||
|
@ -116,11 +116,11 @@ class ExecutionPayload(Container):
|
||||
timestamp: uint64
|
||||
extra_data: ByteList[MAX_EXTRA_DATA_BYTES]
|
||||
base_fee_per_gas: uint256
|
||||
excess_data_gas: uint256 # [New in Deneb]
|
||||
# Extra payload fields
|
||||
block_hash: Hash32 # Hash of execution block
|
||||
transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]
|
||||
withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD]
|
||||
excess_data_gas: uint256 # [New in Deneb]
|
||||
```
|
||||
|
||||
#### `ExecutionPayloadHeader`
|
||||
@ -140,11 +140,11 @@ class ExecutionPayloadHeader(Container):
|
||||
timestamp: uint64
|
||||
extra_data: ByteList[MAX_EXTRA_DATA_BYTES]
|
||||
base_fee_per_gas: uint256
|
||||
excess_data_gas: uint256 # [New in Deneb]
|
||||
# Extra payload fields
|
||||
block_hash: Hash32 # Hash of execution block
|
||||
transactions_root: Root
|
||||
withdrawals_root: Root
|
||||
excess_data_gas: uint256 # [New in Deneb]
|
||||
```
|
||||
|
||||
## Helper functions
|
||||
@ -238,10 +238,10 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe
|
||||
timestamp=payload.timestamp,
|
||||
extra_data=payload.extra_data,
|
||||
base_fee_per_gas=payload.base_fee_per_gas,
|
||||
excess_data_gas=payload.excess_data_gas, # [New in Deneb]
|
||||
block_hash=payload.block_hash,
|
||||
transactions_root=hash_tree_root(payload.transactions),
|
||||
withdrawals_root=hash_tree_root(payload.withdrawals),
|
||||
excess_data_gas=payload.excess_data_gas, # [New in Deneb]
|
||||
)
|
||||
```
|
||||
|
||||
|
@ -57,7 +57,7 @@ def is_data_available(beacon_block_root: Root, blob_kzg_commitments: Sequence[KZ
|
||||
if isinstance(blobs, str):
|
||||
return True
|
||||
|
||||
validate_blobs(expected_kzg_commitments, blobs, proofs)
|
||||
validate_blobs(blob_kzg_commitments, blobs, proofs)
|
||||
return True
|
||||
```
|
||||
|
||||
|
@ -25,11 +25,10 @@
|
||||
- [`bytes_to_kzg_commitment`](#bytes_to_kzg_commitment)
|
||||
- [`bytes_to_kzg_proof`](#bytes_to_kzg_proof)
|
||||
- [`blob_to_polynomial`](#blob_to_polynomial)
|
||||
- [`compute_challenges`](#compute_challenges)
|
||||
- [`compute_challenge`](#compute_challenge)
|
||||
- [`bls_modular_inverse`](#bls_modular_inverse)
|
||||
- [`div`](#div)
|
||||
- [`g1_lincomb`](#g1_lincomb)
|
||||
- [`poly_lincomb`](#poly_lincomb)
|
||||
- [`compute_powers`](#compute_powers)
|
||||
- [Polynomials](#polynomials)
|
||||
- [`evaluate_polynomial_in_evaluation_form`](#evaluate_polynomial_in_evaluation_form)
|
||||
@ -37,11 +36,13 @@
|
||||
- [`blob_to_kzg_commitment`](#blob_to_kzg_commitment)
|
||||
- [`verify_kzg_proof`](#verify_kzg_proof)
|
||||
- [`verify_kzg_proof_impl`](#verify_kzg_proof_impl)
|
||||
- [`verify_kzg_proof_batch`](#verify_kzg_proof_batch)
|
||||
- [`compute_kzg_proof`](#compute_kzg_proof)
|
||||
- [`compute_quotient_eval_within_domain`](#compute_quotient_eval_within_domain)
|
||||
- [`compute_kzg_proof_impl`](#compute_kzg_proof_impl)
|
||||
- [`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)
|
||||
- [`compute_blob_kzg_proof`](#compute_blob_kzg_proof)
|
||||
- [`verify_blob_kzg_proof`](#verify_blob_kzg_proof)
|
||||
- [`verify_blob_kzg_proof_batch`](#verify_blob_kzg_proof_batch)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- /TOC -->
|
||||
@ -83,6 +84,7 @@ Public functions MUST accept raw bytes as input and perform the required cryptog
|
||||
| - | - |
|
||||
| `FIELD_ELEMENTS_PER_BLOB` | `uint64(4096)` |
|
||||
| `FIAT_SHAMIR_PROTOCOL_DOMAIN` | `b'FSBLOBVERIFY_V1_'` |
|
||||
| `RANDOM_CHALLENGE_KZG_BATCH_DOMAIN` | `b'RCKZGBATCH___V1_'` |
|
||||
|
||||
### Crypto
|
||||
|
||||
@ -222,44 +224,24 @@ def blob_to_polynomial(blob: Blob) -> Polynomial:
|
||||
return polynomial
|
||||
```
|
||||
|
||||
#### `compute_challenges`
|
||||
#### `compute_challenge`
|
||||
|
||||
```python
|
||||
def compute_challenges(polynomials: Sequence[Polynomial],
|
||||
commitments: Sequence[KZGCommitment]) -> Tuple[Sequence[BLSFieldElement], BLSFieldElement]:
|
||||
def compute_challenge(blob: Blob,
|
||||
commitment: KZGCommitment) -> BLSFieldElement:
|
||||
"""
|
||||
Return the Fiat-Shamir challenges required by the rest of the protocol.
|
||||
The Fiat-Shamir logic works as per the following pseudocode:
|
||||
|
||||
hashed_data = hash(DOMAIN_SEPARATOR, polynomials, commitments)
|
||||
r = hash(hashed_data, 0)
|
||||
r_powers = [1, r, r**2, r**3, ...]
|
||||
eval_challenge = hash(hashed_data, 1)
|
||||
|
||||
Then return `r_powers` and `eval_challenge` after converting them to BLS field elements.
|
||||
The resulting field elements are not uniform over the BLS field.
|
||||
Return the Fiat-Shamir challenge required by the rest of the protocol.
|
||||
"""
|
||||
# Append the number of polynomials and the degree of each polynomial as a domain separator
|
||||
num_polynomials = int.to_bytes(len(polynomials), 8, ENDIANNESS)
|
||||
degree_poly = int.to_bytes(FIELD_ELEMENTS_PER_BLOB, 8, ENDIANNESS)
|
||||
data = FIAT_SHAMIR_PROTOCOL_DOMAIN + degree_poly + num_polynomials
|
||||
|
||||
# Append each polynomial which is composed by field elements
|
||||
for poly in polynomials:
|
||||
for field_element in poly:
|
||||
data += int.to_bytes(field_element, BYTES_PER_FIELD_ELEMENT, ENDIANNESS)
|
||||
# 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
|
||||
|
||||
# Append serialized G1 points
|
||||
for commitment in commitments:
|
||||
data += commitment
|
||||
data += blob
|
||||
data += commitment
|
||||
|
||||
# Transcript has been prepared: time to create the challenges
|
||||
hashed_data = hash(data)
|
||||
r = hash_to_bls_field(hashed_data + b'\x00')
|
||||
r_powers = compute_powers(r, len(commitments))
|
||||
eval_challenge = hash_to_bls_field(hashed_data + b'\x01')
|
||||
|
||||
return r_powers, eval_challenge
|
||||
# Transcript has been prepared: time to create the challenge
|
||||
return hash_to_bls_field(data)
|
||||
```
|
||||
|
||||
#### `bls_modular_inverse`
|
||||
@ -297,23 +279,6 @@ def g1_lincomb(points: Sequence[KZGCommitment], scalars: Sequence[BLSFieldElemen
|
||||
return KZGCommitment(bls.G1_to_bytes48(result))
|
||||
```
|
||||
|
||||
#### `poly_lincomb`
|
||||
|
||||
```python
|
||||
def poly_lincomb(polys: Sequence[Polynomial],
|
||||
scalars: Sequence[BLSFieldElement]) -> Polynomial:
|
||||
"""
|
||||
Given a list of ``polynomials``, interpret it as a 2D matrix and compute the linear combination
|
||||
of each column with `scalars`: return the resulting polynomials.
|
||||
"""
|
||||
assert len(polys) == len(scalars)
|
||||
result = [0] * FIELD_ELEMENTS_PER_BLOB
|
||||
for v, s in zip(polys, scalars):
|
||||
for i, x in enumerate(v):
|
||||
result[i] = (result[i] + int(s) * int(x)) % BLS_MODULUS
|
||||
return Polynomial([BLSFieldElement(x) for x in result])
|
||||
```
|
||||
|
||||
#### `compute_powers`
|
||||
|
||||
```python
|
||||
@ -414,6 +379,50 @@ def verify_kzg_proof_impl(commitment: KZGCommitment,
|
||||
])
|
||||
```
|
||||
|
||||
#### `verify_kzg_proof_batch`
|
||||
|
||||
```python
|
||||
def verify_kzg_proof_batch(commitments: Sequence[KZGCommitment],
|
||||
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)
|
||||
data = RANDOM_CHALLENGE_KZG_BATCH_DOMAIN + degree_poly + num_commitments
|
||||
|
||||
# Append all inputs to the transcript before we hash
|
||||
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
|
||||
|
||||
r = hash_to_bls_field(data)
|
||||
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)
|
||||
proof_z_lincomb = g1_lincomb(proofs, [z * r_power for z, r_power in zip(zs, r_powers)])
|
||||
C_minus_ys = [bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1, BLS_MODULUS - y))
|
||||
for commitment, y in zip(commitments, ys)]
|
||||
C_minus_y_as_KZGCommitments = [KZGCommitment(bls.G1_to_bytes48(x)) for x in C_minus_ys]
|
||||
C_minus_y_lincomb = g1_lincomb(C_minus_y_as_KZGCommitments, r_powers)
|
||||
|
||||
return bls.pairing_check([
|
||||
[proof_lincomb, bls.neg(KZG_SETUP_G2[1])],
|
||||
[bls.add(C_minus_y_lincomb, proof_z_lincomb), bls.G2]
|
||||
])
|
||||
```
|
||||
|
||||
#### `compute_kzg_proof`
|
||||
|
||||
```python
|
||||
@ -427,6 +436,34 @@ def compute_kzg_proof(blob: Blob, z: Bytes32) -> KZGProof:
|
||||
return compute_kzg_proof_impl(polynomial, bytes_to_bls_field(z))
|
||||
```
|
||||
|
||||
#### `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
|
||||
result += div(BLSFieldElement(numerator), BLSFieldElement(denominator))
|
||||
|
||||
return BLSFieldElement(result % BLS_MODULUS)
|
||||
```
|
||||
|
||||
#### `compute_kzg_proof_impl`
|
||||
|
||||
```python
|
||||
@ -434,85 +471,90 @@ def compute_kzg_proof_impl(polynomial: Polynomial, z: BLSFieldElement) -> KZGPro
|
||||
"""
|
||||
Helper function for compute_kzg_proof() and compute_aggregate_kzg_proof().
|
||||
"""
|
||||
roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY)
|
||||
|
||||
# For all x_i, compute p(x_i) - p(z)
|
||||
y = evaluate_polynomial_in_evaluation_form(polynomial, z)
|
||||
polynomial_shifted = [BLSFieldElement((int(p) - int(y)) % BLS_MODULUS) for p in polynomial]
|
||||
|
||||
# Make sure we won't divide by zero during division
|
||||
assert z not in ROOTS_OF_UNITY
|
||||
# For all x_i, compute (x_i - z)
|
||||
denominator_poly = [BLSFieldElement((int(x) - int(z)) % BLS_MODULUS)
|
||||
for x in bit_reversal_permutation(ROOTS_OF_UNITY)]
|
||||
|
||||
# Calculate quotient polynomial by doing point-by-point division
|
||||
quotient_polynomial = [div(a, b) for a, b in zip(polynomial_shifted, denominator_poly)]
|
||||
# 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)
|
||||
|
||||
return KZGProof(g1_lincomb(bit_reversal_permutation(KZG_SETUP_LAGRANGE), quotient_polynomial))
|
||||
```
|
||||
|
||||
#### `compute_aggregated_poly_and_commitment`
|
||||
#### `compute_blob_kzg_proof`
|
||||
|
||||
```python
|
||||
def compute_aggregated_poly_and_commitment(
|
||||
blobs: Sequence[Blob],
|
||||
kzg_commitments: Sequence[KZGCommitment]) -> Tuple[Polynomial, KZGCommitment, BLSFieldElement]:
|
||||
def compute_blob_kzg_proof(blob: Blob) -> KZGProof:
|
||||
"""
|
||||
Return (1) the aggregated polynomial, (2) the aggregated KZG commitment,
|
||||
and (3) the polynomial evaluation random challenge.
|
||||
This function should also work with blobs == [] and kzg_commitments == []
|
||||
"""
|
||||
assert len(blobs) == len(kzg_commitments)
|
||||
|
||||
# Convert blobs to polynomials
|
||||
polynomials = [blob_to_polynomial(blob) for blob in blobs]
|
||||
|
||||
# Generate random linear combination and evaluation challenges
|
||||
r_powers, evaluation_challenge = compute_challenges(polynomials, kzg_commitments)
|
||||
|
||||
# Create aggregated polynomial in evaluation form
|
||||
aggregated_poly = poly_lincomb(polynomials, r_powers)
|
||||
|
||||
# Compute commitment to aggregated polynomial
|
||||
aggregated_poly_commitment = KZGCommitment(g1_lincomb(kzg_commitments, r_powers))
|
||||
|
||||
return aggregated_poly, aggregated_poly_commitment, evaluation_challenge
|
||||
```
|
||||
|
||||
#### `compute_aggregate_kzg_proof`
|
||||
|
||||
```python
|
||||
def compute_aggregate_kzg_proof(blobs: Sequence[Blob]) -> KZGProof:
|
||||
"""
|
||||
Given a list of blobs, return the aggregated KZG proof that is used to verify them against their commitments.
|
||||
Given a blob, return the KZG proof that is used to verify it against the commitment.
|
||||
Public method.
|
||||
"""
|
||||
commitments = [blob_to_kzg_commitment(blob) for blob in blobs]
|
||||
aggregated_poly, aggregated_poly_commitment, evaluation_challenge = compute_aggregated_poly_and_commitment(
|
||||
blobs,
|
||||
commitments
|
||||
)
|
||||
return compute_kzg_proof_impl(aggregated_poly, evaluation_challenge)
|
||||
commitment = blob_to_kzg_commitment(blob)
|
||||
polynomial = blob_to_polynomial(blob)
|
||||
evaluation_challenge = compute_challenge(blob, commitment)
|
||||
return compute_kzg_proof_impl(polynomial, evaluation_challenge)
|
||||
```
|
||||
|
||||
#### `verify_aggregate_kzg_proof`
|
||||
#### `verify_blob_kzg_proof`
|
||||
|
||||
```python
|
||||
def verify_aggregate_kzg_proof(blobs: Sequence[Blob],
|
||||
commitments_bytes: Sequence[Bytes48],
|
||||
aggregated_proof_bytes: Bytes48) -> bool:
|
||||
def verify_blob_kzg_proof(blob: Blob,
|
||||
commitment_bytes: Bytes48,
|
||||
proof_bytes: Bytes48) -> bool:
|
||||
"""
|
||||
Given a list of blobs and an aggregated KZG proof, verify that they correspond to the provided commitments.
|
||||
Given a blob and a KZG proof, verify that the blob data corresponds to the provided commitment.
|
||||
|
||||
Public method.
|
||||
"""
|
||||
commitments = [bytes_to_kzg_commitment(c) for c in commitments_bytes]
|
||||
commitment = bytes_to_kzg_commitment(commitment_bytes)
|
||||
|
||||
aggregated_poly, aggregated_poly_commitment, evaluation_challenge = compute_aggregated_poly_and_commitment(
|
||||
blobs,
|
||||
commitments
|
||||
)
|
||||
polynomial = blob_to_polynomial(blob)
|
||||
evaluation_challenge = compute_challenge(blob, commitment)
|
||||
|
||||
# Evaluate aggregated polynomial at `evaluation_challenge` (evaluation function checks for div-by-zero)
|
||||
y = evaluate_polynomial_in_evaluation_form(aggregated_poly, evaluation_challenge)
|
||||
# Evaluate polynomial at `evaluation_challenge`
|
||||
y = evaluate_polynomial_in_evaluation_form(polynomial, evaluation_challenge)
|
||||
|
||||
# Verify aggregated proof
|
||||
aggregated_proof = bytes_to_kzg_proof(aggregated_proof_bytes)
|
||||
return verify_kzg_proof_impl(aggregated_poly_commitment, evaluation_challenge, y, aggregated_proof)
|
||||
# Verify proof
|
||||
proof = bytes_to_kzg_proof(proof_bytes)
|
||||
return verify_kzg_proof_impl(commitment, evaluation_challenge, y, proof)
|
||||
```
|
||||
|
||||
#### `verify_blob_kzg_proof_batch`
|
||||
|
||||
```python
|
||||
def verify_blob_kzg_proof_batch(blobs: Sequence[Blob],
|
||||
commitments_bytes: Sequence[Bytes48],
|
||||
proofs_bytes: Sequence[Bytes48]) -> bool:
|
||||
"""
|
||||
Given a list of blobs and blob KZG proofs, verify that they correspond to the provided commitments.
|
||||
|
||||
Public method.
|
||||
"""
|
||||
|
||||
assert len(blobs) == len(commitments_bytes) == len(proofs_bytes)
|
||||
|
||||
commitments, evaluation_challenges, ys, proofs = [], [], [], []
|
||||
for blob, commitment_bytes, proof_bytes in zip(blobs, commitments_bytes, proofs_bytes):
|
||||
commitment = bytes_to_kzg_commitment(commitment_bytes)
|
||||
commitments.append(commitment)
|
||||
polynomial = blob_to_polynomial(blob)
|
||||
evaluation_challenge = compute_challenge(blob, commitment)
|
||||
evaluation_challenges.append(evaluation_challenge)
|
||||
ys.append(evaluate_polynomial_in_evaluation_form(polynomial, evaluation_challenge))
|
||||
proofs.append(bytes_to_kzg_proof(proof_bytes))
|
||||
|
||||
return verify_kzg_proof_batch(commitments, evaluation_challenges, ys, proofs)
|
||||
```
|
||||
|
@ -194,10 +194,7 @@ def get_latest_attesting_balance(store: Store, root: Root) -> Gwei:
|
||||
proposer_score = Gwei(0)
|
||||
# Boost is applied if ``root`` is an ancestor of ``proposer_boost_root``
|
||||
if get_ancestor(store, store.proposer_boost_root, store.blocks[root].slot) == root:
|
||||
num_validators = len(get_active_validator_indices(state, get_current_epoch(state)))
|
||||
avg_balance = get_total_active_balance(state) // num_validators
|
||||
committee_size = num_validators // SLOTS_PER_EPOCH
|
||||
committee_weight = committee_size * avg_balance
|
||||
committee_weight = get_total_active_balance(state) // SLOTS_PER_EPOCH
|
||||
proposer_score = (committee_weight * PROPOSER_SCORE_BOOST) // 100
|
||||
return attestation_score + proposer_score
|
||||
|
||||
|
@ -87,3 +87,23 @@ def test_barycentric_within_domain(spec, state):
|
||||
# The two evaluations should be agree and p(z) should also be the i-th "coefficient" of the polynomial in
|
||||
# evaluation form
|
||||
assert p_z_coeff == p_z_eval == poly_eval[i]
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_compute_kzg_proof_within_domain(spec, state):
|
||||
"""
|
||||
Create and verify KZG proof that p(z) == y
|
||||
where z is in the domain of our KZG scheme (i.e. a relevant root of unity).
|
||||
"""
|
||||
blob = get_sample_blob(spec)
|
||||
commitment = spec.blob_to_kzg_commitment(blob)
|
||||
polynomial = spec.blob_to_polynomial(blob)
|
||||
|
||||
roots_of_unity_brp = spec.bit_reversal_permutation(spec.ROOTS_OF_UNITY)
|
||||
|
||||
for i, z in enumerate(roots_of_unity_brp):
|
||||
proof = spec.compute_kzg_proof_impl(polynomial, z)
|
||||
|
||||
y = spec.evaluate_polynomial_in_evaluation_form(polynomial, z)
|
||||
assert spec.verify_kzg_proof_impl(commitment, z, y, proof)
|
||||
|
@ -29,14 +29,12 @@ def run_fork_test(post_spec, pre_state):
|
||||
'inactivity_scores',
|
||||
# Sync
|
||||
'current_sync_committee', 'next_sync_committee',
|
||||
# Execution
|
||||
'latest_execution_payload_header',
|
||||
]
|
||||
for field in stable_fields:
|
||||
assert getattr(pre_state, field) == getattr(post_state, field)
|
||||
|
||||
# Modified fields
|
||||
modified_fields = ['fork']
|
||||
modified_fields = ['fork', 'latest_execution_payload_header']
|
||||
for field in modified_fields:
|
||||
assert getattr(pre_state, field) != getattr(post_state, field)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user