electrum

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

commit 96d459ab887757610d825670e567733a39cbfb5b
parent f58e54138436b810201d4dc4b2faf9384f78d84c
Author: thomasv <thomasv@gitorious>
Date:   Tue, 26 Feb 2013 16:03:04 +0100

use dumpprivkeys to efficiently dump private keys

Diffstat:
Melectrum | 18+++++++++++-------
Mlib/bitcoin.py | 7+++++--
Mlib/commands.py | 9++++++---
Mlib/wallet.py | 30++++++++++++++++++------------
4 files changed, 40 insertions(+), 24 deletions(-)

diff --git a/electrum b/electrum @@ -89,6 +89,7 @@ options:\n --fee, -f: set transaction fee\n --fromaddr, -s: send from address 'prioritize':'', 'unprioritize':'', 'dumpprivkey':'similar to bitcoind\'s command', + 'dumpprivkeys':'dump all private keys', 'listunspent':'similar to bitcoind\'s command', 'createmultisig':'similar to bitcoind\'s command', 'createrawtransaction':'similar to bitcoind\'s command', @@ -138,7 +139,6 @@ def arg_parser(): parser.add_option("-o", "--offline", action="store_true", dest="offline", default=False, help="remain offline") parser.add_option("-a", "--all", action="store_true", dest="show_all", default=False, help="show all addresses") parser.add_option("-b", "--balance", action="store_true", dest="show_balance", default=False, help="show the balance at listed addresses") - parser.add_option("-k", "--keys",action="store_true", dest="show_keys",default=False, help="show the private keys of listed addresses") parser.add_option("-f", "--fee", dest="tx_fee", default="0.005", help="set tx fee") parser.add_option("-F", "--fromaddr", dest="from_addr", default=None, help="set source address for payto/mktx. if it isn't in the wallet, it will ask for the private key unless supplied in the format public_key:private_key. It's not saved in the wallet.") parser.add_option("-c", "--changeaddr", dest="change_addr", default=None, help="set the change address for payto/mktx. default is a spare address, or the source address if it's not in the wallet") @@ -384,13 +384,13 @@ if __name__ == '__main__': # important warning - if cmd=='addresses' and options.show_keys: + if cmd in ['dumpprivkey', 'dumpprivkeys']: print_msg("WARNING: ALL your private keys are secret.") print_msg("Exposing a single private key can compromise your entire wallet!") print_msg("In particular, DO NOT use 'redeem private key' services proposed by third parties.") # commands needing password - if cmd in protected_commands or ( cmd=='addresses' and options.show_keys): + if cmd in protected_commands: if wallet.use_encryption: password = prompt_password('Password:', False) if not password: @@ -440,7 +440,6 @@ if __name__ == '__main__': args = [ cmd, address, signature, message] elif cmd == 'signrawtransaction': - args = [ cmd, args[1], ast.literal_eval(args[2]) if len(args)>2 else [], ast.literal_eval(args[3]) if len(args)>3 else []] elif cmd == 'createmultisig': @@ -448,6 +447,13 @@ if __name__ == '__main__': elif cmd == 'createrawtransaction': args = [ cmd, ast.literal_eval(args[1]), ast.literal_eval(args[2])] + + elif cmd == 'dumpprivkeys': + if options.show_all: + addresses = wallet.all_addresses() + else: + addresses = wallet.addresses + wallet.imported_keys.keys() + args = [cmd, addresses] elif cmd == 'setlabel': try: @@ -565,8 +571,6 @@ if __name__ == '__main__': b = format_satoshis(wallet.get_addr_balance(addr)[0]) else: b='' m_addr = "%34s"%addr - if options.show_keys: - m_addr += ':' + str(wallet.get_private_key(addr, password)) print_msg(flags, m_addr, b, label) @@ -580,7 +584,7 @@ if __name__ == '__main__': cmd_runner = Commands(wallet, interface) func = eval('cmd_runner.' + cmd) if password: - args.append( password ) + cmd_runner.password = password func(*args[1:]) diff --git a/lib/bitcoin.py b/lib/bitcoin.py @@ -435,13 +435,16 @@ class DeterministicSequence: public_key2 = ecdsa.VerifyingKey.from_public_point( pubkey_point, curve = SECP256k1 ) return '04' + public_key2.to_string().encode('hex') - def get_private_key(self, n, for_change, seed): + def get_private_key_from_stretched_exponent(self, n, for_change, secexp): order = generator_secp256k1.order() - secexp = self.stretch_key(seed) secexp = ( secexp + self.get_sequence(n,for_change) ) % order pk = number_to_string( secexp, generator_secp256k1.order() ) compressed = False return SecretToASecret( pk, compressed ) + + def get_private_key(self, n, for_change, seed): + secexp = self.stretch_key(seed) + return self.get_private_key_from_stretched_exponent(n, for_change, secexp) def check_seed(self, seed): curve = SECP256k1 diff --git a/lib/commands.py b/lib/commands.py @@ -22,7 +22,7 @@ from bitcoin import * from decimal import Decimal import bitcoin -protected_commands = ['payto', 'password', 'mktx', 'get_seed', 'importprivkey','signmessage', 'signrawtransaction','dumpprivkey' ] +protected_commands = ['payto', 'password', 'mktx', 'get_seed', 'importprivkey','signmessage', 'signrawtransaction', 'dumpprivkey', 'dumpprivkeys' ] class Commands: @@ -135,8 +135,11 @@ class Commands: print_msg(self.wallet.unprioritize(addr)) def dumpprivkey(self, addr): - sec = self.wallet.get_private_key(addr, self.password) - print_msg( sec ) + print_msg( self.wallet.get_private_key(addr, self.password) ) + + def dumpprivkeys(self, addresses): + print_json( self.wallet.get_private_keys(addresses, self.password) ) + def validateaddress(self,addr): is_valid = self.wallet.is_valid(addr) diff --git a/lib/wallet.py b/lib/wallet.py @@ -213,23 +213,29 @@ class Wallet: return seed def get_private_key(self, address, password): + return self.get_private_keys([address], password)[address] + def get_private_keys(self, addresses, password): # decode seed in any case, in order to test the password seed = self.decode_seed(password) - - if address in self.imported_keys.keys(): - return pw_decode( self.imported_keys[address], password ) - else: - if address in self.addresses: - n = self.addresses.index(address) - for_change = False - elif address in self.change_addresses: - n = self.change_addresses.index(address) - for_change = True + secexp = self.sequence.stretch_key(seed) + out = {} + for address in addresses: + if address in self.imported_keys.keys(): + pk = pw_decode( self.imported_keys[address], password ) else: - raise BaseException("unknown address", address) + if address in self.addresses: + n = self.addresses.index(address) + for_change = False + elif address in self.change_addresses: + n = self.change_addresses.index(address) + for_change = True + else: + raise BaseException("unknown address", address) + pk = self.sequence.get_private_key_from_stretched_exponent(n, for_change, secexp) + out[address] = pk + return out - return self.sequence.get_private_key(n, for_change, seed) def sign_message(self, address, message, password):