def verify_msg_hash(msg_hash, signature, public_key): log.debug('message=%s type %s', msg_hash, type(msg_hash)) log.debug('public_key=%s type %s', public_key, type(public_key)) log.debug('signature=%s type %s', signature, type(signature)) signature = KeyAPI.Signature(bytes.fromhex(signature)) public_key = KeyAPI.PublicKey(bytes.fromhex(public_key)) return signature.verify_msg_hash(msg_hash, public_key)
def federated_address(self) -> str: signature_pubkey = self.signing_public_key uncompressed_bytes = signature_pubkey.to_bytes(is_compressed=False) without_prefix = uncompressed_bytes[1:] verifying_key_as_eth_key = EthKeyAPI.PublicKey(without_prefix) address = verifying_key_as_eth_key.to_checksum_address() return to_checksum_address(address)
def from_public_key(pub: bytes, chain_code: bytes): ''' Construct an HD Node from an uncompressed public key. (starts with 0x04 as first byte) Parameters ---------- pub : bytes An uncompressed public key in bytes. chain_code : bytes 32 bytes Returns ------- HDNode A new HDNode. ''' # parts net_version = VERSION_MAINNET_PUBLIC depth = DEPTH_MASTER_NODE fprint = FINGER_PRINT_MASTER_KEY index = CHILD_NUMBER_MASTER_KEY chain = chain_code key_bytes = KeyAPI.PublicKey(strip_0x04(pub)).to_compressed_bytes() # assemble all_bytes = net_version + depth + fprint + index + chain + key_bytes # double sha-256 checksum xpub_str = Base58Encoder.CheckEncode(all_bytes) bip32_ctx = Bip32.FromExtendedKey(xpub_str) return HDNode(bip32_ctx)
def derive_federated_address(self): if self.federated_only: verifying_key = self.public_keys(SigningPower) uncompressed_bytes = verifying_key.to_bytes(is_compressed=False) without_prefix = uncompressed_bytes[1:] verifying_key_as_eth_key = EthKeyAPI.PublicKey(without_prefix) federated_address = verifying_key_as_eth_key.to_checksum_address() else: raise RuntimeError('Federated address can only be derived for federated characters.') return federated_address
def verify_signature(signature_hex: str, message_bytes: bytes, public_key_hex: str): """Returns True for a valid signature. Args: signature (str) -- hex string message (bytes) public_key (str) -- hex string """ signature_bytes = bytes.fromhex(signature_hex) signature = KeyAPI.Signature(signature_bytes=signature_bytes) pk_bytes = bytes.fromhex(public_key_hex[2:]) pk = KeyAPI.PublicKey(pk_bytes) return signature.verify_msg(message_bytes, pk)
def encrypt(self, message, public_key=None): """ Return message encrypted with public key @param message bytes @param public_key bytes """ if isinstance(message, str): message = message.encode() if public_key is None: public_key = self.public_key else: public_key = KeyAPI.PublicKey(public_key) return ecies.encrypt(message, public_key)
def verify_sig_msg(self, message: bytes, signature: bytes, pubkey: bytes): """ Verifies that message has been signed by pubkey Args: message: bytes of message to verify signature: bytes of signature to verify pubkey: public key that signed this message Returns: Boolean (True if signature is valid) """ log.debug('from verify_sig_msg message=%s type=%s', message, type(message)) public_key = KeyAPI.PublicKey(pubkey) sig = KeyAPI.Signature(signature) return sig.verify_msg(message, public_key)
def _set_checksum_address(self, checksum_address=None): if checksum_address is not None: # # Decentralized # if not self.federated_only: # TODO: And why not return here then? self._checksum_address = checksum_address # TODO: Check that this matches TransactingPower # # Federated # elif self.federated_only: # TODO: What are we doing here? try: self._set_checksum_address() # type: str except NoSigningPower: self._checksum_address = NO_BLOCKCHAIN_CONNECTION if checksum_address: # We'll take a checksum address, as long as it matches their signing key if not checksum_address == self.checksum_address: error = "Federated-only Characters derive their address from their Signing key; got {} instead." raise self.SuspiciousActivity( error.format(checksum_address)) if self.federated_only: verifying_key = self.public_keys(SigningPower) uncompressed_bytes = verifying_key.to_bytes(is_compressed=False) without_prefix = uncompressed_bytes[1:] verifying_key_as_eth_key = EthKeyAPI.PublicKey(without_prefix) public_address = verifying_key_as_eth_key.to_checksum_address() else: try: # TODO: Some circular logic here if we haven't set the canonical address. public_address = to_checksum_address( self.canonical_public_address) except TypeError: public_address = NO_BLOCKCHAIN_CONNECTION # raise TypeError("You can't use a decentralized character without a _checksum_address.") except NotImplementedError: raise TypeError( "You can't use a plain Character in federated mode - you need to implement ether_address." ) # TODO: update comment self._checksum_address = public_address
def _set_checksum_address(self): if self.federated_only: verifying_key = self.public_keys(SigningPower) uncompressed_bytes = verifying_key.to_bytes(is_compressed=False) without_prefix = uncompressed_bytes[1:] verifying_key_as_eth_key = EthKeyAPI.PublicKey(without_prefix) public_address = verifying_key_as_eth_key.to_checksum_address() else: try: public_address = to_checksum_address(self.canonical_public_address) except TypeError: raise TypeError("You can't use a decentralized character without a _checksum_address.") except NotImplementedError: raise TypeError( "You can't use a plain Character in federated mode - you need to implement ether_address.") self._checksum_address = public_address
def address(self): ''' Get the checksummed address of this hd account :returns: the checksummed public address for this account. :rtype : str .. code-block:: python >>> my_account.address "0xF0109fC8DF283027b6285cc889F5aA624EaC1F55" ''' rawtuple = bip32_deserialize(self.__key) key = rawtuple[-1] if rawtuple[0] in PRIVATE: # slice the last byte, since it is the WIF-Compressed information key = KeyAPI.PrivateKey(key[:-1]).public_key else: # remove 04 prefix for KeyAPI key = KeyAPI.PublicKey(decompress(key)[1:]) return key.to_checksum_address()
def generate( cls, passphrase: str, encrypting: bool = True, wallet: bool = True, tls: bool = True, host: str = None, curve: EllipticCurve = None, keyring_root: str = None, ) -> 'NucypherKeyring': """ Generates new encrypting, signing, and wallet keys encrypted with the passphrase, respectively saving keyfiles on the local filesystem from *default* paths, returning the corresponding Keyring instance. """ failures = cls.validate_passphrase(passphrase) if failures: raise cls.InvalidPassphrase( ", ".join(failures) ) # TODO: Ensure this scope is seperable from the scope containing the passphrase if not any((wallet, encrypting, tls)): raise ValueError( 'Either "encrypting", "wallet", or "tls" must be True ' 'to generate new keys, or set "no_keys" to True to skip generation.' ) _base_filepaths = cls._generate_base_filepaths( keyring_root=keyring_root) _public_key_dir = _base_filepaths['public_key_dir'] _private_key_dir = _base_filepaths['private_key_dir'] # Create the key directories with default paths. Raises OSError if dirs exist # if exists_ok and not os.path.isdir(_public_key_dir): os.mkdir(_public_key_dir, mode=0o744) # public dir # if exists_ok and not os.path.isdir(_private_key_dir): os.mkdir(_private_key_dir, mode=0o700) # private dir # # Generate New Keypairs # keyring_args = dict() if wallet is True: new_address, new_wallet = _generate_wallet(passphrase) new_wallet_path = os.path.join( _private_key_dir, 'wallet-{}.json'.format(new_address)) saved_wallet_path = _write_private_keyfile(new_wallet_path, json.dumps(new_wallet), serializer=None) keyring_args.update(wallet_path=saved_wallet_path) account = new_address if encrypting is True: signing_private_key, signing_public_key = _generate_signing_keys() if not wallet: uncompressed_bytes = signing_public_key.to_bytes( is_compressed=False) without_prefix = uncompressed_bytes[1:] verifying_key_as_eth_key = EthKeyAPI.PublicKey(without_prefix) account = verifying_key_as_eth_key.to_checksum_address() __key_filepaths = cls._generate_key_filepaths( account=account, private_key_dir=_private_key_dir, public_key_dir=_public_key_dir) if encrypting is True: encrypting_private_key, encrypting_public_key = _generate_encryption_keys( ) delegating_keying_material = UmbralKeyingMaterial().to_bytes() # Derive Wrapping Keys passphrase_salt, encrypting_salt, signing_salt, delegating_salt = ( os.urandom(32) for _ in range(4)) derived_key_material = _derive_key_material_from_passphrase( salt=passphrase_salt, passphrase=passphrase) encrypting_wrap_key = _derive_wrapping_key_from_key_material( salt=encrypting_salt, key_material=derived_key_material) signature_wrap_key = _derive_wrapping_key_from_key_material( salt=signing_salt, key_material=derived_key_material) delegating_wrap_key = _derive_wrapping_key_from_key_material( salt=delegating_salt, key_material=derived_key_material) # TODO: Deprecate _encrypt_umbral_key with new pyumbral release # Encapsulate Private Keys encrypting_key_data = _encrypt_umbral_key( umbral_key=encrypting_private_key, wrapping_key=encrypting_wrap_key) signing_key_data = _encrypt_umbral_key( umbral_key=signing_private_key, wrapping_key=signature_wrap_key) delegating_key_data = bytes( SecretBox(delegating_wrap_key).encrypt( delegating_keying_material)) # Assemble Private Keys encrypting_key_metadata = _assemble_key_data( key_data=encrypting_key_data, master_salt=passphrase_salt, wrap_salt=encrypting_salt) signing_key_metadata = _assemble_key_data( key_data=signing_key_data, master_salt=passphrase_salt, wrap_salt=signing_salt) delegating_key_metadata = _assemble_key_data( key_data=delegating_key_data, master_salt=passphrase_salt, wrap_salt=delegating_salt) # Write Private Keys rootkey_path = _write_private_keyfile( keypath=__key_filepaths['root'], key_data=encrypting_key_metadata, serializer=cls._private_key_serializer) sigkey_path = _write_private_keyfile( keypath=__key_filepaths['signing'], key_data=signing_key_metadata, serializer=cls._private_key_serializer) delegating_key_path = _write_private_keyfile( keypath=__key_filepaths['delegating'], key_data=delegating_key_metadata, serializer=cls._private_key_serializer) # Write Public Keys root_keypath = _write_public_keyfile( __key_filepaths['root_pub'], encrypting_public_key.to_bytes()) signing_keypath = _write_public_keyfile( __key_filepaths['signing_pub'], signing_public_key.to_bytes()) # Commit keyring_args.update( keyring_root=keyring_root or cls.__default_keyring_root, root_key_path=rootkey_path, pub_root_key_path=root_keypath, signing_key_path=sigkey_path, pub_signing_key_path=signing_keypath, delegating_key_path=delegating_key_path, ) if tls is True: if not all((host, curve)): raise ValueError( "Host and curve are required to make a new keyring TLS certificate" ) private_key, cert = _generate_tls_keys(host, curve) def __serialize_pem(pk): return pk.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.BestAvailableEncryption( password=derived_key_material)) tls_key_path = _write_private_keyfile( keypath=__key_filepaths['tls'], key_data=__serialize_pem(pk=private_key), serializer=None) certificate_filepath = _write_tls_certificate( full_filepath=__key_filepaths['tls_certificate'], certificate=cert) keyring_args.update(tls_certificate_path=certificate_filepath, tls_key_path=tls_key_path) keyring_instance = cls(account=account, **keyring_args) return keyring_instance
def verify_sig_msg_hash(self, msg_hash: bytes, signature: bytes, pubkey: bytes): public_key = KeyAPI.PublicKey(pubkey) sig = KeyAPI.Signature(signature) return sig.verify_msg_hash(msg_hash, public_key)
def verify_sig_msg(self, message: bytes, signature: bytes, pubkey: bytes): """ Verifies that message has been signed by pubkey """ public_key = KeyAPI.PublicKey(pubkey) sig = KeyAPI.Signature(signature) return sig.verify_msg(message, public_key)
def generate( cls, password: str, encrypting: bool, wallet: bool, rest: bool, host: str = None, curve: EllipticCurve = None, keyring_root: str = None, ) -> 'NucypherKeyring': """ Generates new encrypting, signing, and wallet keys encrypted with the password, respectively saving keyfiles on the local filesystem from *default* paths, returning the corresponding Keyring instance. """ failures = cls.validate_password(password) if failures: raise cls.AuthenticationFailed( ", ".join(failures) ) # TODO: Ensure this scope is seperable from the scope containing the password if not any((wallet, encrypting, rest)): raise ValueError( 'Either "encrypting", "wallet", or "tls" must be True ' 'to generate new keys, or set "no_keys" to True to skip generation.' ) if curve is None: curve = cls.__DEFAULT_TLS_CURVE _base_filepaths = cls._generate_base_filepaths( keyring_root=keyring_root) _public_key_dir = _base_filepaths['public_key_dir'] _private_key_dir = _base_filepaths['private_key_dir'] # Write to disk os.mkdir(_public_key_dir, mode=0o744) # public dir os.mkdir(_private_key_dir, mode=0o700) # private dir # # Generate New Keypairs # keyring_args = dict() if wallet is True: new_address, new_wallet = _generate_wallet(password) new_wallet_path = os.path.join( _private_key_dir, 'wallet-{}.json'.format(new_address)) with open(new_wallet_path, 'w') as wallet: # TODO: is this pub or private? wallet.write(json.dumps(new_wallet)) keyring_args.update(wallet_path=new_wallet_path) if encrypting is True: signing_private_key, signing_public_key = _generate_signing_keys() if not wallet: uncompressed_bytes = signing_public_key.to_bytes( is_compressed=False) without_prefix = uncompressed_bytes[1:] verifying_key_as_eth_key = EthKeyAPI.PublicKey(without_prefix) new_address = verifying_key_as_eth_key.to_checksum_address() __key_filepaths = cls._generate_key_filepaths( account=new_address, private_key_dir=_private_key_dir, public_key_dir=_public_key_dir) if encrypting is True: encrypting_private_key, encrypting_public_key = _generate_encryption_keys( ) delegating_keying_material = UmbralKeyingMaterial().to_bytes() # Derive Wrapping Keys password_salt, encrypting_salt, signing_salt, delegating_salt = ( os.urandom(32) for _ in range(4)) cls.log.info("About to derive key from password.") derived_key_material = derive_key_from_password( salt=password_salt, password=password.encode()) encrypting_wrap_key = _derive_wrapping_key_from_key_material( salt=encrypting_salt, key_material=derived_key_material) signature_wrap_key = _derive_wrapping_key_from_key_material( salt=signing_salt, key_material=derived_key_material) delegating_wrap_key = _derive_wrapping_key_from_key_material( salt=delegating_salt, key_material=derived_key_material) # Encapsulate Private Keys encrypting_key_data = encrypting_private_key.to_bytes( wrapping_key=encrypting_wrap_key) signing_key_data = signing_private_key.to_bytes( wrapping_key=signature_wrap_key) delegating_key_data = bytes( SecretBox(delegating_wrap_key).encrypt( delegating_keying_material)) # Assemble Private Keys encrypting_key_metadata = _assemble_key_data( key_data=encrypting_key_data, master_salt=password_salt, wrap_salt=encrypting_salt) signing_key_metadata = _assemble_key_data( key_data=signing_key_data, master_salt=password_salt, wrap_salt=signing_salt) delegating_key_metadata = _assemble_key_data( key_data=delegating_key_data, master_salt=password_salt, wrap_salt=delegating_salt) # Write Private Keys rootkey_path = _write_private_keyfile( keypath=__key_filepaths['root'], key_data=encrypting_key_metadata, serializer=cls._private_key_serializer) sigkey_path = _write_private_keyfile( keypath=__key_filepaths['signing'], key_data=signing_key_metadata, serializer=cls._private_key_serializer) delegating_key_path = _write_private_keyfile( keypath=__key_filepaths['delegating'], key_data=delegating_key_metadata, serializer=cls._private_key_serializer) # Write Public Keys root_keypath = _write_public_keyfile( __key_filepaths['root_pub'], encrypting_public_key.to_bytes()) signing_keypath = _write_public_keyfile( __key_filepaths['signing_pub'], signing_public_key.to_bytes()) # Commit keyring_args.update( keyring_root=keyring_root or cls.__default_keyring_root, root_key_path=rootkey_path, pub_root_key_path=root_keypath, signing_key_path=sigkey_path, pub_signing_key_path=signing_keypath, delegating_key_path=delegating_key_path, ) if rest is True: if not all( (host, curve, new_address) ): # TODO: Do we want to allow showing up with an old wallet and generating a new cert? Probably. raise ValueError( "host, checksum_address and curve are required to make a new keyring TLS certificate. Got {}, {}" .format(host, curve)) private_key, cert = _generate_tls_keys( host=host, checksum_address=new_address, curve=curve) def __serialize_pem(pk): return pk.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.BestAvailableEncryption( password=derived_key_material)) tls_key_path = _write_private_keyfile( keypath=__key_filepaths['tls'], key_data=__serialize_pem(pk=private_key), serializer=None) certificate_filepath = _write_tls_certificate( full_filepath=__key_filepaths['tls_certificate'], certificate=cert) keyring_args.update(tls_certificate_path=certificate_filepath, tls_key_path=tls_key_path) keyring_instance = cls(account=new_address, **keyring_args) return keyring_instance
def guardian_public_key(self) -> KeyAPI.PublicKey: return KeyAPI.PublicKey( public_key_bytes=bytes.fromhex(self.GUARDIAN_PUBLIC_KEY))
def guardian_public_key(self) -> KeyAPI.PublicKey: # noinspection PyCallByClass return KeyAPI.PublicKey( public_key_bytes=bytes.fromhex(self.GUARDIAN_PUBLIC_KEY))
def public_key_to_address(public_key): return KeyAPI.PublicKey(public_key_bytes=public_key).to_checksum_address()
def generate(cls, checksum_address: str, password: str, encrypting: bool = True, rest: bool = False, host: str = None, curve: EllipticCurve = None, keyring_root: str = None, force: bool = False, ) -> 'NucypherKeyring': """ Generates new encrypting, signing, and wallet keys encrypted with the password, respectively saving keyfiles on the local filesystem from *default* paths, returning the corresponding Keyring instance. """ keyring_root = keyring_root or cls._default_keyring_root failures = cls.validate_password(password) if failures: raise cls.AuthenticationFailed(", ".join(failures)) # TODO: Ensure this scope is seperable from the scope containing the password if not any((encrypting, rest)): raise ValueError('Either "encrypting", "wallet", or "tls" must be True ' 'to generate new keys, or set "no_keys" to True to skip generation.') if curve is None: curve = cls.__DEFAULT_TLS_CURVE _base_filepaths = cls._generate_base_filepaths(keyring_root=keyring_root) _public_key_dir = _base_filepaths['public_key_dir'] _private_key_dir = _base_filepaths['private_key_dir'] # # Generate New Keypairs # keyring_args = dict() if checksum_address is not FEDERATED_ADDRESS: # Addresses read from some node keyrings (clients) are *not* returned in checksum format. checksum_address = to_checksum_address(checksum_address) if encrypting is True: signing_private_key, signing_public_key = _generate_signing_keys() if checksum_address is FEDERATED_ADDRESS: uncompressed_bytes = signing_public_key.to_bytes(is_compressed=False) without_prefix = uncompressed_bytes[1:] verifying_key_as_eth_key = EthKeyAPI.PublicKey(without_prefix) checksum_address = verifying_key_as_eth_key.to_checksum_address() else: # TODO: Consider a "Repair" mode here # signing_private_key, signing_public_key = ... pass if not checksum_address: raise ValueError("Checksum address must be provided for non-federated keyring generation") __key_filepaths = cls._generate_key_filepaths(account=checksum_address, private_key_dir=_private_key_dir, public_key_dir=_public_key_dir) if encrypting is True: encrypting_private_key, encrypting_public_key = _generate_encryption_keys() delegating_keying_material = UmbralKeyingMaterial().to_bytes() # Derive Wrapping Keys password_salt, encrypting_salt, signing_salt, delegating_salt = (os.urandom(32) for _ in range(4)) cls.log.info("About to derive key from password.") derived_key_material = derive_key_from_password(salt=password_salt, password=password.encode()) encrypting_wrap_key = _derive_wrapping_key_from_key_material(salt=encrypting_salt, key_material=derived_key_material) signature_wrap_key = _derive_wrapping_key_from_key_material(salt=signing_salt, key_material=derived_key_material) delegating_wrap_key = _derive_wrapping_key_from_key_material(salt=delegating_salt, key_material=derived_key_material) # Encapsulate Private Keys encrypting_key_data = encrypting_private_key.to_bytes(wrapping_key=encrypting_wrap_key) signing_key_data = signing_private_key.to_bytes(wrapping_key=signature_wrap_key) delegating_key_data = bytes(SecretBox(delegating_wrap_key).encrypt(delegating_keying_material)) # Assemble Private Keys encrypting_key_metadata = _assemble_key_data(key_data=encrypting_key_data, master_salt=password_salt, wrap_salt=encrypting_salt) signing_key_metadata = _assemble_key_data(key_data=signing_key_data, master_salt=password_salt, wrap_salt=signing_salt) delegating_key_metadata = _assemble_key_data(key_data=delegating_key_data, master_salt=password_salt, wrap_salt=delegating_salt) # # Write Keys # # Create base paths if the do not exist. os.makedirs(abspath(keyring_root), exist_ok=True, mode=0o700) if not os.path.isdir(_public_key_dir): os.mkdir(_public_key_dir, mode=0o744) # public dir if not os.path.isdir(_private_key_dir): os.mkdir(_private_key_dir, mode=0o700) # private dir try: rootkey_path = _write_private_keyfile(keypath=__key_filepaths['root'], key_data=encrypting_key_metadata, serializer=cls._private_key_serializer) sigkey_path = _write_private_keyfile(keypath=__key_filepaths['signing'], key_data=signing_key_metadata, serializer=cls._private_key_serializer) delegating_key_path = _write_private_keyfile(keypath=__key_filepaths['delegating'], key_data=delegating_key_metadata, serializer=cls._private_key_serializer) # Write Public Keys root_keypath = _write_public_keyfile(__key_filepaths['root_pub'], encrypting_public_key.to_bytes()) signing_keypath = _write_public_keyfile(__key_filepaths['signing_pub'], signing_public_key.to_bytes()) except (PrivateKeyExistsError, FileExistsError): if not force: raise ExistingKeyringError(f"There is an existing keyring for address '{checksum_address}'") else: # Commit keyring_args.update( keyring_root=keyring_root, root_key_path=rootkey_path, pub_root_key_path=root_keypath, signing_key_path=sigkey_path, pub_signing_key_path=signing_keypath, delegating_key_path=delegating_key_path, ) if rest is True: if not all((host, curve, checksum_address)): # TODO: Do we want to allow showing up with an old wallet and generating a new cert? Probably. raise ValueError("host, checksum_address and curve are required to make a new keyring TLS certificate. Got {}, {}".format(host, curve)) private_key, cert = _generate_tls_keys(host=host, checksum_address=checksum_address, curve=curve) def __serialize_pem(pk): return pk.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.BestAvailableEncryption(password=derived_key_material) ) tls_key_path = _write_private_keyfile(keypath=__key_filepaths['tls'], key_data=__serialize_pem(pk=private_key), serializer=None) certificate_filepath = _write_tls_certificate(full_filepath=__key_filepaths['tls_certificate'], certificate=cert) keyring_args.update(tls_certificate_path=certificate_filepath, tls_key_path=tls_key_path) keyring_instance = cls(account=checksum_address, **keyring_args) return keyring_instance
def canonical_address_from_umbral_key(public_key: UmbralPublicKey) -> bytes: pubkey_raw_bytes = public_key.to_bytes(is_compressed=False)[1:] eth_pubkey = EthKeyAPI.PublicKey(pubkey_raw_bytes) canonical_address = eth_pubkey.to_canonical_address() return canonical_address
def verify_signature(hash, sig, pub): keys = KeyAPI(NativeECCBackend) sign = keys.Signature(sig) public = keys.PublicKey(pub, base.BaseECCBackend) return keys.ecdsa_verify(hash, sign, public)
def canonical_address_from_umbral_key(public_key: UmbralPublicKey) -> bytes: pubkey_raw_bytes = get_coordinates_as_bytes(public_key) eth_pubkey = EthKeyAPI.PublicKey(pubkey_raw_bytes) canonical_address = eth_pubkey.to_canonical_address() return canonical_address