Removed uselss comment.
[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     def get_master_pubkeys(self):
79         return []
80
81 class ImportedAccount(Account):
82     def __init__(self, d):
83         self.keypairs = d['imported']
84
85     def get_addresses(self, for_change):
86         return [] if for_change else sorted(self.keypairs.keys())
87
88     def get_pubkey(self, *sequence):
89         for_change, i = sequence
90         assert for_change == 0
91         addr = self.get_addresses(0)[i]
92         return self.keypairs[addr][0]
93
94     def get_private_key(self, sequence, wallet, password):
95         from wallet import pw_decode
96         for_change, i = sequence
97         assert for_change == 0
98         address = self.get_addresses(0)[i]
99         pk = pw_decode(self.keypairs[address][1], password)
100         # this checks the password
101         assert address == address_from_private_key(pk)
102         return [pk]
103
104     def has_change(self):
105         return False
106
107     def add(self, address, pubkey, privkey, password):
108         from wallet import pw_encode
109         self.keypairs[address] = (pubkey, pw_encode(privkey, password ))
110
111     def remove(self, address):
112         self.keypairs.pop(address)
113
114     def dump(self):
115         return {'imported':self.keypairs}
116
117     def get_name(self, k):
118         return _('Imported keys')
119
120
121     def update_password(self, old_password, new_password):
122         for k, v in self.keypairs.items():
123             pubkey, a = v
124             b = pw_decode(a, old_password)
125             c = pw_encode(b, new_password)
126             self.keypairs[k] = (pubkey, c)
127
128
129 class OldAccount(Account):
130     """  Privatekey(type,n) = Master_private_key + H(n|S|type)  """
131
132     def __init__(self, v):
133         self.addresses = v.get(0, [])
134         self.change = v.get(1, [])
135         self.mpk = v['mpk'].decode('hex')
136
137     def dump(self):
138         return {0:self.addresses, 1:self.change}
139
140     @classmethod
141     def mpk_from_seed(klass, seed):
142         curve = SECP256k1
143         secexp = klass.stretch_key(seed)
144         master_private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
145         master_public_key = master_private_key.get_verifying_key().to_string().encode('hex')
146         return master_public_key
147
148     @classmethod
149     def stretch_key(self,seed):
150         oldseed = seed
151         for i in range(100000):
152             seed = hashlib.sha256(seed + oldseed).digest()
153         return string_to_number( seed )
154
155     @classmethod
156     def get_sequence(self, mpk, for_change, n):
157         return string_to_number( Hash( "%d:%d:"%(n,for_change) + mpk ) )
158
159     def get_address(self, for_change, n):
160         pubkey = self.get_pubkey(for_change, n)
161         address = public_key_to_bc_address( pubkey.decode('hex') )
162         return address
163
164     @classmethod
165     def get_pubkey_from_mpk(self, mpk, for_change, n):
166         curve = SECP256k1
167         z = self.get_sequence(mpk, for_change, n)
168         master_public_key = ecdsa.VerifyingKey.from_string( mpk, curve = SECP256k1 )
169         pubkey_point = master_public_key.pubkey.point + z*curve.generator
170         public_key2 = ecdsa.VerifyingKey.from_public_point( pubkey_point, curve = SECP256k1 )
171         return '04' + public_key2.to_string().encode('hex')
172
173     def get_pubkey(self, for_change, n):
174         return self.get_pubkey_from_mpk(self.mpk, for_change, n)
175
176     def get_private_key_from_stretched_exponent(self, for_change, n, secexp):
177         order = generator_secp256k1.order()
178         secexp = ( secexp + self.get_sequence(self.mpk, for_change, n) ) % order
179         pk = number_to_string( secexp, generator_secp256k1.order() )
180         compressed = False
181         return SecretToASecret( pk, compressed )
182         
183
184     def get_private_key(self, sequence, wallet, password):
185         seed = wallet.get_seed(password)
186         self.check_seed(seed)
187         for_change, n = sequence
188         secexp = self.stretch_key(seed)
189         pk = self.get_private_key_from_stretched_exponent(for_change, n, secexp)
190         return [pk]
191
192
193     def check_seed(self, seed):
194         curve = SECP256k1
195         secexp = self.stretch_key(seed)
196         master_private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
197         master_public_key = master_private_key.get_verifying_key().to_string()
198         if master_public_key != self.mpk:
199             print_error('invalid password (mpk)', self.mpk.encode('hex'), master_public_key.encode('hex'))
200             raise Exception('Invalid password')
201         return True
202
203     def redeem_script(self, sequence):
204         return None
205
206     def get_master_pubkeys(self):
207         return [self.mpk.encode('hex')]
208
209     def get_type(self):
210         return _('Old Electrum format')
211
212     def get_keyID(self, sequence):
213         a, b = sequence
214         return 'old(%s,%d,%d)'%(self.mpk.encode('hex'),a,b)
215
216     def get_xpubkeys(self, sequence):
217         s = ''.join(map(lambda x: bitcoin.int_to_hex(x,2), sequence))
218         mpk = self.mpk.encode('hex')
219         x_pubkey = 'fe' + mpk + s
220         return [ x_pubkey ]
221
222     @classmethod
223     def parse_xpubkey(self, x_pubkey):
224         assert is_extended_pubkey(x_pubkey)
225         pk = x_pubkey[2:]
226         mpk = pk[0:128]
227         dd = pk[128:]
228         s = []
229         while dd:
230             n = int(bitcoin.rev_hex(dd[0:4]), 16)
231             dd = dd[4:]
232             s.append(n)
233         assert len(s) == 2
234         return mpk, s
235
236
237 class BIP32_Account(Account):
238
239     def __init__(self, v):
240         Account.__init__(self, v)
241         self.xpub = v['xpub']
242
243     def dump(self):
244         d = Account.dump(self)
245         d['xpub'] = self.xpub
246         return d
247
248     def get_address(self, for_change, n):
249         pubkey = self.get_pubkey(for_change, n)
250         address = public_key_to_bc_address( pubkey.decode('hex') )
251         return address
252
253     def first_address(self):
254         return self.get_address(0,0)
255
256     def get_master_pubkeys(self):
257         return [self.xpub]
258
259     @classmethod
260     def get_pubkey_from_x(self, xpub, for_change, n):
261         _, _, _, c, cK = deserialize_xkey(xpub)
262         for i in [for_change, n]:
263             cK, c = CKD_pub(cK, c, i)
264         return cK.encode('hex')
265
266     def get_pubkeys(self, sequence):
267         return sorted(map(lambda x: self.get_pubkey_from_x(x, *sequence), self.get_master_pubkeys()))
268
269     def get_pubkey(self, for_change, n):
270         return self.get_pubkeys((for_change, n))[0]
271
272
273     def get_private_key(self, sequence, wallet, password):
274         out = []
275         xpubs = self.get_master_pubkeys()
276         roots = [k for k, v in wallet.master_public_keys.iteritems() if v in xpubs]
277         for root in roots:
278             xpriv = wallet.get_master_private_key(root, password)
279             if not xpriv:
280                 continue
281             _, _, _, c, k = deserialize_xkey(xpriv)
282             pk = bip32_private_key( sequence, k, c )
283             out.append(pk)
284                     
285         return out
286
287
288     def redeem_script(self, sequence):
289         return None
290
291     def get_type(self):
292         return _('Standard 1 of 1')
293
294     def get_xpubkeys(self, sequence):
295         s = ''.join(map(lambda x: bitcoin.int_to_hex(x,2), sequence))
296         mpks = self.get_master_pubkeys()
297         out = []
298         for xpub in mpks:
299             pubkey = self.get_pubkey_from_x(xpub, *sequence)
300             x_pubkey = 'ff' + bitcoin.DecodeBase58Check(xpub).encode('hex') + s
301             out.append( (pubkey, x_pubkey ) )
302         # sort it, so that x_pubkeys are in the same order as pubkeys
303         out.sort()
304         return map(lambda x:x[1], out )
305
306     @classmethod
307     def parse_xpubkey(self, pubkey):
308         assert is_extended_pubkey(pubkey)
309         pk = pubkey.decode('hex')
310         pk = pk[1:]
311         xkey = bitcoin.EncodeBase58Check(pk[0:78])
312         dd = pk[78:]
313         s = []
314         while dd:
315             n = int( bitcoin.rev_hex(dd[0:2].encode('hex')), 16)
316             dd = dd[2:]
317             s.append(n)
318         assert len(s) == 2
319         return xkey, s
320
321
322     def get_name(self, k):
323         name = "Unnamed account"
324         m = re.match("m/(\d+)'", k)
325         if m:
326             num = m.group(1)
327             if num == '0':
328                 name = "Main account"
329             else:
330                 name = "Account %s"%num
331                     
332         return name
333
334
335
336 class BIP32_Account_2of2(BIP32_Account):
337
338     def __init__(self, v):
339         BIP32_Account.__init__(self, v)
340         self.xpub2 = v['xpub2']
341
342     def dump(self):
343         d = BIP32_Account.dump(self)
344         d['xpub2'] = self.xpub2
345         return d
346
347     def redeem_script(self, sequence):
348         pubkeys = self.get_pubkeys(sequence)
349         return Transaction.multisig_script(pubkeys, 2)
350
351     def get_address(self, for_change, n):
352         address = hash_160_to_bc_address(hash_160(self.redeem_script((for_change, n)).decode('hex')), 5)
353         return address
354
355     def get_master_pubkeys(self):
356         return [self.xpub, self.xpub2]
357
358     def get_type(self):
359         return _('Multisig 2 of 2')
360
361
362 class BIP32_Account_2of3(BIP32_Account_2of2):
363
364     def __init__(self, v):
365         BIP32_Account_2of2.__init__(self, v)
366         self.xpub3 = v['xpub3']
367
368     def dump(self):
369         d = BIP32_Account_2of2.dump(self)
370         d['xpub3'] = self.xpub3
371         return d
372
373     def get_master_pubkeys(self):
374         return [self.xpub, self.xpub2, self.xpub3]
375
376     def get_type(self):
377         return _('Multisig 2 of 3')
378
379
380
381