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):