def verify_deposit(deposit_data_dict: Dict[str, Any]) -> bool: ''' Checks whether a deposit is valid based on the eth2 rules. https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#deposits ''' pubkey = BLSPubkey(bytes.fromhex(deposit_data_dict['pubkey'])) withdrawal_credentials = bytes.fromhex(deposit_data_dict['withdrawal_credentials']) amount = deposit_data_dict['amount'] signature = BLSSignature(bytes.fromhex(deposit_data_dict['signature'])) deposit_data_root = bytes.fromhex(deposit_data_dict['signed_deposit_data_root']) # Verify deposit amount if not MIN_DEPOSIT_AMOUNT < amount <= MAX_DEPOSIT_AMOUNT: return False # Verify deposit signature && pubkey deposit_message = DepositMessage(pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount) domain = compute_domain(domain_type=DOMAIN_DEPOSIT) signing_root = compute_signing_root(deposit_message, domain) if not bls.Verify(pubkey, signing_root, signature): return False # Verify Deposit Root deposit = Deposit(pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount, signature=signature) return deposit.hash_tree_root == deposit_data_root
def get_logs(self, block_number: BlockNumber) -> Tuple[DepositLog, ...]: block_hash = block_number.to_bytes(32, byteorder='big') if block_number == self.start_block_number: logs = ( DepositLog( block_hash=Hash32(block_hash), pubkey=deposit.pubkey, withdrawal_credentials=deposit.withdrawal_credentials, signature=deposit.signature, amount=deposit.amount, ) for deposit in self.deposits ) return tuple(logs) else: logs = ( DepositLog( block_hash=Hash32(block_hash), pubkey=BLSPubkey(b'\x12' * 48), withdrawal_credentials=Hash32(b'\x23' * 32), signature=BLSSignature(b'\x34' * 96), amount=Gwei(32 * GWEI_PER_ETH), ) for _ in range(self.num_deposits_per_block) ) return tuple(logs)
def sample_deposit_data_params(sample_signature): return { "pubkey": BLSPubkey(b"\x67" * 48), "withdrawal_credentials": b"\11" * 32, "amount": Gwei(56), "signature": sample_signature, }
def sample_deposit_data_params(sample_signature): return { 'pubkey': BLSPubkey(b'\x67' * 48), 'withdrawal_credentials': b'\11' * 32, 'amount': Gwei(56), 'signature': sample_signature, }
async def _get_attestation(context: Context, request: Request) -> Response: if not isinstance(request, dict): return {} public_key = BLSPubkey(decode_hex(request["validator_pubkey"])) slot = Slot(int(request["slot"])) committee_index = CommitteeIndex(int(request["committee_index"])) attestation = context.get_attestation(public_key, slot, committee_index) return to_formatted_dict(attestation)
def load_genesis_key_map( encoded_key_map: Tuple[Dict[str, Any]], public_key_codec: Callable[ [str], BLSPubkey] = lambda key: BLSPubkey(decode_hex(key)), private_key_codec: Callable[[str], int] = _decode_private_key_from_hex, ) -> Iterable[Tuple[BLSPubkey, int]]: for key_pair in encoded_key_map: public_key = public_key_codec(key_pair["public_key"]) private_key = private_key_codec(key_pair["private_key"]) yield public_key, private_key
def _is_valid_pubkey(cls, pubkey: bytes) -> bool: """ Note: PopVerify is a precondition for -Verify APIs However, it's difficult to verify it with the API interface in runtime. To ensure KeyValidate has been checked, we check it in the input validation. See https://github.com/cfrg/draft-irtf-cfrg-bls-signature/issues/27 for the discussion. """ if not super()._is_valid_pubkey(pubkey): return False return cls.KeyValidate(BLSPubkey(pubkey))
def _load_key_file(self, key_file: Path) -> Tuple[BLSPubkey, BLSPrivateKey, str]: with open(key_file) as key_file_handle: keyfile_json = json.load(key_file_handle) public_key = BLSPubkey(decode_hex(keyfile_json["public_key"])) password = self._password_provider(public_key) try: private_key = eth_keyfile.decode_keyfile_json(keyfile_json, password) except ValueError: self.logger.error( "password was incorrect for public key %s", encode_hex(public_key) ) raise return (public_key, private_key, keyfile_json["id"])
def create_keypair_and_mock_withdraw_credentials( config: Eth2Config, key_set: Sequence[Dict[str, Any]] ) -> Tuple[Tuple[BLSPubkey, ...], Tuple[int, ...], Tuple[Hash32, ...]]: pubkeys: Tuple[BLSPubkey, ...] = () privkeys: Tuple[int, ...] = () withdrawal_credentials: Tuple[Hash32, ...] = () for key_pair in key_set: pubkey = BLSPubkey(decode_hex(key_pair["pubkey"])) privkey = int.from_bytes(decode_hex(key_pair["privkey"]), "big") withdrawal_credential = Hash32( config.BLS_WITHDRAWAL_PREFIX.to_bytes(1, byteorder="big") + hash_eth2(pubkey)[1:]) pubkeys += (pubkey, ) privkeys += (privkey, ) withdrawal_credentials += (withdrawal_credential, ) return (pubkeys, privkeys, withdrawal_credentials)
def create_keypair_and_mock_withdraw_credentials( config: Eth2Config, key_set: Sequence[Dict[str, Any]] ) -> Tuple[Tuple[BLSPubkey, ...], Tuple[int, ...], Tuple[Hash32, ...]]: """ NOTE: this function mixes the parsing of keying material with the generation of derived values. Prefer other functions in this module that do the derivation directly. """ pubkeys: Tuple[BLSPubkey, ...] = () privkeys: Tuple[int, ...] = () withdrawal_credentials: Tuple[Hash32, ...] = () for key_pair in key_set: pubkey = BLSPubkey(decode_hex(key_pair["pubkey"])) privkey = int.from_bytes(decode_hex(key_pair["privkey"]), "big") withdrawal_credential = Hash32(config.BLS_WITHDRAWAL_PREFIX + hash_eth2(pubkey)[1:]) pubkeys += (pubkey, ) privkeys += (privkey, ) withdrawal_credentials += (withdrawal_credential, ) return (pubkeys, privkeys, withdrawal_credentials)
from eth.constants import ZERO_HASH32 from eth_typing import BLSPubkey, BLSSignature from eth2.beacon.typing import Epoch, HashTreeRoot, SigningRoot, Timestamp EMPTY_SIGNATURE = BLSSignature(b"\x00" * 96) EMPTY_PUBKEY = BLSPubkey(b"\x00" * 48) GWEI_PER_ETH = 10 ** 9 FAR_FUTURE_EPOCH = Epoch(2 ** 64 - 1) ZERO_SIGNING_ROOT = SigningRoot(ZERO_HASH32) ZERO_HASH_TREE_ROOT = HashTreeRoot(ZERO_HASH32) GENESIS_PARENT_ROOT = ZERO_SIGNING_ROOT ZERO_TIMESTAMP = Timestamp(0) MAX_INDEX_COUNT = 2 ** 40 MAX_RANDOM_BYTE = 2 ** 8 - 1 BASE_REWARDS_PER_EPOCH = 4 DEPOSIT_CONTRACT_TREE_DEPTH = 2 ** 5 SECONDS_PER_DAY = 86400 JUSTIFICATION_BITS_LENGTH = 4
def _parse_bls_pubkey(encoded_public_key: str) -> BLSPubkey: return BLSPubkey(decode_hex(encoded_public_key))
def G1_to_pubkey(pt: G1Uncompressed) -> BLSPubkey: z = compress_G1(pt) return BLSPubkey(i2osp(z, 48))
def _mini_stf(state: BeaconState, block: Optional[BeaconBlock], config: Eth2Config) -> BeaconState: """ A simplified state transition for testing state storage. - updates ``state_roots`` with the previous slot's state root - updates ``block_roots`` with the previous slot's block root - updates ``randao_mixes`` with an arbitrary mix at the current epoch - creates a new ``latest_block_header`` and adds it to the state - fills in the rest of the attributes with arbitrary values """ current_slot = state.slot + 1 current_epoch = current_slot // config.SLOTS_PER_EPOCH if block: latest_block_header = block.header else: latest_block_header = state.latest_block_header # state changes that depend on the previous state for retrieval randao_mix = Root(Hash32(current_slot.to_bytes(32, byteorder="little"))) state = (state.transform( ("state_roots", state.slot % config.SLOTS_PER_HISTORICAL_ROOT), state.hash_tree_root, ).transform( ("block_roots", state.slot % config.SLOTS_PER_HISTORICAL_ROOT), state.latest_block_header.hash_tree_root, ).transform( ("randao_mixes", current_epoch % config.EPOCHS_PER_HISTORICAL_VECTOR), randao_mix, ).mset("slot", current_slot, "latest_block_header", latest_block_header)) # state changes that do not depend on the previous state for retrieval new_validators = [ Validator.create(pubkey=BLSPubkey(n.to_bytes(48, byteorder="little"))) for n in range(current_slot, current_slot + 20) ] new_eth1_data_votes = [ Eth1Data.create( deposit_root=Root(Hash32(n.to_bytes(32, byteorder="little")))) for n in range(current_slot, current_slot + 7) ] new_previous_epoch_attestations = [ PendingAttestation.create(proposer_index=ValidatorIndex(n)) for n in range(current_slot, current_slot + 5) ] new_current_epoch_attestations = [ PendingAttestation.create(proposer_index=ValidatorIndex(n)) for n in range(current_slot + 5, current_slot + 10) ] state = state.mset( "validators", new_validators, "balances", (32, ) * len(new_validators), "eth1_data_votes", new_eth1_data_votes, "eth1_data", new_eth1_data_votes[0], "previous_epoch_attestations", new_previous_epoch_attestations, "current_epoch_attestations", new_current_epoch_attestations, "previous_justified_checkpoint", Checkpoint.create(epoch=Epoch(current_slot + 42)), "current_justified_checkpoint", Checkpoint.create(epoch=Epoch(current_slot + 43)), "finalized_checkpoint", Checkpoint.create(epoch=Epoch(current_slot + 44)), ) return state
def validate_deposit(deposit_data_dict: Dict[str, Any], credential: Credential) -> bool: ''' Checks whether a deposit is valid based on the eth2 rules. https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#deposits ''' pubkey = BLSPubkey(bytes.fromhex(deposit_data_dict['pubkey'])) withdrawal_credentials = bytes.fromhex( deposit_data_dict['withdrawal_credentials']) amount = deposit_data_dict['amount'] signature = BLSSignature(bytes.fromhex(deposit_data_dict['signature'])) deposit_message_root = bytes.fromhex( deposit_data_dict['deposit_data_root']) fork_version = bytes.fromhex(deposit_data_dict['fork_version']) # Verify pubkey if len(pubkey) != 48: return False if pubkey != credential.signing_pk: return False # Verify withdrawal credential if len(withdrawal_credentials) != 32: return False if withdrawal_credentials[: 1] == BLS_WITHDRAWAL_PREFIX == credential.withdrawal_prefix: if withdrawal_credentials[1:] != SHA256(credential.withdrawal_pk)[1:]: return False elif withdrawal_credentials[: 1] == ETH1_ADDRESS_WITHDRAWAL_PREFIX == credential.withdrawal_prefix: if withdrawal_credentials[1:12] != b'\x00' * 11: return False if credential.eth1_withdrawal_address is None: return False if withdrawal_credentials[12:] != credential.eth1_withdrawal_address: return False else: return False # Verify deposit amount if not MIN_DEPOSIT_AMOUNT < amount <= MAX_DEPOSIT_AMOUNT: return False # Verify deposit signature && pubkey deposit_message = DepositMessage( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount) domain = compute_deposit_domain(fork_version) signing_root = compute_signing_root(deposit_message, domain) if not bls.Verify(pubkey, signing_root, signature): return False # Verify Deposit Root signed_deposit = DepositData( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount, signature=signature, ) return signed_deposit.hash_tree_root == deposit_message_root
def SkToPk(k: int) -> BLSPubkey: return BLSPubkey(k.to_bytes(48, "little"))
def get_input_bls_pubkeys( test_case: Dict[str, Any]) -> Dict[str, Tuple[BLSPubkey, ...]]: return { 'pubkeys': tuple(BLSPubkey(decode_hex(item)) for item in test_case['input']) }
def privtopub(k: int) -> BLSPubkey: return BLSPubkey(k.to_bytes(48, "little"))
from eth.constants import ( ZERO_HASH32, ) from eth_typing import ( BLSSignature, BLSPubkey, ) from eth2.beacon.typing import ( Epoch, Timestamp, ) EMPTY_SIGNATURE = BLSSignature(b'\x00' * 96) EMPTY_PUBKEY = BLSPubkey(b'\x00' * 48) GWEI_PER_ETH = 10**9 FAR_FUTURE_EPOCH = Epoch(2**64 - 1) GENESIS_PARENT_ROOT = ZERO_HASH32 ZERO_TIMESTAMP = Timestamp(0) MAX_INDEX_COUNT = 2**40 MAX_RANDOM_BYTE = 2**8 - 1 BASE_REWARDS_PER_EPOCH = 5 DEPOSIT_CONTRACT_TREE_DEPTH = 2**5
def get_output_bls_pubkey(test_case: Dict[str, Any]) -> BLSPubkey: return BLSPubkey(decode_hex(test_case['output']))
def G1_to_pubkey(pt: G1Uncompressed) -> BLSPubkey: z = compress_G1(pt) return BLSPubkey(z.to_bytes(48, "big"))