electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 736e1253f29c54b0c40a7b84a4bb64037c392818
parent 2ef7b4331a268e263843c0d98cf59994a83504c8
Author: ecdsa <ecdsa@github>
Date:   Sat,  2 Mar 2013 23:31:40 +0100

add class BIP32Sequence

Diffstat:
Mgui/gui_classic.py | 2+-
Mlib/bitcoin.py | 59+++++++++++++++++++++++++++++++++++++++++++++++------------
Mlib/wallet.py | 21+++++++++------------
3 files changed, 57 insertions(+), 25 deletions(-)

diff --git a/gui/gui_classic.py b/gui/gui_classic.py @@ -1674,7 +1674,7 @@ class ElectrumWindow(QMainWindow): #self.print_button.setHidden(self.qr_window is None or not self.qr_window.isVisible()) self.receive_list.setColumnHidden(2, self.qr_window is None or not self.qr_window.isVisible()) - self.receive_list.setColumnWidth(1, 200) + #self.receive_list.setColumnWidth(1, 200) def question(self, msg): diff --git a/lib/bitcoin.py b/lib/bitcoin.py @@ -424,13 +424,12 @@ class DeterministicSequence: self.is_p2sh = False @classmethod - def from_seed(klass, seed): + def mpk_from_seed(klass, seed): curve = SECP256k1 secexp = klass.stretch_key(seed) master_private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 ) master_public_key = master_private_key.get_verifying_key().to_string().encode('hex') - self = klass(master_public_key) - return self + return master_public_key @classmethod def stretch_key(self,seed): @@ -494,21 +493,57 @@ class DeterministicSequence: return True - def add_input_info(self, txin, account, is_change, n): + def get_input_info(self, is_change, n): - txin['electrumKeyID'] = (account, is_change, n) # used by the server to find the key - if not self.p2sh: - txin['pubkeysig'] = [(None, None)] - pk_addr = txin['address'] + if not self.is_p2sh: + pk_addr = self.get_address(is_change, n) + redeemScript = None else: pubkey1 = self.get_pubkey(n, is_change) pubkey2 = self.get_pubkey2(n, is_change) pk_addr = public_key_to_bc_address( pubkey1.decode('hex') ) # we need to return that address to get the right private key - txin['redeemScript'] = Transaction.multisig_script([pubkey1, pubkey2], 2)['redeemScript'] - return pk_addr + redeemScript = Transaction.multisig_script([pubkey1, pubkey2], 2)['redeemScript'] + + return pk_addr, redeemScript + +class BIP32Sequence: + + def __init__(self, mpkc, mpkc2 = None): + self.master_public_key, self.master_chain = mpkc + if mpkc2: + self.master_public_key2, self.master_chain2 = mpkc2 + self.is_p2sh = True + else: + self.is_p2sh = False + + @classmethod + def mpk_from_seed(klass, seed): + master_secret, master_chain, master_public_key, master_public_key_compressed = bip32_init(seed) + return master_public_key, master_chain + + def get_pubkey(self, sequence): + K = self.master_public_key + chain = self.mchain + for i in sequence: + K, K_compressed, chain = CKD_prime(K, chain, i) + return K_compressed + + def get_address(self, sequence): + return hash_160_to_bc_address(hash_160(self.get_pubkey(sequence))) + + def get_private_key(self, seed, sequence): + k = self.master_secret + chain = self.master_chain + for i in sequence: + k, k_compressed, chain = CKD(k, chain, i) + return SecretToASecret(k0, True) + + def check_seed(self, seed): + master_secret, master_chain, master_public_key, master_public_key_compressed = bip32_init(seed) + assert self.master_public_key == master_public_key ################################## transactions @@ -798,11 +833,11 @@ class Transaction: if self.input_info: out['input_info'] = json.dumps(self.input_info).replace(' ','') - - print "out", out return out + + def test_bip32(): seed = "ff000000000000000000000000000000".decode('hex') master_secret, master_chain, master_public_key, master_public_key_compressed = bip32_init(seed) diff --git a/lib/wallet.py b/lib/wallet.py @@ -93,9 +93,10 @@ class Wallet: self.tx_height = config.get('tx_height',{}) self.requested_amounts = config.get('requested_amounts',{}) self.accounts = config.get('accounts', {}) # this should not include public keys - self.sequences = {} + self.sequences = {} self.sequences[0] = DeterministicSequence(self.config.get('master_public_key')) + if self.accounts.get(0) is None: self.accounts[0] = { 0:[], 1:[], 'name':'Main account' } @@ -188,17 +189,12 @@ class Wallet: self.config.set_key('seed', self.seed, True) self.config.set_key('seed_version', self.seed_version, True) - self.init_main_account(self.seed) - + mpk = DeterministicSequence.mpk_from_seed(self.seed) + self.config.set_key('master_public_key', mpk, True) + self.sequences[0] = DeterministicSequence(mpk) - def init_main_account(self, seed): - # public key - sequence = DeterministicSequence.from_seed(seed) self.accounts[0] = { 0:[], 1:[], 'name':'Main account' } - self.sequences[0] = sequence self.config.set_key('accounts', self.accounts, True) - mpk = sequence.master_public_key - self.config.set_key('master_public_key', mpk, True) @@ -330,7 +326,7 @@ class Wallet: def get_new_address(self, account, for_change, n): return self.sequences[account].get_address(for_change, n) - print_msg( address ) + print address return address def change_gap_limit(self, value): @@ -790,12 +786,13 @@ class Wallet: for i in range(len(tx.inputs)): txin = tx.inputs[i] account, is_change, n = self.get_address_index(txin['address']) - pk_addr = self.sequences[account].add_input_info(txin, account, is_change, n) + pk_addr, redeemScript = self.sequences[account].get_input_info(is_change, n) + txin['redeemScript'] = redeemScript + txin['electrumKeyID'] = (account, is_change, n) # used by the server to find the key pk_addresses.append(pk_addr) # get all private keys at once. private_keys = self.get_private_keys(pk_addresses, password) - print "private keys", private_keys tx.sign(private_keys) for address, x in outputs: