From e4c75d67ceee50236dd867f91b6fe5ddf4c0d16d Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 13 Jun 2022 15:30:12 +0300 Subject: [PATCH 1/8] Introduce high-level logic of new efficient block validation --- specs/eip4844/beacon-chain.md | 1 + specs/eip4844/p2p-interface.md | 2 ++ specs/eip4844/validator.md | 20 ++++++++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index 8c84a2862..6011e5832 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -45,6 +45,7 @@ This upgrade adds blobs to the beacon chain as part of EIP-4844. | `Blob` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | | | `VersionedHash` | `Bytes32` | | | `KZGCommitment` | `Bytes48` | Same as BLS standard "is valid pubkey" check but also allows `0x00..00` for point-at-infinity | +| `KZGProof` | Bytes48 | Same as for `KZGCommitment` | ## Constants diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index 68c984950..7a447dbd4 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -57,6 +57,7 @@ class BlobsSidecar(Container): beacon_block_root: Root beacon_block_slot: Slot blobs: List[Blob, MAX_BLOBS_PER_BLOCK] + kzg_aggregated_proof: KZGProof ``` ### `SignedBlobsSidecar` @@ -114,6 +115,7 @@ The following validations MUST pass before forwarding the `signed_blobs_sidecar` Alias `sidecar = signed_blobs_sidecar.message`. - _[IGNORE]_ the `sidecar.beacon_block_slot` is for the current slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- i.e. `blobs_sidecar.beacon_block_slot == current_slot`. - _[REJECT]_ the `sidecar.blobs` are all well formatted, i.e. the `BLSFieldElement` in valid range (`x < BLS_MODULUS`). +- _[REJECT]_ The KZG proof is a correctly encoded compressed BLS G1 Point -- i.e. `bls.KeyValidate(blobs_sidecar.kzg_aggregated_proof) - _[REJECT]_ the beacon proposer signature, `signed_blobs_sidecar.signature`, is valid -- i.e. ```python domain = get_domain(state, DOMAIN_BLOBS_SIDECAR, blobs_sidecar.beacon_block_slot // SLOTS_PER_EPOCH) diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index 2083934c5..aed38639f 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -59,9 +59,25 @@ def verify_blobs_sidecar(slot: Slot, beacon_block_root: Root, assert slot == blobs_sidecar.beacon_block_slot assert beacon_block_root == blobs_sidecar.beacon_block_root blobs = blobs_sidecar.blobs + kzg_aggregated_proof = blobs_sidecar.kzg_aggregated_proof assert len(expected_kzgs) == len(blobs) - for kzg, blob in zip(expected_kzgs, blobs): - assert blob_to_kzg(blob) == kzg + + # Generate random linear combination challenges + r = hash_to_bls_field([blobs, expected_kzgs]) + r_powers = compute_powers(r, len(expected_kzgs)) + + # Compute commitment to aggregated polynomial + aggregated_poly_commitment = lincomb(expected_kzgs, r_powers) + + # Create aggregated polynomial in evaluation form + aggregated_poly = vector_lincomb(blobs, r_powers) + + # Generate challenge `x` and evaluate the aggregated polynomial at `x` + x = hash_to_bls_field([aggregated_poly, aggregated_poly_commitment]) + y = evaluate_polynomial_in_evaluation_form(aggregated_poly, x) + + # Verify aggregated proof + assert verify_kzg_proof(aggregated_poly_commitment, x, y, kzg_aggregated_proof) ``` From 4be0b9d6bc7bc964ce15502759bc637882a757dc Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 13 Jun 2022 15:36:31 +0300 Subject: [PATCH 2/8] Add needed math/crypto functions to validate KZG aggregated proofs All code pretty much straight up copied from https://github.com/ethereum/EIPs/pull/5088 --- specs/eip4844/beacon-chain.md | 19 ++++---- specs/eip4844/validator.md | 81 +++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 8 deletions(-) diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index 6011e5832..ad8731736 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -54,6 +54,7 @@ This upgrade adds blobs to the beacon chain as part of EIP-4844. | `BLOB_TX_TYPE` | `uint8(0x05)` | | `FIELD_ELEMENTS_PER_BLOB` | `4096` | | `BLS_MODULUS` | `52435875175126190479447740508185965837690552500527637822603658699938581184513` | +| `ROOTS_OF_UNITY` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | ### Domain types @@ -110,15 +111,17 @@ KZG core functions. These are also defined in EIP-4844 execution specs. #### `blob_to_kzg` ```python +def lincomb(points: List[KZGCommitment], scalars: List[BLSFieldElement]) -> KZGCommitment: + """ + BLS multiscalar multiplication. This function can be optimized using Pippenger's algorithm and variants. + """ + r = bls.Z1 + for x, a in zip(points, scalars): + r = bls.add(r, bls.multiply(x, a)) + return r + def blob_to_kzg(blob: Blob) -> KZGCommitment: - computed_kzg = bls.Z1 - for value, point_kzg in zip(blob, KZG_SETUP_LAGRANGE): - assert value < BLS_MODULUS - computed_kzg = bls.add( - computed_kzg, - bls.multiply(point_kzg, value) - ) - return computed_kzg + return lincomb(blob, KZG_SETUP_LAGRANGE) ``` #### `kzg_to_versioned_hash` diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index aed38639f..c3dd83a41 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -54,6 +54,87 @@ def is_data_available(slot: Slot, beacon_block_root: Root, kzgs: Sequence[KZGCom ### `verify_blobs_sidecar` ```python +def hash_to_bls_field(x: Container) -> BLSFieldElement: + """ + This function is used to generate Fiat-Shamir challenges. The output is not uniform over the BLS field. + """ + return int.from_bytes(hash_tree_root(x), "little") % BLS_MODULUS + + +def compute_powers(x: BLSFieldElement, n: uint64) -> List[BLSFieldElement]: + current_power = 1 + powers = [] + for _ in range(n): + powers.append(BLSFieldElement(current_power)) + current_power = current_power * int(x) % BLS_MODULUS + return powers + + +def vector_lincomb(vectors: List[List[BLSFieldElement]], scalars: List[BLSFieldElement]) -> List[BLSFieldElement]: + """ + Given a list of vectors, compute the linear combination of each column with `scalars`, and return the resulting + vector. + """ + r = [0]*len(vectors[0]) + for v, a in zip(vectors, scalars): + for i, x in enumerate(v): + r[i] = (r[i] + a * x) % BLS_MODULUS + return [BLSFieldElement(x) for x in r] + + +def bls_modular_inverse(x: BLSFieldElement) -> BLSFieldElement: + """ + Compute the modular inverse of x using the eGCD algorithm + i.e. return y such that x * y % BLS_MODULUS == 1 and return 0 for x == 0 + """ + if x == 0: + return 0 + + lm, hm = 1, 0 + low, high = x % BLS_MODULUS, BLS_MODULUS + while low > 1: + r = high // low + nm, new = hm - lm * r, high - low * r + lm, low, hm, high = nm, new, lm, low + return lm % BLS_MODULUS + + +def div(x, y): + """Divide two field elements: `x` by `y`""" + return x * inv(y) % MODULUS + + +def verify_kzg_proof(polynomial_kzg: KZGCommitment, + x: BLSFieldElement, + y: BLSFieldElement, + quotient_kzg: KZGProof) -> bool: + """Verify KZG proof that `p(x) == y` where `p(x)` is the polynomial represented by `polynomial_kzg`""" + # Verify: P - y = Q * (X - x) + X_minus_x = bls.add(KZG_SETUP_G2[1], bls.multiply(bls.G2, BLS_MODULUS - x)) + P_minus_y = bls.add(polynomial_kzg, bls.multiply(bls.G1, BLS_MODULUS - y)) + return bls.pairing_check([ + [P_minus_y, bls.neg(bls.G2)], + [quotient_kzg, X_minus_x] + ]) + + +def evaluate_polynomial_in_evaluation_form(poly: List[BLSFieldElement], x: BLSFieldElement) -> BLSFieldElement: + """ + Evaluate a polynomial (in evaluation form) at an arbitrary point `x` + Uses the barycentric formula: + f(x) = (1 - x**WIDTH) / WIDTH * sum_(i=0)^WIDTH (f(DOMAIN[i]) * DOMAIN[i]) / (x - DOMAIN[i]) + """ + width = len(poly) + assert width == FIELD_ELEMENTS_PER_BLOB + inverse_width = bls_modular_inverse(width) + + for i in range(width): + r += div(poly[i] * ROOTS_OF_UNITY[i], (x - ROOTS_OF_UNITY[i]) ) + r = r * (pow(x, width, BLS_MODULUS) - 1) * inverse_width % BLS_MODULUS + + return r + + def verify_blobs_sidecar(slot: Slot, beacon_block_root: Root, expected_kzgs: Sequence[KZGCommitment], blobs_sidecar: BlobsSidecar): assert slot == blobs_sidecar.beacon_block_slot From 8a70295a84f1774bb1d5aec8130b14a0ee02008d Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 20 Jun 2022 21:26:41 +0800 Subject: [PATCH 3/8] Fix ToC --- specs/eip4844/beacon-chain.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index ad8731736..2aa5723e6 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -20,6 +20,7 @@ - [`BeaconBlockBody`](#beaconblockbody) - [Helper functions](#helper-functions) - [KZG core](#kzg-core) + - [`lincomb`](#lincomb) - [`blob_to_kzg`](#blob_to_kzg) - [`kzg_to_versioned_hash`](#kzg_to_versioned_hash) - [Misc](#misc) @@ -108,7 +109,7 @@ class BeaconBlockBody(Container): KZG core functions. These are also defined in EIP-4844 execution specs. -#### `blob_to_kzg` +#### `lincomb` ```python def lincomb(points: List[KZGCommitment], scalars: List[BLSFieldElement]) -> KZGCommitment: @@ -119,7 +120,11 @@ def lincomb(points: List[KZGCommitment], scalars: List[BLSFieldElement]) -> KZGC for x, a in zip(points, scalars): r = bls.add(r, bls.multiply(x, a)) return r +``` +#### `blob_to_kzg` + +```python def blob_to_kzg(blob: Blob) -> KZGCommitment: return lincomb(blob, KZG_SETUP_LAGRANGE) ``` From 534a9d1d958ff4fcb4db2f6be808b9892b009d4b Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Wed, 22 Jun 2022 15:13:41 +0300 Subject: [PATCH 4/8] Move EIP-4844 cryptography code to its own file --- specs/eip4844/beacon-chain.md | 50 +------- specs/eip4844/polynomial-commitments.md | 153 ++++++++++++++++++++++++ specs/eip4844/validator.md | 53 -------- 3 files changed, 155 insertions(+), 101 deletions(-) create mode 100644 specs/eip4844/polynomial-commitments.md diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index 2aa5723e6..537b294c7 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -12,18 +12,13 @@ - [Custom types](#custom-types) - [Constants](#constants) - [Domain types](#domain-types) -- [Preset](#preset) - - [Trusted setup](#trusted-setup) - [Configuration](#configuration) - [Containers](#containers) - [Extended containers](#extended-containers) - [`BeaconBlockBody`](#beaconblockbody) - [Helper functions](#helper-functions) - - [KZG core](#kzg-core) - - [`lincomb`](#lincomb) - - [`blob_to_kzg`](#blob_to_kzg) - - [`kzg_to_versioned_hash`](#kzg_to_versioned_hash) - [Misc](#misc) + - [`kzg_to_versioned_hash`](#kzg_to_versioned_hash) - [`tx_peek_blob_versioned_hashes`](#tx_peek_blob_versioned_hashes) - [`verify_kzgs_against_transactions`](#verify_kzgs_against_transactions) - [Beacon chain state transition function](#beacon-chain-state-transition-function) @@ -42,11 +37,8 @@ This upgrade adds blobs to the beacon chain as part of EIP-4844. | Name | SSZ equivalent | Description | | - | - | - | -| `BLSFieldElement` | `uint256` | `x < BLS_MODULUS` | | `Blob` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | | | `VersionedHash` | `Bytes32` | | -| `KZGCommitment` | `Bytes48` | Same as BLS standard "is valid pubkey" check but also allows `0x00..00` for point-at-infinity | -| `KZGProof` | Bytes48 | Same as for `KZGCommitment` | ## Constants @@ -54,8 +46,6 @@ This upgrade adds blobs to the beacon chain as part of EIP-4844. | - | - | | `BLOB_TX_TYPE` | `uint8(0x05)` | | `FIELD_ELEMENTS_PER_BLOB` | `4096` | -| `BLS_MODULUS` | `52435875175126190479447740508185965837690552500527637822603658699938581184513` | -| `ROOTS_OF_UNITY` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | ### Domain types @@ -63,18 +53,6 @@ This upgrade adds blobs to the beacon chain as part of EIP-4844. | - | - | | `DOMAIN_BLOBS_SIDECAR` | `DomainType('0x0a000000')` | -## Preset - -### 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` | `Vector[G2Point, FIELD_ELEMENTS_PER_BLOB]`, contents TBD | -| `KZG_SETUP_LAGRANGE` | `Vector[KZGCommitment, FIELD_ELEMENTS_PER_BLOB]`, contents TBD | - ## Configuration @@ -105,29 +83,7 @@ class BeaconBlockBody(Container): ## Helper functions -### KZG core - -KZG core functions. These are also defined in EIP-4844 execution specs. - -#### `lincomb` - -```python -def lincomb(points: List[KZGCommitment], scalars: List[BLSFieldElement]) -> KZGCommitment: - """ - BLS multiscalar multiplication. This function can be optimized using Pippenger's algorithm and variants. - """ - r = bls.Z1 - for x, a in zip(points, scalars): - r = bls.add(r, bls.multiply(x, a)) - return r -``` - -#### `blob_to_kzg` - -```python -def blob_to_kzg(blob: Blob) -> KZGCommitment: - return lincomb(blob, KZG_SETUP_LAGRANGE) -``` +### Misc #### `kzg_to_versioned_hash` @@ -136,8 +92,6 @@ def kzg_to_versioned_hash(kzg: KZGCommitment) -> VersionedHash: return BLOB_COMMITMENT_VERSION_KZG + hash(kzg)[1:] ``` -### Misc - #### `tx_peek_blob_versioned_hashes` This function retrieves the hashes from the `SignedBlobTransaction` as defined in EIP-4844, using SSZ offsets. diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md new file mode 100644 index 000000000..df5aad146 --- /dev/null +++ b/specs/eip4844/polynomial-commitments.md @@ -0,0 +1,153 @@ +# EIP-4844 -- Polynomial Commitments + +## Table of contents + + + + + +- [Introduction](#introduction) +- [Custom types](#custom-types) +- [Constants](#constants) +- [Preset](#preset) + - [Trusted setup](#trusted-setup) +- [Helper functions](#helper-functions) + - [BLS12-381 helpers](#bls12-381-helpers) + - [`bls_modular_inverse`](#bls_modular_inverse) + - [`div`](#div) + - [`lincomb`](#lincomb) + - [KZG](#kzg) + - [`blob_to_kzg`](#blob_to_kzg) + - [`verify_kzg_proof`](#verify_kzg_proof) + - [Polynomials](#polynomials) + - [`evaluate_polynomial_in_evaluation_form`](#evaluate_polynomial_in_evaluation_form) + + + + + +## Introduction + +This document specifies basic polynomial operations and KZG polynomial commitment operations as they are needed for the EIP-4844 specification. The implementations are not optimized for performance, but readability. All practical implementations should optimize the polynomial operations. + +## Custom types + +| Name | SSZ equivalent | Description | +| - | - | - | +| `BLSFieldElement` | `uint256` | `x < BLS_MODULUS` | +| `KZGCommitment` | `Bytes48` | Same as BLS standard "is valid pubkey" check but also allows `0x00..00` for point-at-infinity | +| `KZGProof` | `Bytes48` | Same as for `KZGCommitment` | + +## Constants + +| Name | Value | Notes | +| - | - | - | +| `BLS_MODULUS` | `52435875175126190479447740508185965837690552500527637822603658699938581184513` | Scalar field modulus of BLS12-381 | +| `ROOTS_OF_UNITY` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | Roots of unity of order FIELD_ELEMENTS_PER_BLOB over the BLS12-381 field | + +## Preset + +### 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` | `Vector[G2Point, FIELD_ELEMENTS_PER_BLOB]`, contents TBD | +| `KZG_SETUP_LAGRANGE` | `Vector[KZGCommitment, FIELD_ELEMENTS_PER_BLOB]`, contents TBD | + +## Helper functions + +### BLS12-381 helpers + +#### `bls_modular_inverse` + +```python +def bls_modular_inverse(x: BLSFieldElement) -> BLSFieldElement: + """ + Compute the modular inverse of x using the eGCD algorithm + i.e. return y such that x * y % BLS_MODULUS == 1 and return 0 for x == 0 + """ + if x == 0: + return 0 + + lm, hm = 1, 0 + low, high = x % BLS_MODULUS, BLS_MODULUS + while low > 1: + r = high // low + nm, new = hm - lm * r, high - low * r + lm, low, hm, high = nm, new, lm, low + return lm % BLS_MODULUS +``` + +#### `div` + +```python +def div(x, y): + """Divide two field elements: `x` by `y`""" + return x * inv(y) % BLS_MODULUS +``` + +#### `lincomb` + +```python +def lincomb(points: List[KZGCommitment], scalars: List[BLSFieldElement]) -> KZGCommitment: + """ + BLS multiscalar multiplication. This function can be optimized using Pippenger's algorithm and variants. + """ + r = bls.Z1 + for x, a in zip(points, scalars): + r = bls.add(r, bls.multiply(x, a)) + return r +``` + +### KZG + +KZG core functions. These are also defined in EIP-4844 execution specs. + +#### `blob_to_kzg` + +```python +def blob_to_kzg(blob: Blob) -> KZGCommitment: + return lincomb(KZG_SETUP_LAGRANGE, blob) +``` + +#### `verify_kzg_proof` + +```python +def verify_kzg_proof(polynomial_kzg: KZGCommitment, + x: BLSFieldElement, + y: BLSFieldElement, + quotient_kzg: KZGProof) -> bool: + """Verify KZG proof that `p(x) == y` where `p(x)` is the polynomial represented by `polynomial_kzg`""" + # Verify: P - y = Q * (X - x) + X_minus_x = bls.add(KZG_SETUP_G2[1], bls.multiply(bls.G2, BLS_MODULUS - x)) + P_minus_y = bls.add(polynomial_kzg, bls.multiply(bls.G1, BLS_MODULUS - y)) + return bls.pairing_check([ + [P_minus_y, bls.neg(bls.G2)], + [quotient_kzg, X_minus_x] + ]) +``` + +### Polynomials + +#### `evaluate_polynomial_in_evaluation_form` + +```python +def evaluate_polynomial_in_evaluation_form(poly: List[BLSFieldElement], x: BLSFieldElement) -> BLSFieldElement: + """ + Evaluate a polynomial (in evaluation form) at an arbitrary point `x` + Uses the barycentric formula: + f(x) = (1 - x**WIDTH) / WIDTH * sum_(i=0)^WIDTH (f(DOMAIN[i]) * DOMAIN[i]) / (x - DOMAIN[i]) + """ + width = len(poly) + assert width == FIELD_ELEMENTS_PER_BLOB + inverse_width = bls_modular_inverse(width) + + for i in range(width): + r += div(poly[i] * ROOTS_OF_UNITY[i], (x - ROOTS_OF_UNITY[i]) ) + r = r * (pow(x, width, BLS_MODULUS) - 1) * inverse_width % BLS_MODULUS + + return r +``` diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index c3dd83a41..d636b39e4 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -82,59 +82,6 @@ def vector_lincomb(vectors: List[List[BLSFieldElement]], scalars: List[BLSFieldE return [BLSFieldElement(x) for x in r] -def bls_modular_inverse(x: BLSFieldElement) -> BLSFieldElement: - """ - Compute the modular inverse of x using the eGCD algorithm - i.e. return y such that x * y % BLS_MODULUS == 1 and return 0 for x == 0 - """ - if x == 0: - return 0 - - lm, hm = 1, 0 - low, high = x % BLS_MODULUS, BLS_MODULUS - while low > 1: - r = high // low - nm, new = hm - lm * r, high - low * r - lm, low, hm, high = nm, new, lm, low - return lm % BLS_MODULUS - - -def div(x, y): - """Divide two field elements: `x` by `y`""" - return x * inv(y) % MODULUS - - -def verify_kzg_proof(polynomial_kzg: KZGCommitment, - x: BLSFieldElement, - y: BLSFieldElement, - quotient_kzg: KZGProof) -> bool: - """Verify KZG proof that `p(x) == y` where `p(x)` is the polynomial represented by `polynomial_kzg`""" - # Verify: P - y = Q * (X - x) - X_minus_x = bls.add(KZG_SETUP_G2[1], bls.multiply(bls.G2, BLS_MODULUS - x)) - P_minus_y = bls.add(polynomial_kzg, bls.multiply(bls.G1, BLS_MODULUS - y)) - return bls.pairing_check([ - [P_minus_y, bls.neg(bls.G2)], - [quotient_kzg, X_minus_x] - ]) - - -def evaluate_polynomial_in_evaluation_form(poly: List[BLSFieldElement], x: BLSFieldElement) -> BLSFieldElement: - """ - Evaluate a polynomial (in evaluation form) at an arbitrary point `x` - Uses the barycentric formula: - f(x) = (1 - x**WIDTH) / WIDTH * sum_(i=0)^WIDTH (f(DOMAIN[i]) * DOMAIN[i]) / (x - DOMAIN[i]) - """ - width = len(poly) - assert width == FIELD_ELEMENTS_PER_BLOB - inverse_width = bls_modular_inverse(width) - - for i in range(width): - r += div(poly[i] * ROOTS_OF_UNITY[i], (x - ROOTS_OF_UNITY[i]) ) - r = r * (pow(x, width, BLS_MODULUS) - 1) * inverse_width % BLS_MODULUS - - return r - - def verify_blobs_sidecar(slot: Slot, beacon_block_root: Root, expected_kzgs: Sequence[KZGCommitment], blobs_sidecar: BlobsSidecar): assert slot == blobs_sidecar.beacon_block_slot From e7e520791d27dad6c82d63611d89b8ddcf3b6aac Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Wed, 22 Jun 2022 15:19:24 +0300 Subject: [PATCH 5/8] Use Python's pow() in bls_modular_inverse(). --- specs/eip4844/polynomial-commitments.md | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index df5aad146..9558641c6 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -66,19 +66,10 @@ but reusing the `mainnet` settings in public networks is a critical security req ```python def bls_modular_inverse(x: BLSFieldElement) -> BLSFieldElement: """ - Compute the modular inverse of x using the eGCD algorithm + Compute the modular inverse of x i.e. return y such that x * y % BLS_MODULUS == 1 and return 0 for x == 0 """ - if x == 0: - return 0 - - lm, hm = 1, 0 - low, high = x % BLS_MODULUS, BLS_MODULUS - while low > 1: - r = high // low - nm, new = hm - lm * r, high - low * r - lm, low, hm, high = nm, new, lm, low - return lm % BLS_MODULUS + return pow(x, -1, BLS_MODULUS) if x != 0 else 0 ``` #### `div` From 0ab280d396ca6566deda294466e92b87f34a5d59 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 23 Jun 2022 18:40:09 +0800 Subject: [PATCH 6/8] minor suggestions --- specs/eip4844/polynomial-commitments.md | 8 +++++--- specs/eip4844/validator.md | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index 9558641c6..fc2339659 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -75,7 +75,7 @@ def bls_modular_inverse(x: BLSFieldElement) -> BLSFieldElement: #### `div` ```python -def div(x, y): +def div(x: BLSFieldElement, y: BLSFieldElement) -> BLSFieldElement: """Divide two field elements: `x` by `y`""" return x * inv(y) % BLS_MODULUS ``` @@ -111,7 +111,9 @@ def verify_kzg_proof(polynomial_kzg: KZGCommitment, x: BLSFieldElement, y: BLSFieldElement, quotient_kzg: KZGProof) -> bool: - """Verify KZG proof that `p(x) == y` where `p(x)` is the polynomial represented by `polynomial_kzg`""" + """ + Verify KZG proof that ``p(x) == y`` where ``p(x)`` is the polynomial represented by ``polynomial_kzg``. + """ # Verify: P - y = Q * (X - x) X_minus_x = bls.add(KZG_SETUP_G2[1], bls.multiply(bls.G2, BLS_MODULUS - x)) P_minus_y = bls.add(polynomial_kzg, bls.multiply(bls.G1, BLS_MODULUS - y)) @@ -137,7 +139,7 @@ def evaluate_polynomial_in_evaluation_form(poly: List[BLSFieldElement], x: BLSFi inverse_width = bls_modular_inverse(width) for i in range(width): - r += div(poly[i] * ROOTS_OF_UNITY[i], (x - ROOTS_OF_UNITY[i]) ) + r += div(poly[i] * ROOTS_OF_UNITY[i], (x - ROOTS_OF_UNITY[i])) r = r * (pow(x, width, BLS_MODULUS) - 1) * inverse_width % BLS_MODULUS return r diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index d636b39e4..fb96282c0 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -83,7 +83,7 @@ def vector_lincomb(vectors: List[List[BLSFieldElement]], scalars: List[BLSFieldE def verify_blobs_sidecar(slot: Slot, beacon_block_root: Root, - expected_kzgs: Sequence[KZGCommitment], blobs_sidecar: BlobsSidecar): + expected_kzgs: Sequence[KZGCommitment], blobs_sidecar: BlobsSidecar) -> None: assert slot == blobs_sidecar.beacon_block_slot assert beacon_block_root == blobs_sidecar.beacon_block_root blobs = blobs_sidecar.blobs From 94da861d9c1b6b7d1424337c187aa5d924be0266 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 23 Jun 2022 18:44:37 +0800 Subject: [PATCH 7/8] Fix ToC --- specs/eip4844/validator.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index fb96282c0..fba328df1 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -12,6 +12,9 @@ - [Prerequisites](#prerequisites) - [Helpers](#helpers) - [`is_data_available`](#is_data_available) + - [`hash_to_bls_field`](#hash_to_bls_field) + - [`compute_powers`](#compute_powers) + - [`vector_lincomb`](#vector_lincomb) - [`verify_blobs_sidecar`](#verify_blobs_sidecar) - [Beacon chain responsibilities](#beacon-chain-responsibilities) - [Block proposal](#block-proposal) @@ -40,7 +43,7 @@ Please see related Beacon Chain doc before continuing and use them as a referenc The implementation of `is_data_available` is meant to change with later sharding upgrades. Initially, it requires every verifying actor to retrieve the matching `BlobsSidecar`, -and verify the sidecar with `verify_blobs`. +and verify the sidecar with `verify_blobs_sidecar`. Without the sidecar the block may be processed further optimistically, but MUST NOT be considered valid until a valid `BlobsSidecar` has been downloaded. @@ -51,7 +54,7 @@ def is_data_available(slot: Slot, beacon_block_root: Root, kzgs: Sequence[KZGCom verify_blobs_sidecar(slot, beacon_block_root, kzgs, sidecar) ``` -### `verify_blobs_sidecar` +### `hash_to_bls_field` ```python def hash_to_bls_field(x: Container) -> BLSFieldElement: @@ -59,8 +62,10 @@ def hash_to_bls_field(x: Container) -> BLSFieldElement: This function is used to generate Fiat-Shamir challenges. The output is not uniform over the BLS field. """ return int.from_bytes(hash_tree_root(x), "little") % BLS_MODULUS +``` - +### `compute_powers` +```python def compute_powers(x: BLSFieldElement, n: uint64) -> List[BLSFieldElement]: current_power = 1 powers = [] @@ -68,8 +73,11 @@ def compute_powers(x: BLSFieldElement, n: uint64) -> List[BLSFieldElement]: powers.append(BLSFieldElement(current_power)) current_power = current_power * int(x) % BLS_MODULUS return powers +``` +### `vector_lincomb` +```python def vector_lincomb(vectors: List[List[BLSFieldElement]], scalars: List[BLSFieldElement]) -> List[BLSFieldElement]: """ Given a list of vectors, compute the linear combination of each column with `scalars`, and return the resulting @@ -80,8 +88,11 @@ def vector_lincomb(vectors: List[List[BLSFieldElement]], scalars: List[BLSFieldE for i, x in enumerate(v): r[i] = (r[i] + a * x) % BLS_MODULUS return [BLSFieldElement(x) for x in r] +``` +### `verify_blobs_sidecar` +```python def verify_blobs_sidecar(slot: Slot, beacon_block_root: Root, expected_kzgs: Sequence[KZGCommitment], blobs_sidecar: BlobsSidecar) -> None: assert slot == blobs_sidecar.beacon_block_slot @@ -108,7 +119,6 @@ def verify_blobs_sidecar(slot: Slot, beacon_block_root: Root, assert verify_kzg_proof(aggregated_poly_commitment, x, y, kzg_aggregated_proof) ``` - ## Beacon chain responsibilities All validator responsibilities remain unchanged other than those noted below. @@ -175,4 +185,3 @@ The validator MUST hold on to blobs for `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` to ensure the data-availability of these blobs throughout the network. After `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` nodes MAY prune the blobs and/or stop serving them. - From a3339c7b7fdc4eb80e5a700542acd90ade424d50 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 25 Jun 2022 00:13:20 +0800 Subject: [PATCH 8/8] PR suggestion from @Inphi --- specs/eip4844/polynomial-commitments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index fc2339659..5d1b86895 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -77,7 +77,7 @@ def bls_modular_inverse(x: BLSFieldElement) -> BLSFieldElement: ```python def div(x: BLSFieldElement, y: BLSFieldElement) -> BLSFieldElement: """Divide two field elements: `x` by `y`""" - return x * inv(y) % BLS_MODULUS + return x * bls_modular_inverse(y) % BLS_MODULUS ``` #### `lincomb`