Merge pull request #3523 from ethereum/dev

[DO NOT MERGE] release v1.4.0-beta.3
This commit is contained in:
danny 2023-10-18 11:19:24 -06:00 committed by GitHub
commit 820f62d481
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 8527 additions and 96 deletions

View File

@ -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.

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -415,38 +415,21 @@ def get_initial_tracker(k: BLSFieldElement) -> WhiskTracker:
```
```python
def apply_deposit(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):
index = get_index_for_new_validator(state)
validator = get_validator_from_deposit(pubkey, withdrawal_credentials, amount)
set_or_append_list(state.validators, index, validator)
set_or_append_list(state.balances, index, amount)
set_or_append_list(state.previous_epoch_participation, index, ParticipationFlags(0b0000_0000))
set_or_append_list(state.current_epoch_participation, index, ParticipationFlags(0b0000_0000))
set_or_append_list(state.inactivity_scores, index, uint64(0))
# [New in Whisk]
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)
def add_validator_to_registry(state: BeaconState,
pubkey: BLSPubkey,
withdrawal_credentials: Bytes32,
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)
set_or_append_list(state.balances, index, amount)
set_or_append_list(state.previous_epoch_participation, index, ParticipationFlags(0b0000_0000))
set_or_append_list(state.current_epoch_participation, index, ParticipationFlags(0b0000_0000))
set_or_append_list(state.inactivity_scores, index, uint64(0))
# [New in Whisk]
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))
```
### `get_beacon_proposer_index`

View File

@ -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:

View File

@ -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)`

View File

@ -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`

View File

@ -1 +1 @@
1.4.0-beta.2
1.4.0-beta.3

View File

@ -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.

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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:]