mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
split bip32 from bitcoin.py
This commit is contained in:
parent
c61e13c1e9
commit
a88a2dea82
24 changed files with 391 additions and 372 deletions
|
@ -30,6 +30,7 @@ from functools import partial
|
||||||
|
|
||||||
from . import bitcoin
|
from . import bitcoin
|
||||||
from . import keystore
|
from . import keystore
|
||||||
|
from .bip32 import is_bip32_derivation, xpub_type
|
||||||
from .keystore import bip44_derivation, purpose48_derivation
|
from .keystore import bip44_derivation, purpose48_derivation
|
||||||
from .wallet import (Imported_Wallet, Standard_Wallet, Multisig_Wallet,
|
from .wallet import (Imported_Wallet, Standard_Wallet, Multisig_Wallet,
|
||||||
wallet_types, Wallet, Abstract_Wallet)
|
wallet_types, Wallet, Abstract_Wallet)
|
||||||
|
@ -339,7 +340,7 @@ class BaseWizard(object):
|
||||||
try:
|
try:
|
||||||
self.choice_and_line_dialog(
|
self.choice_and_line_dialog(
|
||||||
run_next=f, title=_('Script type and Derivation path'), message1=message1,
|
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
|
return
|
||||||
except ScriptTypeNotSupported as e:
|
except ScriptTypeNotSupported as e:
|
||||||
self.show_error(e)
|
self.show_error(e)
|
||||||
|
@ -419,7 +420,6 @@ class BaseWizard(object):
|
||||||
def on_keystore(self, k):
|
def on_keystore(self, k):
|
||||||
has_xpub = isinstance(k, keystore.Xpub)
|
has_xpub = isinstance(k, keystore.Xpub)
|
||||||
if has_xpub:
|
if has_xpub:
|
||||||
from .bitcoin import xpub_type
|
|
||||||
t1 = xpub_type(k.xpub)
|
t1 = xpub_type(k.xpub)
|
||||||
if self.wallet_type == 'standard':
|
if self.wallet_type == 'standard':
|
||||||
if has_xpub and t1 not in ['standard', 'p2wpkh', 'p2wpkh-p2sh']:
|
if has_xpub and t1 not in ['standard', 'p2wpkh', 'p2wpkh-p2sh']:
|
||||||
|
|
269
electrum/bip32.py
Normal file
269
electrum/bip32.py
Normal file
|
@ -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
|
|
@ -26,7 +26,7 @@
|
||||||
import hashlib
|
import hashlib
|
||||||
from typing import List, Tuple
|
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 version
|
||||||
from . import segwit_addr
|
from . import segwit_addr
|
||||||
from . import constants
|
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)
|
hmac_sha_512 = lambda x, y: hmac_oneshot(x, y, hashlib.sha512)
|
||||||
|
|
||||||
|
|
||||||
|
################################## electrum seeds
|
||||||
|
|
||||||
|
|
||||||
def is_new_seed(x, prefix=version.SEED_PREFIX):
|
def is_new_seed(x, prefix=version.SEED_PREFIX):
|
||||||
from . import mnemonic
|
from . import mnemonic
|
||||||
x = mnemonic.normalize_text(x)
|
x = mnemonic.normalize_text(x)
|
||||||
|
@ -277,14 +280,14 @@ def address_to_script(addr, *, net=None):
|
||||||
script = bh2u(bytes([OP_n]))
|
script = bh2u(bytes([OP_n]))
|
||||||
script += push_script(bh2u(bytes(witprog)))
|
script += push_script(bh2u(bytes(witprog)))
|
||||||
return script
|
return script
|
||||||
addrtype, hash_160 = b58_address_to_hash160(addr)
|
addrtype, hash_160_ = b58_address_to_hash160(addr)
|
||||||
if addrtype == net.ADDRTYPE_P2PKH:
|
if addrtype == net.ADDRTYPE_P2PKH:
|
||||||
script = '76a9' # op_dup, op_hash_160
|
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
|
script += '88ac' # op_equalverify, op_checksig
|
||||||
elif addrtype == net.ADDRTYPE_P2SH:
|
elif addrtype == net.ADDRTYPE_P2SH:
|
||||||
script = 'a9' # op_hash_160
|
script = 'a9' # op_hash_160
|
||||||
script += push_script(bh2u(hash_160))
|
script += push_script(bh2u(hash_160_))
|
||||||
script += '87' # op_equal
|
script += '87' # op_equal
|
||||||
else:
|
else:
|
||||||
raise BitcoinException('unknown address type: {}'.format(addrtype))
|
raise BitcoinException('unknown address type: {}'.format(addrtype))
|
||||||
|
@ -409,12 +412,6 @@ WIF_SCRIPT_TYPES = {
|
||||||
WIF_SCRIPT_TYPES_INV = inv_dict(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,
|
def serialize_privkey(secret: bytes, compressed: bool, txin_type: str,
|
||||||
internal_use: bool=False) -> str:
|
internal_use: bool=False) -> str:
|
||||||
|
@ -521,262 +518,3 @@ def is_minikey(text):
|
||||||
|
|
||||||
def minikey_to_private_key(text):
|
def minikey_to_private_key(text):
|
||||||
return sha256(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
|
|
||||||
|
|
|
@ -25,13 +25,19 @@
|
||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
|
|
||||||
from unicodedata import normalize
|
from unicodedata import normalize
|
||||||
|
import hashlib
|
||||||
|
|
||||||
from . import bitcoin, ecc, constants
|
from . import bitcoin, ecc, constants, bip32
|
||||||
from .bitcoin import *
|
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 .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,
|
from .util import (PrintError, InvalidPassword, hfu, WalletFileException,
|
||||||
BitcoinException)
|
BitcoinException, bh2u, bfh, print_error, inv_dict)
|
||||||
from .mnemonic import Mnemonic, load_wordlist
|
from .mnemonic import Mnemonic, load_wordlist
|
||||||
from .plugin import run_hook
|
from .plugin import run_hook
|
||||||
|
|
||||||
|
@ -332,7 +338,7 @@ class BIP32_KeyStore(Deterministic_KeyStore, Xpub):
|
||||||
|
|
||||||
def add_xprv(self, xprv):
|
def add_xprv(self, xprv):
|
||||||
self.xprv = 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):
|
def add_xprv_from_seed(self, bip32_seed, xtype, derivation):
|
||||||
xprv, xpub = bip32_root(bip32_seed, xtype)
|
xprv, xpub = bip32_root(bip32_seed, xtype)
|
||||||
|
@ -614,6 +620,13 @@ def from_bip39_seed(seed, passphrase, derivation, xtype=None):
|
||||||
return k
|
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:
|
def xtype_from_derivation(derivation: str) -> str:
|
||||||
"""Returns the script type to be used for this derivation."""
|
"""Returns the script type to be used for this derivation."""
|
||||||
if derivation.startswith("m/84'"):
|
if derivation.startswith("m/84'"):
|
||||||
|
@ -781,7 +794,7 @@ def from_seed(seed, passphrase, is_p2sh=False):
|
||||||
def from_private_key_list(text):
|
def from_private_key_list(text):
|
||||||
keystore = Imported_KeyStore({})
|
keystore = Imported_KeyStore({})
|
||||||
for x in get_private_keys(text):
|
for x in get_private_keys(text):
|
||||||
keystore.import_key(x, None)
|
keystore.import_privkey(x, None)
|
||||||
return keystore
|
return keystore
|
||||||
|
|
||||||
def from_old_mpk(mpk):
|
def from_old_mpk(mpk):
|
||||||
|
@ -795,7 +808,7 @@ def from_xpub(xpub):
|
||||||
return k
|
return k
|
||||||
|
|
||||||
def from_xprv(xprv):
|
def from_xprv(xprv):
|
||||||
xpub = bitcoin.xpub_from_xprv(xprv)
|
xpub = bip32.xpub_from_xprv(xprv)
|
||||||
k = BIP32_KeyStore({})
|
k = BIP32_KeyStore({})
|
||||||
k.xprv = xprv
|
k.xprv = xprv
|
||||||
k.xpub = xpub
|
k.xpub = xpub
|
||||||
|
|
|
@ -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'")
|
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 . import bitcoin, ecc, util, transaction, x509, rsakey
|
||||||
from .util import print_error, bh2u, bfh
|
from .util import print_error, bh2u, bfh, export_meta, import_meta
|
||||||
from .util import export_meta, import_meta
|
from .crypto import sha256
|
||||||
|
|
||||||
from .bitcoin import TYPE_ADDRESS
|
from .bitcoin import TYPE_ADDRESS
|
||||||
from .transaction import TxOutput
|
from .transaction import TxOutput
|
||||||
|
|
||||||
|
@ -113,7 +112,7 @@ class PaymentRequest:
|
||||||
def parse(self, r):
|
def parse(self, r):
|
||||||
if self.error:
|
if self.error:
|
||||||
return
|
return
|
||||||
self.id = bh2u(bitcoin.sha256(r)[0:16])
|
self.id = bh2u(sha256(r)[0:16])
|
||||||
try:
|
try:
|
||||||
self.data = pb2.PaymentRequest()
|
self.data = pb2.PaymentRequest()
|
||||||
self.data.ParseFromString(r)
|
self.data.ParseFromString(r)
|
||||||
|
|
|
@ -33,7 +33,7 @@ import threading
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
from .util import (profiler, PrintError, DaemonThread, UserCancelled,
|
from .util import (profiler, PrintError, DaemonThread, UserCancelled,
|
||||||
ThreadJob, print_error)
|
ThreadJob, print_error)
|
||||||
from . import bitcoin
|
from . import bip32
|
||||||
from . import plugins
|
from . import plugins
|
||||||
from .simple_config import SimpleConfig
|
from .simple_config import SimpleConfig
|
||||||
|
|
||||||
|
@ -432,7 +432,7 @@ class DeviceMgr(ThreadJob, PrintError):
|
||||||
def force_pair_xpub(self, plugin, handler, info, xpub, derivation, devices):
|
def force_pair_xpub(self, plugin, handler, info, xpub, derivation, devices):
|
||||||
# The wallet has not been previously paired, so let the user
|
# The wallet has not been previously paired, so let the user
|
||||||
# choose an unpaired device and compare its first address.
|
# 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_)
|
client = self.client_lookup(info.device.id_)
|
||||||
if client and client.is_pairable():
|
if client and client.is_pairable():
|
||||||
# See comment above for same code
|
# See comment above for same code
|
||||||
|
|
|
@ -3,25 +3,21 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
import hashlib
|
|
||||||
import os, sys, time, io
|
import os, sys, time, io
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from electrum import bitcoin
|
from electrum.bip32 import serialize_xpub, deserialize_xpub, InvalidMasterKeyVersionBytes
|
||||||
from electrum.bitcoin import serialize_xpub, deserialize_xpub, InvalidMasterKeyVersionBytes
|
|
||||||
from electrum import constants
|
|
||||||
from electrum.bitcoin import TYPE_ADDRESS, int_to_hex
|
|
||||||
from electrum.i18n import _
|
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.keystore import Hardware_KeyStore, xpubkey_to_pubkey, Xpub
|
||||||
from electrum.transaction import Transaction
|
from electrum.transaction import Transaction
|
||||||
from electrum.wallet import Standard_Wallet
|
from electrum.wallet import Standard_Wallet
|
||||||
from electrum.crypto import hash_160
|
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.util import print_error, bfh, bh2u, versiontuple
|
||||||
from electrum.base_wizard import ScriptTypeNotSupported
|
from electrum.base_wizard import ScriptTypeNotSupported
|
||||||
|
|
||||||
|
from ..hw_wallet import HW_PluginBase
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import hid
|
import hid
|
||||||
from ckcc.protocol import CCProtocolPacker, CCProtocolUnpacker
|
from ckcc.protocol import CCProtocolPacker, CCProtocolUnpacker
|
||||||
|
@ -46,7 +42,7 @@ try:
|
||||||
from electrum.ecc import ECPubkey
|
from electrum.ecc import ECPubkey
|
||||||
|
|
||||||
xtype, depth, parent_fingerprint, child_number, chain_code, K_or_k \
|
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)
|
pubkey = ECPubkey(K_or_k)
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -30,7 +30,7 @@ from PyQt5.QtGui import *
|
||||||
from PyQt5.QtCore import *
|
from PyQt5.QtCore import *
|
||||||
from PyQt5.QtWidgets import QPushButton
|
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 import transaction
|
||||||
from electrum.plugin import BasePlugin, hook
|
from electrum.plugin import BasePlugin, hook
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
|
@ -132,8 +132,8 @@ class Plugin(BasePlugin):
|
||||||
self.cosigner_list = []
|
self.cosigner_list = []
|
||||||
for key, keystore in wallet.keystores.items():
|
for key, keystore in wallet.keystores.items():
|
||||||
xpub = keystore.get_master_public_key()
|
xpub = keystore.get_master_public_key()
|
||||||
K = bitcoin.deserialize_xpub(xpub)[-1]
|
K = bip32.deserialize_xpub(xpub)[-1]
|
||||||
_hash = bh2u(bitcoin.Hash(K))
|
_hash = bh2u(crypto.Hash(K))
|
||||||
if not keystore.is_watching_only():
|
if not keystore.is_watching_only():
|
||||||
self.keys.append((key, _hash, window))
|
self.keys.append((key, _hash, window))
|
||||||
else:
|
else:
|
||||||
|
@ -222,7 +222,7 @@ class Plugin(BasePlugin):
|
||||||
if not xprv:
|
if not xprv:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
k = bitcoin.deserialize_xprv(xprv)[-1]
|
k = bip32.deserialize_xprv(xprv)[-1]
|
||||||
EC = ecc.ECPrivkey(k)
|
EC = ecc.ECPrivkey(k)
|
||||||
message = bh2u(EC.decrypt_message(message))
|
message = bh2u(EC.decrypt_message(message))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from electrum.crypto import Hash, EncodeAES, DecodeAES
|
from electrum.crypto import Hash, EncodeAES, DecodeAES
|
||||||
from electrum.bitcoin import (TYPE_ADDRESS, push_script, var_int, public_key_to_p2pkh, is_address,
|
from electrum.bitcoin import (TYPE_ADDRESS, push_script, var_int, public_key_to_p2pkh,
|
||||||
serialize_xpub, deserialize_xpub)
|
is_address)
|
||||||
|
from electrum.bip32 import serialize_xpub, deserialize_xpub
|
||||||
from electrum import ecc
|
from electrum import ecc
|
||||||
from electrum.ecc import msg_magic
|
from electrum.ecc import msg_magic
|
||||||
from electrum.wallet import Standard_Wallet
|
from electrum.wallet import Standard_Wallet
|
||||||
|
|
|
@ -4,7 +4,7 @@ from struct import pack
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.util import PrintError, UserCancelled
|
from electrum.util import PrintError, UserCancelled
|
||||||
from electrum.keystore import bip39_normalize_passphrase
|
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):
|
class GuiMixin(object):
|
||||||
|
|
|
@ -3,14 +3,12 @@ import traceback
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from electrum.util import bfh, bh2u, UserCancelled
|
from electrum.util import bfh, bh2u, UserCancelled
|
||||||
from electrum.bitcoin import (xpub_from_pubkey, deserialize_xpub,
|
from electrum.bitcoin import TYPE_ADDRESS, TYPE_SCRIPT
|
||||||
TYPE_ADDRESS, TYPE_SCRIPT)
|
from electrum.bip32 import deserialize_xpub
|
||||||
from electrum import constants
|
from electrum import constants
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.plugin import BasePlugin
|
|
||||||
from electrum.transaction import deserialize, Transaction
|
from electrum.transaction import deserialize, Transaction
|
||||||
from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey
|
from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey
|
||||||
from electrum.wallet import Standard_Wallet
|
|
||||||
from electrum.base_wizard import ScriptTypeNotSupported
|
from electrum.base_wizard import ScriptTypeNotSupported
|
||||||
|
|
||||||
from ..hw_wallet import HW_PluginBase
|
from ..hw_wallet import HW_PluginBase
|
||||||
|
|
|
@ -7,9 +7,8 @@ from PyQt5.Qt import QVBoxLayout, QLabel
|
||||||
|
|
||||||
from electrum.gui.qt.util import *
|
from electrum.gui.qt.util import *
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.plugin import hook, DeviceMgr
|
from electrum.plugin import hook
|
||||||
from electrum.util import PrintError, UserCancelled, bh2u
|
from electrum.util import bh2u
|
||||||
from electrum.wallet import Wallet, Standard_Wallet
|
|
||||||
|
|
||||||
from ..hw_wallet.qt import QtHandlerBase, QtPluginBase
|
from ..hw_wallet.qt import QtHandlerBase, QtPluginBase
|
||||||
from ..hw_wallet.plugin import only_hook_if_libraries_available
|
from ..hw_wallet.plugin import only_hook_if_libraries_available
|
||||||
|
@ -253,7 +252,7 @@ class QtPlugin(QtPluginBase):
|
||||||
else:
|
else:
|
||||||
msg = _("Enter the master private key beginning with xprv:")
|
msg = _("Enter the master private key beginning with xprv:")
|
||||||
def set_enabled():
|
def set_enabled():
|
||||||
from keystore import is_xprv
|
from electrum.bip32 import is_xprv
|
||||||
wizard.next_button.setEnabled(is_xprv(clean_text(text)))
|
wizard.next_button.setEnabled(is_xprv(clean_text(text)))
|
||||||
text.textChanged.connect(set_enabled)
|
text.textChanged.connect(set_enabled)
|
||||||
next_enabled = False
|
next_enabled = False
|
||||||
|
|
|
@ -3,18 +3,18 @@ import hashlib
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from electrum import bitcoin
|
|
||||||
from electrum.bitcoin import TYPE_ADDRESS, int_to_hex, var_int
|
from electrum.bitcoin import TYPE_ADDRESS, int_to_hex, var_int
|
||||||
|
from electrum.bip32 import serialize_xpub
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.plugin import BasePlugin
|
|
||||||
from electrum.keystore import Hardware_KeyStore
|
from electrum.keystore import Hardware_KeyStore
|
||||||
from electrum.transaction import Transaction
|
from electrum.transaction import Transaction
|
||||||
from electrum.wallet import Standard_Wallet
|
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.util import print_error, bfh, bh2u, versiontuple
|
||||||
from electrum.base_wizard import ScriptTypeNotSupported
|
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:
|
try:
|
||||||
import hid
|
import hid
|
||||||
from btchip.btchipComm import HIDDongleHIDAPI, DongleWait
|
from btchip.btchipComm import HIDDongleHIDAPI, DongleWait
|
||||||
|
@ -112,7 +112,7 @@ class Ledger_Client():
|
||||||
depth = len(splitPath)
|
depth = len(splitPath)
|
||||||
lastChild = splitPath[len(splitPath) - 1].split('\'')
|
lastChild = splitPath[len(splitPath) - 1].split('\'')
|
||||||
childnum = int(lastChild[0]) if len(lastChild) == 1 else 0x80000000 | int(lastChild[0])
|
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
|
return xpub
|
||||||
|
|
||||||
def has_detached_pin_support(self, client):
|
def has_detached_pin_support(self, client):
|
||||||
|
|
|
@ -4,7 +4,7 @@ from struct import pack
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.util import PrintError, UserCancelled
|
from electrum.util import PrintError, UserCancelled
|
||||||
from electrum.keystore import bip39_normalize_passphrase
|
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):
|
class GuiMixin(object):
|
||||||
|
|
|
@ -7,9 +7,8 @@ from PyQt5.Qt import QVBoxLayout, QLabel
|
||||||
|
|
||||||
from electrum.gui.qt.util import *
|
from electrum.gui.qt.util import *
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.plugin import hook, DeviceMgr
|
from electrum.plugin import hook
|
||||||
from electrum.util import PrintError, UserCancelled, bh2u
|
from electrum.util import bh2u
|
||||||
from electrum.wallet import Wallet, Standard_Wallet
|
|
||||||
|
|
||||||
from ..hw_wallet.qt import QtHandlerBase, QtPluginBase
|
from ..hw_wallet.qt import QtHandlerBase, QtPluginBase
|
||||||
from ..hw_wallet.plugin import only_hook_if_libraries_available
|
from ..hw_wallet.plugin import only_hook_if_libraries_available
|
||||||
|
@ -127,7 +126,7 @@ class QtPlugin(QtPluginBase):
|
||||||
else:
|
else:
|
||||||
msg = _("Enter the master private key beginning with xprv:")
|
msg = _("Enter the master private key beginning with xprv:")
|
||||||
def set_enabled():
|
def set_enabled():
|
||||||
from electrum.keystore import is_xprv
|
from electrum.bip32 import is_xprv
|
||||||
wizard.next_button.setEnabled(is_xprv(clean_text(text)))
|
wizard.next_button.setEnabled(is_xprv(clean_text(text)))
|
||||||
text.textChanged.connect(set_enabled)
|
text.textChanged.connect(set_enabled)
|
||||||
next_enabled = False
|
next_enabled = False
|
||||||
|
|
|
@ -3,11 +3,11 @@ import traceback
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from electrum.util import bfh, bh2u, versiontuple, UserCancelled
|
from electrum.util import bfh, bh2u, versiontuple, UserCancelled
|
||||||
from electrum.bitcoin import (b58_address_to_hash160, xpub_from_pubkey, deserialize_xpub,
|
from electrum.bitcoin import TYPE_ADDRESS, TYPE_SCRIPT
|
||||||
TYPE_ADDRESS, TYPE_SCRIPT, is_address)
|
from electrum.bip32 import deserialize_xpub
|
||||||
from electrum import constants
|
from electrum import constants
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.plugin import BasePlugin, Device
|
from electrum.plugin import Device
|
||||||
from electrum.transaction import deserialize, Transaction
|
from electrum.transaction import deserialize, Transaction
|
||||||
from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey
|
from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey
|
||||||
from electrum.base_wizard import ScriptTypeNotSupported
|
from electrum.base_wizard import ScriptTypeNotSupported
|
||||||
|
|
|
@ -4,7 +4,7 @@ from struct import pack
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.util import PrintError, UserCancelled
|
from electrum.util import PrintError, UserCancelled
|
||||||
from electrum.keystore import bip39_normalize_passphrase
|
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):
|
class GuiMixin(object):
|
||||||
|
|
|
@ -7,9 +7,8 @@ from PyQt5.Qt import QVBoxLayout, QLabel
|
||||||
|
|
||||||
from electrum.gui.qt.util import *
|
from electrum.gui.qt.util import *
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.plugin import hook, DeviceMgr
|
from electrum.plugin import hook
|
||||||
from electrum.util import PrintError, UserCancelled, bh2u
|
from electrum.util import bh2u
|
||||||
from electrum.wallet import Wallet, Standard_Wallet
|
|
||||||
|
|
||||||
from ..hw_wallet.qt import QtHandlerBase, QtPluginBase
|
from ..hw_wallet.qt import QtHandlerBase, QtPluginBase
|
||||||
from ..hw_wallet.plugin import only_hook_if_libraries_available
|
from ..hw_wallet.plugin import only_hook_if_libraries_available
|
||||||
|
@ -222,7 +221,7 @@ class QtPlugin(QtPluginBase):
|
||||||
else:
|
else:
|
||||||
msg = _("Enter the master private key beginning with xprv:")
|
msg = _("Enter the master private key beginning with xprv:")
|
||||||
def set_enabled():
|
def set_enabled():
|
||||||
from electrum.keystore import is_xprv
|
from electrum.bip32 import is_xprv
|
||||||
wizard.next_button.setEnabled(is_xprv(clean_text(text)))
|
wizard.next_button.setEnabled(is_xprv(clean_text(text)))
|
||||||
text.textChanged.connect(set_enabled)
|
text.textChanged.connect(set_enabled)
|
||||||
next_enabled = False
|
next_enabled = False
|
||||||
|
|
|
@ -3,11 +3,11 @@ import traceback
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from electrum.util import bfh, bh2u, versiontuple, UserCancelled
|
from electrum.util import bfh, bh2u, versiontuple, UserCancelled
|
||||||
from electrum.bitcoin import (xpub_from_pubkey, deserialize_xpub,
|
from electrum.bitcoin import TYPE_ADDRESS, TYPE_SCRIPT
|
||||||
TYPE_ADDRESS, TYPE_SCRIPT)
|
from electrum.bip32 import deserialize_xpub
|
||||||
from electrum import constants
|
from electrum import constants
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.plugin import BasePlugin, Device
|
from electrum.plugin import Device
|
||||||
from electrum.transaction import deserialize, Transaction
|
from electrum.transaction import deserialize, Transaction
|
||||||
from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey
|
from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey
|
||||||
from electrum.base_wizard import ScriptTypeNotSupported
|
from electrum.base_wizard import ScriptTypeNotSupported
|
||||||
|
|
|
@ -24,14 +24,19 @@
|
||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
import asyncio
|
import asyncio
|
||||||
import socket
|
import socket
|
||||||
import os
|
|
||||||
import json
|
import json
|
||||||
import base64
|
import base64
|
||||||
|
import time
|
||||||
|
import hashlib
|
||||||
|
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
|
|
||||||
from electrum import bitcoin, ecc, constants, keystore, version
|
from electrum import ecc, constants, keystore, version, bip32
|
||||||
from electrum.bitcoin import *
|
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.transaction import TxOutput
|
||||||
from electrum.mnemonic import Mnemonic
|
from electrum.mnemonic import Mnemonic
|
||||||
from electrum.wallet import Multisig_Wallet, Deterministic_Wallet
|
from electrum.wallet import Multisig_Wallet, Deterministic_Wallet
|
||||||
|
@ -348,7 +353,7 @@ class Wallet_2fa(Multisig_Wallet):
|
||||||
|
|
||||||
def get_user_id(storage):
|
def get_user_id(storage):
|
||||||
def make_long_id(xpub_hot, xpub_cold):
|
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']
|
xpub1 = storage.get('x1/')['xpub']
|
||||||
xpub2 = storage.get('x2/')['xpub']
|
xpub2 = storage.get('x2/')['xpub']
|
||||||
long_id = make_long_id(xpub1, xpub2)
|
long_id = make_long_id(xpub1, xpub2)
|
||||||
|
@ -357,15 +362,15 @@ def get_user_id(storage):
|
||||||
|
|
||||||
def make_xpub(xpub, s):
|
def make_xpub(xpub, s):
|
||||||
version, _, _, _, c, cK = deserialize_xpub(xpub)
|
version, _, _, _, c, cK = deserialize_xpub(xpub)
|
||||||
cK2, c2 = bitcoin._CKD_pub(cK, c, s)
|
cK2, c2 = bip32._CKD_pub(cK, c, s)
|
||||||
return bitcoin.serialize_xpub(version, c2, cK2)
|
return serialize_xpub(version, c2, cK2)
|
||||||
|
|
||||||
def make_billing_address(wallet, num):
|
def make_billing_address(wallet, num):
|
||||||
long_id, short_id = wallet.get_user_id()
|
long_id, short_id = wallet.get_user_id()
|
||||||
xpub = make_xpub(get_billing_xpub(), long_id)
|
xpub = make_xpub(get_billing_xpub(), long_id)
|
||||||
version, _, _, _, c, cK = deserialize_xpub(xpub)
|
version, _, _, _, c, cK = deserialize_xpub(xpub)
|
||||||
cK, c = bitcoin.CKD_pub(cK, c, num)
|
cK, c = CKD_pub(cK, c, num)
|
||||||
return bitcoin.public_key_to_p2pkh(cK)
|
return public_key_to_p2pkh(cK)
|
||||||
|
|
||||||
|
|
||||||
class TrustedCoinPlugin(BasePlugin):
|
class TrustedCoinPlugin(BasePlugin):
|
||||||
|
@ -379,7 +384,7 @@ class TrustedCoinPlugin(BasePlugin):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_valid_seed(seed):
|
def is_valid_seed(seed):
|
||||||
return bitcoin.is_new_seed(seed, SEED_PREFIX)
|
return is_new_seed(seed, SEED_PREFIX)
|
||||||
|
|
||||||
def is_available(self):
|
def is_available(self):
|
||||||
return True
|
return True
|
||||||
|
@ -479,8 +484,6 @@ class TrustedCoinPlugin(BasePlugin):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_xkeys(self, seed, passphrase, derivation):
|
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)
|
bip32_seed = Mnemonic.mnemonic_to_seed(seed, passphrase)
|
||||||
xprv, xpub = bip32_root(bip32_seed, 'standard')
|
xprv, xpub = bip32_root(bip32_seed, 'standard')
|
||||||
xprv, xpub = bip32_private_derivation(xprv, "m/", derivation)
|
xprv, xpub = bip32_private_derivation(xprv, "m/", derivation)
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
import base64
|
import base64
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from electrum.bitcoin import (
|
from electrum.bitcoin import (public_key_to_p2pkh, address_from_private_key,
|
||||||
public_key_to_p2pkh,
|
is_address, is_private_key, is_new_seed, is_old_seed,
|
||||||
bip32_root, bip32_public_derivation, bip32_private_derivation,
|
var_int, op_push, address_to_script,
|
||||||
Hash, address_from_private_key,
|
deserialize_privkey, serialize_privkey, is_segwit_address,
|
||||||
is_address, is_private_key, xpub_from_xprv, is_new_seed, is_old_seed,
|
is_b58_address, address_to_scripthash, is_minikey,
|
||||||
var_int, op_push, address_to_script,
|
is_compressed, seed_type, EncodeBase58Check,
|
||||||
deserialize_privkey, serialize_privkey, is_segwit_address,
|
script_num_to_hex, push_script, add_number_to_script, int_to_hex)
|
||||||
is_b58_address, address_to_scripthash, is_minikey, is_compressed, is_xpub,
|
from electrum.bip32 import (bip32_root, bip32_public_derivation, bip32_private_derivation,
|
||||||
xpub_type, is_xprv, is_bip32_derivation, seed_type, EncodeBase58Check,
|
xpub_from_xprv, xpub_type, is_xprv, is_bip32_derivation,
|
||||||
script_num_to_hex, push_script, add_number_to_script, int_to_hex, convert_bip32_path_to_list_of_uint32)
|
is_xpub, convert_bip32_path_to_list_of_uint32)
|
||||||
|
from electrum.crypto import Hash
|
||||||
from electrum import ecc, crypto, constants
|
from electrum import ecc, crypto, constants
|
||||||
from electrum.ecc import number_to_string, string_to_number
|
from electrum.ecc import number_to_string, string_to_number
|
||||||
from electrum.transaction import opcodes
|
from electrum.transaction import opcodes
|
||||||
|
|
|
@ -27,23 +27,22 @@
|
||||||
|
|
||||||
# Note: The deserialization code originally comes from ABE.
|
# 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 struct
|
||||||
import traceback
|
import traceback
|
||||||
import sys
|
import sys
|
||||||
|
from typing import (Sequence, Union, NamedTuple, Tuple, Optional, Iterable,
|
||||||
|
Callable, List)
|
||||||
|
|
||||||
#
|
from . import ecc, bitcoin, constants, segwit_addr
|
||||||
# Workalike python implementation of Bitcoin's CDataStream class.
|
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
|
from .keystore import xpubkey_to_address, xpubkey_to_pubkey
|
||||||
|
|
||||||
|
|
||||||
NO_SIGNATURE = 'ff'
|
NO_SIGNATURE = 'ff'
|
||||||
PARTIAL_TXN_HEADER_MAGIC = b'EPTF\xff'
|
PARTIAL_TXN_HEADER_MAGIC = b'EPTF\xff'
|
||||||
|
|
||||||
|
@ -78,6 +77,8 @@ TxOutputHwInfo = NamedTuple("TxOutputHwInfo", [('address_index', Tuple),
|
||||||
|
|
||||||
|
|
||||||
class BCDataStream(object):
|
class BCDataStream(object):
|
||||||
|
"""Workalike python implementation of Bitcoin's CDataStream class."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.input = None
|
self.input = None
|
||||||
self.read_cursor = 0
|
self.read_cursor = 0
|
||||||
|
@ -353,7 +354,7 @@ def parse_scriptSig(d, _bytes):
|
||||||
if item[0] == 0:
|
if item[0] == 0:
|
||||||
# segwit embedded into p2sh
|
# segwit embedded into p2sh
|
||||||
# witness version 0
|
# 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:
|
if len(item) == 22:
|
||||||
d['type'] = 'p2wpkh-p2sh'
|
d['type'] = 'p2wpkh-p2sh'
|
||||||
elif len(item) == 34:
|
elif len(item) == 34:
|
||||||
|
@ -901,7 +902,7 @@ class Transaction:
|
||||||
witver, witprog = segwit_addr.decode(constants.net.SEGWIT_HRP, addr)
|
witver, witprog = segwit_addr.decode(constants.net.SEGWIT_HRP, addr)
|
||||||
if witprog is not None:
|
if witprog is not None:
|
||||||
return 'p2wpkh'
|
return 'p2wpkh'
|
||||||
addrtype, hash_160 = b58_address_to_hash160(addr)
|
addrtype, hash_160_ = b58_address_to_hash160(addr)
|
||||||
if addrtype == constants.net.ADDRTYPE_P2PKH:
|
if addrtype == constants.net.ADDRTYPE_P2PKH:
|
||||||
return 'p2pkh'
|
return 'p2pkh'
|
||||||
elif addrtype == constants.net.ADDRTYPE_P2SH:
|
elif addrtype == constants.net.ADDRTYPE_P2SH:
|
||||||
|
@ -977,7 +978,7 @@ class Transaction:
|
||||||
return multisig_script(pubkeys, txin['num_sig'])
|
return multisig_script(pubkeys, txin['num_sig'])
|
||||||
elif txin['type'] in ['p2wpkh', 'p2wpkh-p2sh']:
|
elif txin['type'] in ['p2wpkh', 'p2wpkh-p2sh']:
|
||||||
pubkey = pubkeys[0]
|
pubkey = pubkeys[0]
|
||||||
pkh = bh2u(bitcoin.hash_160(bfh(pubkey)))
|
pkh = bh2u(hash_160(bfh(pubkey)))
|
||||||
return '76a9' + push_script(pkh) + '88ac'
|
return '76a9' + push_script(pkh) + '88ac'
|
||||||
elif txin['type'] == 'p2pk':
|
elif txin['type'] == 'p2pk':
|
||||||
pubkey = pubkeys[0]
|
pubkey = pubkeys[0]
|
||||||
|
|
|
@ -27,7 +27,8 @@ from typing import Sequence, Optional, TYPE_CHECKING
|
||||||
import aiorpcx
|
import aiorpcx
|
||||||
|
|
||||||
from .util import bh2u, VerifiedTxInfo, NetworkJobOnDefaultServer
|
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 .transaction import Transaction
|
||||||
from .blockchain import hash_header
|
from .blockchain import hash_header
|
||||||
from .interface import GracefulDisconnect
|
from .interface import GracefulDisconnect
|
||||||
|
|
|
@ -44,18 +44,20 @@ from .util import (NotEnoughFunds, PrintError, UserCancelled, profiler,
|
||||||
format_satoshis, format_fee_satoshis, NoDynamicFeeEstimates,
|
format_satoshis, format_fee_satoshis, NoDynamicFeeEstimates,
|
||||||
TimeoutException, WalletFileException, BitcoinException,
|
TimeoutException, WalletFileException, BitcoinException,
|
||||||
InvalidPassword, format_time, timestamp_to_datetime, Satoshis,
|
InvalidPassword, format_time, timestamp_to_datetime, Satoshis,
|
||||||
Fiat)
|
Fiat, bfh, bh2u)
|
||||||
from .bitcoin import *
|
from .bitcoin import (COIN, TYPE_ADDRESS, is_address, address_to_script,
|
||||||
|
is_minikey)
|
||||||
from .version import *
|
from .version import *
|
||||||
|
from .crypto import Hash
|
||||||
from .keystore import load_keystore, Hardware_KeyStore
|
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 .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 .transaction import Transaction, TxOutput, TxOutputHwInfo
|
||||||
from .plugin import run_hook
|
from .plugin import run_hook
|
||||||
from .address_synchronizer import (AddressSynchronizer, TX_HEIGHT_LOCAL,
|
from .address_synchronizer import (AddressSynchronizer, TX_HEIGHT_LOCAL,
|
||||||
TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED)
|
TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED)
|
||||||
from .paymentrequest import PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED
|
from .paymentrequest import (PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED,
|
||||||
from .paymentrequest import InvoiceStore
|
InvoiceStore)
|
||||||
from .contacts import Contacts
|
from .contacts import Contacts
|
||||||
from .network import Network
|
from .network import Network
|
||||||
from .simple_config import SimpleConfig
|
from .simple_config import SimpleConfig
|
||||||
|
@ -1499,7 +1501,7 @@ class Simple_Deterministic_Wallet(Simple_Wallet, Deterministic_Wallet):
|
||||||
def load_keystore(self):
|
def load_keystore(self):
|
||||||
self.keystore = load_keystore(self.storage, 'keystore')
|
self.keystore = load_keystore(self.storage, 'keystore')
|
||||||
try:
|
try:
|
||||||
xtype = bitcoin.xpub_type(self.keystore.xpub)
|
xtype = bip32.xpub_type(self.keystore.xpub)
|
||||||
except:
|
except:
|
||||||
xtype = 'standard'
|
xtype = 'standard'
|
||||||
self.txin_type = 'p2pkh' if xtype == 'standard' else xtype
|
self.txin_type = 'p2pkh' if xtype == 'standard' else xtype
|
||||||
|
@ -1569,7 +1571,7 @@ class Multisig_Wallet(Deterministic_Wallet):
|
||||||
name = 'x%d/'%(i+1)
|
name = 'x%d/'%(i+1)
|
||||||
self.keystores[name] = load_keystore(self.storage, name)
|
self.keystores[name] = load_keystore(self.storage, name)
|
||||||
self.keystore = self.keystores['x1/']
|
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
|
self.txin_type = 'p2sh' if xtype == 'standard' else xtype
|
||||||
|
|
||||||
def save_keystore(self):
|
def save_keystore(self):
|
||||||
|
|
Loading…
Add table
Reference in a new issue