This commit is contained in:
ThomasV 2013-10-26 11:54:11 +02:00
parent 07bdd6c494
commit 31aaae8ed2
11 changed files with 111 additions and 57 deletions

View File

@ -262,7 +262,7 @@ if __name__ == '__main__':
exit(1)
# check password
try:
seed = wallet.decode_seed(password)
seed = wallet.get_seed(password)
except:
print_msg("Error: This password does not decode this wallet.")
exit(1)

View File

@ -717,7 +717,7 @@ def show_seed():
password = None
try:
seed = wallet.decode_seed(password)
seed = wallet.get_seed(password)
except:
modal_dialog('error','incorrect password')
return
@ -733,7 +733,7 @@ def change_password_dialog():
password = None
try:
seed = wallet.decode_seed(password)
wallet.get_seed(password)
except:
modal_dialog('error','incorrect password')
return
@ -748,7 +748,7 @@ def change_password_dialog():
modal_dialog('error','passwords do not match')
return
wallet.update_password(seed, password, new_password)
wallet.update_password(password, new_password)
if new_password:
modal_dialog('Password updated','your wallet is encrypted')
else:

View File

@ -69,7 +69,7 @@ def show_seed_dialog(wallet, password, parent):
show_message("No seed")
return
try:
seed = wallet.decode_seed(password)
seed = wallet.get_seed(password)
except:
show_message("Incorrect password")
return
@ -435,7 +435,7 @@ def change_password_dialog(wallet, parent, icon):
return
try:
seed = wallet.decode_seed(password)
wallet.get_seed(password)
except:
show_message("Incorrect password")
return
@ -444,7 +444,7 @@ def change_password_dialog(wallet, parent, icon):
show_message("passwords do not match")
return
wallet.update_password(seed, password, new_password)
wallet.update_password(password, new_password)
if icon:
if wallet.use_encryption:

View File

@ -89,10 +89,9 @@ class InstallWizard(QDialog):
vbox = QVBoxLayout(self)
if is_restore:
msg = _("Please enter your wallet seed.") + "\n"
msg += _("Your seed can be entered as a sequence of words, or as a hexadecimal string.")+ ' \n'
else:
msg = _("Your seed is important!") \
+ "\n" + _("To make sure that you have properly saved your seed, please retype it here.") + ' '
+ "\n" + _("To make sure that you have properly saved your seed, please retype it here.")
logo = QLabel()
logo.setPixmap(QPixmap(":icons/seed.png").scaledToWidth(56))
@ -119,15 +118,7 @@ class InstallWizard(QDialog):
if not self.exec_():
return
try:
seed = str(seed_e.toPlainText())
seed.decode('hex')
except:
try:
seed = mnemonic.mn_decode( seed.split() )
except:
QMessageBox.warning(None, _('Error'), _('I cannot decode this'), _('OK'))
return
seed = unicode(seed_e.toPlainText())
if not seed:
QMessageBox.warning(None, _('Error'), _('No seed'), _('OK'))
@ -288,7 +279,12 @@ class InstallWizard(QDialog):
seed = self.seed_dialog()
if not seed:
return
wallet.init_seed(str(seed))
try:
wallet.init_seed(seed)
except:
QMessageBox.warning(None, _('Error'), _('Incorrect seed'), _('OK'))
return
wallet.save_seed()
elif action == 'watching':

View File

@ -1544,12 +1544,12 @@ class ElectrumWindow(QMainWindow):
if self.wallet.seed:
try:
seed = self.wallet.decode_seed(password)
mnemonic = self.wallet.get_mnemonic(password)
except:
QMessageBox.warning(self, _('Error'), _('Incorrect Password'), _('OK'))
return
from seed_dialog import SeedDialog
d = SeedDialog(self, seed, self.wallet.imported_keys)
d = SeedDialog(self, mnemonic, self.wallet.imported_keys)
d.exec_()
else:
l = {}

View File

@ -84,7 +84,7 @@ def run_password_dialog(self, wallet, parent):
new_password2 = unicode(self.conf_pw.text())
try:
seed = wallet.decode_seed(password)
wallet.get_seed(password)
except:
QMessageBox.warning(parent, _('Error'), _('Incorrect Password'), _('OK'))
return
@ -96,7 +96,7 @@ def run_password_dialog(self, wallet, parent):
return
try:
wallet.update_password(seed, password, new_password)
wallet.update_password(password, new_password)
except:
QMessageBox.warning(parent, _('Error'), _('Failed to update password'), _('OK'))
return

View File

@ -57,12 +57,11 @@ class PrivateKeysDialog(QDialog):
def make_seed_dialog(seed, imported_keys):
words = mnemonic.mn_encode(seed)
brainwallet = ' '.join(words)
words = seed.split()
label1 = QLabel(_("Your wallet generation seed is")+ ":")
seed_text = QTextEdit(brainwallet)
seed_text = QTextEdit(seed)
seed_text.setReadOnly(True)
seed_text.setMaximumHeight(130)

View File

@ -19,6 +19,7 @@
import hashlib, base64, ecdsa, re
import hmac
from util import print_error
def rev_hex(s):
@ -56,6 +57,8 @@ Hash = lambda x: hashlib.sha256(hashlib.sha256(x).digest()).digest()
hash_encode = lambda x: x[::-1].encode('hex')
hash_decode = lambda x: x.decode('hex')[::-1]
hmac_sha_512 = lambda x,y: hmac.new(x, y, hashlib.sha512).digest()
mnemonic_hash = lambda x: hmac_sha_512("Bitcoin mnemonic", x).encode('hex')
# pywallet openssl private key implementation

View File

@ -215,9 +215,9 @@ class Commands:
return self.network.get_servers()
def getseed(self):
import mnemonic
seed = self.wallet.decode_seed(self.password)
return { "hex":seed, "mnemonic": ' '.join(mnemonic.mn_encode(seed)) }
mnemonic = self.wallet.get_mnemonic(self.password)
seed = self.wallet.get_seed(self.password)
return { 'mnemonic':mnemonic, 'seed':seed, 'version':self.wallet.seed_version }
def importprivkey(self, sec):
try:

View File

@ -1,4 +1,5 @@
ELECTRUM_VERSION = "1.9" # version of the client package
PROTOCOL_VERSION = '0.6' # protocol version requested
SEED_VERSION = 5 # bump this every time the seed generation is modified
SEED_VERSION = 6 # bump this every time the seed generation is modified
SEED_PREFIX = '100' # the hash of a valid mnemonic seed must begin with this (12 bits)
TRANSLATION_ID = 4127 # version of the wiki page

View File

@ -64,7 +64,7 @@ def pw_decode(s, password):
from version import ELECTRUM_VERSION, SEED_VERSION
from version import *
class WalletStorage:
@ -176,8 +176,10 @@ class Wallet:
self.next_addresses = storage.get('next_addresses',{})
if self.seed_version < 4:
raise ValueError("This wallet seed is deprecated.")
if self.seed_version not in [4, 6]:
msg = "This wallet seed is not supported."
if self.seed_version in [5]: msg += "\nTo open this wallet, try 'git checkout seed_v%d'"%self.seed_version
raise ValueError(msg)
self.load_accounts()
@ -247,7 +249,7 @@ class Wallet:
def import_key(self, sec, password):
# check password
seed = self.decode_seed(password)
seed = self.get_seed(password)
try:
address = address_from_private_key(sec)
except:
@ -269,12 +271,55 @@ class Wallet:
self.storage.put('imported_keys', self.imported_keys, True)
def init_seed(self, seed):
if self.seed: raise BaseException("a seed exists")
if not seed:
seed = random_seed(128)
self.seed = seed
def make_seed(self):
import mnemonic, ecdsa
entropy = ecdsa.util.randrange( pow(2,160) )
nonce = 0
while True:
ss = "%040x"%(entropy+nonce)
s = hashlib.sha256(ss.decode('hex')).digest().encode('hex')
# we keep only 13 words, that's approximately 139 bits of entropy
words = mnemonic.mn_encode(s)[0:13]
seed = ' '.join(words)
if mnemonic_hash(seed)[0:3] == SEED_PREFIX:
break # this removes 12 bits of entropy
nonce += 1
return seed
def init_seed(self, seed):
if self.seed:
raise BaseException("a seed exists")
if not seed:
self.seed = self.make_seed()
self.seed_version = SEED_VERSION
return
# find out what kind of wallet we are
try:
seed.decode('hex')
self.seed_version = 4
return
except:
pass
words = seed.split()
try:
mnemonic.mn_decode(words)
uses_electrum_words = True
except:
uses_electrum_words = False
if uses_electrum_words and len(words) != 13:
self.seed_version = 4
self.seed = mnemonic.mn_encode(seed)
else:
assert mnemonic_hash(seed)[0:3] == SEED_PREFIX
self.seed_version = SEED_VERSION
self.seed = seed
def save_seed(self):
self.storage.put('seed', self.seed, True)
@ -291,12 +336,12 @@ class Wallet:
def create_accounts(self):
# create default account
self.create_master_keys('1', self.seed)
self.create_master_keys('1')
self.create_account('1','Main account')
def create_master_keys(self, account_type, seed):
master_k, master_c, master_K, master_cK = bip32_init(self.seed)
def create_master_keys(self, account_type):
master_k, master_c, master_K, master_cK = bip32_init(self.get_seed(None))
if account_type == '1':
k0, c0, K0, cK0 = bip32_private_derivation(master_k, master_c, "m/", "m/0'/")
self.master_public_keys["m/0'/"] = (c0, K0, cK0)
@ -339,7 +384,7 @@ class Wallet:
def deseed_root(self, seed, password):
# for safety, we ask the user to enter their seed
assert seed == self.decode_seed(password)
assert seed == self.get_seed(password)
self.seed = ''
self.storage.put('seed', '', True)
@ -600,12 +645,26 @@ class Wallet:
def decode_seed(self, password):
seed = pw_decode(self.seed, password)
def get_seed(self, password):
s = pw_decode(self.seed, password)
if self.seed_version == 4:
seed = s
else:
seed = mnemonic_hash(s)
#todo: #self.sequences[0].check_seed(seed)
return seed
def get_mnemonic(self, password):
import mnemonic
s = pw_decode(self.seed, password)
if self.seed_version == 4:
return ' '.join(mnemonic.mn_encode(s))
else:
return s
def get_private_key(self, address, password):
out = []
if address in self.imported_keys.keys():
@ -613,7 +672,7 @@ class Wallet:
else:
account, sequence = self.get_address_index(address)
if account == 0:
seed = self.decode_seed(password)
seed = self.get_seed(password)
pk = self.accounts[account].get_private_key(seed, sequence)
out.append(pk)
return out
@ -673,7 +732,7 @@ class Wallet:
def signrawtransaction(self, tx, input_info, private_keys, password):
# check that the password is correct
seed = self.decode_seed(password)
seed = self.get_seed(password)
# add input info
tx.add_input_info(input_info)
@ -1291,10 +1350,11 @@ class Wallet:
def update_password(self, seed, old_password, new_password):
def update_password(self, old_password, new_password):
if new_password == '': new_password = None
# this will throw an exception if unicode cannot be converted
self.seed = pw_encode( seed, new_password)
decoded = pw_decode(self.seed, old_password)
self.seed = pw_encode( decoded, new_password)
self.storage.put('seed', self.seed, True)
self.use_encryption = (new_password != None)
self.storage.put('use_encryption', self.use_encryption,True)
@ -1485,17 +1545,12 @@ class Wallet:
# wait until we are connected, because the user might have selected another server
wait_for_network()
# try to restore old account
self.create_old_account()
wait_for_wallet()
if self.is_found():
self.seed_version = 4
self.storage.put('seed_version', self.seed_version, True)
if self.seed_version == 4:
self.create_old_account()
else:
self.accounts.pop(0)
self.create_accounts()
wait_for_wallet()
wait_for_wallet()