make xpub/xprv version information user-visible
This commit is contained in:
parent
bd16e20a4d
commit
63a1db1172
|
@ -47,14 +47,30 @@ def read_json_dict(filename):
|
|||
return r
|
||||
|
||||
|
||||
# Version numbers for BIP32 extended keys
|
||||
# standard: xprv, xpub
|
||||
# segwit in p2sh: yprv, ypub
|
||||
# native segwit: zprv, zpub
|
||||
XPRV_HEADERS = {
|
||||
'standard': 0x0488ade4,
|
||||
'segwit_p2sh': 0x049d7878,
|
||||
'segwit': 0x4b2430c
|
||||
}
|
||||
XPUB_HEADERS = {
|
||||
'standard': 0x0488b21e,
|
||||
'segwit_p2sh': 0x049d7cb2,
|
||||
'segwit': 0x4b24746
|
||||
}
|
||||
|
||||
|
||||
# Bitcoin network constants
|
||||
TESTNET = False
|
||||
NOLNET = False
|
||||
ADDRTYPE_P2PKH = 0
|
||||
ADDRTYPE_P2SH = 5
|
||||
SEGWIT_HRP = "bc"
|
||||
XPRV_HEADER = 0x0488ade4
|
||||
XPUB_HEADER = 0x0488b21e
|
||||
|
||||
|
||||
HEADERS_URL = "https://headers.electrum.org/blockchain_headers"
|
||||
GENESIS = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
|
||||
SERVERLIST = 'servers.json'
|
||||
|
@ -63,7 +79,6 @@ DEFAULT_SERVERS = read_json_dict('servers.json')
|
|||
|
||||
def set_testnet():
|
||||
global ADDRTYPE_P2PKH, ADDRTYPE_P2SH
|
||||
global XPRV_HEADER, XPUB_HEADER
|
||||
global TESTNET, HEADERS_URL
|
||||
global GENESIS
|
||||
global SEGWIT_HRP
|
||||
|
@ -72,8 +87,6 @@ def set_testnet():
|
|||
ADDRTYPE_P2PKH = 111
|
||||
ADDRTYPE_P2SH = 196
|
||||
SEGWIT_HRP = "tb"
|
||||
XPRV_HEADER = 0x04358394
|
||||
XPUB_HEADER = 0x043587cf
|
||||
HEADERS_URL = "https://headers.electrum.org/testnet_headers"
|
||||
GENESIS = "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
|
||||
SERVERLIST = 'servers_testnet.json'
|
||||
|
@ -816,11 +829,11 @@ def _CKD_pub(cK, c, s):
|
|||
|
||||
|
||||
def xprv_header(xtype):
|
||||
return bfh("%08x" % (XPRV_HEADER + xtype))
|
||||
return bfh("%08x" % XPRV_HEADERS[xtype])
|
||||
|
||||
|
||||
def xpub_header(xtype):
|
||||
return bfh("%08x" % (XPUB_HEADER + xtype))
|
||||
return bfh("%08x" % XPUB_HEADERS[xtype])
|
||||
|
||||
|
||||
def serialize_xprv(xtype, c, k, depth=0, fingerprint=b'\x00'*4, child_number=b'\x00'*4):
|
||||
|
@ -841,10 +854,11 @@ def deserialize_xkey(xkey, prv):
|
|||
fingerprint = xkey[5:9]
|
||||
child_number = xkey[9:13]
|
||||
c = xkey[13:13+32]
|
||||
header = XPRV_HEADER if prv else XPUB_HEADER
|
||||
xtype = int('0x' + bh2u(xkey[0:4]), 16) - header
|
||||
if xtype not in [0, 1]:
|
||||
raise BaseException('Invalid header')
|
||||
header = int('0x' + bh2u(xkey[0:4]), 16)
|
||||
headers = XPRV_HEADERS if prv else XPUB_HEADERS
|
||||
if header not in headers.values():
|
||||
raise BaseException('Invalid xpub format', hex(header))
|
||||
xtype = list(headers.keys())[list(headers.values()).index(header)]
|
||||
n = 33 if prv else 32
|
||||
K_or_k = xkey[13+n:]
|
||||
return xtype, depth, fingerprint, child_number, c, K_or_k
|
||||
|
|
|
@ -76,8 +76,6 @@ class KeyStore(PrintError):
|
|||
return False
|
||||
return bool(self.get_tx_derivations(tx))
|
||||
|
||||
def is_segwit(self):
|
||||
return False
|
||||
|
||||
|
||||
class Software_KeyStore(KeyStore):
|
||||
|
@ -335,8 +333,6 @@ class BIP32_KeyStore(Deterministic_KeyStore, Xpub):
|
|||
pk = bip32_private_key(sequence, k, c)
|
||||
return pk
|
||||
|
||||
def is_segwit(self):
|
||||
return bool(deserialize_xpub(self.xpub)[0])
|
||||
|
||||
|
||||
class Old_KeyStore(Deterministic_KeyStore):
|
||||
|
@ -699,8 +695,7 @@ def from_seed(seed, passphrase):
|
|||
keystore.add_seed(seed)
|
||||
keystore.passphrase = passphrase
|
||||
bip32_seed = Mnemonic.mnemonic_to_seed(seed, passphrase)
|
||||
xtype = 0 if t == 'standard' else 1
|
||||
keystore.add_xprv_from_seed(bip32_seed, xtype, "m/")
|
||||
keystore.add_xprv_from_seed(bip32_seed, t, "m/")
|
||||
else:
|
||||
raise BaseException(t)
|
||||
return keystore
|
||||
|
|
|
@ -1544,8 +1544,15 @@ class Simple_Wallet(Abstract_Wallet):
|
|||
|
||||
def load_keystore(self):
|
||||
self.keystore = load_keystore(self.storage, 'keystore')
|
||||
self.is_segwit = self.keystore.is_segwit()
|
||||
self.txin_type = 'p2wpkh' if self.is_segwit else 'p2pkh'
|
||||
xtype = deserialize_xpub(self.keystore.xpub)[0]
|
||||
if xtype == 'standard':
|
||||
self.txin_type = 'p2pkh'
|
||||
elif xtype == 'segwit':
|
||||
self.txin_type = 'p2wpkh'
|
||||
elif xtype == 'segwit_p2sh':
|
||||
self.txin_type = 'p2wpkh-p2sh'
|
||||
else:
|
||||
raise BaseException('unknown txin_type', xtype)
|
||||
|
||||
def get_pubkey(self, c, i):
|
||||
return self.derive_pubkeys(c, i)
|
||||
|
@ -1640,7 +1647,6 @@ class Standard_Wallet(Simple_Deterministic_Wallet):
|
|||
wallet_type = 'standard'
|
||||
|
||||
def pubkeys_to_redeem_script(self, pubkey):
|
||||
if self.is_segwit:
|
||||
return transaction.segwit_script(pubkey)
|
||||
|
||||
def pubkeys_to_address(self, pubkey):
|
||||
|
@ -1652,7 +1658,7 @@ class Standard_Wallet(Simple_Deterministic_Wallet):
|
|||
redeem_script = self.pubkeys_to_redeem_script(pubkey)
|
||||
return bitcoin.hash160_to_p2sh(hash_160(bfh(redeem_script)))
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
raise NotImplementedError(self.txin_type)
|
||||
|
||||
|
||||
class Multisig_Wallet(Deterministic_Wallet):
|
||||
|
@ -1693,8 +1699,13 @@ class Multisig_Wallet(Deterministic_Wallet):
|
|||
name = 'x%d/'%(i+1)
|
||||
self.keystores[name] = load_keystore(self.storage, name)
|
||||
self.keystore = self.keystores['x1/']
|
||||
self.is_segwit = self.keystore.is_segwit()
|
||||
self.txin_type = 'p2wsh' if self.is_segwit else 'p2sh'
|
||||
xtype = deserialize_xpub(self.keystore.xpub)[0]
|
||||
if xtype == 'standard':
|
||||
self.txin_type = 'p2sh'
|
||||
elif xtype == 'segwit':
|
||||
self.txin_type = 'p2wsh'
|
||||
elif xtype == 'segwit_p2sh':
|
||||
self.txin_type = 'p2wsh-p2sh'
|
||||
|
||||
def save_keystore(self):
|
||||
for name, k in self.keystores.items():
|
||||
|
|
|
@ -59,6 +59,7 @@ class Ledger_Client():
|
|||
#self.get_client() # prompt for the PIN before displaying the dialog if necessary
|
||||
#self.handler.show_message("Computing master public key")
|
||||
try:
|
||||
xtype = 'segwit_p2sh' if bip32_path.startswith("m/49'/") else 'standard'
|
||||
splitPath = bip32_path.split('/')
|
||||
if splitPath[0] == 'm':
|
||||
splitPath = splitPath[1:]
|
||||
|
@ -75,11 +76,8 @@ class Ledger_Client():
|
|||
publicKey = compress_public_key(nodeData['publicKey'])
|
||||
depth = len(splitPath)
|
||||
lastChild = splitPath[len(splitPath) - 1].split('\'')
|
||||
if len(lastChild) == 1:
|
||||
childnum = int(lastChild[0])
|
||||
else:
|
||||
childnum = 0x80000000 | int(lastChild[0])
|
||||
xpub = bitcoin.serialize_xpub(0, nodeData['chainCode'], publicKey, depth, self.i4b(fingerprint), self.i4b(childnum))
|
||||
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))
|
||||
return xpub
|
||||
except Exception as e:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
|
@ -173,9 +171,6 @@ class Ledger_KeyStore(Hardware_KeyStore):
|
|||
self.signing = False
|
||||
self.cfg = d.get('cfg', {'mode':0,'pair':''})
|
||||
|
||||
def is_segwit(self):
|
||||
return self.derivation.startswith("m/49'/")
|
||||
|
||||
def dump(self):
|
||||
obj = Hardware_KeyStore.dump(self)
|
||||
obj['cfg'] = self.cfg
|
||||
|
|
|
@ -151,7 +151,8 @@ class TrezorClientBase(GuiMixin, PrintError):
|
|||
address_n = self.expand_path(bip32_path)
|
||||
creating = False #self.next_account_number() == 0
|
||||
node = self.get_public_node(address_n, creating).node
|
||||
return serialize_xpub(0, node.chain_code, node.public_key, node.depth, self.i4b(node.fingerprint), self.i4b(node.child_num))
|
||||
xtype = 'segwit_p2sh' if bip32_path.startswith("m/49'/") else 'standard'
|
||||
return serialize_xpub(xtype, node.chain_code, node.public_key, node.depth, self.i4b(node.fingerprint), self.i4b(node.child_num))
|
||||
|
||||
#def address_from_derivation(self, derivation):
|
||||
# return self.get_address('Bitcoin', self.expand_path(derivation))
|
||||
|
|
Loading…
Reference in New Issue