def _xpriv_to_xpub(xpriv: str) -> str: ''' Turns an xpriv into an xpub. Args: xpriv (str): the b58 encoded xpriv Returns: ''' xpub = bytearray() xpriv_bytes = base58.decode(xpriv) # determine what network the key is on if xpriv_bytes[0:4] == utils.VERSION_BYTES['mainnet']['private']: # mainnet xpub.extend(utils.VERSION_BYTES['mainnet']['public']) elif xpriv_bytes[0:4] == utils.VERSION_BYTES['testnet'][ 'private']: # pragma: nocover # noqa: E501 # testnet xpub.extend(utils.VERSION_BYTES['testnet'] ['public']) # pragma: nocover # noqa: E501 else: raise ValueError('unrecognized version bytes. ' 'Is this an xpub?') # pragma: nocover # most parts are verbatim xpub.extend(xpriv_bytes[4:45]) # derive the pubkey and append it xpub.extend(simple.priv_to_pub(xpriv_bytes[46:78])) return base58.encode(xpub)
def _child_from_xpriv(self, index: int, child_xpriv: str) -> 'HDKey': ''' Returns a new HDKey object based on the current object and the new child xpriv. Don't call this directly, it's for child derivation. Args: index (int): the index of the child child_xpriv (str): the child's xpriv Returns HDKey: the new child object ''' # set the path, if this key has a path path: Optional[str] if self.path is not None: if index >= utils.BIP32_HARDEN: index_str = '{}h'.format(str(index - utils.BIP32_HARDEN)) else: index_str = str(index) path = '{}/{}'.format(self.path, index_str) else: path = None # Make the pubkey xpriv_bytes = base58.decode(child_xpriv) privkey = xpriv_bytes[46:78] pubkey = simple.priv_to_pub(privkey) # What network is this for? if xpriv_bytes[0:4] == utils.VERSION_BYTES['mainnet']['private']: network = 'Bitcoin' elif xpriv_bytes[0:4] == utils.VERSION_BYTES['testnet'][ 'private']: # pragma: nocover # noqa: E501 network = 'Testnet' # pragma: nocover else: raise ValueError('unrecognized version bytes. ' 'Is this an xpriv?') # pragma: nocover return HDKey(key_dict=KeyDict(path=path, network=network, depth=xpriv_bytes[4], parent_fingerprint=xpriv_bytes[5:9], index=index, parent=self, chain_code=xpriv_bytes[13:45], fingerprint=utils.hash160(pubkey)[:4], xpriv=child_xpriv, xpub=HDKey._xpriv_to_xpub(child_xpriv), privkey=privkey, pubkey=pubkey), _error_on_call=False)
def _make_child_xpub(self, child_pubkey: bytes, index: int, chain_code: bytes) -> str: ''' Makes a child xpub based on the current key and the child key info. Args: child_pubkey (bytes): the child pubkey index (int): the child index chain_code (bytes): the child chain code Returns (str): the child xpub ''' xpub = bytearray() xpub.extend(base58.decode(cast(str, self.xpub))[0:4]) # prefix xpub.extend([cast(int, self.depth) + 1]) # depth xpub.extend(self.fingerprint) # fingerprint xpub.extend(index.to_bytes(4, byteorder='big')) # index xpub.extend(chain_code) # chain_code xpub.extend(child_pubkey) # pubkey (comp) return base58.encode(xpub)
def _child_from_xpub(self, index: int, child_xpub: str) -> 'HDKey': ''' Returns a new HDKey object based on the current object and the new child xpub. Don't call this directly, it's for child derivation. Args: index (int): the index of the child child_xpub (str): the child's xpub Returns HDKey: the new child object ''' path: Optional[str] if self.path is not None: path = '{}/{}'.format(self.path, str(index)) else: path = None xpub_bytes = base58.decode(child_xpub) pubkey = xpub_bytes[45:78] if xpub_bytes[0:4] == utils.VERSION_BYTES['mainnet']['public']: network = 'Bitcoin' elif xpub_bytes[0:4] == utils.VERSION_BYTES['testnet'][ 'public']: # pragma: nocover # noqa: E501 network = 'Testnet' # pragma: nocover else: raise ValueError('unrecognized version bytes.' ' Is this an xpub?') # pragma: nocover return HDKey(key_dict=KeyDict(path=path, network=network, depth=xpub_bytes[4], parent_fingerprint=xpub_bytes[5:9], index=int.from_bytes(xpub_bytes[9:13], byteorder='big'), parent=self, chain_code=xpub_bytes[13:45], fingerprint=utils.hash160(pubkey)[:4], xpriv=None, xpub=child_xpub, privkey=None, pubkey=pubkey), _error_on_call=False)
def from_xpub(HDKey, xpub: str, path: Optional[str] = None) -> 'HDKey': ''' Instantiate an HDKey from an xpub. Populates all possible fields Args: xpub (str): the xpub path (str): the path if it's known. useful for calling derive_path Returns: (HDKey): the key object ''' xpub_bytes = base58.decode(xpub) pubkey = xpub_bytes[45:78] try: simple.compress_pubkey(pubkey) except Exception: raise ValueError('Cannot parse public key') if xpub_bytes[0:4] == utils.VERSION_BYTES['mainnet']['public']: network = 'Bitcoin' elif xpub_bytes[0:4] == utils.VERSION_BYTES['testnet'][ 'public']: # pragma: nocover # noqa: E501 network = 'Testnet' # pragma: nocover else: raise ValueError('unrecognized version bytes. Is this an xpub?' ) # pragma: nocover # noqa: E501 return HDKey(key_dict=KeyDict(path=path, network=network, depth=xpub_bytes[4], parent_fingerprint=xpub_bytes[5:9], index=int.from_bytes(xpub_bytes[9:13], byteorder='big'), parent=None, chain_code=xpub_bytes[13:45], fingerprint=utils.hash160(pubkey)[:4], xpriv=None, xpub=xpub, privkey=None, pubkey=pubkey), _error_on_call=False)