Skip to content

Commit

Permalink
EIP4844: Implement reverse bit ordering in KZG commitments
Browse files Browse the repository at this point in the history
Co-authored-by: Dankrad Feist <mail@dankradfeist.de>
Co-authored-by: Hsiao-Wei Wang <hsiaowei.eth@gmail.com>
  • Loading branch information
3 people authored Sep 26, 2022
1 parent 189d61e commit f4ba8b5
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 6 deletions.
9 changes: 8 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -589,9 +589,16 @@ def imports(cls, preset_name: str):
from eth2spec.utils.ssz.ssz_impl import serialize as ssz_serialize
'''


@classmethod
def preparations(cls):
return super().preparations() + '\n' + '''
T = TypeVar('T') # For generic function
'''

@classmethod
def sundry_functions(cls) -> str:
return super().sundry_functions() + '''
return super().sundry_functions() + '\n\n' + '''
# TODO: for mainnet, load pre-generated trusted setup file to reduce building time.
# TESTING_FIELD_ELEMENTS_PER_BLOB is hardcoded copy from minimal presets
TESTING_FIELD_ELEMENTS_PER_BLOB = 4
Expand Down
59 changes: 54 additions & 5 deletions specs/eip4844/polynomial-commitments.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
- [Preset](#preset)
- [Trusted setup](#trusted-setup)
- [Helper functions](#helper-functions)
- [Bit-reversal permutation](#bit-reversal-permutation)
- [`is_power_of_two`](#is_power_of_two)
- [`reverse_bits`](#reverse_bits)
- [`bit_reversal_permutation`](#bit_reversal_permutation)
- [BLS12-381 helpers](#bls12-381-helpers)
- [`bls_modular_inverse`](#bls_modular_inverse)
- [`div`](#div)
Expand Down Expand Up @@ -64,6 +68,47 @@ but reusing the `mainnet` settings in public networks is a critical security req

## Helper functions

### Bit-reversal permutation

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
have to be called once at startup.

#### `is_power_of_two`

```python
def is_power_of_two(value: int) -> bool:
"""
Check if ``value`` is a power of two integer.
"""
return (value > 0) and (value & (value - 1) == 0)
```

#### `reverse_bits`

```python
def reverse_bits(n: int, order: int) -> int:
"""
Reverse the bit order of an integer n
"""
assert is_power_of_two(order)
# Convert n to binary with the same number of bits as "order" - 1, then reverse its bit order
return int(('{:0' + str(order.bit_length() - 1) + 'b}').format(n)[::-1], 2)
```

#### `bit_reversal_permutation`

```python
def bit_reversal_permutation(l: Sequence[T]) -> Sequence[T]:
"""
Return a copy with bit-reversed permutation. This operation is idempotent.
The input and output are a sequence of generic type ``T`` objects.
"""
return [l[reverse_bits(i, len(l))] for i in range(len(l))]
```

### BLS12-381 helpers

#### `bls_modular_inverse`
Expand Down Expand Up @@ -123,7 +168,7 @@ KZG core functions. These are also defined in EIP-4844 execution specs.

```python
def blob_to_kzg_commitment(blob: Blob) -> KZGCommitment:
return g1_lincomb(KZG_SETUP_LAGRANGE, blob)
return g1_lincomb(bit_reversal_permutation(KZG_SETUP_LAGRANGE), blob)
```

#### `verify_kzg_proof`
Expand All @@ -149,7 +194,9 @@ def verify_kzg_proof(polynomial_kzg: KZGCommitment,

```python
def compute_kzg_proof(polynomial: Sequence[BLSFieldElement], z: BLSFieldElement) -> KZGProof:
"""Compute KZG proof at point `z` with `polynomial` being in evaluation form"""
"""
Compute KZG proof at point `z` with `polynomial` being in evaluation form
"""

# To avoid SSZ overflow/underflow, convert element into int
polynomial = [int(i) for i in polynomial]
Expand All @@ -161,11 +208,11 @@ def compute_kzg_proof(polynomial: Sequence[BLSFieldElement], z: BLSFieldElement)

# Make sure we won't divide by zero during division
assert z not in ROOTS_OF_UNITY
denominator_poly = [(x - z) % BLS_MODULUS for x in ROOTS_OF_UNITY]
denominator_poly = [(x - z) % BLS_MODULUS for x in bit_reversal_permutation(ROOTS_OF_UNITY)]

# Calculate quotient polynomial by doing point-by-point division
quotient_polynomial = [div(a, b) for a, b in zip(polynomial_shifted, denominator_poly)]
return KZGProof(g1_lincomb(KZG_SETUP_LAGRANGE, quotient_polynomial))
return KZGProof(g1_lincomb(bit_reversal_permutation(KZG_SETUP_LAGRANGE), quotient_polynomial))
```

### Polynomials
Expand All @@ -187,9 +234,11 @@ def evaluate_polynomial_in_evaluation_form(polynomial: Sequence[BLSFieldElement]
# Make sure we won't divide by zero during division
assert z not in ROOTS_OF_UNITY

roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY)

result = 0
for i in range(width):
result += div(int(polynomial[i]) * int(ROOTS_OF_UNITY[i]), (z - ROOTS_OF_UNITY[i]))
result += div(int(polynomial[i]) * int(roots_of_unity_brp[i]), (z - roots_of_unity_brp[i]))
result = result * (pow(z, width, BLS_MODULUS) - 1) * inverse_width % BLS_MODULUS
return result
```
Expand Down

0 comments on commit f4ba8b5

Please sign in to comment.