Daniel Sanchez cf899d2384
Da encoding protocol (#76)
* Implement generator polynomial and rs encoding

* Implement encode/decode+test using fft. Non-working

* Use lagrange for interpolation

* Remove fft, use evaluations instead

* Move and rename kzg and rs test modules

* Update docs

* Added columns property to chunks matrix
Added test for columns

* Added chunkify and test

* Added compute row commitments
Added row commitments size test

* Fix poly from evaluations method

* Implement encode rows and test

* Update encode row test

* Implement compute row proofs (not working on extended data)

* Use same polynomials for commitment and proof creation after extend

* Fix polynomial from/to evaluations

* Use chunks for verification

* Refactor interpolate

* Implement chunks matrix transposed method

* Added compute column kzg commitments

* Use square size data for encoder tests

* Add column type to columns method

* Added compute columns aggregated commitment
Added aggregated commitment test
Fixed and expanded encode test

* Use sha3 for hashing
2024-03-08 14:16:14 +01:00

75 lines
2.6 KiB
Python

from functools import reduce
from itertools import batched
from typing import Sequence, Tuple
from eth2spec.deneb.mainnet import bytes_to_bls_field, BLSFieldElement, KZGCommitment as Commitment, KZGProof as Proof
from eth2spec.utils import bls
from .common import BYTES_PER_FIELD_ELEMENT, G1, BLS_MODULUS, GLOBAL_PARAMETERS_G2
from .poly import Polynomial
def bytes_to_polynomial(b: bytes) -> Polynomial:
"""
Convert bytes to list of BLS field scalars.
"""
assert len(b) % BYTES_PER_FIELD_ELEMENT == 0
eval_form = [int(bytes_to_bls_field(b)) for b in batched(b, int(BYTES_PER_FIELD_ELEMENT))]
return Polynomial.from_evaluations(eval_form, BLS_MODULUS)
def g1_linear_combination(polynomial: Polynomial[BLSFieldElement], global_parameters: Sequence[G1]) -> Commitment:
"""
BLS multiscalar multiplication.
"""
# we assert to have more points available than elements,
# this is dependent on the available kzg setup size
assert len(polynomial) <= len(global_parameters)
point = reduce(
bls.add,
(bls.multiply(g, p) for g, p in zip(global_parameters, polynomial)),
bls.Z1()
)
return Commitment(bls.G1_to_bytes48(point))
def bytes_to_commitment(b: bytes, global_parameters: Sequence[G1]) -> Tuple[Polynomial, Commitment]:
poly = bytes_to_polynomial(b)
return poly, g1_linear_combination(poly, global_parameters)
def generate_element_proof(
element_index: int,
polynomial: Polynomial,
global_parameters: Sequence[G1],
roots_of_unity: Sequence[BLSFieldElement],
) -> Proof:
# compute a witness polynomial in that satisfies `witness(x) = (f(x)-v)/(x-u)`
u = int(roots_of_unity[element_index])
v = polynomial.eval(u)
f_x_v = polynomial - Polynomial([v], BLS_MODULUS)
x_u = Polynomial([-u, 1], BLS_MODULUS)
witness, _ = f_x_v / x_u
return g1_linear_combination(witness, global_parameters)
def verify_element_proof(
chunk: BLSFieldElement,
commitment: Commitment,
proof: Proof,
element_index: int,
roots_of_unity: Sequence[BLSFieldElement],
) -> bool:
u = int(roots_of_unity[element_index])
v = chunk
commitment_check_G1 = bls.bytes48_to_G1(commitment) - bls.multiply(bls.G1(), v)
proof_check_g2 = bls.add(
GLOBAL_PARAMETERS_G2[1],
bls.neg(bls.multiply(bls.G2(), u))
)
return bls.pairing_check([
# G2 here needs to be negated due to library requirements as pairing_check([[G1, -G2], [G1, G2]])
[commitment_check_G1, bls.neg(bls.G2())],
[bls.bytes48_to_G1(proof), proof_check_g2],
])