def derive_xkey(xkey, *path_level, base58=True, hex=False): """ Child Key derivation for extended private/public keys :param bytes xkey: extended private/public in base58, HEX or bytes string format. :param list path_level: list of derivation path levels. For hardened derivation use HARDENED_KEY flag. :param boolean base58: (optional) return result as base58 encoded string, by default True. :param boolean hex: (optional) return result as HEX encoded string, by default False. In case True base58 flag value will be ignored. :return: extended child private/public key in base58, HEX or bytes string format. """ xkey = decode_base58_with_checksum(xkey) if xkey[:4] in [MAINNET_XPRIVATE_KEY_PREFIX, TESTNET_XPRIVATE_KEY_PREFIX]: for i in path_level: xkey = derive_child_xprivate_key(xkey, i) elif xkey[:4] in [MAINNET_XPUBLIC_KEY_PREFIX, TESTNET_XPUBLIC_KEY_PREFIX]: for i in path_level: xkey = derive_child_xpublic_key(xkey, i) else: raise ValueError("invalid extended key") if hex: return xkey.hex() elif base58: return encode_base58_with_checksum(xkey) else: return xkey
def private_from_xprivate_key(xprivate_key, wif=True, hex=False): """ Get private key from extended private key :param bytes xprivate_key: extended public in base58, HEX or bytes string format. :param boolean wif: (optional) return result as WIF format, by default True. :param boolean hex: (optional) return result as HEX encoded string, by default False. In case True WIF flag value will be ignored. :return: private key in HEX or bytes string format. """ if isinstance(xprivate_key, str): if len(xprivate_key) == 156: xprivate_key = bytes.fromhex(xprivate_key) else: xprivate_key = decode_base58_with_checksum(xprivate_key) if not isinstance(xprivate_key, bytes): raise TypeError("xprivate_key should be HEX, Base58 or bytes string") if xprivate_key[:4] not in [ MAINNET_XPRIVATE_KEY_PREFIX, TESTNET_XPRIVATE_KEY_PREFIX ]: raise ValueError("invalid extended private key") if hex: return xprivate_key[46:].hex() elif wif: if xprivate_key[:4] == MAINNET_XPRIVATE_KEY_PREFIX: testnet = False else: testnet = True return private_key_to_wif(xprivate_key[46:], testnet=testnet) return xprivate_key[46:].hex() if hex else xprivate_key[46:]
def is_xpublic_key_valid(key): """ Check the extended private key is valid according to BIP-0032. :param key: extended private key in BASE58, HEX or bytes string format. :return: boolean. """ if isinstance(key, str): try: key = decode_base58_with_checksum(key) except: try: key = bytes.fromhex(key) except: pass if not isinstance(key, bytes) or len(key) != 78: return False if key[:4] not in [MAINNET_XPUBLIC_KEY_PREFIX, TESTNET_XPUBLIC_KEY_PREFIX]: return False return True
def xprivate_to_xpublic_key(xprivate_key, base58=True, hex=False): """ Get extended public key from extended private key using ECDSA secp256k1 :param str,bytes key: extended private key in base58, HEX or bytes string. :param boolean base58: (optional) return result as base58 encoded string, by default True. :param boolean hex: (optional) return result as HEX encoded string, by default False. In case True base58 flag value will be ignored. :return: extended public key in base58, HEX or bytes string format. """ if isinstance(xprivate_key, str): try: if len(xprivate_key) == 156: xprivate_key = bytes.fromhex(xprivate_key) else: xprivate_key = decode_base58_with_checksum(xprivate_key) except: raise ValueError("invalid extended private key") if not isinstance(xprivate_key, bytes): raise TypeError( "extended private key should be base58 string or bytes") if xprivate_key[:4] == TESTNET_XPRIVATE_KEY_PREFIX: prefix = TESTNET_XPUBLIC_KEY_PREFIX elif xprivate_key[:4] == MAINNET_XPRIVATE_KEY_PREFIX: prefix = MAINNET_XPUBLIC_KEY_PREFIX else: raise ValueError("invalid extended private key") key = b"".join([ prefix, xprivate_key[4:45], private_to_public_key(xprivate_key[46:], hex=False) ]) if hex: return key.hex() elif base58: key = b"".join([key, double_sha256(key)[:4]]) return encode_base58(key) else: return key
def public_from_xpublic_key(xpublic_key, hex=True): """ Get public key from extended public key :param bytes xpublic_key: extended public in base58, HEX or bytes string format. :param boolean base58: (optional) return result as base58 encoded string, by default True. :param boolean hex: (optional) return result as HEX encoded string, by default False. In case True base58 flag value will be ignored. :return: public key in HEX or bytes string format. """ if isinstance(xpublic_key, str): if len(xpublic_key) == 156: xpublic_key = bytes.fromhex(xpublic_key) else: xpublic_key = decode_base58_with_checksum(xpublic_key) if not isinstance(xpublic_key, bytes): raise TypeError("xpublic_key should be HEX, Base58 or bytes string") if xpublic_key[:4] not in [ MAINNET_XPUBLIC_KEY_PREFIX, TESTNET_XPUBLIC_KEY_PREFIX ]: raise ValueError("invalid extended public key") return xpublic_key[45:].hex() if hex else xpublic_key[45:]