Ejemplo n.º 1
0
 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)
Ejemplo n.º 2
0
    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:])
Ejemplo n.º 3
0
    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()