Merge branch 'dev' into pr3034
This commit is contained in:
commit
d8440f8bb4
2
Makefile
2
Makefile
|
@ -212,7 +212,7 @@ gen_kzg_setups:
|
|||
if ! test -d venv; then python3 -m venv venv; fi; \
|
||||
. venv/bin/activate; \
|
||||
pip3 install -r requirements.txt; \
|
||||
python3 ./gen_kzg_trusted_setups.py --secret=1337 --g1-length=4 --g2-length=65 --output-dir ${CURRENT_DIR}/presets/minimal/trusted_setups; \
|
||||
python3 ./gen_kzg_trusted_setups.py --secret=1337 --g1-length=4096 --g2-length=65 --output-dir ${CURRENT_DIR}/presets/minimal/trusted_setups; \
|
||||
python3 ./gen_kzg_trusted_setups.py --secret=1337 --g1-length=4096 --g2-length=65 --output-dir ${CURRENT_DIR}/presets/mainnet/trusted_setups
|
||||
|
||||
# For any generator, build it using the run_generator function.
|
||||
|
|
|
@ -87,7 +87,8 @@ EJECTION_BALANCE: 16000000000
|
|||
MIN_PER_EPOCH_CHURN_LIMIT: 4
|
||||
# 2**16 (= 65,536)
|
||||
CHURN_LIMIT_QUOTIENT: 65536
|
||||
|
||||
# [New in Deneb:EIP7514] 2**3 (= 8)
|
||||
MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 8
|
||||
|
||||
# Fork choice
|
||||
# ---------------------------------------------------------------
|
||||
|
|
|
@ -82,10 +82,12 @@ INACTIVITY_SCORE_BIAS: 4
|
|||
INACTIVITY_SCORE_RECOVERY_RATE: 16
|
||||
# 2**4 * 10**9 (= 16,000,000,000) Gwei
|
||||
EJECTION_BALANCE: 16000000000
|
||||
# 2**2 (= 4)
|
||||
MIN_PER_EPOCH_CHURN_LIMIT: 4
|
||||
# [customized] more easily demonstrate the difference between this value and the activation churn limit
|
||||
MIN_PER_EPOCH_CHURN_LIMIT: 2
|
||||
# [customized] scale queue churn at much lower validator counts for testing
|
||||
CHURN_LIMIT_QUOTIENT: 32
|
||||
# [New in Deneb:EIP7514] [customized]
|
||||
MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 4
|
||||
|
||||
|
||||
# Fork choice
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -2,8 +2,8 @@
|
|||
|
||||
# Misc
|
||||
# ---------------------------------------------------------------
|
||||
# [customized]
|
||||
FIELD_ELEMENTS_PER_BLOB: 4
|
||||
# `uint64(4096)`
|
||||
FIELD_ELEMENTS_PER_BLOB: 4096
|
||||
# [customized]
|
||||
MAX_BLOB_COMMITMENTS_PER_BLOCK: 16
|
||||
# `uint64(6)`
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
23
setup.py
23
setup.py
|
@ -108,21 +108,14 @@ def _is_constant_id(name: str) -> bool:
|
|||
|
||||
|
||||
def _load_kzg_trusted_setups(preset_name):
|
||||
"""
|
||||
[TODO] it's not the final mainnet trusted setup.
|
||||
We will update it after the KZG ceremony.
|
||||
"""
|
||||
file_path = str(Path(__file__).parent) + '/presets/' + preset_name + '/trusted_setups/testing_trusted_setups.json'
|
||||
trusted_setups_file_path = str(Path(__file__).parent) + '/presets/' + preset_name + '/trusted_setups/trusted_setup_4096.json'
|
||||
|
||||
with open(file_path, 'r') as f:
|
||||
with open(trusted_setups_file_path, 'r') as f:
|
||||
json_data = json.load(f)
|
||||
trusted_setup_G1_lagrange = json_data['g1_lagrange']
|
||||
trusted_setup_G2_monomial = json_data['g2_monomial']
|
||||
|
||||
trusted_setup_G1 = json_data['setup_G1']
|
||||
trusted_setup_G2 = json_data['setup_G2']
|
||||
trusted_setup_G1_lagrange = json_data['setup_G1_lagrange']
|
||||
roots_of_unity = json_data['roots_of_unity']
|
||||
|
||||
return trusted_setup_G1, trusted_setup_G2, trusted_setup_G1_lagrange, roots_of_unity
|
||||
return trusted_setup_G2_monomial, trusted_setup_G1_lagrange
|
||||
|
||||
|
||||
ALL_KZG_SETUPS = {
|
||||
|
@ -158,10 +151,8 @@ def _parse_value(name: str, typed_value: str, type_hint: Optional[str] = None) -
|
|||
def _update_constant_vars_with_kzg_setups(constant_vars, preset_name):
|
||||
comment = "noqa: E501"
|
||||
kzg_setups = ALL_KZG_SETUPS[preset_name]
|
||||
constant_vars['KZG_SETUP_G1'] = VariableDefinition(constant_vars['KZG_SETUP_G1'].value, str(kzg_setups[0]), comment, None)
|
||||
constant_vars['KZG_SETUP_G2'] = VariableDefinition(constant_vars['KZG_SETUP_G2'].value, str(kzg_setups[1]), comment, None)
|
||||
constant_vars['KZG_SETUP_LAGRANGE'] = VariableDefinition(constant_vars['KZG_SETUP_LAGRANGE'].value, str(kzg_setups[2]), comment, None)
|
||||
constant_vars['ROOTS_OF_UNITY'] = VariableDefinition(constant_vars['ROOTS_OF_UNITY'].value, str(kzg_setups[3]), comment, None)
|
||||
constant_vars['KZG_SETUP_G2_MONOMIAL'] = VariableDefinition(constant_vars['KZG_SETUP_G2_MONOMIAL'].value, str(kzg_setups[0]), comment, None)
|
||||
constant_vars['KZG_SETUP_G1_LAGRANGE'] = VariableDefinition(constant_vars['KZG_SETUP_G1_LAGRANGE'].value, str(kzg_setups[1]), comment, None)
|
||||
|
||||
|
||||
def get_spec(file_name: Path, preset: Dict[str, str], config: Dict[str, str], preset_name=str) -> SpecObject:
|
||||
|
|
|
@ -52,7 +52,7 @@ Up to `MAX_CUSTODY_KEY_REVEALS`, [`CustodyKeyReveal`](./beacon-chain.md#custodyk
|
|||
|
||||
##### Early derived secret reveals
|
||||
|
||||
Up to `MAX_EARLY_DERIVED_SECRET_REVEALS`, [`EarlyDerivedSecretReveal`](./beacon-chain.md#earlyderivedsecretreveal) objects can be included in the `block`. The early derived secret reveals must satisfy the verification conditions found in [early derived secret reveal processing](beacon-chain.md#custody-key-reveals). The validator receives a small "whistleblower" reward for each early derived secrete reveal included.
|
||||
Up to `MAX_EARLY_DERIVED_SECRET_REVEALS`, [`EarlyDerivedSecretReveal`](./beacon-chain.md#earlyderivedsecretreveal) objects can be included in the `block`. The early derived secret reveals must satisfy the verification conditions found in [early derived secret reveal processing](beacon-chain.md#custody-key-reveals). The validator receives a small "whistleblower" reward for each early derived secret reveal included.
|
||||
|
||||
#### Construct attestation
|
||||
|
||||
|
|
|
@ -415,23 +415,10 @@ def get_initial_tracker(k: BLSFieldElement) -> WhiskTracker:
|
|||
```
|
||||
|
||||
```python
|
||||
def apply_deposit(state: BeaconState,
|
||||
def add_validator_to_registry(state: BeaconState,
|
||||
pubkey: BLSPubkey,
|
||||
withdrawal_credentials: Bytes32,
|
||||
amount: uint64,
|
||||
signature: BLSSignature) -> None:
|
||||
validator_pubkeys = [validator.pubkey for validator in state.validators]
|
||||
if pubkey not in validator_pubkeys:
|
||||
# Verify the deposit signature (proof of possession) which is not checked by the deposit contract
|
||||
deposit_message = DepositMessage(
|
||||
pubkey=pubkey,
|
||||
withdrawal_credentials=withdrawal_credentials,
|
||||
amount=amount,
|
||||
)
|
||||
domain = compute_domain(DOMAIN_DEPOSIT) # Fork-agnostic domain since deposits are valid across forks
|
||||
signing_root = compute_signing_root(deposit_message, domain)
|
||||
# Initialize validator if the deposit signature is valid
|
||||
if bls.Verify(pubkey, signing_root, signature):
|
||||
amount: uint64) -> None:
|
||||
index = get_index_for_new_validator(state)
|
||||
validator = get_validator_from_deposit(pubkey, withdrawal_credentials, amount)
|
||||
set_or_append_list(state.validators, index, validator)
|
||||
|
@ -443,10 +430,6 @@ def apply_deposit(state: BeaconState,
|
|||
k = get_unique_whisk_k(state, ValidatorIndex(len(state.validators) - 1))
|
||||
state.whisk_trackers.append(get_initial_tracker(k))
|
||||
state.whisk_k_commitments.append(get_k_commitment(k))
|
||||
else:
|
||||
# Increase balance by deposit amount
|
||||
index = ValidatorIndex(validator_pubkeys.index(pubkey))
|
||||
increase_balance(state, index, amount)
|
||||
```
|
||||
|
||||
### `get_beacon_proposer_index`
|
||||
|
|
|
@ -76,7 +76,7 @@ Alias `block = signed_beacon_block.message`, `execution_payload = block.body.exe
|
|||
then validate the following:
|
||||
- _[REJECT]_ The block's execution payload timestamp is correct with respect to the slot
|
||||
-- i.e. `execution_payload.timestamp == compute_timestamp_at_slot(state, block.slot)`.
|
||||
- If `exection_payload` verification of block's parent by an execution node is *not* complete:
|
||||
- If `execution_payload` verification of block's parent by an execution node is *not* complete:
|
||||
- [REJECT] The block's parent (defined by `block.parent_root`) passes all
|
||||
validation (excluding execution node verification of the `block.body.execution_payload`).
|
||||
- otherwise:
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
- [Preset](#preset)
|
||||
- [Execution](#execution)
|
||||
- [Configuration](#configuration)
|
||||
- [Validator cycle](#validator-cycle)
|
||||
- [Containers](#containers)
|
||||
- [Extended containers](#extended-containers)
|
||||
- [`BeaconBlockBody`](#beaconblockbody)
|
||||
|
@ -26,6 +27,7 @@
|
|||
- [`kzg_commitment_to_versioned_hash`](#kzg_commitment_to_versioned_hash)
|
||||
- [Beacon state accessors](#beacon-state-accessors)
|
||||
- [Modified `get_attestation_participation_flag_indices`](#modified-get_attestation_participation_flag_indices)
|
||||
- [New `get_validator_activation_churn_limit`](#new-get_validator_activation_churn_limit)
|
||||
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
|
||||
- [Execution engine](#execution-engine)
|
||||
- [Request data](#request-data)
|
||||
|
@ -40,6 +42,8 @@
|
|||
- [Execution payload](#execution-payload)
|
||||
- [Modified `process_execution_payload`](#modified-process_execution_payload)
|
||||
- [Modified `process_voluntary_exit`](#modified-process_voluntary_exit)
|
||||
- [Epoch processing](#epoch-processing)
|
||||
- [Registry updates](#registry-updates)
|
||||
- [Testing](#testing)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
@ -50,8 +54,9 @@
|
|||
Deneb is a consensus-layer upgrade containing a number of features. Including:
|
||||
* [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788): Beacon block root in the EVM
|
||||
* [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844): Shard Blob Transactions scale data-availability of Ethereum in a simple, forwards-compatible manner
|
||||
* [EIP-7044](https://github.com/ethereum/EIPs/pull/7044): Perpetually Valid Signed Voluntary Exits
|
||||
* [EIP-7044](https://eips.ethereum.org/EIPS/eip-7044): Perpetually Valid Signed Voluntary Exits
|
||||
* [EIP-7045](https://eips.ethereum.org/EIPS/eip-7045): Increase Max Attestation Inclusion Slot
|
||||
* [EIP-7514](https://eips.ethereum.org/EIPS/eip-7514): Add Max Epoch Churn Limit
|
||||
|
||||
## Custom types
|
||||
|
||||
|
@ -89,6 +94,12 @@ and are limited by `MAX_BLOB_GAS_PER_BLOCK // GAS_PER_BLOB`. However the CL limi
|
|||
|
||||
## Configuration
|
||||
|
||||
### Validator cycle
|
||||
|
||||
| Name | Value |
|
||||
| - | - |
|
||||
| `MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT` | `uint64(2**3)` (= 8) |
|
||||
|
||||
## Containers
|
||||
|
||||
### Extended containers
|
||||
|
@ -211,6 +222,16 @@ def get_attestation_participation_flag_indices(state: BeaconState,
|
|||
return participation_flag_indices
|
||||
```
|
||||
|
||||
#### New `get_validator_activation_churn_limit`
|
||||
|
||||
```python
|
||||
def get_validator_activation_churn_limit(state: BeaconState) -> uint64:
|
||||
"""
|
||||
Return the validator activation churn limit for the current epoch.
|
||||
"""
|
||||
return min(MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT, get_validator_churn_limit(state))
|
||||
```
|
||||
|
||||
## Beacon chain state transition function
|
||||
|
||||
### Execution engine
|
||||
|
@ -415,6 +436,38 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu
|
|||
initiate_validator_exit(state, voluntary_exit.validator_index)
|
||||
```
|
||||
|
||||
### Epoch processing
|
||||
|
||||
#### Registry updates
|
||||
|
||||
*Note*: The function `process_registry_updates` is modified to utilize `get_validator_activation_churn_limit()` to rate limit the activation queue for EIP-7514.
|
||||
|
||||
```python
|
||||
def process_registry_updates(state: BeaconState) -> None:
|
||||
# Process activation eligibility and ejections
|
||||
for index, validator in enumerate(state.validators):
|
||||
if is_eligible_for_activation_queue(validator):
|
||||
validator.activation_eligibility_epoch = get_current_epoch(state) + 1
|
||||
|
||||
if (
|
||||
is_active_validator(validator, get_current_epoch(state))
|
||||
and validator.effective_balance <= EJECTION_BALANCE
|
||||
):
|
||||
initiate_validator_exit(state, ValidatorIndex(index))
|
||||
|
||||
# Queue validators eligible for activation and not yet dequeued for activation
|
||||
activation_queue = sorted([
|
||||
index for index, validator in enumerate(state.validators)
|
||||
if is_eligible_for_activation(state, validator)
|
||||
# Order by the sequence of activation_eligibility_epoch setting and then index
|
||||
], key=lambda index: (state.validators[index].activation_eligibility_epoch, index))
|
||||
# Dequeued validators for activation up to activation churn limit
|
||||
# [Modified in Deneb:EIP7514]
|
||||
for index in activation_queue[:get_validator_activation_churn_limit(state)]:
|
||||
validator = state.validators[index]
|
||||
validator.activation_epoch = compute_activation_exit_epoch(get_current_epoch(state))
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure Deneb testing only.
|
||||
|
|
|
@ -47,6 +47,8 @@ Initially, verification requires every verifying actor to retrieve all matching
|
|||
|
||||
The block MUST NOT be considered valid until all valid `Blob`s have been downloaded. Blocks that have been previously validated as available SHOULD be considered available even if the associated `Blob`s have subsequently been pruned.
|
||||
|
||||
*Note*: Extraneous or invalid Blobs (in addition to KZG expected/referenced valid blobs) received on the p2p network MUST NOT invalidate a block that is otherwise valid and available.
|
||||
|
||||
```python
|
||||
def is_data_available(beacon_block_root: Root, blob_kzg_commitments: Sequence[KZGCommitment]) -> bool:
|
||||
# `retrieve_blobs_and_proofs` is implementation and context dependent
|
||||
|
@ -91,6 +93,8 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
|
|||
# [New in Deneb:EIP4844]
|
||||
# Check if blob data is available
|
||||
# If not, this block MAY be queued and subsequently considered when blob data becomes available
|
||||
# *Note*: Extraneous or invalid Blobs (in addition to the expected/referenced valid blobs)
|
||||
# received on the p2p network MUST NOT invalidate a block that is otherwise valid and available
|
||||
assert is_data_available(hash_tree_root(block), block.body.blob_kzg_commitments)
|
||||
|
||||
# Check the block is valid and compute the post-state
|
||||
|
|
|
@ -148,6 +148,7 @@ This topic is used to propagate signed blob sidecars, where each blob index maps
|
|||
|
||||
The following validations MUST pass before forwarding the `signed_blob_sidecar` on the network, assuming the alias `sidecar = signed_blob_sidecar.message`:
|
||||
|
||||
- _[REJECT]_ The sidecar's index is consistent with `MAX_BLOBS_PER_BLOCK` -- i.e. `sidecar.index < MAX_BLOBS_PER_BLOCK`.
|
||||
- _[REJECT]_ The sidecar is for the correct subnet -- i.e. `compute_subnet_for_blob_sidecar(sidecar.index) == subnet_id`.
|
||||
- _[IGNORE]_ The sidecar is not from a future slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- i.e. validate that `sidecar.slot <= current_slot` (a client MAY queue future sidecars for processing at the appropriate slot).
|
||||
- _[IGNORE]_ The sidecar is from a slot greater than the latest finalized slot -- i.e. validate that `sidecar.slot > compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)`
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
- [Constants](#constants)
|
||||
- [Preset](#preset)
|
||||
- [Blob](#blob)
|
||||
- [Crypto](#crypto)
|
||||
- [Trusted setup](#trusted-setup)
|
||||
- [Helper functions](#helper-functions)
|
||||
- [Bit-reversal permutation](#bit-reversal-permutation)
|
||||
|
@ -30,6 +29,7 @@
|
|||
- [`div`](#div)
|
||||
- [`g1_lincomb`](#g1_lincomb)
|
||||
- [`compute_powers`](#compute_powers)
|
||||
- [`compute_roots_of_unity`](#compute_roots_of_unity)
|
||||
- [Polynomials](#polynomials)
|
||||
- [`evaluate_polynomial_in_evaluation_form`](#evaluate_polynomial_in_evaluation_form)
|
||||
- [KZG](#kzg)
|
||||
|
@ -78,7 +78,7 @@ Public functions MUST accept raw bytes as input and perform the required cryptog
|
|||
| `BYTES_PER_BLOB` | `uint64(BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB)` | The number of bytes in a blob |
|
||||
| `G1_POINT_AT_INFINITY` | `Bytes48(b'\xc0' + b'\x00' * 47)` | Serialized form of the point at infinity on the G1 group |
|
||||
| `KZG_ENDIANNESS` | `'big'` | The endianness of the field elements including blobs |
|
||||
|
||||
| `PRIMITIVE_ROOT_OF_UNITY` | `7` | Primitive root of unity of the BLS12_381 (inner) BLS_MODULUS |
|
||||
|
||||
## Preset
|
||||
|
||||
|
@ -90,23 +90,13 @@ Public functions MUST accept raw bytes as input and perform the required cryptog
|
|||
| `FIAT_SHAMIR_PROTOCOL_DOMAIN` | `b'FSBLOBVERIFY_V1_'` |
|
||||
| `RANDOM_CHALLENGE_KZG_BATCH_DOMAIN` | `b'RCKZGBATCH___V1_'` |
|
||||
|
||||
### 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 |
|
||||
|
||||
### 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_LENGTH` | `65` |
|
||||
| `KZG_SETUP_G1` | `Vector[G1Point, FIELD_ELEMENTS_PER_BLOB]`, contents TBD |
|
||||
| `KZG_SETUP_G2` | `Vector[G2Point, KZG_SETUP_G2_LENGTH]`, contents TBD |
|
||||
| `KZG_SETUP_LAGRANGE` | `Vector[G1Point, FIELD_ELEMENTS_PER_BLOB]`, contents TBD |
|
||||
| `KZG_SETUP_G2_MONOMIAL` | `Vector[G2Point, KZG_SETUP_G2_LENGTH]` |
|
||||
| `KZG_SETUP_G1_LAGRANGE` | `Vector[G1Point, FIELD_ELEMENTS_PER_BLOB]` |
|
||||
|
||||
## Helper functions
|
||||
|
||||
|
@ -114,7 +104,7 @@ but reusing the `mainnet` settings in public networks is a critical security req
|
|||
|
||||
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
|
||||
`KZG_SETUP_G1_LAGRANGE` and roots of unity in bit-reversal permutation, so these functions only
|
||||
have to be called once at startup.
|
||||
|
||||
#### `is_power_of_two`
|
||||
|
@ -299,6 +289,17 @@ def compute_powers(x: BLSFieldElement, n: uint64) -> Sequence[BLSFieldElement]:
|
|||
return powers
|
||||
```
|
||||
|
||||
#### `compute_roots_of_unity`
|
||||
|
||||
```python
|
||||
def compute_roots_of_unity(order: uint64) -> Sequence[BLSFieldElement]:
|
||||
"""
|
||||
Return roots of unity of ``order``.
|
||||
"""
|
||||
assert (BLS_MODULUS - 1) % int(order) == 0
|
||||
root_of_unity = BLSFieldElement(pow(PRIMITIVE_ROOT_OF_UNITY, (BLS_MODULUS - 1) // int(order), BLS_MODULUS))
|
||||
return compute_powers(root_of_unity, order)
|
||||
```
|
||||
|
||||
### Polynomials
|
||||
|
||||
|
@ -318,7 +319,7 @@ def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial,
|
|||
assert width == FIELD_ELEMENTS_PER_BLOB
|
||||
inverse_width = bls_modular_inverse(BLSFieldElement(width))
|
||||
|
||||
roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY)
|
||||
roots_of_unity_brp = bit_reversal_permutation(compute_roots_of_unity(FIELD_ELEMENTS_PER_BLOB))
|
||||
|
||||
# If we are asked to evaluate within the domain, we already know the answer
|
||||
if z in roots_of_unity_brp:
|
||||
|
@ -346,7 +347,7 @@ def blob_to_kzg_commitment(blob: Blob) -> KZGCommitment:
|
|||
Public method.
|
||||
"""
|
||||
assert len(blob) == BYTES_PER_BLOB
|
||||
return g1_lincomb(bit_reversal_permutation(KZG_SETUP_LAGRANGE), blob_to_polynomial(blob))
|
||||
return g1_lincomb(bit_reversal_permutation(KZG_SETUP_G1_LAGRANGE), blob_to_polynomial(blob))
|
||||
```
|
||||
|
||||
#### `verify_kzg_proof`
|
||||
|
@ -384,7 +385,10 @@ def verify_kzg_proof_impl(commitment: KZGCommitment,
|
|||
Verify KZG proof that ``p(z) == y`` where ``p(z)`` is the polynomial represented by ``polynomial_kzg``.
|
||||
"""
|
||||
# Verify: P - y = Q * (X - z)
|
||||
X_minus_z = bls.add(bls.bytes96_to_G2(KZG_SETUP_G2[1]), bls.multiply(bls.G2(), (BLS_MODULUS - z) % BLS_MODULUS))
|
||||
X_minus_z = bls.add(
|
||||
bls.bytes96_to_G2(KZG_SETUP_G2_MONOMIAL[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))
|
||||
return bls.pairing_check([
|
||||
[P_minus_y, bls.neg(bls.G2())],
|
||||
|
@ -434,7 +438,7 @@ def verify_kzg_proof_batch(commitments: Sequence[KZGCommitment],
|
|||
C_minus_y_lincomb = g1_lincomb(C_minus_y_as_KZGCommitments, r_powers)
|
||||
|
||||
return bls.pairing_check([
|
||||
[bls.bytes48_to_G1(proof_lincomb), bls.neg(bls.bytes96_to_G2(KZG_SETUP_G2[1]))],
|
||||
[bls.bytes48_to_G1(proof_lincomb), bls.neg(bls.bytes96_to_G2(KZG_SETUP_G2_MONOMIAL[1]))],
|
||||
[bls.add(bls.bytes48_to_G1(C_minus_y_lincomb), bls.bytes48_to_G1(proof_z_lincomb)), bls.G2()]
|
||||
])
|
||||
```
|
||||
|
@ -464,12 +468,12 @@ def compute_quotient_eval_within_domain(z: 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`.
|
||||
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)
|
||||
roots_of_unity_brp = bit_reversal_permutation(compute_roots_of_unity(FIELD_ELEMENTS_PER_BLOB))
|
||||
result = 0
|
||||
for i, omega_i in enumerate(roots_of_unity_brp):
|
||||
if omega_i == z: # skip the evaluation point in the sum
|
||||
|
@ -490,7 +494,7 @@ def compute_kzg_proof_impl(polynomial: Polynomial, z: BLSFieldElement) -> Tuple[
|
|||
"""
|
||||
Helper function for `compute_kzg_proof()` and `compute_blob_kzg_proof()`.
|
||||
"""
|
||||
roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY)
|
||||
roots_of_unity_brp = bit_reversal_permutation(compute_roots_of_unity(FIELD_ELEMENTS_PER_BLOB))
|
||||
|
||||
# For all x_i, compute p(x_i) - p(z)
|
||||
y = evaluate_polynomial_in_evaluation_form(polynomial, z)
|
||||
|
@ -510,7 +514,7 @@ def compute_kzg_proof_impl(polynomial: Polynomial, z: BLSFieldElement) -> Tuple[
|
|||
# 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)), y
|
||||
return KZGProof(g1_lincomb(bit_reversal_permutation(KZG_SETUP_G1_LAGRANGE), quotient_polynomial)), y
|
||||
```
|
||||
|
||||
#### `compute_blob_kzg_proof`
|
||||
|
|
|
@ -158,11 +158,11 @@ This applies to transports that are natively incapable of multiplexing (e.g. TCP
|
|||
and is omitted for capable transports (e.g. QUIC).
|
||||
|
||||
Two multiplexers are commonplace in libp2p implementations:
|
||||
[mplex](https://github.com/libp2p/specs/tree/master/mplex) and [yamux](https://github.com/hashicorp/yamux/blob/master/spec.md).
|
||||
[mplex](https://github.com/libp2p/specs/tree/master/mplex) and [yamux](https://github.com/libp2p/specs/blob/master/yamux/README.md).
|
||||
Their protocol IDs are, respectively: `/mplex/6.7.0` and `/yamux/1.0.0`.
|
||||
|
||||
Clients MUST support [mplex](https://github.com/libp2p/specs/tree/master/mplex)
|
||||
and MAY support [yamux](https://github.com/hashicorp/yamux/blob/master/spec.md).
|
||||
and MAY support [yamux](https://github.com/libp2p/specs/blob/master/yamux/README.md).
|
||||
If both are supported by the client, yamux MUST take precedence during negotiation.
|
||||
See the [Rationale](#design-decision-rationale) section below for tradeoffs.
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.4.0-beta.1
|
||||
1.4.0-beta.3
|
||||
|
|
|
@ -373,8 +373,8 @@ def test_invalid_signature_previous_committee(spec, state):
|
|||
current_epoch = spec.get_current_epoch(state)
|
||||
old_sync_committee = state.next_sync_committee
|
||||
|
||||
epoch_in_future_sync_commitee_period = current_epoch + 2 * spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD
|
||||
slot_in_future_sync_committee_period = epoch_in_future_sync_commitee_period * spec.SLOTS_PER_EPOCH
|
||||
epoch_in_future_sync_committee_period = current_epoch + 2 * spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD
|
||||
slot_in_future_sync_committee_period = epoch_in_future_sync_committee_period * spec.SLOTS_PER_EPOCH
|
||||
transition_to(spec, state, slot_in_future_sync_committee_period)
|
||||
|
||||
# Use the previous sync committee to produce the signature.
|
||||
|
|
|
@ -162,14 +162,34 @@ def default_balances(spec: Spec):
|
|||
return [spec.MAX_EFFECTIVE_BALANCE] * num_validators
|
||||
|
||||
|
||||
def scaled_churn_balances(spec: Spec):
|
||||
def scaled_churn_balances_min_churn_limit(spec: Spec):
|
||||
"""
|
||||
Helper method to create enough validators to scale the churn limit.
|
||||
(This is *firmly* over the churn limit -- thus the +2 instead of just +1)
|
||||
See the second argument of ``max`` in ``get_validator_churn_limit``.
|
||||
Usage: `@with_custom_state(balances_fn=scaled_churn_balances, ...)`
|
||||
Usage: `@with_custom_state(balances_fn=scaled_churn_balances_min_churn_limit, ...)`
|
||||
"""
|
||||
num_validators = spec.config.CHURN_LIMIT_QUOTIENT * (2 + spec.config.MIN_PER_EPOCH_CHURN_LIMIT)
|
||||
num_validators = spec.config.CHURN_LIMIT_QUOTIENT * (spec.config.MIN_PER_EPOCH_CHURN_LIMIT + 2)
|
||||
return [spec.MAX_EFFECTIVE_BALANCE] * num_validators
|
||||
|
||||
|
||||
def scaled_churn_balances_equal_activation_churn_limit(spec: Spec):
|
||||
"""
|
||||
Helper method to create enough validators to scale the churn limit.
|
||||
(This is *firmly* over the churn limit -- thus the +2 instead of just +1)
|
||||
Usage: `@with_custom_state(balances_fn=scaled_churn_balances_exceed_activation_churn_limit, ...)`
|
||||
"""
|
||||
num_validators = spec.config.CHURN_LIMIT_QUOTIENT * (spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT)
|
||||
return [spec.MAX_EFFECTIVE_BALANCE] * num_validators
|
||||
|
||||
|
||||
def scaled_churn_balances_exceed_activation_churn_limit(spec: Spec):
|
||||
"""
|
||||
Helper method to create enough validators to scale the churn limit.
|
||||
(This is *firmly* over the churn limit -- thus the +2 instead of just +1)
|
||||
Usage: `@with_custom_state(balances_fn=scaled_churn_balances_exceed_activation_churn_limit, ...)`
|
||||
"""
|
||||
num_validators = spec.config.CHURN_LIMIT_QUOTIENT * (spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT + 2)
|
||||
return [spec.MAX_EFFECTIVE_BALANCE] * num_validators
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
from eth2spec.test.helpers.keys import pubkeys
|
||||
from eth2spec.test.helpers.constants import MINIMAL
|
||||
from eth2spec.test.context import (
|
||||
with_deneb_and_later,
|
||||
spec_test,
|
||||
spec_state_test,
|
||||
single_phase,
|
||||
with_custom_state,
|
||||
with_presets,
|
||||
scaled_churn_balances_exceed_activation_churn_limit,
|
||||
scaled_churn_balances_equal_activation_churn_limit,
|
||||
)
|
||||
from eth2spec.test.helpers.epoch_processing import run_epoch_processing_with
|
||||
|
||||
|
||||
def run_process_registry_updates(spec, state):
|
||||
yield from run_epoch_processing_with(spec, state, 'process_registry_updates')
|
||||
|
||||
|
||||
def run_test_activation_churn_limit(spec, state):
|
||||
mock_activations = spec.get_validator_activation_churn_limit(state) * 2
|
||||
|
||||
validator_count_0 = len(state.validators)
|
||||
|
||||
for i in range(mock_activations):
|
||||
index = validator_count_0 + i
|
||||
validator = spec.Validator(
|
||||
pubkey=pubkeys[index],
|
||||
withdrawal_credentials=spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + b'\x00' * 11 + b'\x56' * 20,
|
||||
activation_eligibility_epoch=0,
|
||||
activation_epoch=spec.FAR_FUTURE_EPOCH,
|
||||
exit_epoch=spec.FAR_FUTURE_EPOCH,
|
||||
withdrawable_epoch=spec.FAR_FUTURE_EPOCH,
|
||||
effective_balance=spec.MAX_EFFECTIVE_BALANCE,
|
||||
)
|
||||
state.validators.append(validator)
|
||||
state.balances.append(spec.MAX_EFFECTIVE_BALANCE)
|
||||
state.previous_epoch_participation.append(spec.ParticipationFlags(0b0000_0000))
|
||||
state.current_epoch_participation.append(spec.ParticipationFlags(0b0000_0000))
|
||||
state.inactivity_scores.append(0)
|
||||
state.validators[index].activation_epoch = spec.FAR_FUTURE_EPOCH
|
||||
|
||||
churn_limit_0 = spec.get_validator_activation_churn_limit(state)
|
||||
|
||||
yield from run_process_registry_updates(spec, state)
|
||||
|
||||
# Half should churn in first run of registry update
|
||||
for i in range(mock_activations):
|
||||
index = validator_count_0 + i
|
||||
if index < validator_count_0 + churn_limit_0:
|
||||
# The eligible validators within the activation churn limit should have been activated
|
||||
assert state.validators[index].activation_epoch < spec.FAR_FUTURE_EPOCH
|
||||
else:
|
||||
assert state.validators[index].activation_epoch == spec.FAR_FUTURE_EPOCH
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@with_presets([MINIMAL],
|
||||
reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated")
|
||||
@spec_test
|
||||
@with_custom_state(balances_fn=scaled_churn_balances_exceed_activation_churn_limit,
|
||||
threshold_fn=lambda spec: spec.config.EJECTION_BALANCE)
|
||||
@single_phase
|
||||
def test_activation_churn_limit__greater_than_activation_limit(spec, state):
|
||||
assert spec.get_validator_activation_churn_limit(state) == spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT
|
||||
assert spec.get_validator_churn_limit(state) > spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT
|
||||
yield from run_test_activation_churn_limit(spec, state)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@with_presets([MINIMAL],
|
||||
reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated")
|
||||
@spec_test
|
||||
@with_custom_state(balances_fn=scaled_churn_balances_equal_activation_churn_limit,
|
||||
threshold_fn=lambda spec: spec.config.EJECTION_BALANCE)
|
||||
@single_phase
|
||||
def test_activation_churn_limit__equal_to_activation_limit(spec, state):
|
||||
assert spec.get_validator_activation_churn_limit(state) == spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT
|
||||
assert spec.get_validator_churn_limit(state) == spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT
|
||||
yield from run_test_activation_churn_limit(spec, state)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@with_presets([MINIMAL],
|
||||
reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated")
|
||||
@spec_state_test
|
||||
def test_activation_churn_limit__less_than_activation_limit(spec, state):
|
||||
assert spec.get_validator_activation_churn_limit(state) < spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT
|
||||
assert spec.get_validator_churn_limit(state) < spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT
|
||||
yield from run_test_activation_churn_limit(spec, state)
|
|
@ -58,7 +58,6 @@ def test_simple_blob_data(spec, state):
|
|||
assert spec.get_head(store) == signed_block.message.hash_tree_root()
|
||||
|
||||
# On receiving a block of next epoch
|
||||
store.time = current_time + spec.config.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
|
||||
block, blobs, blob_kzg_proofs = get_block_with_blob(spec, state, rng=rng)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
blob_data = BlobData(blobs, blob_kzg_proofs)
|
||||
|
|
|
@ -113,7 +113,7 @@ def test_barycentric_outside_domain(spec):
|
|||
"""
|
||||
rng = random.Random(5566)
|
||||
poly_coeff, poly_eval = get_poly_in_both_forms(spec)
|
||||
roots_of_unity_brp = spec.bit_reversal_permutation(spec.ROOTS_OF_UNITY)
|
||||
roots_of_unity_brp = spec.bit_reversal_permutation(spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB))
|
||||
|
||||
assert len(poly_coeff) == len(poly_eval) == len(roots_of_unity_brp)
|
||||
n_samples = 12
|
||||
|
@ -139,20 +139,22 @@ def test_barycentric_outside_domain(spec):
|
|||
@single_phase
|
||||
def test_barycentric_within_domain(spec):
|
||||
"""
|
||||
Test barycentric formula correctness by using it to evaluate a polynomial at all the points of its domain
|
||||
Test barycentric formula correctness by using it to evaluate a polynomial at various points inside its domain
|
||||
(the roots of unity).
|
||||
|
||||
Then make sure that we would get the same result if we evaluated it from coefficient form without using the
|
||||
barycentric formula
|
||||
"""
|
||||
rng = random.Random(5566)
|
||||
poly_coeff, poly_eval = get_poly_in_both_forms(spec)
|
||||
roots_of_unity_brp = spec.bit_reversal_permutation(spec.ROOTS_OF_UNITY)
|
||||
roots_of_unity_brp = spec.bit_reversal_permutation(spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB))
|
||||
|
||||
assert len(poly_coeff) == len(poly_eval) == len(roots_of_unity_brp)
|
||||
n = len(poly_coeff)
|
||||
|
||||
# Iterate over the entire domain
|
||||
for i in range(n):
|
||||
# Iterate over some roots of unity
|
||||
for i in range(12):
|
||||
i = rng.randint(0, n - 1)
|
||||
# Grab a root of unity and use it as the evaluation point
|
||||
z = int(roots_of_unity_brp[i])
|
||||
|
||||
|
@ -175,15 +177,17 @@ def test_compute_kzg_proof_within_domain(spec):
|
|||
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).
|
||||
"""
|
||||
rng = random.Random(5566)
|
||||
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)
|
||||
roots_of_unity_brp = spec.bit_reversal_permutation(spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB))
|
||||
|
||||
for i, z in enumerate(roots_of_unity_brp):
|
||||
# Let's test some roots of unity
|
||||
for _ in range(6):
|
||||
z = rng.choice(roots_of_unity_brp)
|
||||
proof, y = spec.compute_kzg_proof_impl(polynomial, z)
|
||||
|
||||
assert spec.verify_kzg_proof_impl(commitment, z, y, proof)
|
||||
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ def get_poly_in_both_forms(spec, rng=None):
|
|||
if rng is None:
|
||||
rng = random.Random(5566)
|
||||
|
||||
roots_of_unity_brp = spec.bit_reversal_permutation(spec.ROOTS_OF_UNITY)
|
||||
roots_of_unity_brp = spec.bit_reversal_permutation(spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB))
|
||||
|
||||
coeffs = [
|
||||
rng.randint(0, spec.BLS_MODULUS - 1)
|
||||
|
|
|
@ -3,7 +3,8 @@ from eth2spec.test.context import (
|
|||
spec_state_test,
|
||||
always_bls, with_all_phases, with_presets,
|
||||
spec_test, single_phase,
|
||||
with_custom_state, scaled_churn_balances,
|
||||
with_custom_state,
|
||||
scaled_churn_balances_min_churn_limit,
|
||||
)
|
||||
from eth2spec.test.helpers.keys import pubkey_to_privkey
|
||||
from eth2spec.test.helpers.voluntary_exits import (
|
||||
|
@ -102,7 +103,8 @@ def test_success_exit_queue__min_churn(spec, state):
|
|||
@with_presets([MINIMAL],
|
||||
reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated")
|
||||
@spec_test
|
||||
@with_custom_state(balances_fn=scaled_churn_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE)
|
||||
@with_custom_state(balances_fn=scaled_churn_balances_min_churn_limit,
|
||||
threshold_fn=lambda spec: spec.config.EJECTION_BALANCE)
|
||||
@single_phase
|
||||
def test_success_exit_queue__scaled_churn(spec, state):
|
||||
churn_limit = spec.get_validator_churn_limit(state)
|
||||
|
|
|
@ -5,7 +5,7 @@ from eth2spec.test.context import (
|
|||
spec_test, spec_state_test,
|
||||
with_all_phases, single_phase,
|
||||
with_custom_state, with_presets,
|
||||
scaled_churn_balances,
|
||||
scaled_churn_balances_min_churn_limit,
|
||||
)
|
||||
from eth2spec.test.helpers.epoch_processing import run_epoch_processing_with
|
||||
|
||||
|
@ -164,7 +164,8 @@ def test_activation_queue_efficiency_min(spec, state):
|
|||
@with_presets([MINIMAL],
|
||||
reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated")
|
||||
@spec_test
|
||||
@with_custom_state(balances_fn=scaled_churn_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE)
|
||||
@with_custom_state(balances_fn=scaled_churn_balances_min_churn_limit,
|
||||
threshold_fn=lambda spec: spec.config.EJECTION_BALANCE)
|
||||
@single_phase
|
||||
def test_activation_queue_efficiency_scaled(spec, state):
|
||||
assert spec.get_validator_churn_limit(state) > spec.config.MIN_PER_EPOCH_CHURN_LIMIT
|
||||
|
@ -227,7 +228,8 @@ def test_ejection_past_churn_limit_min(spec, state):
|
|||
@with_presets([MINIMAL],
|
||||
reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated")
|
||||
@spec_test
|
||||
@with_custom_state(balances_fn=scaled_churn_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE)
|
||||
@with_custom_state(balances_fn=scaled_churn_balances_min_churn_limit,
|
||||
threshold_fn=lambda spec: spec.config.EJECTION_BALANCE)
|
||||
@single_phase
|
||||
def test_ejection_past_churn_limit_scaled(spec, state):
|
||||
assert spec.get_validator_churn_limit(state) > spec.config.MIN_PER_EPOCH_CHURN_LIMIT
|
||||
|
@ -324,7 +326,8 @@ def test_activation_queue_activation_and_ejection__exceed_churn_limit(spec, stat
|
|||
@with_presets([MINIMAL],
|
||||
reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated")
|
||||
@spec_test
|
||||
@with_custom_state(balances_fn=scaled_churn_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE)
|
||||
@with_custom_state(balances_fn=scaled_churn_balances_min_churn_limit,
|
||||
threshold_fn=lambda spec: spec.config.EJECTION_BALANCE)
|
||||
@single_phase
|
||||
def test_activation_queue_activation_and_ejection__scaled_churn_limit(spec, state):
|
||||
churn_limit = spec.get_validator_churn_limit(state)
|
||||
|
@ -336,7 +339,8 @@ def test_activation_queue_activation_and_ejection__scaled_churn_limit(spec, stat
|
|||
@with_presets([MINIMAL],
|
||||
reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated")
|
||||
@spec_test
|
||||
@with_custom_state(balances_fn=scaled_churn_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE)
|
||||
@with_custom_state(balances_fn=scaled_churn_balances_min_churn_limit,
|
||||
threshold_fn=lambda spec: spec.config.EJECTION_BALANCE)
|
||||
@single_phase
|
||||
def test_activation_queue_activation_and_ejection__exceed_scaled_churn_limit(spec, state):
|
||||
churn_limit = spec.get_validator_churn_limit(state)
|
||||
|
|
|
@ -48,8 +48,8 @@ class fastest_bls:
|
|||
# Flag to make BLS active or not. Used for testing, do not ignore BLS in production unless you know what you are doing.
|
||||
bls_active = True
|
||||
|
||||
# To change bls implementation, default to PyECC for correctness. Milagro is a good faster alternative.
|
||||
bls = py_ecc_bls
|
||||
# Default to fastest_bls
|
||||
bls = fastest_bls
|
||||
|
||||
STUB_SIGNATURE = b'\x11' * 96
|
||||
STUB_PUBKEY = b'\x22' * 48
|
||||
|
|
|
@ -519,7 +519,7 @@ def create_provider(fork_name: SpecForkName,
|
|||
preset_name='general',
|
||||
runner_name='bls',
|
||||
handler_name=handler_name,
|
||||
suite_name='small',
|
||||
suite_name='bls',
|
||||
case_name=case_name,
|
||||
case_fn=lambda: [('data', 'data', case_content)]
|
||||
)
|
||||
|
|
|
@ -32,7 +32,10 @@ if __name__ == "__main__":
|
|||
]}
|
||||
capella_mods = combine_mods(_new_capella_mods, bellatrix_mods)
|
||||
|
||||
deneb_mods = capella_mods
|
||||
_new_deneb_mods = {key: 'eth2spec.test.deneb.epoch_processing.test_process_' + key for key in [
|
||||
'registry_updates',
|
||||
]}
|
||||
deneb_mods = combine_mods(_new_deneb_mods, capella_mods)
|
||||
|
||||
eip6110_mods = deneb_mods
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ INVALID_G1_POINTS = [G1_INVALID_TOO_FEW_BYTES, G1_INVALID_TOO_MANY_BYTES,
|
|||
G1_INVALID_P1_NOT_IN_G1, G1_INVALID_P1_NOT_ON_CURVE]
|
||||
|
||||
BLOB_ALL_ZEROS = spec.Blob()
|
||||
BLOB_ALL_TWOS = spec.Blob(b''.join([field_element_bytes(2) for n in range(4096)]))
|
||||
BLOB_RANDOM_VALID1 = spec.Blob(b''.join([field_element_bytes(pow(2, n + 256, spec.BLS_MODULUS)) for n in range(4096)]))
|
||||
BLOB_RANDOM_VALID2 = spec.Blob(b''.join([field_element_bytes(pow(3, n + 256, spec.BLS_MODULUS)) for n in range(4096)]))
|
||||
BLOB_RANDOM_VALID3 = spec.Blob(b''.join([field_element_bytes(pow(5, n + 256, spec.BLS_MODULUS)) for n in range(4096)]))
|
||||
|
@ -79,7 +80,7 @@ BLOB_INVALID_CLOSE = spec.Blob(b''.join(
|
|||
BLOB_INVALID_LENGTH_PLUS_ONE = BLOB_RANDOM_VALID1 + b"\x00"
|
||||
BLOB_INVALID_LENGTH_MINUS_ONE = BLOB_RANDOM_VALID1[:-1]
|
||||
|
||||
VALID_BLOBS = [BLOB_ALL_ZEROS, BLOB_RANDOM_VALID1, BLOB_RANDOM_VALID2,
|
||||
VALID_BLOBS = [BLOB_ALL_ZEROS, BLOB_ALL_TWOS, BLOB_RANDOM_VALID1, BLOB_RANDOM_VALID2,
|
||||
BLOB_RANDOM_VALID3, BLOB_ALL_MODULUS_MINUS_ONE, BLOB_ALMOST_ZERO]
|
||||
INVALID_BLOBS = [BLOB_INVALID, BLOB_INVALID_CLOSE, BLOB_INVALID_LENGTH_PLUS_ONE, BLOB_INVALID_LENGTH_MINUS_ONE]
|
||||
|
||||
|
@ -88,7 +89,7 @@ FE_VALID2 = field_element_bytes(1)
|
|||
FE_VALID3 = field_element_bytes(2)
|
||||
FE_VALID4 = field_element_bytes(pow(5, 1235, spec.BLS_MODULUS))
|
||||
FE_VALID5 = field_element_bytes(spec.BLS_MODULUS - 1)
|
||||
FE_VALID6 = field_element_bytes(spec.ROOTS_OF_UNITY[1])
|
||||
FE_VALID6 = field_element_bytes(spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB)[1])
|
||||
VALID_FIELD_ELEMENTS = [FE_VALID1, FE_VALID2, FE_VALID3, FE_VALID4, FE_VALID5, FE_VALID6]
|
||||
|
||||
FE_INVALID_EQUAL_TO_MODULUS = field_element_bytes_unchecked(spec.BLS_MODULUS)
|
||||
|
@ -214,6 +215,64 @@ def case03_verify_kzg_proof():
|
|||
'output': False
|
||||
}
|
||||
|
||||
# Incorrect `G1_POINT_AT_INFINITY` proof
|
||||
blob = BLOB_RANDOM_VALID1
|
||||
for z in VALID_FIELD_ELEMENTS:
|
||||
_, y = spec.compute_kzg_proof(blob, z)
|
||||
commitment = spec.blob_to_kzg_commitment(blob)
|
||||
proof = spec.G1_POINT_AT_INFINITY
|
||||
assert not spec.verify_kzg_proof(commitment, z, y, proof)
|
||||
prefix = 'verify_kzg_proof_case_incorrect_proof_point_at_infinity'
|
||||
identifier = f'{encode_hex(hash(blob))}_{encode_hex(z)}'
|
||||
yield f'{prefix}_{(hash(bytes(identifier, "utf-8"))[:8]).hex()}', {
|
||||
'input': {
|
||||
'commitment': encode_hex(commitment),
|
||||
'z': encode_hex(z),
|
||||
'y': encode_hex(y),
|
||||
'proof': encode_hex(proof),
|
||||
},
|
||||
'output': False
|
||||
}
|
||||
|
||||
# Correct `G1_POINT_AT_INFINITY` proof for zero poly
|
||||
blob = BLOB_ALL_ZEROS
|
||||
for z in VALID_FIELD_ELEMENTS:
|
||||
_, y = spec.compute_kzg_proof(blob, z)
|
||||
commitment = spec.blob_to_kzg_commitment(blob)
|
||||
proof = spec.G1_POINT_AT_INFINITY
|
||||
assert spec.verify_kzg_proof(commitment, z, y, proof)
|
||||
prefix = 'verify_kzg_proof_case_correct_proof_point_at_infinity_for_zero_poly'
|
||||
identifier = f'{encode_hex(hash(blob))}_{encode_hex(z)}'
|
||||
yield f'{prefix}_{(hash(bytes(identifier, "utf-8"))[:8]).hex()}', {
|
||||
'input': {
|
||||
'commitment': encode_hex(commitment),
|
||||
'z': encode_hex(z),
|
||||
'y': encode_hex(y),
|
||||
'proof': encode_hex(proof),
|
||||
},
|
||||
'output': True
|
||||
}
|
||||
|
||||
# Correct `G1_POINT_AT_INFINITY` proof for poly of all twos
|
||||
blob = BLOB_ALL_TWOS
|
||||
for z in VALID_FIELD_ELEMENTS:
|
||||
_, y = spec.compute_kzg_proof(blob, z)
|
||||
commitment = spec.blob_to_kzg_commitment(blob)
|
||||
proof = spec.G1_POINT_AT_INFINITY
|
||||
assert spec.verify_kzg_proof(commitment, z, y, proof)
|
||||
assert y == field_element_bytes(2)
|
||||
prefix = 'verify_kzg_proof_case_correct_proof_point_at_infinity_for_twos_poly'
|
||||
identifier = f'{encode_hex(hash(blob))}_{encode_hex(z)}'
|
||||
yield f'{prefix}_{(hash(bytes(identifier, "utf-8"))[:8]).hex()}', {
|
||||
'input': {
|
||||
'commitment': encode_hex(commitment),
|
||||
'z': encode_hex(z),
|
||||
'y': encode_hex(y),
|
||||
'proof': encode_hex(proof),
|
||||
},
|
||||
'output': True
|
||||
}
|
||||
|
||||
# Edge case: Invalid commitment
|
||||
for commitment in INVALID_G1_POINTS:
|
||||
blob, z = VALID_BLOBS[2], VALID_FIELD_ELEMENTS[1]
|
||||
|
@ -354,6 +413,50 @@ def case05_verify_blob_kzg_proof():
|
|||
'output': False
|
||||
}
|
||||
|
||||
# Incorrect `G1_POINT_AT_INFINITY` proof
|
||||
blob = BLOB_RANDOM_VALID1
|
||||
commitment = spec.blob_to_kzg_commitment(blob)
|
||||
proof = spec.G1_POINT_AT_INFINITY
|
||||
assert not spec.verify_blob_kzg_proof(blob, commitment, proof)
|
||||
yield 'verify_blob_kzg_proof_case_incorrect_proof_point_at_infinity', {
|
||||
'input': {
|
||||
'blob': encode_hex(blob),
|
||||
'commitment': encode_hex(commitment),
|
||||
'proof': encode_hex(proof),
|
||||
},
|
||||
'output': False
|
||||
}
|
||||
|
||||
# Correct `G1_POINT_AT_INFINITY` proof and commitment for zero poly
|
||||
blob = BLOB_ALL_ZEROS
|
||||
commitment = spec.blob_to_kzg_commitment(blob)
|
||||
proof = spec.G1_POINT_AT_INFINITY
|
||||
assert commitment == spec.G1_POINT_AT_INFINITY
|
||||
assert spec.verify_blob_kzg_proof(blob, commitment, proof)
|
||||
yield 'verify_blob_kzg_proof_case_correct_proof_point_at_infinity_for_zero_poly', {
|
||||
'input': {
|
||||
'blob': encode_hex(blob),
|
||||
'commitment': encode_hex(commitment),
|
||||
'proof': encode_hex(proof),
|
||||
},
|
||||
'output': True
|
||||
}
|
||||
|
||||
# Correct `G1_POINT_AT_INFINITY` proof for all twos poly
|
||||
blob = BLOB_ALL_TWOS
|
||||
commitment = spec.blob_to_kzg_commitment(blob)
|
||||
proof = spec.G1_POINT_AT_INFINITY
|
||||
assert commitment != spec.G1_POINT_AT_INFINITY
|
||||
assert spec.verify_blob_kzg_proof(blob, commitment, proof)
|
||||
yield 'verify_blob_kzg_proof_case_correct_proof_point_at_infinity_for_twos_poly', {
|
||||
'input': {
|
||||
'blob': encode_hex(blob),
|
||||
'commitment': encode_hex(commitment),
|
||||
'proof': encode_hex(proof),
|
||||
},
|
||||
'output': True
|
||||
}
|
||||
|
||||
# Edge case: Invalid blob
|
||||
for blob in INVALID_BLOBS:
|
||||
proof = G1
|
||||
|
@ -423,7 +526,7 @@ def case06_verify_blob_kzg_proof_batch():
|
|||
# Incorrect proof
|
||||
proofs_incorrect = [bls_add_one(proofs[0])] + proofs[1:]
|
||||
assert not spec.verify_blob_kzg_proof_batch(VALID_BLOBS, commitments, proofs_incorrect)
|
||||
yield 'verify_blob_kzg_proof_batch_case_invalid_proof', {
|
||||
yield 'verify_blob_kzg_proof_batch_case_incorrect_proof_add_one', {
|
||||
'input': {
|
||||
'blobs': encode_hex_list(VALID_BLOBS),
|
||||
'commitments': encode_hex_list(commitments),
|
||||
|
@ -432,6 +535,20 @@ def case06_verify_blob_kzg_proof_batch():
|
|||
'output': False
|
||||
}
|
||||
|
||||
# Incorrect `G1_POINT_AT_INFINITY` proof
|
||||
blob = BLOB_RANDOM_VALID1
|
||||
commitment = spec.blob_to_kzg_commitment(blob)
|
||||
proof = spec.G1_POINT_AT_INFINITY
|
||||
assert not spec.verify_blob_kzg_proof_batch([blob], [commitment], [proof])
|
||||
yield 'verify_blob_kzg_proof_batch_case_incorrect_proof_point_at_infinity', {
|
||||
'input': {
|
||||
'blobs': encode_hex_list([blob]),
|
||||
'commitments': encode_hex_list([commitment]),
|
||||
'proofs': encode_hex_list([proof]),
|
||||
},
|
||||
'output': False
|
||||
}
|
||||
|
||||
# Edge case: Invalid blobs
|
||||
for blob in INVALID_BLOBS:
|
||||
blobs_invalid = VALID_BLOBS[:4] + [blob] + VALID_BLOBS[5:]
|
||||
|
@ -527,7 +644,7 @@ def create_provider(fork_name: SpecForkName,
|
|||
preset_name='general',
|
||||
runner_name='kzg',
|
||||
handler_name=handler_name,
|
||||
suite_name='small',
|
||||
suite_name='kzg-mainnet',
|
||||
case_name=case_name,
|
||||
case_fn=lambda: [('data', 'data', case_content)]
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue