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