URI: 
       tkeystore: change derive_pubkey API to return bytes - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit fcd9752f190d02a04f31137a5910988de2405e68
   DIR parent ea62027599d6efaf6ac6fe3b963e04a833a9950b
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Tue, 10 Dec 2019 20:41:47 +0100
       
       keystore: change derive_pubkey API to return bytes
       
       Diffstat:
         M electrum/keystore.py                |      23 +++++++++--------------
         M electrum/plugins/coldcard/coldcard… |       8 ++++----
         M electrum/tests/test_wallet_vertica… |       8 ++++----
         M electrum/wallet.py                  |      18 +++++++++---------
       
       4 files changed, 26 insertions(+), 31 deletions(-)
       ---
   DIR diff --git a/electrum/keystore.py b/electrum/keystore.py
       t@@ -336,7 +336,7 @@ class MasterPublicKeyMixin(ABC):
                pass
        
            @abstractmethod
       -    def derive_pubkey(self, for_change: int, n: int) -> str:
       +    def derive_pubkey(self, for_change: int, n: int) -> bytes:
                pass
        
            def get_pubkey_derivation(self, pubkey: bytes,
       t@@ -346,7 +346,7 @@ class MasterPublicKeyMixin(ABC):
                def test_der_suffix_against_pubkey(der_suffix: Sequence[int], pubkey: bytes) -> bool:
                    if len(der_suffix) != 2:
                        return False
       -            if pubkey.hex() != self.derive_pubkey(*der_suffix):
       +            if pubkey != self.derive_pubkey(*der_suffix):
                        return False
                    return True
        
       t@@ -452,10 +452,9 @@ class Xpub(MasterPublicKeyMixin):
                self._root_fingerprint = root_fingerprint
                self._derivation_prefix = normalize_bip32_derivation(derivation_prefix)
        
       -    # note: this helper method exists as derive_pubkey returns hex strings,
       -    #       and it saves space to cache bytes instead
            @lru_cache(maxsize=None)
       -    def _derive_pubkey_bytes(self, for_change: int, n: int) -> bytes:
       +    def derive_pubkey(self, for_change: int, n: int) -> bytes:
       +        for_change = int(for_change)
                assert for_change in (0, 1)
                xpub = self.xpub_change if for_change else self.xpub_receive
                if xpub is None:
       t@@ -467,11 +466,6 @@ class Xpub(MasterPublicKeyMixin):
                        self.xpub_receive = xpub
                return self.get_pubkey_from_xpub(xpub, (n,))
        
       -    def derive_pubkey(self, for_change: int, n: int) -> str:
       -        for_change = int(for_change)
       -        assert for_change in (0, 1)
       -        return self._derive_pubkey_bytes(for_change, n).hex()
       -
            @classmethod
            def get_pubkey_from_xpub(self, xpub: str, sequence) -> bytes:
                node = BIP32Node.from_xkey(xpub).subkey_at_public_derivation(sequence)
       t@@ -618,13 +612,14 @@ class Old_KeyStore(MasterPublicKeyMixin, Deterministic_KeyStore):
                return string_to_number(sha256d(("%d:%d:"%(n, for_change)).encode('ascii') + bfh(mpk)))
        
            @classmethod
       -    def get_pubkey_from_mpk(self, mpk, for_change, n):
       -        z = self.get_sequence(mpk, for_change, n)
       +    def get_pubkey_from_mpk(cls, mpk, for_change, n) -> bytes:
       +        z = cls.get_sequence(mpk, for_change, n)
                master_public_key = ecc.ECPubkey(bfh('04'+mpk))
                public_key = master_public_key + z*ecc.generator()
       -        return public_key.get_public_key_hex(compressed=False)
       +        return public_key.get_public_key_bytes(compressed=False)
        
       -    def derive_pubkey(self, for_change, n) -> str:
       +    @lru_cache(maxsize=None)
       +    def derive_pubkey(self, for_change, n) -> bytes:
                for_change = int(for_change)
                assert for_change in (0, 1)
                return self.get_pubkey_from_mpk(self.mpk, for_change, n)
   DIR diff --git a/electrum/plugins/coldcard/coldcard.py b/electrum/plugins/coldcard/coldcard.py
       t@@ -610,15 +610,15 @@ class ColdcardPlugin(HW_PluginBase):
                    # all those keys
        
                    pubkey_deriv_info = wallet.get_public_keys_with_deriv_info(address)
       -            pubkeys = sorted([pk for pk in list(pubkey_deriv_info)])
       +            pubkey_hexes = sorted([pk.hex() for pk in list(pubkey_deriv_info)])
                    xfp_paths = []
       -            for pubkey_hex in pubkey_deriv_info:
       -                ks, der_suffix = pubkey_deriv_info[pubkey_hex]
       +            for pubkey in pubkey_deriv_info:
       +                ks, der_suffix = pubkey_deriv_info[pubkey]
                        fp_bytes, der_full = ks.get_fp_and_derivation_to_be_used_in_partial_tx(der_suffix, only_der_suffix=False)
                        xfp_int = xfp_int_from_xfp_bytes(fp_bytes)
                        xfp_paths.append([xfp_int] + list(der_full))
        
       -            script = bfh(wallet.pubkeys_to_scriptcode(pubkeys))
       +            script = bfh(wallet.pubkeys_to_scriptcode(pubkey_hexes))
        
                    keystore.show_p2sh_address(wallet.m, script, xfp_paths, txin_type)
        
   DIR diff --git a/electrum/tests/test_wallet_vertical.py b/electrum/tests/test_wallet_vertical.py
       t@@ -415,8 +415,8 @@ class TestWalletKeystoreAddressIntegrityForMainnet(ElectrumTestCase):
                    return ks
        
                ks = create_keystore_from_bip32seed(xtype='standard')
       -        self.assertEqual('033a05ec7ae9a9833b0696eb285a762f17379fa208b3dc28df1c501cf84fe415d0', ks.derive_pubkey(0, 0))
       -        self.assertEqual('02bf27f41683d84183e4e930e66d64fc8af5508b4b5bf3c473c505e4dbddaeed80', ks.derive_pubkey(1, 0))
       +        self.assertEqual('033a05ec7ae9a9833b0696eb285a762f17379fa208b3dc28df1c501cf84fe415d0', ks.derive_pubkey(0, 0).hex())
       +        self.assertEqual('02bf27f41683d84183e4e930e66d64fc8af5508b4b5bf3c473c505e4dbddaeed80', ks.derive_pubkey(1, 0).hex())
        
                ks = create_keystore_from_bip32seed(xtype='standard')  # p2pkh
                w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
       t@@ -503,8 +503,8 @@ class TestWalletKeystoreAddressIntegrityForTestnet(TestCaseForTestnet):
                    return ks
        
                ks = create_keystore_from_bip32seed(xtype='standard')
       -        self.assertEqual('033a05ec7ae9a9833b0696eb285a762f17379fa208b3dc28df1c501cf84fe415d0', ks.derive_pubkey(0, 0))
       -        self.assertEqual('02bf27f41683d84183e4e930e66d64fc8af5508b4b5bf3c473c505e4dbddaeed80', ks.derive_pubkey(1, 0))
       +        self.assertEqual('033a05ec7ae9a9833b0696eb285a762f17379fa208b3dc28df1c501cf84fe415d0', ks.derive_pubkey(0, 0).hex())
       +        self.assertEqual('02bf27f41683d84183e4e930e66d64fc8af5508b4b5bf3c473c505e4dbddaeed80', ks.derive_pubkey(1, 0).hex())
        
                ks = create_keystore_from_bip32seed(xtype='standard')  # p2pkh
                w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
   DIR diff --git a/electrum/wallet.py b/electrum/wallet.py
       t@@ -454,8 +454,8 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
            def get_public_keys(self, address: str) -> Sequence[str]:
                pass
        
       -    def get_public_keys_with_deriv_info(self, address: str) -> Dict[str, Tuple[KeyStoreWithMPK, Sequence[int]]]:
       -        """Returns a map: pubkey_hex -> (keystore, derivation_suffix)"""
       +    def get_public_keys_with_deriv_info(self, address: str) -> Dict[bytes, Tuple[KeyStoreWithMPK, Sequence[int]]]:
       +        """Returns a map: pubkey -> (keystore, derivation_suffix)"""
                return {}
        
            def get_tx_info(self, tx) -> TxWalletDetails:
       t@@ -2152,12 +2152,12 @@ class Deterministic_Wallet(Abstract_Wallet):
                if not self.is_mine(address):
                    return
                pubkey_deriv_info = self.get_public_keys_with_deriv_info(address)
       -        txinout.pubkeys = sorted([bfh(pk) for pk in list(pubkey_deriv_info)])
       -        for pubkey_hex in pubkey_deriv_info:
       -            ks, der_suffix = pubkey_deriv_info[pubkey_hex]
       +        txinout.pubkeys = sorted([pk for pk in list(pubkey_deriv_info)])
       +        for pubkey in pubkey_deriv_info:
       +            ks, der_suffix = pubkey_deriv_info[pubkey]
                    fp_bytes, der_full = ks.get_fp_and_derivation_to_be_used_in_partial_tx(der_suffix,
                                                                                           only_der_suffix=only_der_suffix)
       -            txinout.bip32_paths[bfh(pubkey_hex)] = (fp_bytes, der_full)
       +            txinout.bip32_paths[pubkey] = (fp_bytes, der_full)
        
            def create_new_address(self, for_change: bool = False):
                assert type(for_change) is bool
       t@@ -2254,7 +2254,7 @@ class Simple_Deterministic_Wallet(Simple_Wallet, Deterministic_Wallet):
                return self.keystore.get_master_public_key()
        
            def derive_pubkeys(self, c, i):
       -        return [self.keystore.derive_pubkey(c, i)]
       +        return [self.keystore.derive_pubkey(c, i).hex()]
        
        
        
       t@@ -2278,7 +2278,7 @@ class Multisig_Wallet(Deterministic_Wallet):
                Deterministic_Wallet.__init__(self, storage, config=config)
        
            def get_public_keys(self, address):
       -        return list(self.get_public_keys_with_deriv_info(address))
       +        return [pk.hex() for pk in self.get_public_keys_with_deriv_info(address)]
        
            def pubkeys_to_address(self, pubkeys):
                redeem_script = self.pubkeys_to_scriptcode(pubkeys)
       t@@ -2310,7 +2310,7 @@ class Multisig_Wallet(Deterministic_Wallet):
                raise UnknownTxinType(f'unexpected txin_type {txin_type}')
        
            def derive_pubkeys(self, c, i):
       -        return [k.derive_pubkey(c, i) for k in self.get_keystores()]
       +        return [k.derive_pubkey(c, i).hex() for k in self.get_keystores()]
        
            def load_keystore(self):
                self.keystores = {}