diff --git a/da/common.py b/da/common.py index cb832a1..8d00f29 100644 --- a/da/common.py +++ b/da/common.py @@ -34,7 +34,7 @@ class ChunksMatrix(List[Row | Column]): return ChunksMatrix(self.columns) -BLSPublickey = bytes +BLSPublicKey = bytes BLSPrivateKey = int BLSSignature = bytes @@ -58,7 +58,7 @@ class Certificate: def id(self) -> bytes: return build_attestation_message(self.aggregated_column_commitment, self.row_commitments) - def verify(self, nodes_public_keys: List[BLSPublickey]) -> bool: + 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 diff --git a/da/dispersal.py b/da/dispersal.py index 9a6fb12..5ef7ff7 100644 --- a/da/dispersal.py +++ b/da/dispersal.py @@ -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, build_attestation_message +from da.common import Certificate, NodeId, BLSPublicKey, Bitfield, build_attestation_message from da.encoder import EncodedData from da.verifier import DABlob, Attestation @@ -12,7 +12,7 @@ from da.verifier import DABlob, Attestation @dataclass class DispersalSettings: nodes_ids: List[NodeId] - nodes_pubkey: List[BLSPublickey] + nodes_pubkey: List[BLSPublicKey] threshold: int @@ -33,10 +33,9 @@ class Dispersal: rows_proofs = encoded_data.row_proofs aggregated_column_commitment = encoded_data.aggregated_column_commitment aggregated_column_proofs = encoded_data.aggregated_column_proofs - blobs_data = enumerate(zip(columns, column_commitments, zip(*rows_proofs), aggregated_column_proofs)) - for index, (column, column_commitment, row_proofs, column_proof) in blobs_data: + blobs_data = zip(columns, column_commitments, zip(*rows_proofs), aggregated_column_proofs) + for (column, column_commitment, row_proofs, column_proof) in blobs_data: blob = DABlob( - index, column, column_commitment, aggregated_column_commitment, @@ -66,7 +65,7 @@ class Dispersal: ) @staticmethod - def _verify_attestation(public_key: BLSPublickey, attested_message: bytes, attestation: Attestation) -> bool: + def _verify_attestation(public_key: BLSPublicKey, attested_message: bytes, attestation: Attestation) -> bool: return bls_pop.Verify(public_key, attested_message, attestation.signature) @staticmethod diff --git a/da/test_dispersal.py b/da/test_dispersal.py index 9ec3644..69a8ccd 100644 --- a/da/test_dispersal.py +++ b/da/test_dispersal.py @@ -16,6 +16,10 @@ class TestDispersal(TestCase): self.nodes_ids = [NodeId(x.to_bytes(length=32, byteorder='big')) for x in range(self.n_nodes)] self.secret_keys = list(range(1, self.n_nodes+1)) self.public_keys = [bls_pop.SkToPk(sk) for sk in self.secret_keys] + # sort by pk as we do in dispersal + self.secret_keys, self.public_keys = zip( + *sorted(zip(self.secret_keys, self.public_keys), key=lambda x: x[1]) + ) dispersal_settings = DispersalSettings( self.nodes_ids, self.public_keys, @@ -56,7 +60,7 @@ class TestDispersal(TestCase): # mock send and await method with local verifiers def __send_and_await_response(node: NodeId, blob: DABlob): sk = self.secret_keys[int.from_bytes(node)] - verifier = DAVerifier(sk) + verifier = DAVerifier(sk, self.public_keys) return verifier.verify(blob) # inject mock send and await method self.dispersal._send_and_await_response = __send_and_await_response diff --git a/da/test_full_flow.py b/da/test_full_flow.py index 1615f0d..08e26c0 100644 --- a/da/test_full_flow.py +++ b/da/test_full_flow.py @@ -4,7 +4,7 @@ from typing import List, Optional from py_ecc.bls import G2ProofOfPossession as bls_pop -from da.common import NodeId, build_attestation_message +from da.common import NodeId, build_attestation_message, BLSPublicKey from da.api.common import DAApi, VID, Metadata from da.verifier import DAVerifier, DABlob from da.api.test_flow import MockStore @@ -14,10 +14,10 @@ from da.encoder import DAEncoderParams, DAEncoder class DAVerifierWApi: - def __init__(self, sk: int): + def __init__(self, sk: int, public_keys: List[BLSPublicKey]): self.store = MockStore() self.api = DAApi(self.store) - self.verifier = DAVerifier(sk) + self.verifier = DAVerifier(sk, public_keys) def receive_blob(self, blob: DABlob): if attestation := self.verifier.verify(blob): @@ -43,6 +43,10 @@ class TestFullFlow(TestCase): self.nodes_ids = [NodeId(x.to_bytes(length=32, byteorder='big')) for x in range(self.n_nodes)] self.secret_keys = list(range(1, self.n_nodes+1)) self.public_keys = [bls_pop.SkToPk(sk) for sk in self.secret_keys] + # sort by pk as we do in dispersal + self.secret_keys, self.public_keys = zip( + *sorted(zip(self.secret_keys, self.public_keys), key=lambda x: x[1]) + ) dispersal_settings = DispersalSettings( self.nodes_ids, self.public_keys, @@ -52,7 +56,7 @@ class TestFullFlow(TestCase): self.encoder_test = TestEncoder() self.encoder_test.setUp() - self.api_nodes = [DAVerifierWApi(k) for k in self.secret_keys] + self.api_nodes = [DAVerifierWApi(k, self.public_keys) for k in self.secret_keys] def test_full_flow(self): app_id = int.to_bytes(1) diff --git a/da/test_verifier.py b/da/test_verifier.py index fd29aa2..5216dd1 100644 --- a/da/test_verifier.py +++ b/da/test_verifier.py @@ -1,5 +1,7 @@ from unittest import TestCase +from py_ecc.bls import G2ProofOfPossession as bls_pop + from da.common import Column from da.encoder import DAEncoder from da.kzg_rs import kzg @@ -11,7 +13,7 @@ from da.verifier import Attestation, DAVerifier, DABlob class TestVerifier(TestCase): def setUp(self): - self.verifier = DAVerifier(1987) + self.verifier = DAVerifier(1987, [bls_pop.SkToPk(1987)]) def test_verify_column(self): column = Column(int.to_bytes(i, length=32) for i in range(8)) @@ -30,10 +32,11 @@ class TestVerifier(TestCase): _ = TestEncoder() _.setUp() encoded_data = _.encoder.encode(_.data) + verifiers_sk = [i for i in range(1000, 1000+len(encoded_data.chunked_data[0]))] + vefiers_pk = [bls_pop.SkToPk(k) for k in verifiers_sk] for i, column in enumerate(encoded_data.chunked_data.columns): - verifier = DAVerifier(1987) + verifier = DAVerifier(verifiers_sk[i], vefiers_pk) da_blob = DABlob( - i, Column(column), encoded_data.column_commitments[i], encoded_data.aggregated_column_commitment, @@ -50,7 +53,6 @@ class TestVerifier(TestCase): columns = enumerate(encoded_data.chunked_data.columns) i, column = next(columns) da_blob = DABlob( - i, Column(column), encoded_data.column_commitments[i], encoded_data.aggregated_column_commitment, @@ -61,7 +63,6 @@ class TestVerifier(TestCase): self.assertIsNotNone(self.verifier.verify(da_blob)) for i, column in columns: da_blob = DABlob( - i, Column(column), encoded_data.column_commitments[i], encoded_data.aggregated_column_commitment, diff --git a/da/verifier.py b/da/verifier.py index a9dae52..730024c 100644 --- a/da/verifier.py +++ b/da/verifier.py @@ -10,7 +10,7 @@ from eth2spec.eip7594.mainnet import ( from py_ecc.bls import G2ProofOfPossession as bls_pop import da.common -from da.common import Column, Chunk, Attestation, BLSPrivateKey +from da.common import Column, Chunk, Attestation, BLSPrivateKey, BLSPublicKey from da.encoder import DAEncoder from da.kzg_rs import kzg from da.kzg_rs.common import ROOTS_OF_UNITY, GLOBAL_PARAMETERS, BLS_MODULUS @@ -18,7 +18,6 @@ from da.kzg_rs.common import ROOTS_OF_UNITY, GLOBAL_PARAMETERS, BLS_MODULUS @dataclass class DABlob: - index: int column: Column column_commitment: Commitment aggregated_column_commitment: Commitment @@ -34,9 +33,10 @@ class DABlob: class DAVerifier: - def __init__(self, sk: BLSPrivateKey): + def __init__(self, sk: BLSPrivateKey, nodes_pks: List[BLSPublicKey]): self.attested_blobs: Dict[bytes, (bytes, Attestation)] = dict() self.sk = sk + self.index = nodes_pks.index(bls_pop.SkToPk(self.sk)) @staticmethod def _verify_column( @@ -101,12 +101,12 @@ class DAVerifier: blob.column_commitment, blob.aggregated_column_commitment, blob.aggregated_column_proof, - blob.index + self.index ) if not is_column_verified: return are_chunks_verified = DAVerifier._verify_chunks( - blob.column, blob.rows_commitments, blob.rows_proofs, blob.index + blob.column, blob.rows_commitments, blob.rows_proofs, self.index ) if not are_chunks_verified: return