def validate_indexed_attestation_aggregate_signature( state: BeaconState, indexed_attestation: IndexedAttestation, slots_per_epoch: int) -> None: bit_0_indices = indexed_attestation.custody_bit_0_indices bit_1_indices = indexed_attestation.custody_bit_1_indices pubkeys = ( bls.aggregate_pubkeys( tuple(state.validators[i].pubkey for i in bit_0_indices)), bls.aggregate_pubkeys( tuple(state.validators[i].pubkey for i in bit_1_indices)), ) message_hashes = ( AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=False).hash_tree_root, AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=True).hash_tree_root, ) domain = get_domain( state, SignatureDomain.DOMAIN_ATTESTATION, slots_per_epoch, indexed_attestation.data.target.epoch, ) bls.validate_multiple( pubkeys=pubkeys, message_hashes=message_hashes, signature=indexed_attestation.signature, domain=domain, )
def test_signature_aggregation(backend, msg, privkeys, domain): bls.use(backend) sigs = [bls.sign(msg, k, domain=domain) for k in privkeys] pubs = [bls.privtopub(k) for k in privkeys] aggsig = bls.aggregate_signatures(sigs) aggpub = bls.aggregate_pubkeys(pubs) assert bls.verify(msg, aggpub, aggsig, domain=domain)
def test_multi_aggregation(backend, msg_1, msg_2, privkeys_1, privkeys_2, domain): bls.use(backend) sigs_1 = [bls.sign(msg_1, k, domain=domain) for k in privkeys_1] # signatures to msg_1 pubs_1 = [bls.privtopub(k) for k in privkeys_1] aggpub_1 = bls.aggregate_pubkeys(pubs_1) # sig_1 to msg_1 sigs_2 = [bls.sign(msg_2, k, domain=domain) for k in privkeys_2] # signatures to msg_2 pubs_2 = [bls.privtopub(k) for k in privkeys_2] aggpub_2 = bls.aggregate_pubkeys(pubs_2) # sig_2 to msg_2 message_hashes = [msg_1, msg_2] pubs = [aggpub_1, aggpub_2] aggsig = bls.aggregate_signatures(sigs_1 + sigs_2) assert bls.verify_multiple(pubkeys=pubs, message_hashes=message_hashes, signature=aggsig, domain=domain)
def test_aggregate_votes(votes_count, random, privkeys, pubkeys): bit_count = 10 pre_bitfield = get_empty_bitfield(bit_count) pre_sigs = () domain = compute_domain(SignatureDomain.DOMAIN_ATTESTATION) random_votes = random.sample(range(bit_count), votes_count) message_hash = b"\x12" * 32 # Get votes: (committee_index, sig, public_key) votes = [ ( committee_index, bls.sign(message_hash, privkeys[committee_index], domain), pubkeys[committee_index], ) for committee_index in random_votes ] # Verify sigs, committee_indices = verify_votes(message_hash, votes, domain) # Aggregate the votes bitfield, sigs = aggregate_votes( bitfield=pre_bitfield, sigs=pre_sigs, voting_sigs=sigs, attesting_indices=committee_indices, ) try: _, _, pubs = zip(*votes) except ValueError: pubs = () voted_index = [ committee_index for committee_index in random_votes if has_voted(bitfield, committee_index) ] assert len(voted_index) == len(votes) aggregated_pubs = bls.aggregate_pubkeys(pubs) if votes_count == 0 and bls.backend in (ChiaBackend, MilagroBackend): with pytest.raises(ValidationError): bls.validate(message_hash, aggregated_pubs, sigs, domain) else: bls.validate(message_hash, aggregated_pubs, sigs, domain)
def test_aggregate_votes(votes_count, random, privkeys, pubkeys): bit_count = 10 pre_bitfield = get_empty_bitfield(bit_count) pre_sigs = () domain = 0 random_votes = random.sample(range(bit_count), votes_count) message_hash = b'\x12' * 32 # Get votes: (committee_index, sig, public_key) votes = [( committee_index, bls.sign(message_hash, privkeys[committee_index], domain), pubkeys[committee_index], ) for committee_index in random_votes] # Verify sigs, committee_indices = verify_votes(message_hash, votes, domain) # Aggregate the votes bitfield, sigs = aggregate_votes(bitfield=pre_bitfield, sigs=pre_sigs, voting_sigs=sigs, attesting_indices=committee_indices) try: _, _, pubs = zip(*votes) except ValueError: pubs = () voted_index = [ committee_index for committee_index in random_votes if has_voted(bitfield, committee_index) ] assert len(voted_index) == len(votes) aggregated_pubs = bls.aggregate_pubkeys(pubs) if votes_count != 0: bls.validate(message_hash, aggregated_pubs, sigs, domain) else: # EMPTY_SIGNATURE is considered invalid with pytest.raises(ValueError): bls.validate(message_hash, aggregated_pubs, sigs, domain)
def test_sanity(backend): bls.use(backend) msg_0 = b"\x32" * 32 domain = 123 # Test: Verify the basic sign/verify process privkey_0 = 5566 sig_0 = bls.sign(msg_0, privkey_0, domain) assert_signature(sig_0) pubkey_0 = bls.privtopub(privkey_0) assert_pubkey(pubkey_0) assert bls.verify(msg_0, pubkey_0, sig_0, domain) privkey_1 = 5567 sig_1 = bls.sign(msg_0, privkey_1, domain) pubkey_1 = bls.privtopub(privkey_1) assert bls.verify(msg_0, pubkey_1, sig_1, domain) # Test: Verify signatures are correctly aggregated aggregated_signature = bls.aggregate_signatures([sig_0, sig_1]) assert_signature(aggregated_signature) # Test: Verify pubkeys are correctly aggregated aggregated_pubkey = bls.aggregate_pubkeys([pubkey_0, pubkey_1]) assert_pubkey(aggregated_pubkey) # Test: Verify with `aggregated_signature` and `aggregated_pubkey` assert bls.verify(msg_0, aggregated_pubkey, aggregated_signature, domain) # Test: `verify_multiple` msg_1 = b"x22" * 32 privkey_2 = 55688 sig_2 = bls.sign(msg_1, privkey_2, domain) assert_signature(sig_2) pubkey_2 = bls.privtopub(privkey_2) assert_pubkey(pubkey_2) sig_1_2 = bls.aggregate_signatures([sig_1, sig_2]) assert bls.verify_multiple( pubkeys=[pubkey_1, pubkey_2], message_hashes=[msg_0, msg_1], signature=sig_1_2, domain=domain, )
def validate_indexed_attestation_aggregate_signature( state: BeaconState, indexed_attestation: IndexedAttestation, slots_per_epoch: int) -> None: attesting_indices = indexed_attestation.attesting_indices pubkey = bls.aggregate_pubkeys( tuple(state.validators[i].pubkey for i in attesting_indices)) message_hash = indexed_attestation.data.hash_tree_root domain = get_domain( state, SignatureDomain.DOMAIN_BEACON_ATTESTER, slots_per_epoch, indexed_attestation.data.target.epoch, ) bls.validate( pubkey=pubkey, message_hash=message_hash, signature=indexed_attestation.signature, domain=domain, )
def run_with(_cls, inputs: SequenceOfBLSPubkey, _config: Optional[Eth2Config]) -> BLSPubkey: # BLS override bls.use(MilagroBackend) return bls.aggregate_pubkeys(inputs)
def test_empty_aggregation(backend): bls.use(backend) assert bls.aggregate_pubkeys([]) == EMPTY_PUBKEY assert bls.aggregate_signatures([]) == EMPTY_SIGNATURE