electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit a88a2dea8255532abdd20002c866b443237a509c
parent c61e13c1e953c962a2083feecb3905186492fb81
Author: SomberNight <somber.night@protonmail.com>
Date:   Thu, 25 Oct 2018 22:20:33 +0200

split bip32 from bitcoin.py

Diffstat:
Melectrum/base_wizard.py | 4++--
Aelectrum/bip32.py | 269+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Melectrum/bitcoin.py | 276++-----------------------------------------------------------------------------
Melectrum/keystore.py | 29+++++++++++++++++++++--------
Melectrum/paymentrequest.py | 7+++----
Melectrum/plugin.py | 4++--
Melectrum/plugins/coldcard/coldcard.py | 14+++++---------
Melectrum/plugins/cosigner_pool/qt.py | 8++++----
Melectrum/plugins/digitalbitbox/digitalbitbox.py | 5+++--
Melectrum/plugins/keepkey/clientbase.py | 2+-
Melectrum/plugins/keepkey/keepkey.py | 6++----
Melectrum/plugins/keepkey/qt.py | 7+++----
Melectrum/plugins/ledger/ledger.py | 10+++++-----
Melectrum/plugins/safe_t/clientbase.py | 2+-
Melectrum/plugins/safe_t/qt.py | 7+++----
Melectrum/plugins/safe_t/safe_t.py | 6+++---
Melectrum/plugins/trezor/clientbase.py | 2+-
Melectrum/plugins/trezor/qt.py | 7+++----
Melectrum/plugins/trezor/trezor.py | 6+++---
Melectrum/plugins/trustedcoin/trustedcoin.py | 25++++++++++++++-----------
Melectrum/tests/test_bitcoin.py | 21+++++++++++----------
Melectrum/transaction.py | 31++++++++++++++++---------------
Melectrum/verifier.py | 3++-
Melectrum/wallet.py | 16+++++++++-------
24 files changed, 393 insertions(+), 374 deletions(-)

diff --git a/electrum/base_wizard.py b/electrum/base_wizard.py @@ -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) @@ -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) @@ -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']: diff --git a/electrum/bip32.py b/electrum/bip32.py @@ -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 diff --git a/electrum/bitcoin.py b/electrum/bitcoin.py @@ -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 @@ -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) @@ -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)) @@ -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: @@ -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 diff --git a/electrum/keystore.py b/electrum/keystore.py @@ -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 @@ -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) @@ -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'"): @@ -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): @@ -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 diff --git a/electrum/paymentrequest.py b/electrum/paymentrequest.py @@ -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 @@ -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) diff --git a/electrum/plugin.py b/electrum/plugin.py @@ -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 @@ -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 diff --git a/electrum/plugins/coldcard/coldcard.py b/electrum/plugins/coldcard/coldcard.py @@ -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 @@ -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: diff --git a/electrum/plugins/cosigner_pool/qt.py b/electrum/plugins/cosigner_pool/qt.py @@ -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 _ @@ -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: @@ -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: diff --git a/electrum/plugins/digitalbitbox/digitalbitbox.py b/electrum/plugins/digitalbitbox/digitalbitbox.py @@ -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 diff --git a/electrum/plugins/keepkey/clientbase.py b/electrum/plugins/keepkey/clientbase.py @@ -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): diff --git a/electrum/plugins/keepkey/keepkey.py b/electrum/plugins/keepkey/keepkey.py @@ -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 diff --git a/electrum/plugins/keepkey/qt.py b/electrum/plugins/keepkey/qt.py @@ -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 @@ -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 diff --git a/electrum/plugins/ledger/ledger.py b/electrum/plugins/ledger/ledger.py @@ -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 @@ -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): diff --git a/electrum/plugins/safe_t/clientbase.py b/electrum/plugins/safe_t/clientbase.py @@ -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): diff --git a/electrum/plugins/safe_t/qt.py b/electrum/plugins/safe_t/qt.py @@ -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 @@ -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 diff --git a/electrum/plugins/safe_t/safe_t.py b/electrum/plugins/safe_t/safe_t.py @@ -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 diff --git a/electrum/plugins/trezor/clientbase.py b/electrum/plugins/trezor/clientbase.py @@ -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): diff --git a/electrum/plugins/trezor/qt.py b/electrum/plugins/trezor/qt.py @@ -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 @@ -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 diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py @@ -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 diff --git a/electrum/plugins/trustedcoin/trustedcoin.py b/electrum/plugins/trustedcoin/trustedcoin.py @@ -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 @@ -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) @@ -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): @@ -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 @@ -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) diff --git a/electrum/tests/test_bitcoin.py b/electrum/tests/test_bitcoin.py @@ -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 diff --git a/electrum/transaction.py b/electrum/transaction.py @@ -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' @@ -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 @@ -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: @@ -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: @@ -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] diff --git a/electrum/verifier.py b/electrum/verifier.py @@ -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 diff --git a/electrum/wallet.py b/electrum/wallet.py @@ -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 @@ -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 @@ -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):