URI: 
       tsplit bip32 from bitcoin.py - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit a88a2dea8255532abdd20002c866b443237a509c
   DIR parent c61e13c1e953c962a2083feecb3905186492fb81
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Thu, 25 Oct 2018 22:20:33 +0200
       
       split bip32 from bitcoin.py
       
       Diffstat:
         M electrum/base_wizard.py             |       4 ++--
         A electrum/bip32.py                   |     269 +++++++++++++++++++++++++++++++
         M electrum/bitcoin.py                 |     276 +------------------------------
         M electrum/keystore.py                |      29 +++++++++++++++++++++--------
         M electrum/paymentrequest.py          |       7 +++----
         M electrum/plugin.py                  |       4 ++--
         M electrum/plugins/coldcard/coldcard… |      14 +++++---------
         M electrum/plugins/cosigner_pool/qt.… |       8 ++++----
         M electrum/plugins/digitalbitbox/dig… |       5 +++--
         M electrum/plugins/keepkey/clientbas… |       2 +-
         M electrum/plugins/keepkey/keepkey.py |       6 ++----
         M electrum/plugins/keepkey/qt.py      |       7 +++----
         M electrum/plugins/ledger/ledger.py   |      10 +++++-----
         M electrum/plugins/safe_t/clientbase… |       2 +-
         M electrum/plugins/safe_t/qt.py       |       7 +++----
         M electrum/plugins/safe_t/safe_t.py   |       6 +++---
         M electrum/plugins/trezor/clientbase… |       2 +-
         M electrum/plugins/trezor/qt.py       |       7 +++----
         M electrum/plugins/trezor/trezor.py   |       6 +++---
         M electrum/plugins/trustedcoin/trust… |      25 ++++++++++++++-----------
         M electrum/tests/test_bitcoin.py      |      21 +++++++++++----------
         M electrum/transaction.py             |      31 ++++++++++++++++---------------
         M electrum/verifier.py                |       3 ++-
         M electrum/wallet.py                  |      16 +++++++++-------
       
       24 files changed, 393 insertions(+), 374 deletions(-)
       ---
   DIR diff --git a/electrum/base_wizard.py b/electrum/base_wizard.py
       t@@ -30,6 +30,7 @@ from functools import partial
        
        from . import bitcoin
        from . import keystore
       +from .bip32 import is_bip32_derivation, xpub_type
        from .keystore import bip44_derivation, purpose48_derivation
        from .wallet import (Imported_Wallet, Standard_Wallet, Multisig_Wallet,
                             wallet_types, Wallet, Abstract_Wallet)
       t@@ -339,7 +340,7 @@ class BaseWizard(object):
                    try:
                        self.choice_and_line_dialog(
                            run_next=f, title=_('Script type and Derivation path'), message1=message1,
       -                    message2=message2, choices=choices, test_text=bitcoin.is_bip32_derivation)
       +                    message2=message2, choices=choices, test_text=is_bip32_derivation)
                        return
                    except ScriptTypeNotSupported as e:
                        self.show_error(e)
       t@@ -419,7 +420,6 @@ class BaseWizard(object):
            def on_keystore(self, k):
                has_xpub = isinstance(k, keystore.Xpub)
                if has_xpub:
       -            from .bitcoin import xpub_type
                    t1 = xpub_type(k.xpub)
                if self.wallet_type == 'standard':
                    if has_xpub and t1 not in ['standard', 'p2wpkh', 'p2wpkh-p2sh']:
   DIR diff --git a/electrum/bip32.py b/electrum/bip32.py
       t@@ -0,0 +1,269 @@
       +# Copyright (C) 2018 The Electrum developers
       +# Distributed under the MIT software license, see the accompanying
       +# file LICENCE or http://www.opensource.org/licenses/mit-license.php
       +
       +import hashlib
       +from typing import List
       +
       +from .util import bfh, bh2u, BitcoinException, print_error
       +from . import constants
       +from . import ecc
       +from .crypto import hash_160, hmac_oneshot
       +from .bitcoin import rev_hex, int_to_hex, EncodeBase58Check, DecodeBase58Check
       +
       +
       +BIP32_PRIME = 0x80000000
       +
       +
       +def protect_against_invalid_ecpoint(func):
       +    def func_wrapper(*args):
       +        n = args[-1]
       +        while True:
       +            is_prime = n & BIP32_PRIME
       +            try:
       +                return func(*args[:-1], n=n)
       +            except ecc.InvalidECPointException:
       +                print_error('bip32 protect_against_invalid_ecpoint: skipping index')
       +                n += 1
       +                is_prime2 = n & BIP32_PRIME
       +                if is_prime != is_prime2: raise OverflowError()
       +    return func_wrapper
       +
       +
       +# Child private key derivation function (from master private key)
       +# k = master private key (32 bytes)
       +# c = master chain code (extra entropy for key derivation) (32 bytes)
       +# n = the index of the key we want to derive. (only 32 bits will be used)
       +# If n is hardened (i.e. the 32nd bit is set), the resulting private key's
       +#  corresponding public key can NOT be determined without the master private key.
       +# However, if n is not hardened, the resulting private key's corresponding
       +#  public key can be determined without the master private key.
       +@protect_against_invalid_ecpoint
       +def CKD_priv(k, c, n):
       +    if n < 0: raise ValueError('the bip32 index needs to be non-negative')
       +    is_prime = n & BIP32_PRIME
       +    return _CKD_priv(k, c, bfh(rev_hex(int_to_hex(n,4))), is_prime)
       +
       +
       +def _CKD_priv(k, c, s, is_prime):
       +    try:
       +        keypair = ecc.ECPrivkey(k)
       +    except ecc.InvalidECPointException as e:
       +        raise BitcoinException('Impossible xprv (not within curve order)') from e
       +    cK = keypair.get_public_key_bytes(compressed=True)
       +    data = bytes([0]) + k + s if is_prime else cK + s
       +    I = hmac_oneshot(c, data, hashlib.sha512)
       +    I_left = ecc.string_to_number(I[0:32])
       +    k_n = (I_left + ecc.string_to_number(k)) % ecc.CURVE_ORDER
       +    if I_left >= ecc.CURVE_ORDER or k_n == 0:
       +        raise ecc.InvalidECPointException()
       +    k_n = ecc.number_to_string(k_n, ecc.CURVE_ORDER)
       +    c_n = I[32:]
       +    return k_n, c_n
       +
       +# Child public key derivation function (from public key only)
       +# K = master public key
       +# c = master chain code
       +# n = index of key we want to derive
       +# This function allows us to find the nth public key, as long as n is
       +#  not hardened. If n is hardened, we need the master private key to find it.
       +@protect_against_invalid_ecpoint
       +def CKD_pub(cK, c, n):
       +    if n < 0: raise ValueError('the bip32 index needs to be non-negative')
       +    if n & BIP32_PRIME: raise Exception()
       +    return _CKD_pub(cK, c, bfh(rev_hex(int_to_hex(n,4))))
       +
       +# helper function, callable with arbitrary string.
       +# note: 's' does not need to fit into 32 bits here! (c.f. trustedcoin billing)
       +def _CKD_pub(cK, c, s):
       +    I = hmac_oneshot(c, cK + s, hashlib.sha512)
       +    pubkey = ecc.ECPrivkey(I[0:32]) + ecc.ECPubkey(cK)
       +    if pubkey.is_at_infinity():
       +        raise ecc.InvalidECPointException()
       +    cK_n = pubkey.get_public_key_bytes(compressed=True)
       +    c_n = I[32:]
       +    return cK_n, c_n
       +
       +
       +def xprv_header(xtype, *, net=None):
       +    if net is None:
       +        net = constants.net
       +    return bfh("%08x" % net.XPRV_HEADERS[xtype])
       +
       +
       +def xpub_header(xtype, *, net=None):
       +    if net is None:
       +        net = constants.net
       +    return bfh("%08x" % net.XPUB_HEADERS[xtype])
       +
       +
       +def serialize_xprv(xtype, c, k, depth=0, fingerprint=b'\x00'*4,
       +                   child_number=b'\x00'*4, *, net=None):
       +    if not ecc.is_secret_within_curve_range(k):
       +        raise BitcoinException('Impossible xprv (not within curve order)')
       +    xprv = xprv_header(xtype, net=net) \
       +           + bytes([depth]) + fingerprint + child_number + c + bytes([0]) + k
       +    return EncodeBase58Check(xprv)
       +
       +
       +def serialize_xpub(xtype, c, cK, depth=0, fingerprint=b'\x00'*4,
       +                   child_number=b'\x00'*4, *, net=None):
       +    xpub = xpub_header(xtype, net=net) \
       +           + bytes([depth]) + fingerprint + child_number + c + cK
       +    return EncodeBase58Check(xpub)
       +
       +
       +class InvalidMasterKeyVersionBytes(BitcoinException): pass
       +
       +
       +def deserialize_xkey(xkey, prv, *, net=None):
       +    if net is None:
       +        net = constants.net
       +    xkey = DecodeBase58Check(xkey)
       +    if len(xkey) != 78:
       +        raise BitcoinException('Invalid length for extended key: {}'
       +                               .format(len(xkey)))
       +    depth = xkey[4]
       +    fingerprint = xkey[5:9]
       +    child_number = xkey[9:13]
       +    c = xkey[13:13+32]
       +    header = int('0x' + bh2u(xkey[0:4]), 16)
       +    headers = net.XPRV_HEADERS if prv else net.XPUB_HEADERS
       +    if header not in headers.values():
       +        raise InvalidMasterKeyVersionBytes('Invalid extended key format: {}'
       +                                           .format(hex(header)))
       +    xtype = list(headers.keys())[list(headers.values()).index(header)]
       +    n = 33 if prv else 32
       +    K_or_k = xkey[13+n:]
       +    if prv and not ecc.is_secret_within_curve_range(K_or_k):
       +        raise BitcoinException('Impossible xprv (not within curve order)')
       +    return xtype, depth, fingerprint, child_number, c, K_or_k
       +
       +
       +def deserialize_xpub(xkey, *, net=None):
       +    return deserialize_xkey(xkey, False, net=net)
       +
       +def deserialize_xprv(xkey, *, net=None):
       +    return deserialize_xkey(xkey, True, net=net)
       +
       +def xpub_type(x):
       +    return deserialize_xpub(x)[0]
       +
       +
       +def is_xpub(text):
       +    try:
       +        deserialize_xpub(text)
       +        return True
       +    except:
       +        return False
       +
       +
       +def is_xprv(text):
       +    try:
       +        deserialize_xprv(text)
       +        return True
       +    except:
       +        return False
       +
       +
       +def xpub_from_xprv(xprv):
       +    xtype, depth, fingerprint, child_number, c, k = deserialize_xprv(xprv)
       +    cK = ecc.ECPrivkey(k).get_public_key_bytes(compressed=True)
       +    return serialize_xpub(xtype, c, cK, depth, fingerprint, child_number)
       +
       +
       +def bip32_root(seed, xtype):
       +    I = hmac_oneshot(b"Bitcoin seed", seed, hashlib.sha512)
       +    master_k = I[0:32]
       +    master_c = I[32:]
       +    # create xprv first, as that will check if master_k is within curve order
       +    xprv = serialize_xprv(xtype, master_c, master_k)
       +    cK = ecc.ECPrivkey(master_k).get_public_key_bytes(compressed=True)
       +    xpub = serialize_xpub(xtype, master_c, cK)
       +    return xprv, xpub
       +
       +
       +def xpub_from_pubkey(xtype, cK):
       +    if cK[0] not in (0x02, 0x03):
       +        raise ValueError('Unexpected first byte: {}'.format(cK[0]))
       +    return serialize_xpub(xtype, b'\x00'*32, cK)
       +
       +
       +def bip32_derivation(s):
       +    if not s.startswith('m/'):
       +        raise ValueError('invalid bip32 derivation path: {}'.format(s))
       +    s = s[2:]
       +    for n in s.split('/'):
       +        if n == '': continue
       +        i = int(n[:-1]) + BIP32_PRIME if n[-1] == "'" else int(n)
       +        yield i
       +
       +def convert_bip32_path_to_list_of_uint32(n: str) -> List[int]:
       +    """Convert bip32 path to list of uint32 integers with prime flags
       +    m/0/-1/1' -> [0, 0x80000001, 0x80000001]
       +
       +    based on code in trezorlib
       +    """
       +    path = []
       +    for x in n.split('/')[1:]:
       +        if x == '': continue
       +        prime = 0
       +        if x.endswith("'"):
       +            x = x.replace('\'', '')
       +            prime = BIP32_PRIME
       +        if x.startswith('-'):
       +            prime = BIP32_PRIME
       +        path.append(abs(int(x)) | prime)
       +    return path
       +
       +def is_bip32_derivation(x):
       +    try:
       +        [ i for i in bip32_derivation(x)]
       +        return True
       +    except :
       +        return False
       +
       +def bip32_private_derivation(xprv, branch, sequence):
       +    if not sequence.startswith(branch):
       +        raise ValueError('incompatible branch ({}) and sequence ({})'
       +                         .format(branch, sequence))
       +    if branch == sequence:
       +        return xprv, xpub_from_xprv(xprv)
       +    xtype, depth, fingerprint, child_number, c, k = deserialize_xprv(xprv)
       +    sequence = sequence[len(branch):]
       +    for n in sequence.split('/'):
       +        if n == '': continue
       +        i = int(n[:-1]) + BIP32_PRIME if n[-1] == "'" else int(n)
       +        parent_k = k
       +        k, c = CKD_priv(k, c, i)
       +        depth += 1
       +    parent_cK = ecc.ECPrivkey(parent_k).get_public_key_bytes(compressed=True)
       +    fingerprint = hash_160(parent_cK)[0:4]
       +    child_number = bfh("%08X"%i)
       +    cK = ecc.ECPrivkey(k).get_public_key_bytes(compressed=True)
       +    xpub = serialize_xpub(xtype, c, cK, depth, fingerprint, child_number)
       +    xprv = serialize_xprv(xtype, c, k, depth, fingerprint, child_number)
       +    return xprv, xpub
       +
       +
       +def bip32_public_derivation(xpub, branch, sequence):
       +    xtype, depth, fingerprint, child_number, c, cK = deserialize_xpub(xpub)
       +    if not sequence.startswith(branch):
       +        raise ValueError('incompatible branch ({}) and sequence ({})'
       +                         .format(branch, sequence))
       +    sequence = sequence[len(branch):]
       +    for n in sequence.split('/'):
       +        if n == '': continue
       +        i = int(n)
       +        parent_cK = cK
       +        cK, c = CKD_pub(cK, c, i)
       +        depth += 1
       +    fingerprint = hash_160(parent_cK)[0:4]
       +    child_number = bfh("%08X"%i)
       +    return serialize_xpub(xtype, c, cK, depth, fingerprint, child_number)
       +
       +
       +def bip32_private_key(sequence, k, chain):
       +    for i in sequence:
       +        k, chain = CKD_priv(k, chain, i)
       +    return k
   DIR diff --git a/electrum/bitcoin.py b/electrum/bitcoin.py
       t@@ -26,7 +26,7 @@
        import hashlib
        from typing import List, Tuple
        
       -from .util import bfh, bh2u, BitcoinException, print_error, assert_bytes, to_bytes, inv_dict
       +from .util import bfh, bh2u, BitcoinException, assert_bytes, to_bytes, inv_dict
        from . import version
        from . import segwit_addr
        from . import constants
       t@@ -152,6 +152,9 @@ hash_decode = lambda x: bfh(x)[::-1]
        hmac_sha_512 = lambda x, y: hmac_oneshot(x, y, hashlib.sha512)
        
        
       +################################## electrum seeds
       +
       +
        def is_new_seed(x, prefix=version.SEED_PREFIX):
            from . import mnemonic
            x = mnemonic.normalize_text(x)
       t@@ -277,14 +280,14 @@ def address_to_script(addr, *, net=None):
                script = bh2u(bytes([OP_n]))
                script += push_script(bh2u(bytes(witprog)))
                return script
       -    addrtype, hash_160 = b58_address_to_hash160(addr)
       +    addrtype, hash_160_ = b58_address_to_hash160(addr)
            if addrtype == net.ADDRTYPE_P2PKH:
                script = '76a9'                                      # op_dup, op_hash_160
       -        script += push_script(bh2u(hash_160))
       +        script += push_script(bh2u(hash_160_))
                script += '88ac'                                     # op_equalverify, op_checksig
            elif addrtype == net.ADDRTYPE_P2SH:
                script = 'a9'                                        # op_hash_160
       -        script += push_script(bh2u(hash_160))
       +        script += push_script(bh2u(hash_160_))
                script += '87'                                       # op_equal
            else:
                raise BitcoinException('unknown address type: {}'.format(addrtype))
       t@@ -409,12 +412,6 @@ WIF_SCRIPT_TYPES = {
        WIF_SCRIPT_TYPES_INV = inv_dict(WIF_SCRIPT_TYPES)
        
        
       -PURPOSE48_SCRIPT_TYPES = {
       -    'p2wsh-p2sh': 1,  # specifically multisig
       -    'p2wsh': 2,       # specifically multisig
       -}
       -PURPOSE48_SCRIPT_TYPES_INV = inv_dict(PURPOSE48_SCRIPT_TYPES)
       -
        
        def serialize_privkey(secret: bytes, compressed: bool, txin_type: str,
                              internal_use: bool=False) -> str:
       t@@ -521,262 +518,3 @@ def is_minikey(text):
        
        def minikey_to_private_key(text):
            return sha256(text)
       -
       -
       -###################################### BIP32 ##############################
       -
       -BIP32_PRIME = 0x80000000
       -
       -
       -def protect_against_invalid_ecpoint(func):
       -    def func_wrapper(*args):
       -        n = args[-1]
       -        while True:
       -            is_prime = n & BIP32_PRIME
       -            try:
       -                return func(*args[:-1], n=n)
       -            except ecc.InvalidECPointException:
       -                print_error('bip32 protect_against_invalid_ecpoint: skipping index')
       -                n += 1
       -                is_prime2 = n & BIP32_PRIME
       -                if is_prime != is_prime2: raise OverflowError()
       -    return func_wrapper
       -
       -
       -# Child private key derivation function (from master private key)
       -# k = master private key (32 bytes)
       -# c = master chain code (extra entropy for key derivation) (32 bytes)
       -# n = the index of the key we want to derive. (only 32 bits will be used)
       -# If n is hardened (i.e. the 32nd bit is set), the resulting private key's
       -#  corresponding public key can NOT be determined without the master private key.
       -# However, if n is not hardened, the resulting private key's corresponding
       -#  public key can be determined without the master private key.
       -@protect_against_invalid_ecpoint
       -def CKD_priv(k, c, n):
       -    if n < 0: raise ValueError('the bip32 index needs to be non-negative')
       -    is_prime = n & BIP32_PRIME
       -    return _CKD_priv(k, c, bfh(rev_hex(int_to_hex(n,4))), is_prime)
       -
       -
       -def _CKD_priv(k, c, s, is_prime):
       -    try:
       -        keypair = ecc.ECPrivkey(k)
       -    except ecc.InvalidECPointException as e:
       -        raise BitcoinException('Impossible xprv (not within curve order)') from e
       -    cK = keypair.get_public_key_bytes(compressed=True)
       -    data = bytes([0]) + k + s if is_prime else cK + s
       -    I = hmac_oneshot(c, data, hashlib.sha512)
       -    I_left = ecc.string_to_number(I[0:32])
       -    k_n = (I_left + ecc.string_to_number(k)) % ecc.CURVE_ORDER
       -    if I_left >= ecc.CURVE_ORDER or k_n == 0:
       -        raise ecc.InvalidECPointException()
       -    k_n = ecc.number_to_string(k_n, ecc.CURVE_ORDER)
       -    c_n = I[32:]
       -    return k_n, c_n
       -
       -# Child public key derivation function (from public key only)
       -# K = master public key
       -# c = master chain code
       -# n = index of key we want to derive
       -# This function allows us to find the nth public key, as long as n is
       -#  not hardened. If n is hardened, we need the master private key to find it.
       -@protect_against_invalid_ecpoint
       -def CKD_pub(cK, c, n):
       -    if n < 0: raise ValueError('the bip32 index needs to be non-negative')
       -    if n & BIP32_PRIME: raise Exception()
       -    return _CKD_pub(cK, c, bfh(rev_hex(int_to_hex(n,4))))
       -
       -# helper function, callable with arbitrary string.
       -# note: 's' does not need to fit into 32 bits here! (c.f. trustedcoin billing)
       -def _CKD_pub(cK, c, s):
       -    I = hmac_oneshot(c, cK + s, hashlib.sha512)
       -    pubkey = ecc.ECPrivkey(I[0:32]) + ecc.ECPubkey(cK)
       -    if pubkey.is_at_infinity():
       -        raise ecc.InvalidECPointException()
       -    cK_n = pubkey.get_public_key_bytes(compressed=True)
       -    c_n = I[32:]
       -    return cK_n, c_n
       -
       -
       -def xprv_header(xtype, *, net=None):
       -    if net is None:
       -        net = constants.net
       -    return bfh("%08x" % net.XPRV_HEADERS[xtype])
       -
       -
       -def xpub_header(xtype, *, net=None):
       -    if net is None:
       -        net = constants.net
       -    return bfh("%08x" % net.XPUB_HEADERS[xtype])
       -
       -
       -def serialize_xprv(xtype, c, k, depth=0, fingerprint=b'\x00'*4,
       -                   child_number=b'\x00'*4, *, net=None):
       -    if not ecc.is_secret_within_curve_range(k):
       -        raise BitcoinException('Impossible xprv (not within curve order)')
       -    xprv = xprv_header(xtype, net=net) \
       -           + bytes([depth]) + fingerprint + child_number + c + bytes([0]) + k
       -    return EncodeBase58Check(xprv)
       -
       -
       -def serialize_xpub(xtype, c, cK, depth=0, fingerprint=b'\x00'*4,
       -                   child_number=b'\x00'*4, *, net=None):
       -    xpub = xpub_header(xtype, net=net) \
       -           + bytes([depth]) + fingerprint + child_number + c + cK
       -    return EncodeBase58Check(xpub)
       -
       -
       -class InvalidMasterKeyVersionBytes(BitcoinException): pass
       -
       -
       -def deserialize_xkey(xkey, prv, *, net=None):
       -    if net is None:
       -        net = constants.net
       -    xkey = DecodeBase58Check(xkey)
       -    if len(xkey) != 78:
       -        raise BitcoinException('Invalid length for extended key: {}'
       -                               .format(len(xkey)))
       -    depth = xkey[4]
       -    fingerprint = xkey[5:9]
       -    child_number = xkey[9:13]
       -    c = xkey[13:13+32]
       -    header = int('0x' + bh2u(xkey[0:4]), 16)
       -    headers = net.XPRV_HEADERS if prv else net.XPUB_HEADERS
       -    if header not in headers.values():
       -        raise InvalidMasterKeyVersionBytes('Invalid extended key format: {}'
       -                                           .format(hex(header)))
       -    xtype = list(headers.keys())[list(headers.values()).index(header)]
       -    n = 33 if prv else 32
       -    K_or_k = xkey[13+n:]
       -    if prv and not ecc.is_secret_within_curve_range(K_or_k):
       -        raise BitcoinException('Impossible xprv (not within curve order)')
       -    return xtype, depth, fingerprint, child_number, c, K_or_k
       -
       -
       -def deserialize_xpub(xkey, *, net=None):
       -    return deserialize_xkey(xkey, False, net=net)
       -
       -def deserialize_xprv(xkey, *, net=None):
       -    return deserialize_xkey(xkey, True, net=net)
       -
       -def xpub_type(x):
       -    return deserialize_xpub(x)[0]
       -
       -
       -def is_xpub(text):
       -    try:
       -        deserialize_xpub(text)
       -        return True
       -    except:
       -        return False
       -
       -
       -def is_xprv(text):
       -    try:
       -        deserialize_xprv(text)
       -        return True
       -    except:
       -        return False
       -
       -
       -def xpub_from_xprv(xprv):
       -    xtype, depth, fingerprint, child_number, c, k = deserialize_xprv(xprv)
       -    cK = ecc.ECPrivkey(k).get_public_key_bytes(compressed=True)
       -    return serialize_xpub(xtype, c, cK, depth, fingerprint, child_number)
       -
       -
       -def bip32_root(seed, xtype):
       -    I = hmac_oneshot(b"Bitcoin seed", seed, hashlib.sha512)
       -    master_k = I[0:32]
       -    master_c = I[32:]
       -    # create xprv first, as that will check if master_k is within curve order
       -    xprv = serialize_xprv(xtype, master_c, master_k)
       -    cK = ecc.ECPrivkey(master_k).get_public_key_bytes(compressed=True)
       -    xpub = serialize_xpub(xtype, master_c, cK)
       -    return xprv, xpub
       -
       -
       -def xpub_from_pubkey(xtype, cK):
       -    if cK[0] not in (0x02, 0x03):
       -        raise ValueError('Unexpected first byte: {}'.format(cK[0]))
       -    return serialize_xpub(xtype, b'\x00'*32, cK)
       -
       -
       -def bip32_derivation(s):
       -    if not s.startswith('m/'):
       -        raise ValueError('invalid bip32 derivation path: {}'.format(s))
       -    s = s[2:]
       -    for n in s.split('/'):
       -        if n == '': continue
       -        i = int(n[:-1]) + BIP32_PRIME if n[-1] == "'" else int(n)
       -        yield i
       -
       -def convert_bip32_path_to_list_of_uint32(n: str) -> List[int]:
       -    """Convert bip32 path to list of uint32 integers with prime flags
       -    m/0/-1/1' -> [0, 0x80000001, 0x80000001]
       -
       -    based on code in trezorlib
       -    """
       -    path = []
       -    for x in n.split('/')[1:]:
       -        if x == '': continue
       -        prime = 0
       -        if x.endswith("'"):
       -            x = x.replace('\'', '')
       -            prime = BIP32_PRIME
       -        if x.startswith('-'):
       -            prime = BIP32_PRIME
       -        path.append(abs(int(x)) | prime)
       -    return path
       -
       -def is_bip32_derivation(x):
       -    try:
       -        [ i for i in bip32_derivation(x)]
       -        return True
       -    except :
       -        return False
       -
       -def bip32_private_derivation(xprv, branch, sequence):
       -    if not sequence.startswith(branch):
       -        raise ValueError('incompatible branch ({}) and sequence ({})'
       -                         .format(branch, sequence))
       -    if branch == sequence:
       -        return xprv, xpub_from_xprv(xprv)
       -    xtype, depth, fingerprint, child_number, c, k = deserialize_xprv(xprv)
       -    sequence = sequence[len(branch):]
       -    for n in sequence.split('/'):
       -        if n == '': continue
       -        i = int(n[:-1]) + BIP32_PRIME if n[-1] == "'" else int(n)
       -        parent_k = k
       -        k, c = CKD_priv(k, c, i)
       -        depth += 1
       -    parent_cK = ecc.ECPrivkey(parent_k).get_public_key_bytes(compressed=True)
       -    fingerprint = hash_160(parent_cK)[0:4]
       -    child_number = bfh("%08X"%i)
       -    cK = ecc.ECPrivkey(k).get_public_key_bytes(compressed=True)
       -    xpub = serialize_xpub(xtype, c, cK, depth, fingerprint, child_number)
       -    xprv = serialize_xprv(xtype, c, k, depth, fingerprint, child_number)
       -    return xprv, xpub
       -
       -
       -def bip32_public_derivation(xpub, branch, sequence):
       -    xtype, depth, fingerprint, child_number, c, cK = deserialize_xpub(xpub)
       -    if not sequence.startswith(branch):
       -        raise ValueError('incompatible branch ({}) and sequence ({})'
       -                         .format(branch, sequence))
       -    sequence = sequence[len(branch):]
       -    for n in sequence.split('/'):
       -        if n == '': continue
       -        i = int(n)
       -        parent_cK = cK
       -        cK, c = CKD_pub(cK, c, i)
       -        depth += 1
       -    fingerprint = hash_160(parent_cK)[0:4]
       -    child_number = bfh("%08X"%i)
       -    return serialize_xpub(xtype, c, cK, depth, fingerprint, child_number)
       -
       -
       -def bip32_private_key(sequence, k, chain):
       -    for i in sequence:
       -        k, chain = CKD_priv(k, chain, i)
       -    return k
   DIR diff --git a/electrum/keystore.py b/electrum/keystore.py
       t@@ -25,13 +25,19 @@
        # SOFTWARE.
        
        from unicodedata import normalize
       -
       -from . import bitcoin, ecc, constants
       -from .bitcoin import *
       +import hashlib
       +
       +from . import bitcoin, ecc, constants, bip32
       +from .bitcoin import (deserialize_privkey, serialize_privkey,
       +                      public_key_to_p2pkh, seed_type, is_seed)
       +from .bip32 import (bip32_public_derivation, deserialize_xpub, CKD_pub,
       +                    bip32_root, deserialize_xprv, bip32_private_derivation,
       +                    bip32_private_key, bip32_derivation, BIP32_PRIME,
       +                    is_xpub, is_xprv)
        from .ecc import string_to_number, number_to_string
       -from .crypto import pw_decode, pw_encode
       +from .crypto import pw_decode, pw_encode, Hash
        from .util import (PrintError, InvalidPassword, hfu, WalletFileException,
       -                   BitcoinException)
       +                   BitcoinException, bh2u, bfh, print_error, inv_dict)
        from .mnemonic import Mnemonic, load_wordlist
        from .plugin import run_hook
        
       t@@ -332,7 +338,7 @@ class BIP32_KeyStore(Deterministic_KeyStore, Xpub):
        
            def add_xprv(self, xprv):
                self.xprv = xprv
       -        self.xpub = bitcoin.xpub_from_xprv(xprv)
       +        self.xpub = bip32.xpub_from_xprv(xprv)
        
            def add_xprv_from_seed(self, bip32_seed, xtype, derivation):
                xprv, xpub = bip32_root(bip32_seed, xtype)
       t@@ -614,6 +620,13 @@ def from_bip39_seed(seed, passphrase, derivation, xtype=None):
            return k
        
        
       +PURPOSE48_SCRIPT_TYPES = {
       +    'p2wsh-p2sh': 1,  # specifically multisig
       +    'p2wsh': 2,       # specifically multisig
       +}
       +PURPOSE48_SCRIPT_TYPES_INV = inv_dict(PURPOSE48_SCRIPT_TYPES)
       +
       +
        def xtype_from_derivation(derivation: str) -> str:
            """Returns the script type to be used for this derivation."""
            if derivation.startswith("m/84'"):
       t@@ -781,7 +794,7 @@ def from_seed(seed, passphrase, is_p2sh=False):
        def from_private_key_list(text):
            keystore = Imported_KeyStore({})
            for x in get_private_keys(text):
       -        keystore.import_key(x, None)
       +        keystore.import_privkey(x, None)
            return keystore
        
        def from_old_mpk(mpk):
       t@@ -795,7 +808,7 @@ def from_xpub(xpub):
            return k
        
        def from_xprv(xprv):
       -    xpub = bitcoin.xpub_from_xprv(xprv)
       +    xpub = bip32.xpub_from_xprv(xprv)
            k = BIP32_KeyStore({})
            k.xprv = xprv
            k.xpub = xpub
   DIR diff --git a/electrum/paymentrequest.py b/electrum/paymentrequest.py
       t@@ -38,9 +38,8 @@ except ImportError:
            sys.exit("Error: could not find paymentrequest_pb2.py. Create it with 'protoc --proto_path=electrum/ --python_out=electrum/ electrum/paymentrequest.proto'")
        
        from . import bitcoin, ecc, util, transaction, x509, rsakey
       -from .util import print_error, bh2u, bfh
       -from .util import export_meta, import_meta
       -
       +from .util import print_error, bh2u, bfh, export_meta, import_meta
       +from .crypto import sha256
        from .bitcoin import TYPE_ADDRESS
        from .transaction import TxOutput
        
       t@@ -113,7 +112,7 @@ class PaymentRequest:
            def parse(self, r):
                if self.error:
                    return
       -        self.id = bh2u(bitcoin.sha256(r)[0:16])
       +        self.id = bh2u(sha256(r)[0:16])
                try:
                    self.data = pb2.PaymentRequest()
                    self.data.ParseFromString(r)
   DIR diff --git a/electrum/plugin.py b/electrum/plugin.py
       t@@ -33,7 +33,7 @@ import threading
        from .i18n import _
        from .util import (profiler, PrintError, DaemonThread, UserCancelled,
                           ThreadJob, print_error)
       -from . import bitcoin
       +from . import bip32
        from . import plugins
        from .simple_config import SimpleConfig
        
       t@@ -432,7 +432,7 @@ class DeviceMgr(ThreadJob, PrintError):
            def force_pair_xpub(self, plugin, handler, info, xpub, derivation, devices):
                # The wallet has not been previously paired, so let the user
                # choose an unpaired device and compare its first address.
       -        xtype = bitcoin.xpub_type(xpub)
       +        xtype = bip32.xpub_type(xpub)
                client = self.client_lookup(info.device.id_)
                if client and client.is_pairable():
                    # See comment above for same code
   DIR diff --git a/electrum/plugins/coldcard/coldcard.py b/electrum/plugins/coldcard/coldcard.py
       t@@ -3,25 +3,21 @@
        #
        #
        from struct import pack, unpack
       -import hashlib
        import os, sys, time, io
        import traceback
        
       -from electrum import bitcoin
       -from electrum.bitcoin import serialize_xpub, deserialize_xpub, InvalidMasterKeyVersionBytes
       -from electrum import constants
       -from electrum.bitcoin import TYPE_ADDRESS, int_to_hex
       +from electrum.bip32 import serialize_xpub, deserialize_xpub, InvalidMasterKeyVersionBytes
        from electrum.i18n import _
       -from electrum.plugin import BasePlugin, Device
       +from electrum.plugin import Device
        from electrum.keystore import Hardware_KeyStore, xpubkey_to_pubkey, Xpub
        from electrum.transaction import Transaction
        from electrum.wallet import Standard_Wallet
        from electrum.crypto import hash_160
       -from ..hw_wallet import HW_PluginBase
       -from ..hw_wallet.plugin import is_any_tx_output_on_change_branch
        from electrum.util import print_error, bfh, bh2u, versiontuple
        from electrum.base_wizard import ScriptTypeNotSupported
        
       +from ..hw_wallet import HW_PluginBase
       +
        try:
            import hid
            from ckcc.protocol import CCProtocolPacker, CCProtocolUnpacker
       t@@ -46,7 +42,7 @@ try:
                    from electrum.ecc import ECPubkey
        
                    xtype, depth, parent_fingerprint, child_number, chain_code, K_or_k \
       -                = bitcoin.deserialize_xpub(expect_xpub)
       +                = deserialize_xpub(expect_xpub)
        
                    pubkey = ECPubkey(K_or_k)
                    try:
   DIR diff --git a/electrum/plugins/cosigner_pool/qt.py b/electrum/plugins/cosigner_pool/qt.py
       t@@ -30,7 +30,7 @@ from PyQt5.QtGui import *
        from PyQt5.QtCore import *
        from PyQt5.QtWidgets import QPushButton
        
       -from electrum import bitcoin, util, keystore, ecc
       +from electrum import util, keystore, ecc, bip32, crypto
        from electrum import transaction
        from electrum.plugin import BasePlugin, hook
        from electrum.i18n import _
       t@@ -132,8 +132,8 @@ class Plugin(BasePlugin):
                self.cosigner_list = []
                for key, keystore in wallet.keystores.items():
                    xpub = keystore.get_master_public_key()
       -            K = bitcoin.deserialize_xpub(xpub)[-1]
       -            _hash = bh2u(bitcoin.Hash(K))
       +            K = bip32.deserialize_xpub(xpub)[-1]
       +            _hash = bh2u(crypto.Hash(K))
                    if not keystore.is_watching_only():
                        self.keys.append((key, _hash, window))
                    else:
       t@@ -222,7 +222,7 @@ class Plugin(BasePlugin):
                if not xprv:
                    return
                try:
       -            k = bitcoin.deserialize_xprv(xprv)[-1]
       +            k = bip32.deserialize_xprv(xprv)[-1]
                    EC = ecc.ECPrivkey(k)
                    message = bh2u(EC.decrypt_message(message))
                except Exception as e:
   DIR diff --git a/electrum/plugins/digitalbitbox/digitalbitbox.py b/electrum/plugins/digitalbitbox/digitalbitbox.py
       t@@ -5,8 +5,9 @@
        
        try:
            from electrum.crypto import Hash, EncodeAES, DecodeAES
       -    from electrum.bitcoin import (TYPE_ADDRESS, push_script, var_int, public_key_to_p2pkh, is_address,
       -                                  serialize_xpub, deserialize_xpub)
       +    from electrum.bitcoin import (TYPE_ADDRESS, push_script, var_int, public_key_to_p2pkh,
       +                                  is_address)
       +    from electrum.bip32 import serialize_xpub, deserialize_xpub
            from electrum import ecc
            from electrum.ecc import msg_magic
            from electrum.wallet import Standard_Wallet
   DIR diff --git a/electrum/plugins/keepkey/clientbase.py b/electrum/plugins/keepkey/clientbase.py
       t@@ -4,7 +4,7 @@ from struct import pack
        from electrum.i18n import _
        from electrum.util import PrintError, UserCancelled
        from electrum.keystore import bip39_normalize_passphrase
       -from electrum.bitcoin import serialize_xpub, convert_bip32_path_to_list_of_uint32
       +from electrum.bip32 import serialize_xpub, convert_bip32_path_to_list_of_uint32
        
        
        class GuiMixin(object):
   DIR diff --git a/electrum/plugins/keepkey/keepkey.py b/electrum/plugins/keepkey/keepkey.py
       t@@ -3,14 +3,12 @@ import traceback
        import sys
        
        from electrum.util import bfh, bh2u, UserCancelled
       -from electrum.bitcoin import (xpub_from_pubkey, deserialize_xpub,
       -                              TYPE_ADDRESS, TYPE_SCRIPT)
       +from electrum.bitcoin import TYPE_ADDRESS, TYPE_SCRIPT
       +from electrum.bip32 import deserialize_xpub
        from electrum import constants
        from electrum.i18n import _
       -from electrum.plugin import BasePlugin
        from electrum.transaction import deserialize, Transaction
        from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey
       -from electrum.wallet import Standard_Wallet
        from electrum.base_wizard import ScriptTypeNotSupported
        
        from ..hw_wallet import HW_PluginBase
   DIR diff --git a/electrum/plugins/keepkey/qt.py b/electrum/plugins/keepkey/qt.py
       t@@ -7,9 +7,8 @@ from PyQt5.Qt import QVBoxLayout, QLabel
        
        from electrum.gui.qt.util import *
        from electrum.i18n import _
       -from electrum.plugin import hook, DeviceMgr
       -from electrum.util import PrintError, UserCancelled, bh2u
       -from electrum.wallet import Wallet, Standard_Wallet
       +from electrum.plugin import hook
       +from electrum.util import bh2u
        
        from ..hw_wallet.qt import QtHandlerBase, QtPluginBase
        from ..hw_wallet.plugin import only_hook_if_libraries_available
       t@@ -253,7 +252,7 @@ class QtPlugin(QtPluginBase):
                    else:
                        msg = _("Enter the master private key beginning with xprv:")
                        def set_enabled():
       -                    from keystore import is_xprv
       +                    from electrum.bip32 import is_xprv
                            wizard.next_button.setEnabled(is_xprv(clean_text(text)))
                        text.textChanged.connect(set_enabled)
                        next_enabled = False
   DIR diff --git a/electrum/plugins/ledger/ledger.py b/electrum/plugins/ledger/ledger.py
       t@@ -3,18 +3,18 @@ import hashlib
        import sys
        import traceback
        
       -from electrum import bitcoin
        from electrum.bitcoin import TYPE_ADDRESS, int_to_hex, var_int
       +from electrum.bip32 import serialize_xpub
        from electrum.i18n import _
       -from electrum.plugin import BasePlugin
        from electrum.keystore import Hardware_KeyStore
        from electrum.transaction import Transaction
        from electrum.wallet import Standard_Wallet
       -from ..hw_wallet import HW_PluginBase
       -from ..hw_wallet.plugin import is_any_tx_output_on_change_branch
        from electrum.util import print_error, bfh, bh2u, versiontuple
        from electrum.base_wizard import ScriptTypeNotSupported
        
       +from ..hw_wallet import HW_PluginBase
       +from ..hw_wallet.plugin import is_any_tx_output_on_change_branch
       +
        try:
            import hid
            from btchip.btchipComm import HIDDongleHIDAPI, DongleWait
       t@@ -112,7 +112,7 @@ class Ledger_Client():
                depth = len(splitPath)
                lastChild = splitPath[len(splitPath) - 1].split('\'')
                childnum = int(lastChild[0]) if len(lastChild) == 1 else 0x80000000 | int(lastChild[0])
       -        xpub = bitcoin.serialize_xpub(xtype, nodeData['chainCode'], publicKey, depth, self.i4b(fingerprint), self.i4b(childnum))
       +        xpub = serialize_xpub(xtype, nodeData['chainCode'], publicKey, depth, self.i4b(fingerprint), self.i4b(childnum))
                return xpub
        
            def has_detached_pin_support(self, client):
   DIR diff --git a/electrum/plugins/safe_t/clientbase.py b/electrum/plugins/safe_t/clientbase.py
       t@@ -4,7 +4,7 @@ from struct import pack
        from electrum.i18n import _
        from electrum.util import PrintError, UserCancelled
        from electrum.keystore import bip39_normalize_passphrase
       -from electrum.bitcoin import serialize_xpub, convert_bip32_path_to_list_of_uint32
       +from electrum.bip32 import serialize_xpub, convert_bip32_path_to_list_of_uint32
        
        
        class GuiMixin(object):
   DIR diff --git a/electrum/plugins/safe_t/qt.py b/electrum/plugins/safe_t/qt.py
       t@@ -7,9 +7,8 @@ from PyQt5.Qt import QVBoxLayout, QLabel
        
        from electrum.gui.qt.util import *
        from electrum.i18n import _
       -from electrum.plugin import hook, DeviceMgr
       -from electrum.util import PrintError, UserCancelled, bh2u
       -from electrum.wallet import Wallet, Standard_Wallet
       +from electrum.plugin import hook
       +from electrum.util import bh2u
        
        from ..hw_wallet.qt import QtHandlerBase, QtPluginBase
        from ..hw_wallet.plugin import only_hook_if_libraries_available
       t@@ -127,7 +126,7 @@ class QtPlugin(QtPluginBase):
                    else:
                        msg = _("Enter the master private key beginning with xprv:")
                        def set_enabled():
       -                    from electrum.keystore import is_xprv
       +                    from electrum.bip32 import is_xprv
                            wizard.next_button.setEnabled(is_xprv(clean_text(text)))
                        text.textChanged.connect(set_enabled)
                        next_enabled = False
   DIR diff --git a/electrum/plugins/safe_t/safe_t.py b/electrum/plugins/safe_t/safe_t.py
       t@@ -3,11 +3,11 @@ import traceback
        import sys
        
        from electrum.util import bfh, bh2u, versiontuple, UserCancelled
       -from electrum.bitcoin import (b58_address_to_hash160, xpub_from_pubkey, deserialize_xpub,
       -                              TYPE_ADDRESS, TYPE_SCRIPT, is_address)
       +from electrum.bitcoin import TYPE_ADDRESS, TYPE_SCRIPT
       +from electrum.bip32 import deserialize_xpub
        from electrum import constants
        from electrum.i18n import _
       -from electrum.plugin import BasePlugin, Device
       +from electrum.plugin import Device
        from electrum.transaction import deserialize, Transaction
        from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey
        from electrum.base_wizard import ScriptTypeNotSupported
   DIR diff --git a/electrum/plugins/trezor/clientbase.py b/electrum/plugins/trezor/clientbase.py
       t@@ -4,7 +4,7 @@ from struct import pack
        from electrum.i18n import _
        from electrum.util import PrintError, UserCancelled
        from electrum.keystore import bip39_normalize_passphrase
       -from electrum.bitcoin import serialize_xpub, convert_bip32_path_to_list_of_uint32
       +from electrum.bip32 import serialize_xpub, convert_bip32_path_to_list_of_uint32
        
        
        class GuiMixin(object):
   DIR diff --git a/electrum/plugins/trezor/qt.py b/electrum/plugins/trezor/qt.py
       t@@ -7,9 +7,8 @@ from PyQt5.Qt import QVBoxLayout, QLabel
        
        from electrum.gui.qt.util import *
        from electrum.i18n import _
       -from electrum.plugin import hook, DeviceMgr
       -from electrum.util import PrintError, UserCancelled, bh2u
       -from electrum.wallet import Wallet, Standard_Wallet
       +from electrum.plugin import hook
       +from electrum.util import bh2u
        
        from ..hw_wallet.qt import QtHandlerBase, QtPluginBase
        from ..hw_wallet.plugin import only_hook_if_libraries_available
       t@@ -222,7 +221,7 @@ class QtPlugin(QtPluginBase):
                    else:
                        msg = _("Enter the master private key beginning with xprv:")
                        def set_enabled():
       -                    from electrum.keystore import is_xprv
       +                    from electrum.bip32 import is_xprv
                            wizard.next_button.setEnabled(is_xprv(clean_text(text)))
                        text.textChanged.connect(set_enabled)
                        next_enabled = False
   DIR diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py
       t@@ -3,11 +3,11 @@ import traceback
        import sys
        
        from electrum.util import bfh, bh2u, versiontuple, UserCancelled
       -from electrum.bitcoin import (xpub_from_pubkey, deserialize_xpub,
       -                              TYPE_ADDRESS, TYPE_SCRIPT)
       +from electrum.bitcoin import TYPE_ADDRESS, TYPE_SCRIPT
       +from electrum.bip32 import deserialize_xpub
        from electrum import constants
        from electrum.i18n import _
       -from electrum.plugin import BasePlugin, Device
       +from electrum.plugin import Device
        from electrum.transaction import deserialize, Transaction
        from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey
        from electrum.base_wizard import ScriptTypeNotSupported
   DIR diff --git a/electrum/plugins/trustedcoin/trustedcoin.py b/electrum/plugins/trustedcoin/trustedcoin.py
       t@@ -24,14 +24,19 @@
        # SOFTWARE.
        import asyncio
        import socket
       -import os
        import json
        import base64
       +import time
       +import hashlib
       +
        from urllib.parse import urljoin
        from urllib.parse import quote
        
       -from electrum import bitcoin, ecc, constants, keystore, version
       -from electrum.bitcoin import *
       +from electrum import ecc, constants, keystore, version, bip32
       +from electrum.bitcoin import TYPE_ADDRESS, is_new_seed, public_key_to_p2pkh
       +from electrum.bip32 import (deserialize_xpub, deserialize_xprv, bip32_private_key, CKD_pub,
       +                            serialize_xpub, bip32_root, bip32_private_derivation)
       +from electrum.crypto import sha256
        from electrum.transaction import TxOutput
        from electrum.mnemonic import Mnemonic
        from electrum.wallet import Multisig_Wallet, Deterministic_Wallet
       t@@ -348,7 +353,7 @@ class Wallet_2fa(Multisig_Wallet):
        
        def get_user_id(storage):
            def make_long_id(xpub_hot, xpub_cold):
       -        return bitcoin.sha256(''.join(sorted([xpub_hot, xpub_cold])))
       +        return sha256(''.join(sorted([xpub_hot, xpub_cold])))
            xpub1 = storage.get('x1/')['xpub']
            xpub2 = storage.get('x2/')['xpub']
            long_id = make_long_id(xpub1, xpub2)
       t@@ -357,15 +362,15 @@ def get_user_id(storage):
        
        def make_xpub(xpub, s):
            version, _, _, _, c, cK = deserialize_xpub(xpub)
       -    cK2, c2 = bitcoin._CKD_pub(cK, c, s)
       -    return bitcoin.serialize_xpub(version, c2, cK2)
       +    cK2, c2 = bip32._CKD_pub(cK, c, s)
       +    return serialize_xpub(version, c2, cK2)
        
        def make_billing_address(wallet, num):
            long_id, short_id = wallet.get_user_id()
            xpub = make_xpub(get_billing_xpub(), long_id)
            version, _, _, _, c, cK = deserialize_xpub(xpub)
       -    cK, c = bitcoin.CKD_pub(cK, c, num)
       -    return bitcoin.public_key_to_p2pkh(cK)
       +    cK, c = CKD_pub(cK, c, num)
       +    return public_key_to_p2pkh(cK)
        
        
        class TrustedCoinPlugin(BasePlugin):
       t@@ -379,7 +384,7 @@ class TrustedCoinPlugin(BasePlugin):
        
            @staticmethod
            def is_valid_seed(seed):
       -        return bitcoin.is_new_seed(seed, SEED_PREFIX)
       +        return is_new_seed(seed, SEED_PREFIX)
        
            def is_available(self):
                return True
       t@@ -479,8 +484,6 @@ class TrustedCoinPlugin(BasePlugin):
        
            @classmethod
            def get_xkeys(self, seed, passphrase, derivation):
       -        from electrum.mnemonic import Mnemonic
       -        from electrum.keystore import bip32_root, bip32_private_derivation
                bip32_seed = Mnemonic.mnemonic_to_seed(seed, passphrase)
                xprv, xpub = bip32_root(bip32_seed, 'standard')
                xprv, xpub = bip32_private_derivation(xprv, "m/", derivation)
   DIR diff --git a/electrum/tests/test_bitcoin.py b/electrum/tests/test_bitcoin.py
       t@@ -1,16 +1,17 @@
        import base64
        import sys
        
       -from electrum.bitcoin import (
       -    public_key_to_p2pkh,
       -    bip32_root, bip32_public_derivation, bip32_private_derivation,
       -    Hash, address_from_private_key,
       -    is_address, is_private_key, xpub_from_xprv, is_new_seed, is_old_seed,
       -    var_int, op_push, address_to_script,
       -    deserialize_privkey, serialize_privkey, is_segwit_address,
       -    is_b58_address, address_to_scripthash, is_minikey, is_compressed, is_xpub,
       -    xpub_type, is_xprv, is_bip32_derivation, seed_type, EncodeBase58Check,
       -    script_num_to_hex, push_script, add_number_to_script, int_to_hex, convert_bip32_path_to_list_of_uint32)
       +from electrum.bitcoin import (public_key_to_p2pkh, address_from_private_key,
       +                              is_address, is_private_key, is_new_seed, is_old_seed,
       +                              var_int, op_push, address_to_script,
       +                              deserialize_privkey, serialize_privkey, is_segwit_address,
       +                              is_b58_address, address_to_scripthash, is_minikey,
       +                              is_compressed, seed_type, EncodeBase58Check,
       +                              script_num_to_hex, push_script, add_number_to_script, int_to_hex)
       +from electrum.bip32 import (bip32_root, bip32_public_derivation, bip32_private_derivation,
       +                            xpub_from_xprv, xpub_type, is_xprv, is_bip32_derivation,
       +                            is_xpub, convert_bip32_path_to_list_of_uint32)
       +from electrum.crypto import Hash
        from electrum import ecc, crypto, constants
        from electrum.ecc import number_to_string, string_to_number
        from electrum.transaction import opcodes
   DIR diff --git a/electrum/transaction.py b/electrum/transaction.py
       t@@ -27,23 +27,22 @@
        
        # Note: The deserialization code originally comes from ABE.
        
       -from typing import (Sequence, Union, NamedTuple, Tuple, Optional, Iterable,
       -                    Callable)
       -
       -from .util import print_error, profiler
       -
       -from . import ecc
       -from . import bitcoin
       -from .bitcoin import *
        import struct
        import traceback
        import sys
       -
       -#
       -# Workalike python implementation of Bitcoin's CDataStream class.
       -#
       +from typing import (Sequence, Union, NamedTuple, Tuple, Optional, Iterable,
       +                    Callable, List)
       +
       +from . import ecc, bitcoin, constants, segwit_addr
       +from .util import print_error, profiler, to_bytes, bh2u, bfh
       +from .bitcoin import (TYPE_ADDRESS, TYPE_PUBKEY, TYPE_SCRIPT, hash_160,
       +                      hash160_to_p2sh, hash160_to_p2pkh, hash_to_segwit_addr,
       +                      hash_encode, var_int, TOTAL_COIN_SUPPLY_LIMIT_IN_BTC, COIN,
       +                      op_push, int_to_hex, push_script, b58_address_to_hash160)
       +from .crypto import Hash
        from .keystore import xpubkey_to_address, xpubkey_to_pubkey
        
       +
        NO_SIGNATURE = 'ff'
        PARTIAL_TXN_HEADER_MAGIC = b'EPTF\xff'
        
       t@@ -78,6 +77,8 @@ TxOutputHwInfo = NamedTuple("TxOutputHwInfo", [('address_index', Tuple),
        
        
        class BCDataStream(object):
       +    """Workalike python implementation of Bitcoin's CDataStream class."""
       +
            def __init__(self):
                self.input = None
                self.read_cursor = 0
       t@@ -353,7 +354,7 @@ def parse_scriptSig(d, _bytes):
                if item[0] == 0:
                    # segwit embedded into p2sh
                    # witness version 0
       -            d['address'] = bitcoin.hash160_to_p2sh(bitcoin.hash_160(item))
       +            d['address'] = bitcoin.hash160_to_p2sh(hash_160(item))
                    if len(item) == 22:
                        d['type'] = 'p2wpkh-p2sh'
                    elif len(item) == 34:
       t@@ -901,7 +902,7 @@ class Transaction:
                witver, witprog = segwit_addr.decode(constants.net.SEGWIT_HRP, addr)
                if witprog is not None:
                    return 'p2wpkh'
       -        addrtype, hash_160 = b58_address_to_hash160(addr)
       +        addrtype, hash_160_ = b58_address_to_hash160(addr)
                if addrtype == constants.net.ADDRTYPE_P2PKH:
                    return 'p2pkh'
                elif addrtype == constants.net.ADDRTYPE_P2SH:
       t@@ -977,7 +978,7 @@ class Transaction:
                    return multisig_script(pubkeys, txin['num_sig'])
                elif txin['type'] in ['p2wpkh', 'p2wpkh-p2sh']:
                    pubkey = pubkeys[0]
       -            pkh = bh2u(bitcoin.hash_160(bfh(pubkey)))
       +            pkh = bh2u(hash_160(bfh(pubkey)))
                    return '76a9' + push_script(pkh) + '88ac'
                elif txin['type'] == 'p2pk':
                    pubkey = pubkeys[0]
   DIR diff --git a/electrum/verifier.py b/electrum/verifier.py
       t@@ -27,7 +27,8 @@ from typing import Sequence, Optional, TYPE_CHECKING
        import aiorpcx
        
        from .util import bh2u, VerifiedTxInfo, NetworkJobOnDefaultServer
       -from .bitcoin import Hash, hash_decode, hash_encode
       +from .crypto import Hash
       +from .bitcoin import hash_decode, hash_encode
        from .transaction import Transaction
        from .blockchain import hash_header
        from .interface import GracefulDisconnect
   DIR diff --git a/electrum/wallet.py b/electrum/wallet.py
       t@@ -44,18 +44,20 @@ from .util import (NotEnoughFunds, PrintError, UserCancelled, profiler,
                           format_satoshis, format_fee_satoshis, NoDynamicFeeEstimates,
                           TimeoutException, WalletFileException, BitcoinException,
                           InvalidPassword, format_time, timestamp_to_datetime, Satoshis,
       -                   Fiat)
       -from .bitcoin import *
       +                   Fiat, bfh, bh2u)
       +from .bitcoin import (COIN, TYPE_ADDRESS, is_address, address_to_script,
       +                      is_minikey)
        from .version import *
       +from .crypto import Hash
        from .keystore import load_keystore, Hardware_KeyStore
        from .storage import multisig_type, STO_EV_PLAINTEXT, STO_EV_USER_PW, STO_EV_XPUB_PW, WalletStorage
       -from . import transaction, bitcoin, coinchooser, paymentrequest, contacts
       +from . import transaction, bitcoin, coinchooser, paymentrequest, ecc, bip32
        from .transaction import Transaction, TxOutput, TxOutputHwInfo
        from .plugin import run_hook
        from .address_synchronizer import (AddressSynchronizer, TX_HEIGHT_LOCAL,
                                           TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED)
       -from .paymentrequest import PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED
       -from .paymentrequest import InvoiceStore
       +from .paymentrequest import (PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED,
       +                             InvoiceStore)
        from .contacts import Contacts
        from .network import Network
        from .simple_config import SimpleConfig
       t@@ -1499,7 +1501,7 @@ class Simple_Deterministic_Wallet(Simple_Wallet, Deterministic_Wallet):
            def load_keystore(self):
                self.keystore = load_keystore(self.storage, 'keystore')
                try:
       -            xtype = bitcoin.xpub_type(self.keystore.xpub)
       +            xtype = bip32.xpub_type(self.keystore.xpub)
                except:
                    xtype = 'standard'
                self.txin_type = 'p2pkh' if xtype == 'standard' else xtype
       t@@ -1569,7 +1571,7 @@ class Multisig_Wallet(Deterministic_Wallet):
                    name = 'x%d/'%(i+1)
                    self.keystores[name] = load_keystore(self.storage, name)
                self.keystore = self.keystores['x1/']
       -        xtype = bitcoin.xpub_type(self.keystore.xpub)
       +        xtype = bip32.xpub_type(self.keystore.xpub)
                self.txin_type = 'p2sh' if xtype == 'standard' else xtype
        
            def save_keystore(self):