mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-09-03 20:35:13 +00:00
privkeys WIF: store in extended WIF internally; export as "txin_type:old_wif"
This commit is contained in:
parent
9110c0542c
commit
51c235a8be
5 changed files with 55 additions and 36 deletions
|
@ -2094,8 +2094,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
rds_e = ShowQRTextEdit(text=redeem_script)
|
rds_e = ShowQRTextEdit(text=redeem_script)
|
||||||
rds_e.addCopyButton(self.app)
|
rds_e.addCopyButton(self.app)
|
||||||
vbox.addWidget(rds_e)
|
vbox.addWidget(rds_e)
|
||||||
if xtype in ['p2wpkh', 'p2wsh', 'p2wpkh-p2sh', 'p2wsh-p2sh']:
|
|
||||||
vbox.addWidget(WWLabel(_("Warning: the format of private keys associated to segwit addresses may not be compatible with other wallets")))
|
|
||||||
vbox.addLayout(Buttons(CloseButton(d)))
|
vbox.addLayout(Buttons(CloseButton(d)))
|
||||||
d.setLayout(vbox)
|
d.setLayout(vbox)
|
||||||
d.exec_()
|
d.exec_()
|
||||||
|
@ -2334,7 +2332,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
_('It can not be "backed up" by simply exporting these private keys.'))
|
_('It can not be "backed up" by simply exporting these private keys.'))
|
||||||
|
|
||||||
d = WindowModalDialog(self, _('Private keys'))
|
d = WindowModalDialog(self, _('Private keys'))
|
||||||
d.setMinimumSize(850, 300)
|
d.setMinimumSize(980, 300)
|
||||||
vbox = QVBoxLayout(d)
|
vbox = QVBoxLayout(d)
|
||||||
|
|
||||||
msg = "%s\n%s\n%s" % (_("WARNING: ALL your private keys are secret."),
|
msg = "%s\n%s\n%s" % (_("WARNING: ALL your private keys are secret."),
|
||||||
|
|
|
@ -254,7 +254,7 @@ def line_dialog(parent, title, label, ok_label, default=None):
|
||||||
def text_dialog(parent, title, label, ok_label, default=None, allow_multi=False):
|
def text_dialog(parent, title, label, ok_label, default=None, allow_multi=False):
|
||||||
from .qrtextedit import ScanQRTextEdit
|
from .qrtextedit import ScanQRTextEdit
|
||||||
dialog = WindowModalDialog(parent, title)
|
dialog = WindowModalDialog(parent, title)
|
||||||
dialog.setMinimumWidth(500)
|
dialog.setMinimumWidth(600)
|
||||||
l = QVBoxLayout()
|
l = QVBoxLayout()
|
||||||
dialog.setLayout(l)
|
dialog.setLayout(l)
|
||||||
l.addWidget(QLabel(label))
|
l.addWidget(QLabel(label))
|
||||||
|
|
|
@ -508,9 +508,8 @@ def DecodeBase58Check(psz):
|
||||||
return key
|
return key
|
||||||
|
|
||||||
|
|
||||||
|
# backwards compat
|
||||||
# extended key export format for segwit
|
# extended WIF for segwit (used in 3.0.x; but still used internally)
|
||||||
|
|
||||||
SCRIPT_TYPES = {
|
SCRIPT_TYPES = {
|
||||||
'p2pkh':0,
|
'p2pkh':0,
|
||||||
'p2wpkh':1,
|
'p2wpkh':1,
|
||||||
|
@ -521,26 +520,43 @@ SCRIPT_TYPES = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def serialize_privkey(secret, compressed, txin_type):
|
def serialize_privkey(secret, compressed, txin_type, internal_use=False):
|
||||||
prefix = bytes([(SCRIPT_TYPES[txin_type]+NetworkConstants.WIF_PREFIX)&255])
|
if internal_use:
|
||||||
|
prefix = bytes([(SCRIPT_TYPES[txin_type] + NetworkConstants.WIF_PREFIX) & 255])
|
||||||
|
else:
|
||||||
|
prefix = bytes([NetworkConstants.WIF_PREFIX])
|
||||||
suffix = b'\01' if compressed else b''
|
suffix = b'\01' if compressed else b''
|
||||||
vchIn = prefix + secret + suffix
|
vchIn = prefix + secret + suffix
|
||||||
return EncodeBase58Check(vchIn)
|
base58_wif = EncodeBase58Check(vchIn)
|
||||||
|
if internal_use:
|
||||||
|
return base58_wif
|
||||||
|
else:
|
||||||
|
return '{}:{}'.format(txin_type, base58_wif)
|
||||||
|
|
||||||
|
|
||||||
def deserialize_privkey(key):
|
def deserialize_privkey(key):
|
||||||
# whether the pubkey is compressed should be visible from the keystore
|
|
||||||
vch = DecodeBase58Check(key)
|
|
||||||
if is_minikey(key):
|
if is_minikey(key):
|
||||||
return 'p2pkh', minikey_to_private_key(key), True
|
return 'p2pkh', minikey_to_private_key(key), True
|
||||||
elif vch:
|
|
||||||
txin_type = inv_dict(SCRIPT_TYPES)[vch[0] - NetworkConstants.WIF_PREFIX]
|
txin_type = None
|
||||||
assert len(vch) in [33, 34]
|
if ':' in key:
|
||||||
compressed = len(vch) == 34
|
txin_type, key = key.split(sep=':', maxsplit=1)
|
||||||
return txin_type, vch[1:33], compressed
|
assert txin_type in SCRIPT_TYPES
|
||||||
else:
|
vch = DecodeBase58Check(key)
|
||||||
|
if not vch:
|
||||||
raise BaseException("cannot deserialize", key)
|
raise BaseException("cannot deserialize", key)
|
||||||
|
|
||||||
|
if txin_type is None:
|
||||||
|
# keys exported in version 3.0.x encoded script type in first byte
|
||||||
|
txin_type = inv_dict(SCRIPT_TYPES)[vch[0] - NetworkConstants.WIF_PREFIX]
|
||||||
|
else:
|
||||||
|
assert vch[0] == NetworkConstants.WIF_PREFIX
|
||||||
|
|
||||||
|
assert len(vch) in [33, 34]
|
||||||
|
compressed = len(vch) == 34
|
||||||
|
return txin_type, vch[1:33], compressed
|
||||||
|
|
||||||
|
|
||||||
def regenerate_key(pk):
|
def regenerate_key(pk):
|
||||||
assert len(pk) == 32
|
assert len(pk) == 32
|
||||||
return EC_KEY(pk)
|
return EC_KEY(pk)
|
||||||
|
|
|
@ -139,7 +139,10 @@ class Imported_KeyStore(Software_KeyStore):
|
||||||
def import_privkey(self, sec, password):
|
def import_privkey(self, sec, password):
|
||||||
txin_type, privkey, compressed = deserialize_privkey(sec)
|
txin_type, privkey, compressed = deserialize_privkey(sec)
|
||||||
pubkey = public_key_from_private_key(privkey, compressed)
|
pubkey = public_key_from_private_key(privkey, compressed)
|
||||||
self.keypairs[pubkey] = pw_encode(sec, password)
|
# re-serialize the key so the internal storage format is consistent
|
||||||
|
serialized_privkey = serialize_privkey(
|
||||||
|
privkey, compressed, txin_type, internal_use=True)
|
||||||
|
self.keypairs[pubkey] = pw_encode(serialized_privkey, password)
|
||||||
return txin_type, pubkey
|
return txin_type, pubkey
|
||||||
|
|
||||||
def delete_imported_key(self, key):
|
def delete_imported_key(self, key):
|
||||||
|
|
|
@ -388,23 +388,21 @@ class Abstract_Wallet(PrintError):
|
||||||
def get_address_index(self, address):
|
def get_address_index(self, address):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def get_redeem_script(self, address):
|
||||||
|
return None
|
||||||
|
|
||||||
def export_private_key(self, address, password):
|
def export_private_key(self, address, password):
|
||||||
""" extended WIF format """
|
|
||||||
if self.is_watching_only():
|
if self.is_watching_only():
|
||||||
return []
|
return []
|
||||||
index = self.get_address_index(address)
|
index = self.get_address_index(address)
|
||||||
pk, compressed = self.keystore.get_private_key(index, password)
|
pk, compressed = self.keystore.get_private_key(index, password)
|
||||||
if self.txin_type in ['p2sh', 'p2wsh', 'p2wsh-p2sh']:
|
txin_type = self.get_txin_type(address)
|
||||||
pubkeys = self.get_public_keys(address)
|
redeem_script = self.get_redeem_script(address)
|
||||||
redeem_script = self.pubkeys_to_redeem_script(pubkeys)
|
serialized_privkey = bitcoin.serialize_privkey(pk, compressed, txin_type)
|
||||||
else:
|
return serialized_privkey, redeem_script
|
||||||
redeem_script = None
|
|
||||||
return bitcoin.serialize_privkey(pk, compressed, self.txin_type), redeem_script
|
|
||||||
|
|
||||||
|
|
||||||
def get_public_keys(self, address):
|
def get_public_keys(self, address):
|
||||||
sequence = self.get_address_index(address)
|
return [self.get_public_key(address)]
|
||||||
return self.get_pubkeys(*sequence)
|
|
||||||
|
|
||||||
def add_unverified_tx(self, tx_hash, tx_height):
|
def add_unverified_tx(self, tx_hash, tx_height):
|
||||||
if tx_height in (TX_HEIGHT_UNCONFIRMED, TX_HEIGHT_UNCONF_PARENT) \
|
if tx_height in (TX_HEIGHT_UNCONFIRMED, TX_HEIGHT_UNCONF_PARENT) \
|
||||||
|
@ -1896,12 +1894,10 @@ class Imported_Wallet(Simple_Wallet):
|
||||||
self.add_address(addr)
|
self.add_address(addr)
|
||||||
return addr
|
return addr
|
||||||
|
|
||||||
def export_private_key(self, address, password):
|
def get_redeem_script(self, address):
|
||||||
d = self.addresses[address]
|
d = self.addresses[address]
|
||||||
pubkey = d['pubkey']
|
|
||||||
redeem_script = d['redeem_script']
|
redeem_script = d['redeem_script']
|
||||||
sec = pw_decode(self.keystore.keypairs[pubkey], password)
|
return redeem_script
|
||||||
return sec, redeem_script
|
|
||||||
|
|
||||||
def get_txin_type(self, address):
|
def get_txin_type(self, address):
|
||||||
return self.addresses[address].get('type', 'address')
|
return self.addresses[address].get('type', 'address')
|
||||||
|
@ -2079,9 +2075,6 @@ class Simple_Deterministic_Wallet(Simple_Wallet, Deterministic_Wallet):
|
||||||
def get_pubkey(self, c, i):
|
def get_pubkey(self, c, i):
|
||||||
return self.derive_pubkeys(c, i)
|
return self.derive_pubkeys(c, i)
|
||||||
|
|
||||||
def get_public_keys(self, address):
|
|
||||||
return [self.get_public_key(address)]
|
|
||||||
|
|
||||||
def add_input_sig_info(self, txin, address):
|
def add_input_sig_info(self, txin, address):
|
||||||
derivation = self.get_address_index(address)
|
derivation = self.get_address_index(address)
|
||||||
x_pubkey = self.keystore.get_xpubkey(*derivation)
|
x_pubkey = self.keystore.get_xpubkey(*derivation)
|
||||||
|
@ -2119,6 +2112,10 @@ class Multisig_Wallet(Deterministic_Wallet):
|
||||||
def get_pubkeys(self, c, i):
|
def get_pubkeys(self, c, i):
|
||||||
return self.derive_pubkeys(c, i)
|
return self.derive_pubkeys(c, i)
|
||||||
|
|
||||||
|
def get_public_keys(self, address):
|
||||||
|
sequence = self.get_address_index(address)
|
||||||
|
return self.get_pubkeys(*sequence)
|
||||||
|
|
||||||
def pubkeys_to_address(self, pubkeys):
|
def pubkeys_to_address(self, pubkeys):
|
||||||
redeem_script = self.pubkeys_to_redeem_script(pubkeys)
|
redeem_script = self.pubkeys_to_redeem_script(pubkeys)
|
||||||
return bitcoin.redeem_script_to_address(self.txin_type, redeem_script)
|
return bitcoin.redeem_script_to_address(self.txin_type, redeem_script)
|
||||||
|
@ -2126,6 +2123,11 @@ class Multisig_Wallet(Deterministic_Wallet):
|
||||||
def pubkeys_to_redeem_script(self, pubkeys):
|
def pubkeys_to_redeem_script(self, pubkeys):
|
||||||
return transaction.multisig_script(sorted(pubkeys), self.m)
|
return transaction.multisig_script(sorted(pubkeys), self.m)
|
||||||
|
|
||||||
|
def get_redeem_script(self, address):
|
||||||
|
pubkeys = self.get_public_keys(address)
|
||||||
|
redeem_script = self.pubkeys_to_redeem_script(pubkeys)
|
||||||
|
return redeem_script
|
||||||
|
|
||||||
def derive_pubkeys(self, c, i):
|
def derive_pubkeys(self, c, i):
|
||||||
return [k.derive_pubkey(c, i) for k in self.get_keystores()]
|
return [k.derive_pubkey(c, i) for k in self.get_keystores()]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue