def test_generate_aggregate_pubkeys(activated_genesis_validators, sample_slashable_vote_data_params, data): max_value_for_list = len(activated_genesis_validators) - 1 (indices, some_index) = _list_and_index( data, elements=st.integers( min_value=0, max_value=max_value_for_list, ) ) custody_bit_0_indices = indices[:some_index] custody_bit_1_indices = indices[some_index:] key = "custody_bit_0_indices" sample_slashable_vote_data_params[key] = custody_bit_0_indices key = "custody_bit_1_indices" sample_slashable_vote_data_params[key] = custody_bit_1_indices votes = SlashableVoteData(**sample_slashable_vote_data_params) keys = generate_aggregate_pubkeys(activated_genesis_validators, votes) assert len(keys) == 2 (poc_0_key, poc_1_key) = keys poc_0_keys = get_pubkey_for_indices(activated_genesis_validators, custody_bit_0_indices) poc_1_keys = get_pubkey_for_indices(activated_genesis_validators, custody_bit_1_indices) assert bls.aggregate_pubkeys(poc_0_keys) == poc_0_key assert bls.aggregate_pubkeys(poc_1_keys) == poc_1_key
def test_signature_aggregation(msg, privkeys): domain = 0 sigs = [sign(msg, k, domain=domain) for k in privkeys] pubs = [privtopub(k) for k in privkeys] aggsig = aggregate_signatures(sigs) aggpub = aggregate_pubkeys(pubs) assert verify(msg, aggpub, aggsig, domain=domain)
def test_generate_aggregate_pubkeys(activated_genesis_validators, sample_slashable_attestation_params, data): max_value_for_list = len(activated_genesis_validators) - 1 (validator_indices, some_index) = _list_and_index(data, elements=st.integers( min_value=0, max_value=max_value_for_list, )) key = "validator_indices" sample_slashable_attestation_params[key] = validator_indices custody_bitfield = get_empty_bitfield(len(validator_indices)) for index in range(some_index): custody_bitfield = set_voted(custody_bitfield, index) key = "custody_bitfield" sample_slashable_attestation_params[key] = custody_bitfield slashable_attestation = SlashableAttestation( **sample_slashable_attestation_params) custody_bit_0_indices, custody_bit_1_indices = slashable_attestation.custody_bit_indices assert len( set(custody_bit_0_indices).intersection( set(custody_bit_1_indices))) == 0 keys = generate_aggregate_pubkeys_from_indices( activated_genesis_validators, *slashable_attestation.custody_bit_indices, ) assert len(keys) == 2 (poc_0_key, poc_1_key) = keys poc_0_keys = get_pubkey_for_indices(activated_genesis_validators, custody_bit_0_indices) poc_1_keys = get_pubkey_for_indices(activated_genesis_validators, custody_bit_1_indices) assert bls.aggregate_pubkeys(poc_0_keys) == poc_0_key assert bls.aggregate_pubkeys(poc_1_keys) == poc_1_key
def validate_attestation_aggregate_signature(state: BeaconState, attestation: Attestation, genesis_epoch: EpochNumber, epoch_length: int, target_committee_size: int, shard_count: int) -> None: """ Validate ``aggregate_signature`` field of ``attestation``. Raise ``ValidationError`` if it's invalid. Note: This is the phase 0 version of `aggregate_signature`` validation. All proof of custody bits are assumed to be 0 within the signed data. This will change to reflect real proof of custody bits in the Phase 1. """ participant_indices = get_attestation_participants( state=state, attestation_data=attestation.data, bitfield=attestation.aggregation_bitfield, genesis_epoch=genesis_epoch, epoch_length=epoch_length, target_committee_size=target_committee_size, shard_count=shard_count, ) pubkeys = tuple( state.validator_registry[validator_index].pubkey for validator_index in participant_indices ) group_public_key = bls.aggregate_pubkeys(pubkeys) # TODO: change to tree hashing when we have SSZ message = AttestationDataAndCustodyBit.create_attestation_message(attestation.data) domain = get_domain( fork=state.fork, epoch=slot_to_epoch(attestation.data.slot, epoch_length), domain_type=SignatureDomain.DOMAIN_ATTESTATION, ) is_valid_signature = bls.verify( message=message, pubkey=group_public_key, signature=attestation.aggregate_signature, domain=domain, ) if not is_valid_signature: raise ValidationError( "Attestation aggregate_signature is invalid. " "message={}, participant_indices={} " "domain={}".format( message, participant_indices, domain, ) )
def test_multi_aggregation(msg_1, msg_2, privkeys_1, privkeys_2): domain = 0 sigs_1 = [sign(msg_1, k, domain=domain) for k in privkeys_1] pubs_1 = [privtopub(k) for k in privkeys_1] aggsig_1 = aggregate_signatures(sigs_1) aggpub_1 = aggregate_pubkeys(pubs_1) sigs_2 = [sign(msg_2, k, domain=domain) for k in privkeys_2] pubs_2 = [privtopub(k) for k in privkeys_2] aggsig_2 = aggregate_signatures(sigs_2) aggpub_2 = aggregate_pubkeys(pubs_2) msgs = [msg_1, msg_2] pubs = [aggpub_1, aggpub_2] aggsig = aggregate_signatures([aggsig_1, aggsig_2]) assert verify_multiple( pubkeys=pubs, messages=msgs, signature=aggsig, domain=domain, )
def validate_serenity_attestation_aggregate_signature( state: BeaconState, attestation: Attestation, epoch_length: int) -> None: """ Validate ``aggregate_signature`` field of ``attestation``. Raise ``ValidationError`` if it's invalid. Note: This is the phase 0 version of `aggregate_signature`` validation. All proof of custody bits are assumed to be 0 within the signed data. This will change to reflect real proof of custody bits in the Phase 1. """ participant_indices = get_attestation_participants( state=state, slot=attestation.data.slot, shard=attestation.data.shard, participation_bitfield=attestation.participation_bitfield, epoch_length=epoch_length, ) pubkeys = tuple(state.validator_registry[validator_index].pubkey for validator_index in participant_indices) group_public_key = bls.aggregate_pubkeys(pubkeys) # TODO: change to tree hashing when we have SSZ # TODO: Replace with AttestationAndCustodyBit data structure message = hash_eth2(rlp.encode(attestation.data) + (0).to_bytes(1, "big")) is_valid_signature = bls.verify( message=message, pubkey=group_public_key, signature=attestation.aggregate_signature, domain=get_domain( fork_data=state.fork_data, slot=attestation.data.slot, domain_type=SignatureDomain.DOMAIN_ATTESTATION, ), ) if not is_valid_signature: raise ValidationError( "Attestation ``aggregate_signature`` is invalid.")
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, voting_committee_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) assert bls.verify(message_hash, aggregated_pubs, sigs, domain)