def _validate_voluntary_exit_signature( state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit, validator: Validator, slots_per_epoch: int, ) -> None: voluntary_exit = signed_voluntary_exit.message domain = get_domain( state, SignatureDomain.DOMAIN_VOLUNTARY_EXIT, slots_per_epoch, voluntary_exit.epoch, ) try: bls.validate( pubkey=validator.pubkey, message_hash=voluntary_exit.hash_tree_root, signature=signed_voluntary_exit.signature, domain=domain, ) except SignatureError as error: raise ValidationError( f"Invalid VoluntaryExit signature, validator_index={voluntary_exit.validator_index}", error, )
def validate_proposer_signature(state: BeaconState, block: BaseBeaconBlock, committee_config: CommitteeConfig) -> None: message_hash = block.signing_root # Get the public key of proposer beacon_proposer_index = get_beacon_proposer_index( state, committee_config, ) proposer_pubkey = state.validators[beacon_proposer_index].pubkey domain = get_domain( state, SignatureDomain.DOMAIN_BEACON_PROPOSER, committee_config.SLOTS_PER_EPOCH, ) try: bls.validate( pubkey=proposer_pubkey, message_hash=message_hash, signature=block.signature, domain=domain, ) except SignatureError as error: raise ValidationError( f"Invalid Proposer Signature on block, beacon_proposer_index={beacon_proposer_index}", error, )
def test_validate(backend): bls.use(backend) msg = b"\x32" * 32 privkey = 42 pubkey = bls.sk_to_pk(privkey) sig = bls.sign(privkey, msg) bls.validate(msg, sig, pubkey)
def test_validate_invalid(backend): bls.use(backend) msg = b"\x32" * 32 privkey = 42 pubkey = bls.sk_to_pk(privkey) sig = b"\x42" * 96 with pytest.raises(SignatureError): bls.validate(msg, sig, pubkey)
def test_validate_multiple(backend): bls.use(backend) msg = b"\x32" * 32 privkey_0 = 42 privkey_1 = 4242 pubkey_0 = bls.sk_to_pk(privkey_0) pubkey_1 = bls.sk_to_pk(privkey_1) aggregate_sig = bls.aggregate(bls.sign(privkey_0, msg), bls.sign(privkey_1, msg)) bls.validate(msg, aggregate_sig, pubkey_0, pubkey_1)
def validate_indexed_attestation_aggregate_signature( state: BeaconState, indexed_attestation: IndexedAttestation, slots_per_epoch: int) -> None: public_keys = tuple(state.validators[i].pubkey for i in indexed_attestation.attesting_indices) domain = get_domain( state, SignatureDomain.DOMAIN_BEACON_ATTESTER, slots_per_epoch, indexed_attestation.data.target.epoch, ) signing_root = compute_signing_root(indexed_attestation.data, domain) bls.validate(signing_root, indexed_attestation.signature, *public_keys)
def test_validate_multiple_one_invalid(backend): bls.use(backend) msg = b"\x32" * 32 privkey_0 = 42 privkey_1 = 4242 privkey_other = 424242 pubkey_0 = bls.sk_to_pk(privkey_0) pubkey_1 = bls.sk_to_pk(privkey_1) aggregate_sig = bls.aggregate( bls.sign(privkey_0, msg), bls.sign(privkey_other, msg) ) with pytest.raises(SignatureError): bls.validate(msg, aggregate_sig, pubkey_0, pubkey_1)
def validate_aggregator_proof( state: BeaconState, aggregate_and_proof: AggregateAndProof, config: Eth2Config ) -> None: slot = aggregate_and_proof.aggregate.data.slot pubkey = state.validators[aggregate_and_proof.aggregator_index].pubkey domain = get_domain( state, SignatureDomain.DOMAIN_BEACON_ATTESTER, config.SLOTS_PER_EPOCH, message_epoch=compute_epoch_at_slot(slot, config.SLOTS_PER_EPOCH), ) signing_root = compute_signing_root(SerializableUint64(slot), domain) bls.validate(signing_root, aggregate_and_proof.selection_proof, pubkey)
def _validate_transfer_signature(state: BeaconState, transfer: Transfer, config: Eth2Config) -> None: domain = get_domain(state, SignatureDomain.DOMAIN_TRANSFER, config.SLOTS_PER_EPOCH) try: bls.validate( pubkey=transfer.pubkey, message_hash=transfer.signing_root, signature=transfer.signature, domain=domain, ) except SignatureError as error: raise ValidationError(f"Invalid signature for transfer {transfer}", error)
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 validate_block_header_signature(state: BeaconState, header: BeaconBlockHeader, pubkey: BLSPubkey, slots_per_epoch: int) -> None: try: bls.validate(pubkey=pubkey, message_hash=header.signing_root, signature=header.signature, domain=get_domain( state, SignatureDomain.DOMAIN_BEACON_PROPOSER, slots_per_epoch, slot_to_epoch(header.slot, slots_per_epoch), )) except SignatureError as error: raise ValidationError("Header signature is invalid", error)
def process_deposit(state: BeaconState, deposit: Deposit, config: Eth2Config) -> BeaconState: """ Process a deposit from Ethereum 1.0. """ validate_deposit_proof(state, deposit, DEPOSIT_CONTRACT_TREE_DEPTH) # Increment the next deposit index we are expecting. Note that this # needs to be done here because while the deposit contract will never # create an invalid Merkle branch, it may admit an invalid deposit # object, and we need to be able to skip over it state = state.copy(eth1_deposit_index=state.eth1_deposit_index + 1, ) pubkey = deposit.data.pubkey amount = deposit.data.amount validator_pubkeys = tuple(v.pubkey for v in state.validators) if pubkey not in validator_pubkeys: # Verify the proof of possession try: bls.validate( pubkey=pubkey, message_hash=deposit.data.signing_root, signature=deposit.data.signature, domain=bls_domain(SignatureDomain.DOMAIN_DEPOSIT, ), ) except SignatureError: return state withdrawal_credentials = deposit.data.withdrawal_credentials validator = Validator.create_pending_validator( pubkey, withdrawal_credentials, amount, config, ) return state.copy( validators=state.validators + (validator, ), balances=state.balances + (amount, ), ) else: index = ValidatorIndex(validator_pubkeys.index(pubkey)) return increase_balance( state, index, amount, )
def validate_randao_reveal(state: BeaconState, proposer_index: int, epoch: Epoch, randao_reveal: Hash32, slots_per_epoch: int) -> None: proposer = state.validators[proposer_index] proposer_pubkey = proposer.pubkey message_hash = ssz.hash_tree_root(epoch, sedes=ssz.sedes.uint64) domain = get_domain(state, SignatureDomain.DOMAIN_RANDAO, slots_per_epoch) try: bls.validate( pubkey=proposer_pubkey, message_hash=message_hash, signature=cast(BLSSignature, randao_reveal), domain=domain, ) except SignatureError as error: raise ValidationError("RANDAO reveal is invalid", error)
def validate_block_header_signature( state: BeaconState, header: SignedBeaconBlockHeader, pubkey: BLSPubkey, slots_per_epoch: int, ) -> None: domain = get_domain( state, SignatureDomain.DOMAIN_BEACON_PROPOSER, slots_per_epoch, compute_epoch_at_slot(header.message.slot, slots_per_epoch), ) signing_root = compute_signing_root(header.message, domain) try: bls.validate(signing_root, header.signature, pubkey) except SignatureError as error: raise ValidationError("Header signature is invalid:", error)
def validate_proposer_signature( state: BeaconState, signed_block: BaseSignedBeaconBlock, config: Eth2Config ) -> None: # Get the public key of proposer beacon_proposer_index = get_beacon_proposer_index(state, config) proposer_pubkey = state.validators[beacon_proposer_index].pubkey domain = get_domain( state, SignatureDomain.DOMAIN_BEACON_PROPOSER, config.SLOTS_PER_EPOCH ) signing_root = compute_signing_root(signed_block.message, domain) try: bls.validate(signing_root, signed_block.signature, proposer_pubkey) except SignatureError as error: raise ValidationError( f"Invalid Proposer Signature on block, beacon_proposer_index={beacon_proposer_index}", error, )
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 validate_aggregator_proof(state: BeaconState, aggregate_and_proof: AggregateAndProof, config: Eth2Config) -> None: slot = aggregate_and_proof.aggregate.data.slot pubkey = state.validators[aggregate_and_proof.aggregator_index].pubkey domain = get_domain( state, SignatureDomain.DOMAIN_BEACON_ATTESTER, config.SLOTS_PER_EPOCH, message_epoch=compute_epoch_at_slot(slot, config.SLOTS_PER_EPOCH), ) message_hash = get_hash_tree_root(slot, sedes=uint64) bls.validate( message_hash=message_hash, pubkey=pubkey, signature=aggregate_and_proof.selection_proof, domain=domain, )
def test_aggregate_votes(votes_count, random, privkeys, pubkeys): bit_count = 10 pre_bitfield = get_empty_bitfield(bit_count) pre_sigs = () 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(privkeys[committee_index], message_hash), pubkeys[committee_index], ) for committee_index in random_votes] # Verify sigs, committee_indices = verify_votes(message_hash, votes) # 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) if votes_count == 0: with pytest.raises(ValidationError): bls.validate(message_hash, sigs, *pubs) else: bls.validate(message_hash, sigs, *pubs)
def validate_randao_reveal( state: BeaconState, proposer_index: int, epoch: Epoch, randao_reveal: BLSSignature, slots_per_epoch: int, ) -> None: proposer = state.validators[proposer_index] proposer_pubkey = proposer.pubkey domain = get_domain(state, SignatureDomain.DOMAIN_RANDAO, slots_per_epoch) signing_root = compute_signing_root(SerializableUint64(epoch), domain) try: bls.validate(signing_root, randao_reveal, proposer_pubkey) except SignatureError as error: raise ValidationError( f"RANDAO reveal is invalid for proposer index {proposer_index} at slot {state.slot}", error, )
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 test_validate_invalid_lengths(backend): msg = b"\x32" * 32 with pytest.raises(SignatureError): bls.validate(msg, b"\x00", b"\x00" * 48) with pytest.raises(SignatureError): bls.validate(msg, b"\x00" * 96, b"\x00")
def validate(): bls.validate(b"\x11" * 32, EMPTY_PUBKEY, EMPTY_SIGNATURE, domain)
def test_validate_empty(backend): bls.use(backend) msg = b"\x32" * 32 sig = b"\x42" * 96 with pytest.raises(SignatureError): bls.validate(msg, sig)