1
0
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

@@ -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()