Skip to content

Commit

Permalink
Threshold bitfield on certificate (#81)
Browse files Browse the repository at this point in the history
* Added threshold bitfield to certificate

* Short nodes_ids and public_keys
  • Loading branch information
danielSanchezQ authored Mar 14, 2024
1 parent 8c34f8a commit bd964e7
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 7 deletions.
5 changes: 5 additions & 0 deletions da/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ def transposed(self) -> Self:
BLSSignature = bytes


class Bitfield(List[bool]):
pass


@dataclass
class Attestation:
signature: BLSSignature
Expand All @@ -47,6 +51,7 @@ class Attestation:
@dataclass
class Certificate:
aggregated_signatures: BLSSignature
signers: Bitfield
aggregated_column_commitment: Commitment
row_commitments: List[Commitment]

28 changes: 24 additions & 4 deletions da/dispersal.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from py_ecc.bls import G2ProofOfPossession as bls_pop

from da.common import Certificate, NodeId, BLSPublickey
from da.common import Certificate, NodeId, BLSPublickey, Bitfield
from da.encoder import EncodedData
from da.verifier import DABlob, Attestation

Expand All @@ -19,6 +19,10 @@ class DispersalSettings:
class Dispersal:
def __init__(self, settings: DispersalSettings):
self.settings = settings
# sort nodes_ids and related 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])
)

def _prepare_data(self, encoded_data: EncodedData) -> Generator[DABlob, None, None]:
assert len(encoded_data.column_commitments) == len(self.settings.nodes_ids)
Expand All @@ -45,11 +49,18 @@ def _prepare_data(self, encoded_data: EncodedData) -> Generator[DABlob, None, No
def _send_and_await_response(self, node: NodeId, blob: DABlob) -> Optional[Attestation]:
pass

def _build_certificate(self, encoded_data: EncodedData, attestations: Sequence[Attestation]) -> Certificate:
def _build_certificate(
self,
encoded_data: EncodedData,
attestations: Sequence[Attestation],
signers: Bitfield
) -> Certificate:
assert len(attestations) >= self.settings.threshold
assert len(attestations) == signers.count(True)
aggregated = bls_pop.Aggregate([attestation.signature for attestation in attestations])
return Certificate(
aggregated_signatures=aggregated,
signers=signers,
aggregated_column_commitment=encoded_data.aggregated_column_commitment,
row_commitments=encoded_data.row_commitments
)
Expand All @@ -69,9 +80,18 @@ def _build_attestation_message(encoded_data: EncodedData) -> bytes:
def disperse(self, encoded_data: EncodedData) -> Optional[Certificate]:
attestations = []
attested_message = self._build_attestation_message(encoded_data)
for node, pk, blob in zip(self.settings.nodes_ids, self.settings.nodes_pubkey, self._prepare_data(encoded_data)):
signed = Bitfield(False for _ in range(len(self.settings.nodes_ids)))
blob_data = zip(
range(len(self.settings.nodes_ids)),
self.settings.nodes_ids,
self.settings.nodes_pubkey,
self._prepare_data(encoded_data)
)
for i, node, pk, blob in blob_data:
if attestation := self._send_and_await_response(node, blob):
if self._verify_attestation(pk, attested_message, attestation):
# mark as received
signed[i] = True
attestations.append(attestation)
if len(attestations) >= self.settings.threshold:
return self._build_certificate(encoded_data, attestations)
return self._build_certificate(encoded_data, attestations, signed)
14 changes: 11 additions & 3 deletions da/test_dispersal.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from .encoder import DAEncoderParams, DAEncoder
from .test_encoder import TestEncoder

from da.common import NodeId, Attestation
from da.common import NodeId, Attestation, Bitfield
from da.dispersal import Dispersal, EncodedData, DispersalSettings
from py_ecc.bls import G2ProofOfPossession as bls_pop

Expand All @@ -28,15 +28,19 @@ def setUp(self):

def test_build_certificate_insufficient_attestations(self):
with self.assertRaises(AssertionError):
self.dispersal._build_certificate(None, [])
self.dispersal._build_certificate(None, [], [])

def test_build_certificate_enough_attestations(self):
mock_encoded_data = EncodedData(
None, None, None, [], [], [], bytes(b"f"*48), []
)
mock_message = sha3_256(mock_encoded_data.aggregated_column_commitment).digest()
mock_attestations = [Attestation(bls_pop.Sign(sk, mock_message)) for sk in self.secret_keys]
certificate = self.dispersal._build_certificate(mock_encoded_data, mock_attestations)
certificate = self.dispersal._build_certificate(
mock_encoded_data,
mock_attestations,
Bitfield([True for _ in range(len(self.secret_keys))])
)
self.assertIsNotNone(certificate)
self.assertEqual(certificate.aggregated_column_commitment, mock_encoded_data.aggregated_column_commitment)
self.assertEqual(certificate.row_commitments, [])
Expand Down Expand Up @@ -67,4 +71,8 @@ def __send_and_await_response(node: NodeId, blob: DABlob):
certificate.aggregated_signatures
)
)
self.assertEqual(
certificate.signers,
[True if i < self.dispersal.settings.threshold else False for i in range(self.n_nodes)]
)

0 comments on commit bd964e7

Please sign in to comment.