abstract and improve seed and key methods
This commit is contained in:
parent
41f9da1559
commit
5d9b9492e1
11
electrum
11
electrum
|
@ -273,15 +273,16 @@ if __name__ == '__main__':
|
|||
else:
|
||||
if not config.get('2of3'):
|
||||
wallet = Wallet(storage)
|
||||
wallet.init_seed(None)
|
||||
wallet.save_seed(password)
|
||||
seed = wallet.make_seed()
|
||||
wallet.save_seed(seed, password)
|
||||
wallet.create_accounts(password)
|
||||
wallet.synchronize()
|
||||
print_msg("Your wallet generation seed is:\n\"%s\"" % wallet.get_mnemonic(password))
|
||||
print_msg("Your wallet generation seed is:\n\"%s\"" % seed)
|
||||
print_msg("Please keep it in a safe place; if you lose it, you will not be able to restore your wallet.")
|
||||
else:
|
||||
wallet = Wallet_2of3(storage)
|
||||
cold_seed = wallet.init_cold_seed()
|
||||
wallet.save_cold_seed()
|
||||
cold_seed = wallet.make_seed()
|
||||
#wallet.save_seed()
|
||||
print_msg("Your cold seed is:\n\"%s\"" % cold_seed)
|
||||
print_msg("Please store it on paper. ")
|
||||
print_msg("Open this file on your online computer to complete your wallet creation.")
|
||||
|
|
|
@ -219,12 +219,12 @@ class InstallWizard(QDialog):
|
|||
return self.exec_()
|
||||
|
||||
|
||||
def password_dialog(self, wallet):
|
||||
def password_dialog(self):
|
||||
msg = _("Please choose a password to encrypt your wallet keys.")+'\n'\
|
||||
+_("Leave these fields empty if you want to disable encryption.")
|
||||
from password_dialog import make_password_dialog, run_password_dialog
|
||||
self.set_layout( make_password_dialog(self, wallet, msg) )
|
||||
return run_password_dialog(self, wallet, self)
|
||||
self.set_layout( make_password_dialog(self, None, msg) )
|
||||
return run_password_dialog(self, None, self)[2]
|
||||
|
||||
|
||||
def choose_wallet_type(self):
|
||||
|
@ -285,16 +285,14 @@ class InstallWizard(QDialog):
|
|||
if action in ['create', 'create2of3']:
|
||||
|
||||
wallet = Wallet(self.storage)
|
||||
|
||||
wallet.init_seed(None)
|
||||
seed = wallet.get_mnemonic(None)
|
||||
seed = wallet.make_seed()
|
||||
sid = 'hot' if action == 'create2of3' else None
|
||||
if not self.show_seed(seed, sid):
|
||||
return
|
||||
if not self.verify_seed(seed, sid):
|
||||
return
|
||||
ok, old_password, password = self.password_dialog(wallet)
|
||||
wallet.save_seed(password)
|
||||
password = self.password_dialog()
|
||||
wallet.save_seed(seed, password)
|
||||
|
||||
if action == 'create2of3':
|
||||
run_hook('create_third_key', wallet, self)
|
||||
|
@ -306,8 +304,6 @@ class InstallWizard(QDialog):
|
|||
self.waiting_dialog(wallet.synchronize)
|
||||
|
||||
elif action == 'restore':
|
||||
# dialog box will accept either seed or xpub.
|
||||
# use two boxes for 2of3
|
||||
t = self.choose_wallet_type()
|
||||
if not t:
|
||||
return
|
||||
|
@ -315,9 +311,9 @@ class InstallWizard(QDialog):
|
|||
if t == 'standard':
|
||||
text = self.enter_seed_dialog(True, None)
|
||||
if Wallet.is_seed(text):
|
||||
password = self.password_dialog()
|
||||
wallet = Wallet.from_seed(text, self.storage)
|
||||
ok, old_password, password = self.password_dialog(wallet)
|
||||
wallet.save_seed(password)
|
||||
wallet.save_seed(text, password)
|
||||
wallet.create_accounts(password)
|
||||
elif Wallet.is_mpk(text):
|
||||
wallet = Wallet.from_mpk(text, self.storage)
|
||||
|
@ -329,19 +325,18 @@ class InstallWizard(QDialog):
|
|||
if not r:
|
||||
return
|
||||
text1, text2 = r
|
||||
password = self.password_dialog()
|
||||
wallet = Wallet_2of3(self.storage)
|
||||
|
||||
if Wallet.is_seed(text1):
|
||||
xpriv, xpub = bip32_root(text1)
|
||||
wallet.add_root("m/", text1, password)
|
||||
elif Wallet.is_mpk(text1):
|
||||
xpub = text1
|
||||
wallet.add_master_public_key("m/", xpub)
|
||||
|
||||
wallet.add_master_public_key("m/", text1)
|
||||
|
||||
if Wallet.is_seed(text2):
|
||||
xpriv2, xpub2 = bip32_root(text2)
|
||||
wallet.add_root("cold/", text2, password)
|
||||
elif Wallet.is_mpk(text2):
|
||||
xpub2 = text2
|
||||
wallet.add_master_public_key("cold/", xpub2)
|
||||
wallet.add_master_public_key("cold/", text2)
|
||||
|
||||
run_hook('restore_third_key', wallet, self)
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ def make_password_dialog(self, wallet, msg):
|
|||
grid.setColumnStretch(1,1)
|
||||
|
||||
logo = QLabel()
|
||||
lockfile = ":icons/lock.png" if wallet.use_encryption else ":icons/unlock.png"
|
||||
lockfile = ":icons/lock.png" if wallet and wallet.use_encryption else ":icons/unlock.png"
|
||||
logo.setPixmap(QPixmap(lockfile).scaledToWidth(36))
|
||||
logo.setAlignment(Qt.AlignCenter)
|
||||
|
||||
|
@ -55,7 +55,7 @@ def make_password_dialog(self, wallet, msg):
|
|||
grid.setColumnMinimumWidth(0, 250)
|
||||
grid.setColumnStretch(1,1)
|
||||
|
||||
if wallet.use_encryption:
|
||||
if wallet and wallet.use_encryption:
|
||||
grid.addWidget(QLabel(_('Password')), 0, 0)
|
||||
grid.addWidget(self.pw, 0, 1)
|
||||
|
||||
|
@ -73,14 +73,14 @@ def make_password_dialog(self, wallet, msg):
|
|||
|
||||
def run_password_dialog(self, wallet, parent):
|
||||
|
||||
if not wallet.seed:
|
||||
if wallet and not wallet.seed:
|
||||
QMessageBox.information(parent, _('Error'), _('No seed'), _('OK'))
|
||||
return False, None, None
|
||||
|
||||
if not self.exec_():
|
||||
return False, None, None
|
||||
|
||||
password = unicode(self.pw.text()) if wallet.use_encryption else None
|
||||
password = unicode(self.pw.text()) if wallet and wallet.use_encryption else None
|
||||
new_password = unicode(self.new_pw.text())
|
||||
new_password2 = unicode(self.conf_pw.text())
|
||||
|
||||
|
|
173
lib/wallet.py
173
lib/wallet.py
|
@ -295,27 +295,22 @@ class NewWallet:
|
|||
return seed
|
||||
|
||||
|
||||
def init_seed(self, seed):
|
||||
import mnemonic, unicodedata
|
||||
|
||||
def prepare_seed(self, seed):
|
||||
import unicodedata
|
||||
return NEW_SEED_VERSION, unicodedata.normalize('NFC', unicode(seed.strip()))
|
||||
|
||||
|
||||
def save_seed(self, seed, password):
|
||||
if self.seed:
|
||||
raise Exception("a seed exists")
|
||||
|
||||
self.seed_version = NEW_SEED_VERSION
|
||||
|
||||
if not seed:
|
||||
self.seed = self.make_seed()
|
||||
return
|
||||
|
||||
self.seed = unicodedata.normalize('NFC', unicode(seed.strip()))
|
||||
|
||||
|
||||
|
||||
|
||||
def save_seed(self, password):
|
||||
|
||||
self.seed_version, self.seed = self.prepare_seed(seed)
|
||||
if password:
|
||||
self.seed = pw_encode( self.seed, password)
|
||||
self.use_encryption = True
|
||||
else:
|
||||
self.use_encryption = False
|
||||
|
||||
self.storage.put('seed', self.seed, True)
|
||||
self.storage.put('seed_version', self.seed_version, True)
|
||||
self.storage.put('use_encryption', self.use_encryption,True)
|
||||
|
@ -323,11 +318,11 @@ class NewWallet:
|
|||
|
||||
|
||||
def create_watching_only_wallet(self, xpub):
|
||||
self.master_public_keys = { "m/": xpub }
|
||||
self.storage.put('master_public_keys', self.master_public_keys, True)
|
||||
self.storage.put('seed_version', self.seed_version, True)
|
||||
account = BIP32_Account({'xpub':xpub})
|
||||
self.add_account("m/", account)
|
||||
self.add_master_public_key("m/", xpub)
|
||||
xpub0 = self.add_master_keys("m/", "m/0'", None)
|
||||
account = BIP32_Account({'xpub':xpub0})
|
||||
self.add_account("m/0'", account)
|
||||
|
||||
|
||||
def create_accounts(self, password):
|
||||
|
@ -340,11 +335,37 @@ class NewWallet:
|
|||
self.storage.put('master_public_keys', self.master_public_keys, True)
|
||||
|
||||
|
||||
def add_master_private_key(self, name, xpriv, password):
|
||||
self.master_private_keys[name] = pw_encode(xpriv, password)
|
||||
self.storage.put('master_private_keys', self.master_private_keys, True)
|
||||
|
||||
|
||||
def add_master_keys(self, root, account_id, password):
|
||||
x = self.master_private_keys.get(root)
|
||||
if x:
|
||||
master_xpriv = pw_decode(x, password )
|
||||
xpriv, xpub = bip32_private_derivation(master_xpriv, root, account_id)
|
||||
self.add_master_public_key(account_id, xpub)
|
||||
self.add_master_private_key(account_id, xpriv, password)
|
||||
else:
|
||||
master_xpub = self.master_public_keys[root]
|
||||
xpub = bip32_public_derivation(master_xpub, root, account_id)
|
||||
self.add_master_public_key(account_id, xpub)
|
||||
return xpub
|
||||
|
||||
|
||||
def add_root(self, name, mnemonic, password, add_private = True):
|
||||
seed = mnemonic_to_seed(mnemonic,'').encode('hex')
|
||||
xpriv, xpub = bip32_root(seed)
|
||||
self.add_master_public_key(name, xpub)
|
||||
if add_private:
|
||||
self.add_master_private_key(name, xpriv, password)
|
||||
|
||||
|
||||
def create_master_keys(self, password):
|
||||
xpriv, xpub = bip32_root(self.get_seed(password))
|
||||
self.add_master_public_key("m/", xpub)
|
||||
self.master_private_keys["m/"] = pw_encode(xpriv, password)
|
||||
self.storage.put('master_private_keys', self.master_private_keys, True)
|
||||
self.add_master_private_key("m/", xpriv, password)
|
||||
|
||||
|
||||
def find_root_by_master_key(self, xpub):
|
||||
|
@ -357,19 +378,19 @@ class NewWallet:
|
|||
return (self.seed == '') and (self.master_private_keys == {})
|
||||
|
||||
|
||||
def num_accounts(self, account_type = '1of1'):
|
||||
def num_accounts(self):
|
||||
keys = self.accounts.keys()
|
||||
i = 0
|
||||
while True:
|
||||
account_id = self.account_id(account_type, i)
|
||||
account_id = self.account_id(i)
|
||||
if account_id not in keys: break
|
||||
i += 1
|
||||
return i
|
||||
|
||||
|
||||
def next_account_address(self, account_type, password):
|
||||
i = self.num_accounts(account_type)
|
||||
account_id = self.account_id(account_type, i)
|
||||
def next_account_address(self, password):
|
||||
i = self.num_accounts()
|
||||
account_id = self.account_id(i)
|
||||
|
||||
addr = self.next_addresses.get(account_id)
|
||||
if not addr:
|
||||
|
@ -380,20 +401,12 @@ class NewWallet:
|
|||
|
||||
return account_id, addr
|
||||
|
||||
def account_id(self, account_type, i):
|
||||
if account_type == '1of1':
|
||||
return "m/%d'"%i
|
||||
else:
|
||||
raise
|
||||
def account_id(self, i):
|
||||
return "m/%d'"%i
|
||||
|
||||
def make_account(self, account_id, password):
|
||||
"""Creates and saves the master keys, but does not save the account"""
|
||||
master_xpriv = pw_decode( self.master_private_keys["m/"] , password )
|
||||
xpriv, xpub = bip32_private_derivation(master_xpriv, "m/", account_id)
|
||||
self.master_private_keys[account_id] = pw_encode(xpriv, password)
|
||||
self.master_public_keys[account_id] = xpub
|
||||
self.storage.put('master_public_keys', self.master_public_keys, True)
|
||||
self.storage.put('master_private_keys', self.master_private_keys, True)
|
||||
xpub = self.add_master_keys("m/", account_id, password)
|
||||
account = BIP32_Account({'xpub':xpub})
|
||||
return account
|
||||
|
||||
|
@ -418,15 +431,15 @@ class NewWallet:
|
|||
|
||||
|
||||
def create_account(self, name, password):
|
||||
i = self.num_accounts('1of1')
|
||||
account_id = self.account_id('1of1', i)
|
||||
i = self.num_accounts()
|
||||
account_id = self.account_id(i)
|
||||
account = self.make_account(account_id, password)
|
||||
self.add_account(account_id, account)
|
||||
if name:
|
||||
self.set_label(account_id, name)
|
||||
|
||||
# add address of the next account
|
||||
_, _ = self.next_account_address('1of1', password)
|
||||
_, _ = self.next_account_address(password)
|
||||
|
||||
|
||||
def add_account(self, account_id, account):
|
||||
|
@ -471,8 +484,8 @@ class NewWallet:
|
|||
def account_is_pending(self, k):
|
||||
return k in self.pending_accounts
|
||||
|
||||
def create_pending_account(self, acct_type, name, password):
|
||||
account_id, addr = self.next_account_address(acct_type, password)
|
||||
def create_pending_account(self, name, password):
|
||||
account_id, addr = self.next_account_address(password)
|
||||
self.set_label(account_id, name)
|
||||
self.pending_accounts[account_id] = addr
|
||||
self.storage.put('pending_accounts', self.pending_accounts)
|
||||
|
@ -1472,32 +1485,16 @@ class Wallet_2of2(NewWallet):
|
|||
NewWallet.__init__(self, storage)
|
||||
self.storage.put('wallet_type', '2of2', True)
|
||||
|
||||
def init_cold_seed(self):
|
||||
cold_seed = self.make_seed()
|
||||
seed = mnemonic_to_seed(cold_seed,'').encode('hex')
|
||||
xpriv, xpub = bip32_root(seed)
|
||||
self.master_public_keys["cold/"] = xpub
|
||||
return cold_seed
|
||||
|
||||
def save_cold_seed(self):
|
||||
self.storage.put('master_public_keys', self.master_public_keys, True)
|
||||
|
||||
|
||||
def make_account(self, account_id, password):
|
||||
# if accounts are hardened, we cannot make it symmetric on the other wallet
|
||||
|
||||
"""Creates and saves the master keys, but does not save the account"""
|
||||
master_xpriv = pw_decode( self.master_private_keys["m/"] , password )
|
||||
xpriv, xpub = bip32_private_derivation(master_xpriv, "m/", account_id)
|
||||
self.master_private_keys[account_id] = pw_encode(xpriv, password)
|
||||
self.master_public_keys[account_id] = xpub
|
||||
self.storage.put('master_public_keys', self.master_public_keys, True)
|
||||
self.storage.put('master_private_keys', self.master_private_keys, True)
|
||||
|
||||
xpub_cold = self.master_public_keys["cold/"]
|
||||
account = BIP32_Account_2of2({'xpub':xpub, 'xpub2':xpub_cold})
|
||||
xpub1 = self.add_master_keys("m/", account_id, password)
|
||||
xpub2 = self.add_master_keys("cold/", account_id, password)
|
||||
account = BIP32_Account_2of2({'xpub':xpub1, 'xpub2':xpub2})
|
||||
return account
|
||||
|
||||
def account_id(self, i):
|
||||
return "m/%d"%i
|
||||
|
||||
class Wallet_2of3(Wallet_2of2):
|
||||
|
||||
|
@ -1506,21 +1503,14 @@ class Wallet_2of3(Wallet_2of2):
|
|||
self.storage.put('wallet_type', '2of3', True)
|
||||
|
||||
def make_account(self, account_id, password):
|
||||
# if accounts are hardened, we cannot make it symmetric on the other wallet
|
||||
|
||||
"""Creates and saves the master keys, but does not save the account"""
|
||||
master_xpriv = pw_decode( self.master_private_keys["m/"] , password )
|
||||
xpriv, xpub = bip32_private_derivation(master_xpriv, "m/", account_id)
|
||||
self.master_private_keys[account_id] = pw_encode(xpriv, password)
|
||||
self.master_public_keys[account_id] = xpub
|
||||
self.storage.put('master_public_keys', self.master_public_keys, True)
|
||||
self.storage.put('master_private_keys', self.master_private_keys, True)
|
||||
|
||||
xpub_cold = self.master_public_keys["cold/"]
|
||||
xpub_remote = self.master_public_keys["remote/"]
|
||||
account = BIP32_Account_2of3({'xpub':xpub, 'xpub2':xpub_cold, 'xpub3':xpub_remote})
|
||||
xpub1 = self.add_master_keys("m/", account_id, password)
|
||||
xpub2 = self.add_master_keys("cold/", account_id.replace("m/","cold/"), password)
|
||||
xpub3 = self.add_master_keys("remote/", account_id.replace("m/","remote/"), password)
|
||||
account = BIP32_Account_2of3({'xpub':xpub1, 'xpub2':xpub2, 'xpub3':xpub3})
|
||||
return account
|
||||
|
||||
def account_id(self, i):
|
||||
return "m/%d"%i
|
||||
|
||||
|
||||
|
||||
|
@ -1699,38 +1689,30 @@ class WalletSynchronizer(threading.Thread):
|
|||
|
||||
class OldWallet(NewWallet):
|
||||
|
||||
def init_seed(self, seed):
|
||||
def make_seed(self):
|
||||
import mnemonic
|
||||
|
||||
if self.seed:
|
||||
raise Exception("a seed exists")
|
||||
seed = random_seed(128)
|
||||
return ' '.join(mnemonic.mn_encode(seed))
|
||||
|
||||
if not seed:
|
||||
seed = random_seed(128)
|
||||
|
||||
self.seed_version = OLD_SEED_VERSION
|
||||
|
||||
def prepare_seed(self, seed):
|
||||
import mnemonic
|
||||
# see if seed was entered as hex
|
||||
seed = seed.strip()
|
||||
try:
|
||||
assert seed
|
||||
seed.decode('hex')
|
||||
self.seed = str(seed)
|
||||
return
|
||||
return OLD_SEED_VERSION, str(seed)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
words = seed.split()
|
||||
try:
|
||||
mnemonic.mn_decode(words)
|
||||
except Exception:
|
||||
raise
|
||||
|
||||
self.seed = mnemonic.mn_decode(words)
|
||||
|
||||
if not self.seed:
|
||||
seed = mnemonic.mn_decode(words)
|
||||
if not seed:
|
||||
raise Exception("Invalid seed")
|
||||
|
||||
return OLD_SEED_VERSION, seed
|
||||
|
||||
|
||||
def create_master_keys(self, password):
|
||||
seed = pw_decode(self.seed, password)
|
||||
|
@ -1886,7 +1868,6 @@ class Wallet(object):
|
|||
elif is_new_seed(seed):
|
||||
klass = NewWallet
|
||||
w = klass(storage)
|
||||
w.init_seed(seed)
|
||||
return w
|
||||
|
||||
@classmethod
|
||||
|
|
Loading…
Reference in New Issue