def get_private_key(self, change, n): """ Returns a private key in the chain for use in signing messages or transactions. Args: change (bool): If True, returns an address for change purposes, otherwise returns an address for payment. n (int): index of address in chain. Returns: HDPrivateKey: a private key in this account's chain. """ # We only use public key derivation per BIP44 k = self._chain_priv_keys[change] if k is None: raise ValueError("No private key provided for account.") return HDPrivateKey.from_parent(k, n)
def from_bytes(b): """ Generates either a HDPrivateKey or HDPublicKey from the underlying bytes. The serialization must conform to the description in: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#serialization-format Args: b (bytes): A byte stream conforming to the above. Returns: HDPrivateKey or HDPublicKey: Either an HD private or public key object, depending on what was serialized. """ if len(b) < 78: raise ValueError("b must be at least 78 bytes long.") version = int.from_bytes(b[:4], 'big') depth = b[4] parent_fingerprint = b[5:9] index = int.from_bytes(b[9:13], 'big') chain_code = b[13:45] key_bytes = b[45:78] rv = None if version == HDPrivateKey.MAINNET_VERSION or version == HDPrivateKey.TESTNET_VERSION: if key_bytes[0] != 0: raise ValueError("First byte of private key must be 0x00!") private_key = int.from_bytes(key_bytes[1:], 'big') rv = HDPrivateKey(key=private_key, chain_code=chain_code, index=index, depth=depth, parent_fingerprint=parent_fingerprint) elif version == HDPublicKey.MAINNET_VERSION or version == HDPublicKey.TESTNET_VERSION: if key_bytes[0] != 0x02 and key_bytes[0] != 0x03: raise ValueError("First byte of public key must be 0x02 or 0x03!") public_key = PublicKey.from_bytes(key_bytes) rv = HDPublicKey(x=public_key.point.x, y=public_key.point.y, chain_code=chain_code, index=index, depth=depth, parent_fingerprint=parent_fingerprint) else: raise ValueError("incorrect encoding.") return (rv, b[78:])
def __init__(self, hd_key, name, index, data_provider, cache_manager, testnet=False, last_state=None, skip_discovery=False): # Take in either public or private key for this account as we # can derive everything from it. if not isinstance(hd_key, HDKey): raise TypeError("hd_key must be a HDKey object") self.key = hd_key self.name = name self.index = index self.data_provider = data_provider self.testnet = testnet self.last_indices = [-1, -1] self._cache_manager = cache_manager self._last_update = 0 self._last_full_update = 0 if last_state is not None and isinstance(last_state, dict): if "last_payout_index" in last_state: self.last_indices[self.PAYOUT_CHAIN] = last_state["last_payout_index"] if "last_change_index" in last_state: self.last_indices[self.CHANGE_CHAIN] = last_state["last_change_index"] # Check to see that the address cache has up to last_indices for change in [self.PAYOUT_CHAIN, self.CHANGE_CHAIN]: k = self._cache_manager.get_chain_indices(self.index, change) for i in range(self.last_indices[change] + 1): if i not in k or k[i] != i: self.last_indices[change] = -1 break self._chain_priv_keys = [None, None] self._chain_pub_keys = [None, None] for change in [0, 1]: if isinstance(self.key, HDPrivateKey): self._chain_priv_keys[change] = HDPrivateKey.from_parent(self.key, change) self._chain_pub_keys[change] = self._chain_priv_keys[change].public_key else: self._chain_pub_keys[change] = HDPublicKey.from_parent(self.key, change) if not skip_discovery: self._sync_txns(check_all=True) self._update_balance()