Added verification to certificate (#82)

* Added verification method to certificate

* Update da/common.py

typo short -> sort

Co-authored-by: gusto <bacv@users.noreply.github.com>

* Fix test imports

* Added verification comment

---------

Co-authored-by: gusto <bacv@users.noreply.github.com>
This commit is contained in:
Daniel Sanchez 2024-03-15 11:34:43 +01:00 committed by GitHub
parent bd964e7b27
commit 0e142c0888
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 32 additions and 24 deletions

View File

@ -1,10 +1,10 @@
from dataclasses import dataclass
from itertools import chain, zip_longest
from typing import List, Generator, Self
from hashlib import sha3_256
from itertools import chain, zip_longest, compress
from typing import List, Generator, Self, Sequence
from eth2spec.eip7594.mainnet import Bytes32, KZGCommitment as Commitment
from py_ecc.bls import G2ProofOfPossession as bls_pop
class NodeId(Bytes32):
@ -55,3 +55,21 @@ class Certificate:
aggregated_column_commitment: Commitment
row_commitments: List[Commitment]
def verify(self, nodes_public_keys: List[BLSPublickey]) -> bool:
"""
List of nodes public keys should be a trusted list of verified proof of possession keys.
Otherwise, we could fall under the Rogue Key Attack
`assert all(bls_pop.PopVerify(pk, proof) for pk, proof in zip(node_public_keys, pops))`
"""
# we sort them as the signers bitfield is sorted by the public keys as well
signers_keys = list(compress(sorted(nodes_public_keys), self.signers))
message = build_attestation_message(self.aggregated_column_commitment, self.row_commitments)
return bls_pop.AggregateVerify(signers_keys, [message]*len(signers_keys), self.aggregated_signatures)
def build_attestation_message(aggregated_column_commitment: Commitment, row_commitments: Sequence[Commitment]) -> bytes:
hasher = sha3_256()
hasher.update(bytes(aggregated_column_commitment))
for c in row_commitments:
hasher.update(bytes(c))
return hasher.digest()

View File

@ -4,7 +4,7 @@ from typing import List, Optional, Generator, Sequence
from py_ecc.bls import G2ProofOfPossession as bls_pop
from da.common import Certificate, NodeId, BLSPublickey, Bitfield
from da.common import Certificate, NodeId, BLSPublickey, Bitfield, build_attestation_message
from da.encoder import EncodedData
from da.verifier import DABlob, Attestation
@ -19,9 +19,9 @@ class DispersalSettings:
class Dispersal:
def __init__(self, settings: DispersalSettings):
self.settings = settings
# sort nodes_ids and related public keys
# sort over public keys
self.settings.nodes_ids, self.settings.nodes_pubkey = zip(
*sorted(zip(self.settings.nodes_ids, self.settings.nodes_pubkey), key=lambda x: x[0])
*sorted(zip(self.settings.nodes_ids, self.settings.nodes_pubkey), key=lambda x: x[1])
)
def _prepare_data(self, encoded_data: EncodedData) -> Generator[DABlob, None, None]:
@ -71,11 +71,7 @@ class Dispersal:
@staticmethod
def _build_attestation_message(encoded_data: EncodedData) -> bytes:
hasher = sha3_256()
hasher.update(bytes(encoded_data.aggregated_column_commitment))
for c in encoded_data.row_commitments:
hasher.update(bytes(c))
return hasher.digest()
return build_attestation_message(encoded_data.aggregated_column_commitment, encoded_data.row_commitments)
def disperse(self, encoded_data: EncodedData) -> Optional[Certificate]:
attestations = []

View File

@ -1,14 +1,13 @@
from hashlib import sha3_256
from unittest import TestCase
from .encoder import DAEncoderParams, DAEncoder
from .test_encoder import TestEncoder
from da.encoder import DAEncoderParams, DAEncoder
from da.test_encoder import TestEncoder
from da.verifier import DAVerifier, DABlob
from da.common import NodeId, Attestation, Bitfield
from da.dispersal import Dispersal, EncodedData, DispersalSettings
from py_ecc.bls import G2ProofOfPossession as bls_pop
from .verifier import DAVerifier, DABlob
from py_ecc.bls import G2ProofOfPossession as bls_pop
class TestDispersal(TestCase):
@ -46,7 +45,7 @@ class TestDispersal(TestCase):
self.assertEqual(certificate.row_commitments, [])
self.assertIsNotNone(certificate.aggregated_signatures)
self.assertTrue(
bls_pop.AggregateVerify(self.public_keys, [mock_message]*len(self.public_keys), certificate.aggregated_signatures)
certificate.verify(self.public_keys)
)
def test_disperse(self):
@ -64,12 +63,7 @@ class TestDispersal(TestCase):
certificate = self.dispersal.disperse(encoded_data)
self.assertIsNotNone(certificate)
self.assertTrue(
bls_pop.AggregateVerify(
self.public_keys[:self.dispersal.settings.threshold],
[self.dispersal._build_attestation_message(encoded_data)]*self.dispersal.settings.threshold,
certificate.aggregated_signatures
)
self.assertTrue(certificate.verify(self.public_keys)
)
self.assertEqual(
certificate.signers,