Changes were done based on the feedback

This commit is contained in:
mgonen 2025-06-04 13:58:18 +03:00
parent c2d5272408
commit f735f514e6
5 changed files with 47 additions and 49 deletions

View File

@ -68,19 +68,19 @@ class DAEncoder:
def _combined_polynomial(
polys: Sequence[Polynomial], h: BLSFieldElement
) -> Polynomial:
combined = Polynomial([0], BLS_MODULUS)
combined_polynomial = polys[0]
h_int = int(h) # raw integer challenge
int_pow = 1
for poly in polys:
combined = combined + (poly * int_pow)
for poly in polys[1:]:
int_pow = (int_pow * h_int) % BLS_MODULUS
return combined
combined_polynomial = combined_polynomial + Polynomial({int_pow * coeff for coeff in poly},BLS_MODULUS)
return combined_polynomial
def _compute_combined_column_proofs(self, combined_poly: Polynomial) -> List[Proof]:
total_cols = self.params.column_count * 2
return [
kzg.generate_element_proof(j, combined_poly, GLOBAL_PARAMETERS, ROOTS_OF_UNITY)
for j in range(total_cols)
kzg.generate_element_proof(i, combined_poly, GLOBAL_PARAMETERS, ROOTS_OF_UNITY)
for i in range(total_cols)
]
def encode(self, data: bytes) -> EncodedData:

View File

@ -1,3 +1,4 @@
from itertools import zip_longest
from typing import List, Sequence, Self
@ -49,19 +50,11 @@ class Polynomial[T]:
)
def __mul__(self, other):
if isinstance(other, int):
return Polynomial(
[(a * other) % self.modulus for a in self.coefficients],
self.modulus
)
elif isinstance(other, Polynomial):
result = [0] * (len(self.coefficients) + len(other.coefficients) - 1)
for i in range(len(self.coefficients)):
for j in range(len(other.coefficients)):
result[i + j] = (result[i + j] + self.coefficients[i] * other.coefficients[j]) % self.modulus
return Polynomial(result, self.modulus)
else:
raise TypeError(f"Unsupported type for multiplication: {type(other)}")
result = [0] * (len(self.coefficients) + len(other.coefficients) - 1)
for i in range(len(self.coefficients)):
for j in range(len(other.coefficients)):
result[i + j] = (result[i + j] + self.coefficients[i] * other.coefficients[j]) % self.modulus
return Polynomial(result, self.modulus)
def divide(self, other):
if not isinstance(other, Polynomial):
@ -116,4 +109,4 @@ class Polynomial[T]:
)) % self.modulus
def evaluation_form(self) -> List[T]:
return [self.eval(ROOTS_OF_UNITY[i]) for i in range(len(self))]
return [self.eval(ROOTS_OF_UNITY[i]) for i in range(len(self))]

View File

@ -39,19 +39,21 @@ class TestEncoder(TestCase):
# verify rows
h = derive_challenge(encoded_data.row_commitments)
combined_commitment = encoded_data.row_commitments[0]
power = h
combined_commitment = bls.bytes48_to_G1(encoded_data.row_commitments[0])
power = int(h) % BLS_MODULUS
for commitment in encoded_data.row_commitments[1:]:
combined_commitment = bls.add(combined_commitment,bls.multiply(commitment, power))
power = power * h
commitment=bls.bytes48_to_G1(commitment)
combined_commitment = bls.add(combined_commitment,bls.multiply(commitment,power))
power = (power * int(h)) % BLS_MODULUS
combined_commitment = bls.G1_to_bytes48(combined_commitment)
for i, (column, proof) in enumerate(zip(encoded_data.extended_matrix.columns, encoded_data.combined_column_proofs)):
combined_eval_point = BLSFieldElement(0)
power = BLSFieldElement(1)
for data in column.chunks:
chunk = BLSFieldElement(int.from_bytes(bytes(data), byteorder="big"))
combined_eval_point = combined_eval_point + chunk * power
power = power * h
combined_eval_int = 0
power_int = 1
h_int = int(h)
for data in column:
chunk_int = int.from_bytes(bytes(data), byteorder="big")
combined_eval_point = (combined_eval_int + chunk_int * power_int) % BLS_MODULUS
power_int = (power_int * h_int) % BLS_MODULUS
kzg.verify_element_proof(
combined_eval_point,
combined_commitment,
@ -95,7 +97,8 @@ class TestEncoder(TestCase):
h = derive_challenge(row_commitments)
combined_poly = self.encoder._combined_polynomial(row_polynomials, h)
proofs = self.encoder._compute_combined_column_proofs(combined_poly)
self.assertEqual(len(proofs), len(row_commitments))
expected_extended_columns = self.params.column_count * 2
self.assertEqual(len(proofs), expected_extended_columns)
def test_encode(self):
from random import randbytes
@ -111,4 +114,4 @@ class TestEncoder(TestCase):
for _ in range(size*encoder_params.column_count)
)
)
self.assert_encoding(encoder_params, data)
self.assert_encoding(encoder_params, data)

View File

@ -18,7 +18,7 @@ class TestVerifier(TestCase):
_ = TestEncoder()
_.setUp()
encoded_data = _.encoder.encode(_.data)
for i, column in enumerate(encoded_data.chunked_data.columns):
for i, column in enumerate(encoded_data.extended_matrix.columns):
verifier = DAVerifier()
da_blob = DAShare(
Column(column),
@ -32,7 +32,7 @@ class TestVerifier(TestCase):
_ = TestEncoder()
_.setUp()
encoded_data = _.encoder.encode(_.data)
columns = enumerate(encoded_data.chunked_data.columns)
columns = enumerate(encoded_data.extended_matrix.columns)
i, column = next(columns)
da_blob = DAShare(
Column(column),
@ -48,4 +48,4 @@ class TestVerifier(TestCase):
encoded_data.combined_column_proofs[i],
encoded_data.row_commitments,
)
self.assertTrue(self.verifier.verify(da_blob))
self.assertIsNotNone(self.verifier.verify(da_blob))

View File

@ -1,6 +1,5 @@
from dataclasses import dataclass
from typing import List, Sequence, Set
from hashlib import blake2b
from eth2spec.utils import bls
from eth2spec.deneb.mainnet import BLSFieldElement
from eth2spec.eip7594.mainnet import (
@ -30,26 +29,29 @@ class DAVerifier:
@staticmethod
def verify(blob: DAShare) -> bool:
"""
Verifies that blob.column.chunks at index blob.column_idx is consistent
with the row commitments and the single column proof.
Verifies that blob.column at index blob.column_idx is consistent
with the row commitments and the combined column proof.
Returns True if verification succeeds, False otherwise.
"""
# 1. Derive challenge
h = derive_challenge(blob.row_commitments)
# 2. Reconstruct combined commitment: combined_commitment = sum_{i=0..l-1} h^i * row_commitments[i]
combined_commitment = blob.row_commitments[0]
power = h
combined_commitment = bls.bytes48_to_G1(blob.row_commitments[0])
power = int(h) % BLS_MODULUS
for commitment in blob.row_commitments[1:]:
commitment = bls.bytes48_to_G1(commitment)
combined_commitment = bls.add(combined_commitment,bls.multiply(commitment, power))
power = power * h
power = (power * int(h)) % BLS_MODULUS
combined_commitment = bls.G1_to_bytes48(combined_commitment)
# 3. Compute combined evaluation v = sum_{i=0..l-1} (h^i * column_data[i])
combined_eval_point = BLSFieldElement(0)
power = BLSFieldElement(1)
for data in blob.column.chunks:
chunk = BLSFieldElement(int.from_bytes(bytes(data), byteorder="big"))
combined_eval_point = combined_eval_point + chunk * power
power = power * h
combined_eval_int = 0
power_int = 1
h_int = int(h) % BLS_MODULUS
for chunk in blob.column:
chunk_int = int.from_bytes(bytes(chunk), byteorder="big")
combined_eval_int = (combined_eval_int + chunk_int * power_int) % BLS_MODULUS
power_int = (power_int * h_int) % BLS_MODULUS
combined_eval_point = BLSFieldElement(combined_eval_int)
# 4. Verify the single KZG proof for evaluation at point w^{column_idx}
return kzg.verify_element_proof(combined_eval_point,combined_commitment,blob.combined_column_proof,blob.column_idx,ROOTS_OF_UNITY)