compact serialized format for unsigned and partially signed transactions.
[electrum-nvc.git] / lib / account.py
1 #!/usr/bin/env python
2 #
3 # Electrum - lightweight Bitcoin client
4 # Copyright (C) 2013 thomasv@gitorious
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19 import bitcoin
20 from bitcoin import *
21 from i18n import _
22 from transaction import Transaction, is_extended_pubkey
23 from util import print_msg
24
25
26 class Account(object):
27     def __init__(self, v):
28         self.addresses = v.get('0', [])
29         self.change = v.get('1', [])
30
31     def dump(self):
32         return {'0':self.addresses, '1':self.change}
33
34     def get_addresses(self, for_change):
35         return self.change[:] if for_change else self.addresses[:]
36
37     def create_new_address(self, for_change):
38         addresses = self.change if for_change else self.addresses
39         n = len(addresses)
40         address = self.get_address( for_change, n)
41         addresses.append(address)
42         print_msg(address)
43         return address
44
45     def get_address(self, for_change, n):
46         pass
47         
48     def get_pubkeys(self, sequence):
49         return [ self.get_pubkey( *sequence )]
50
51     def has_change(self):
52         return True
53
54     def get_name(self, k):
55         return _('Main account')
56
57     def get_keyID(self, *sequence):
58         pass
59
60     def redeem_script(self, *sequence):
61         pass
62
63
64 class PendingAccount(Account):
65     def __init__(self, v):
66         self.addresses = [ v['pending'] ]
67         self.change = []
68
69     def has_change(self):
70         return False
71
72     def dump(self):
73         return {'pending':self.addresses[0]}
74
75     def get_name(self, k):
76         return _('Pending account')
77
78
79 class ImportedAccount(Account):
80     def __init__(self, d):
81         self.keypairs = d['imported']
82
83     def get_addresses(self, for_change):
84         return [] if for_change else sorted(self.keypairs.keys())
85
86     def get_pubkey(self, *sequence):
87         for_change, i = sequence
88         assert for_change == 0
89         addr = self.get_addresses(0)[i]
90         return self.keypairs[addr][0]
91
92     def get_private_key(self, sequence, wallet, password):
93         from wallet import pw_decode
94         for_change, i = sequence
95         assert for_change == 0
96         address = self.get_addresses(0)[i]
97         pk = pw_decode(self.keypairs[address][1], password)
98         # this checks the password
99         assert address == address_from_private_key(pk)
100         return [pk]
101
102     def has_change(self):
103         return False
104
105     def add(self, address, pubkey, privkey, password):
106         from wallet import pw_encode
107         self.keypairs[address] = (pubkey, pw_encode(privkey, password ))
108
109     def remove(self, address):
110         self.keypairs.pop(address)
111
112     def dump(self):
113         return {'imported':self.keypairs}
114
115     def get_name(self, k):
116         return _('Imported keys')
117
118
119     def update_password(self, old_password, new_password):
120         for k, v in self.keypairs.items():
121             pubkey, a = v
122             b = pw_decode(a, old_password)
123             c = pw_encode(b, new_password)
124             self.keypairs[k] = (pubkey, c)
125
126
127 class OldAccount(Account):
128     """  Privatekey(type,n) = Master_private_key + H(n|S|type)  """
129
130     def __init__(self, v):
131         self.addresses = v.get(0, [])
132         self.change = v.get(1, [])
133         self.mpk = v['mpk'].decode('hex')
134
135     def dump(self):
136         return {0:self.addresses, 1:self.change}
137
138     @classmethod
139     def mpk_from_seed(klass, seed):
140         curve = SECP256k1
141         secexp = klass.stretch_key(seed)
142         master_private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
143         master_public_key = master_private_key.get_verifying_key().to_string().encode('hex')
144         return master_public_key
145
146     @classmethod
147     def stretch_key(self,seed):
148         oldseed = seed
149         for i in range(100000):
150             seed = hashlib.sha256(seed + oldseed).digest()
151         return string_to_number( seed )
152
153     @classmethod
154     def get_sequence(self, mpk, for_change, n):
155         return string_to_number( Hash( "%d:%d:"%(n,for_change) + mpk ) )
156
157     def get_address(self, for_change, n):
158         pubkey = self.get_pubkey(for_change, n)
159         address = public_key_to_bc_address( pubkey.decode('hex') )
160         return address
161
162     @classmethod
163     def get_pubkey_from_mpk(self, mpk, for_change, n):
164         curve = SECP256k1
165         z = self.get_sequence(mpk, for_change, n)
166         master_public_key = ecdsa.VerifyingKey.from_string( mpk, curve = SECP256k1 )
167         pubkey_point = master_public_key.pubkey.point + z*curve.generator
168         public_key2 = ecdsa.VerifyingKey.from_public_point( pubkey_point, curve = SECP256k1 )
169         return '04' + public_key2.to_string().encode('hex')
170
171     def get_pubkey(self, for_change, n):
172         return self.get_pubkey_from_mpk(self.mpk, for_change, n)
173
174     def get_private_key_from_stretched_exponent(self, for_change, n, secexp):
175         order = generator_secp256k1.order()
176         secexp = ( secexp + self.get_sequence(self.mpk, for_change, n) ) % order
177         pk = number_to_string( secexp, generator_secp256k1.order() )
178         compressed = False
179         return SecretToASecret( pk, compressed )
180         
181
182     def get_private_key(self, sequence, wallet, password):
183         seed = wallet.get_seed(password)
184         self.check_seed(seed)
185         for_change, n = sequence
186         secexp = self.stretch_key(seed)
187         pk = self.get_private_key_from_stretched_exponent(for_change, n, secexp)
188         return [pk]
189
190
191     def check_seed(self, seed):
192         curve = SECP256k1
193         secexp = self.stretch_key(seed)
194         master_private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
195         master_public_key = master_private_key.get_verifying_key().to_string()
196         if master_public_key != self.mpk:
197             print_error('invalid password (mpk)', self.mpk.encode('hex'), master_public_key.encode('hex'))
198             raise Exception('Invalid password')
199         return True
200
201     def redeem_script(self, sequence):
202         return None
203
204     def get_master_pubkeys(self):
205         return [self.mpk.encode('hex')]
206
207     def get_type(self):
208         return _('Old Electrum format')
209
210     def get_keyID(self, sequence):
211         a, b = sequence
212         return 'old(%s,%d,%d)'%(self.mpk.encode('hex'),a,b)
213
214     def get_xpubkeys(self, sequence):
215         s = ''.join(map(lambda x: bitcoin.int_to_hex(x,2), sequence))
216         mpk = self.mpk.encode('hex')
217         x_pubkey = 'fe' + mpk + s
218         return [ x_pubkey ]
219
220     @classmethod
221     def parse_xpubkey(self, x_pubkey):
222         assert is_extended_pubkey(x_pubkey)
223         pk = x_pubkey[2:]
224         mpk = pk[0:128]
225         dd = pk[128:]
226         s = []
227         while dd:
228             n = int(bitcoin.rev_hex(dd[0:4]), 16)
229             dd = dd[4:]
230             s.append(n)
231         assert len(s) == 2
232         return mpk, s
233
234
235 class BIP32_Account(Account):
236
237     def __init__(self, v):
238         Account.__init__(self, v)
239         self.xpub = v['xpub']
240
241     def dump(self):
242         d = Account.dump(self)
243         d['xpub'] = self.xpub
244         return d
245
246     def get_address(self, for_change, n):
247         pubkey = self.get_pubkey(for_change, n)
248         address = public_key_to_bc_address( pubkey.decode('hex') )
249         return address
250
251     def first_address(self):
252         return self.get_address(0,0)
253
254     def get_master_pubkeys(self):
255         return [self.xpub]
256
257     @classmethod
258     def get_pubkey_from_x(self, xpub, for_change, n):
259         _, _, _, c, cK = deserialize_xkey(xpub)
260         for i in [for_change, n]:
261             cK, c = CKD_pub(cK, c, i)
262         return cK.encode('hex')
263
264     def get_pubkeys(self, sequence):
265         return sorted(map(lambda x: self.get_pubkey_from_x(x, *sequence), self.get_master_pubkeys()))
266
267     def get_pubkey(self, for_change, n):
268         return self.get_pubkeys((for_change, n))[0]
269
270
271     def get_private_key(self, sequence, wallet, password):
272         out = []
273         xpubs = self.get_master_pubkeys()
274         roots = [k for k, v in wallet.master_public_keys.iteritems() if v in xpubs]
275         for root in roots:
276             xpriv = wallet.get_master_private_key(root, password)
277             if not xpriv:
278                 continue
279             _, _, _, c, k = deserialize_xkey(xpriv)
280             pk = bip32_private_key( sequence, k, c )
281             out.append(pk)
282                     
283         return out
284
285
286     def redeem_script(self, sequence):
287         return None
288
289     def get_type(self):
290         return _('Standard 1 of 1')
291
292     def get_xpubkeys(self, sequence):
293         s = ''.join(map(lambda x: bitcoin.int_to_hex(x,2), sequence))
294         mpks = self.get_master_pubkeys()
295         out = []
296         for xpub in mpks:
297             pubkey = self.get_pubkey_from_x(xpub, *sequence)
298             x_pubkey = 'ff' + bitcoin.DecodeBase58Check(xpub).encode('hex') + s
299             out.append( (pubkey, x_pubkey ) )
300         # sort it, so that x_pubkeys are in the same order as pubkeys
301         out.sort()
302         return map(lambda x:x[1], out )
303
304     @classmethod
305     def parse_xpubkey(self, pubkey):
306         assert is_extended_pubkey(pubkey)
307         pk = pubkey.decode('hex')
308         pk = pk[1:]
309         xkey = bitcoin.EncodeBase58Check(pk[0:78])
310         dd = pk[78:]
311         s = []
312         while dd:
313             n = int( bitcoin.rev_hex(dd[0:2].encode('hex')), 16)
314             dd = dd[2:]
315             s.append(n)
316         assert len(s) == 2
317         return xkey, s
318
319
320     def get_name(self, k):
321         name = "Unnamed account"
322         m = re.match("m/(\d+)'", k)
323         if m:
324             num = m.group(1)
325             if num == '0':
326                 name = "Main account"
327             else:
328                 name = "Account %s"%num
329                     
330         return name
331
332
333
334 class BIP32_Account_2of2(BIP32_Account):
335
336     def __init__(self, v):
337         BIP32_Account.__init__(self, v)
338         self.xpub2 = v['xpub2']
339
340     def dump(self):
341         d = BIP32_Account.dump(self)
342         d['xpub2'] = self.xpub2
343         return d
344
345     def redeem_script(self, sequence):
346         pubkeys = self.get_pubkeys(sequence)
347         return Transaction.multisig_script(pubkeys, 2)
348
349     def get_address(self, for_change, n):
350         address = hash_160_to_bc_address(hash_160(self.redeem_script((for_change, n)).decode('hex')), 5)
351         return address
352
353     def get_master_pubkeys(self):
354         return [self.xpub, self.xpub2]
355
356     def get_type(self):
357         return _('Multisig 2 of 2')
358
359
360 class BIP32_Account_2of3(BIP32_Account_2of2):
361
362     def __init__(self, v):
363         BIP32_Account_2of2.__init__(self, v)
364         self.xpub3 = v['xpub3']
365
366     def dump(self):
367         d = BIP32_Account_2of2.dump(self)
368         d['xpub3'] = self.xpub3
369         return d
370
371     def get_master_pubkeys(self):
372         return [self.xpub, self.xpub2, self.xpub3]
373
374     def get_type(self):
375         return _('Multisig 2 of 3')
376
377
378
379