Moved bitcoin.py tests to their own file
[electrum-nvc.git] / lib / bitcoin.py
1 # -*- coding: utf-8 -*-
2 #!/usr/bin/env python
3 #
4 # Electrum - lightweight Bitcoin client
5 # Copyright (C) 2011 thomasv@gitorious
6 #
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 import hashlib
21 import base64
22 import re
23 import sys
24 import hmac
25
26 from util import print_error
27
28 try:
29     import ecdsa
30 except ImportError:
31     sys.exit("Error: python-ecdsa does not seem to be installed. Try 'sudo pip install ecdsa'")
32
33 try:
34     import aes
35 except ImportError:
36     sys.exit("Error: AES does not seem to be installed. Try 'sudo pip install slowaes'")
37
38 ################################## transactions
39
40 MIN_RELAY_TX_FEE = 1000
41
42
43 # AES encryption
44 EncodeAES = lambda secret, s: base64.b64encode(aes.encryptData(secret,s))
45 DecodeAES = lambda secret, e: aes.decryptData(secret, base64.b64decode(e))
46
47 def pw_encode(s, password):
48     if password:
49         secret = Hash(password)
50         return EncodeAES(secret, s.encode("utf8"))
51     else:
52         return s
53
54 def pw_decode(s, password):
55     if password is not None:
56         secret = Hash(password)
57         try:
58             d = DecodeAES(secret, s).decode("utf8")
59         except Exception:
60             raise Exception('Invalid password')
61         return d
62     else:
63         return s
64
65
66
67
68
69 def rev_hex(s):
70     return s.decode('hex')[::-1].encode('hex')
71
72 def int_to_hex(i, length=1):
73     s = hex(i)[2:].rstrip('L')
74     s = "0"*(2*length - len(s)) + s
75     return rev_hex(s)
76
77 def var_int(i):
78     # https://en.bitcoin.it/wiki/Protocol_specification#Variable_length_integer
79     if i<0xfd:
80         return int_to_hex(i)
81     elif i<=0xffff:
82         return "fd"+int_to_hex(i,2)
83     elif i<=0xffffffff:
84         return "fe"+int_to_hex(i,4)
85     else:
86         return "ff"+int_to_hex(i,8)
87
88 def op_push(i):
89     if i<0x4c:
90         return int_to_hex(i)
91     elif i<0xff:
92         return '4c' + int_to_hex(i)
93     elif i<0xffff:
94         return '4d' + int_to_hex(i,2)
95     else:
96         return '4e' + int_to_hex(i,4)
97
98
99
100 def sha256(x):
101     return hashlib.sha256(x).digest()
102
103 def Hash(x):
104     if type(x) is unicode: x=x.encode('utf-8')
105     return sha256(sha256(x))
106
107 hash_encode = lambda x: x[::-1].encode('hex')
108 hash_decode = lambda x: x.decode('hex')[::-1]
109 hmac_sha_512 = lambda x,y: hmac.new(x, y, hashlib.sha512).digest()
110
111 def mnemonic_to_seed(mnemonic, passphrase):
112     from pbkdf2 import PBKDF2
113     import hmac
114     PBKDF2_ROUNDS = 2048
115     return PBKDF2(mnemonic, 'mnemonic' + passphrase, iterations = PBKDF2_ROUNDS, macmodule = hmac, digestmodule = hashlib.sha512).read(64)
116
117 from version import SEED_PREFIX
118 is_new_seed = lambda x: hmac_sha_512("Seed version", x.encode('utf8')).encode('hex')[0:2].startswith(SEED_PREFIX)
119
120 def is_old_seed(seed):
121     import mnemonic
122     words = seed.strip().split()
123     try:
124         mnemonic.mn_decode(words)
125         uses_electrum_words = True
126     except Exception:
127         uses_electrum_words = False
128
129     try:
130         seed.decode('hex')
131         is_hex = (len(seed) == 32)
132     except Exception:
133         is_hex = False
134
135     return is_hex or (uses_electrum_words and len(words) == 12)
136
137
138 # pywallet openssl private key implementation
139
140 def i2d_ECPrivateKey(pkey, compressed=False):
141     if compressed:
142         key = '3081d30201010420' + \
143               '%064x' % pkey.secret + \
144               'a081a53081a2020101302c06072a8648ce3d0101022100' + \
145               '%064x' % _p + \
146               '3006040100040107042102' + \
147               '%064x' % _Gx + \
148               '022100' + \
149               '%064x' % _r + \
150               '020101a124032200'
151     else:
152         key = '308201130201010420' + \
153               '%064x' % pkey.secret + \
154               'a081a53081a2020101302c06072a8648ce3d0101022100' + \
155               '%064x' % _p + \
156               '3006040100040107044104' + \
157               '%064x' % _Gx + \
158               '%064x' % _Gy + \
159               '022100' + \
160               '%064x' % _r + \
161               '020101a144034200'
162
163     return key.decode('hex') + i2o_ECPublicKey(pkey.pubkey, compressed)
164
165 def i2o_ECPublicKey(pubkey, compressed=False):
166     # public keys are 65 bytes long (520 bits)
167     # 0x04 + 32-byte X-coordinate + 32-byte Y-coordinate
168     # 0x00 = point at infinity, 0x02 and 0x03 = compressed, 0x04 = uncompressed
169     # compressed keys: <sign> <x> where <sign> is 0x02 if y is even and 0x03 if y is odd
170     if compressed:
171         if pubkey.point.y() & 1:
172             key = '03' + '%064x' % pubkey.point.x()
173         else:
174             key = '02' + '%064x' % pubkey.point.x()
175     else:
176         key = '04' + \
177               '%064x' % pubkey.point.x() + \
178               '%064x' % pubkey.point.y()
179
180     return key.decode('hex')
181
182 # end pywallet openssl private key implementation
183
184
185
186 ############ functions from pywallet #####################
187
188 def hash_160(public_key):
189     try:
190         md = hashlib.new('ripemd160')
191         md.update(sha256(public_key))
192         return md.digest()
193     except Exception:
194         import ripemd
195         md = ripemd.new(sha256(public_key))
196         return md.digest()
197
198
199 def public_key_to_bc_address(public_key):
200     h160 = hash_160(public_key)
201     return hash_160_to_bc_address(h160)
202
203 def hash_160_to_bc_address(h160, addrtype = 0):
204     vh160 = chr(addrtype) + h160
205     h = Hash(vh160)
206     addr = vh160 + h[0:4]
207     return b58encode(addr)
208
209 def bc_address_to_hash_160(addr):
210     bytes = b58decode(addr, 25)
211     return ord(bytes[0]), bytes[1:21]
212
213
214 __b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
215 __b58base = len(__b58chars)
216
217 def b58encode(v):
218     """ encode v, which is a string of bytes, to base58."""
219
220     long_value = 0L
221     for (i, c) in enumerate(v[::-1]):
222         long_value += (256**i) * ord(c)
223
224     result = ''
225     while long_value >= __b58base:
226         div, mod = divmod(long_value, __b58base)
227         result = __b58chars[mod] + result
228         long_value = div
229     result = __b58chars[long_value] + result
230
231     # Bitcoin does a little leading-zero-compression:
232     # leading 0-bytes in the input become leading-1s
233     nPad = 0
234     for c in v:
235         if c == '\0': nPad += 1
236         else: break
237
238     return (__b58chars[0]*nPad) + result
239
240 def b58decode(v, length):
241     """ decode v into a string of len bytes."""
242     long_value = 0L
243     for (i, c) in enumerate(v[::-1]):
244         long_value += __b58chars.find(c) * (__b58base**i)
245
246     result = ''
247     while long_value >= 256:
248         div, mod = divmod(long_value, 256)
249         result = chr(mod) + result
250         long_value = div
251     result = chr(long_value) + result
252
253     nPad = 0
254     for c in v:
255         if c == __b58chars[0]: nPad += 1
256         else: break
257
258     result = chr(0)*nPad + result
259     if length is not None and len(result) != length:
260         return None
261
262     return result
263
264
265 def EncodeBase58Check(vchIn):
266     hash = Hash(vchIn)
267     return b58encode(vchIn + hash[0:4])
268
269 def DecodeBase58Check(psz):
270     vchRet = b58decode(psz, None)
271     key = vchRet[0:-4]
272     csum = vchRet[-4:]
273     hash = Hash(key)
274     cs32 = hash[0:4]
275     if cs32 != csum:
276         return None
277     else:
278         return key
279
280 def PrivKeyToSecret(privkey):
281     return privkey[9:9+32]
282
283 def SecretToASecret(secret, compressed=False, addrtype=0):
284     vchIn = chr((addrtype+128)&255) + secret
285     if compressed: vchIn += '\01'
286     return EncodeBase58Check(vchIn)
287
288 def ASecretToSecret(key, addrtype=0):
289     vch = DecodeBase58Check(key)
290     if vch and vch[0] == chr((addrtype+128)&255):
291         return vch[1:]
292     else:
293         return False
294
295 def regenerate_key(sec):
296     b = ASecretToSecret(sec)
297     if not b:
298         return False
299     b = b[0:32]
300     return EC_KEY(b)
301
302 def GetPubKey(pubkey, compressed=False):
303     return i2o_ECPublicKey(pubkey, compressed)
304
305 def GetPrivKey(pkey, compressed=False):
306     return i2d_ECPrivateKey(pkey, compressed)
307
308 def GetSecret(pkey):
309     return ('%064x' % pkey.secret).decode('hex')
310
311 def is_compressed(sec):
312     b = ASecretToSecret(sec)
313     return len(b) == 33
314
315
316 def public_key_from_private_key(sec):
317     # rebuild public key from private key, compressed or uncompressed
318     pkey = regenerate_key(sec)
319     assert pkey
320     compressed = is_compressed(sec)
321     public_key = GetPubKey(pkey.pubkey, compressed)
322     return public_key.encode('hex')
323
324
325 def address_from_private_key(sec):
326     public_key = public_key_from_private_key(sec)
327     address = public_key_to_bc_address(public_key.decode('hex'))
328     return address
329
330
331 def is_valid(addr):
332     return is_address(addr)
333
334
335 def is_address(addr):
336     ADDRESS_RE = re.compile('[1-9A-HJ-NP-Za-km-z]{26,}\\Z')
337     if not ADDRESS_RE.match(addr): return False
338     try:
339         addrtype, h = bc_address_to_hash_160(addr)
340     except Exception:
341         return False
342     return addr == hash_160_to_bc_address(h, addrtype)
343
344
345 def is_private_key(key):
346     try:
347         k = ASecretToSecret(key)
348         return k is not False
349     except:
350         return False
351
352
353 ########### end pywallet functions #######################
354
355 try:
356     from ecdsa.ecdsa import curve_secp256k1, generator_secp256k1
357 except Exception:
358     print "cannot import ecdsa.curve_secp256k1. You probably need to upgrade ecdsa.\nTry: sudo pip install --upgrade ecdsa"
359     exit()
360
361 from ecdsa.curves import SECP256k1
362 from ecdsa.ellipticcurve import Point
363 from ecdsa.util import string_to_number, number_to_string
364
365 def msg_magic(message):
366     varint = var_int(len(message))
367     encoded_varint = "".join([chr(int(varint[i:i+2], 16)) for i in xrange(0, len(varint), 2)])
368     return "\x18Bitcoin Signed Message:\n" + encoded_varint + message
369
370
371 def verify_message(address, signature, message):
372     try:
373         EC_KEY.verify_message(address, signature, message)
374         return True
375     except Exception as e:
376         print_error("Verification error: {0}".format(e))
377         return False
378
379
380 def encrypt_message(message, pubkey):
381     return EC_KEY.encrypt_message(message, pubkey.decode('hex'))
382
383
384 def chunks(l, n):
385     return [l[i:i+n] for i in xrange(0, len(l), n)]
386
387
388 def ECC_YfromX(x,curved=curve_secp256k1, odd=True):
389     _p = curved.p()
390     _a = curved.a()
391     _b = curved.b()
392     for offset in range(128):
393         Mx = x + offset
394         My2 = pow(Mx, 3, _p) + _a * pow(Mx, 2, _p) + _b % _p
395         My = pow(My2, (_p+1)/4, _p )
396
397         if curved.contains_point(Mx,My):
398             if odd == bool(My&1):
399                 return [My,offset]
400             return [_p-My,offset]
401     raise Exception('ECC_YfromX: No Y found')
402
403
404 def negative_point(P):
405     return Point( P.curve(), P.x(), -P.y(), P.order() )
406
407
408 def point_to_ser(P, comp=True ):
409     if comp:
410         return ( ('%02x'%(2+(P.y()&1)))+('%064x'%P.x()) ).decode('hex')
411     return ( '04'+('%064x'%P.x())+('%064x'%P.y()) ).decode('hex')
412
413
414 def ser_to_point(Aser):
415     curve = curve_secp256k1
416     generator = generator_secp256k1
417     _r  = generator.order()
418     assert Aser[0] in ['\x02','\x03','\x04']
419     if Aser[0] == '\x04':
420         return Point( curve, string_to_number(Aser[1:33]), string_to_number(Aser[33:]), _r )
421     Mx = string_to_number(Aser[1:])
422     return Point( curve, Mx, ECC_YfromX(Mx, curve, Aser[0]=='\x03')[0], _r )
423
424
425
426 class MyVerifyingKey(ecdsa.VerifyingKey):
427     @classmethod
428     def from_signature(klass, sig, recid, h, curve):
429         """ See http://www.secg.org/download/aid-780/sec1-v2.pdf, chapter 4.1.6 """
430         from ecdsa import util, numbertheory
431         import msqr
432         curveFp = curve.curve
433         G = curve.generator
434         order = G.order()
435         # extract r,s from signature
436         r, s = util.sigdecode_string(sig, order)
437         # 1.1
438         x = r + (recid/2) * order
439         # 1.3
440         alpha = ( x * x * x  + curveFp.a() * x + curveFp.b() ) % curveFp.p()
441         beta = msqr.modular_sqrt(alpha, curveFp.p())
442         y = beta if (beta - recid) % 2 == 0 else curveFp.p() - beta
443         # 1.4 the constructor checks that nR is at infinity
444         R = Point(curveFp, x, y, order)
445         # 1.5 compute e from message:
446         e = string_to_number(h)
447         minus_e = -e % order
448         # 1.6 compute Q = r^-1 (sR - eG)
449         inv_r = numbertheory.inverse_mod(r,order)
450         Q = inv_r * ( s * R + minus_e * G )
451         return klass.from_public_point( Q, curve )
452
453
454 class EC_KEY(object):
455     def __init__( self, k ):
456         secret = string_to_number(k)
457         self.pubkey = ecdsa.ecdsa.Public_key( generator_secp256k1, generator_secp256k1 * secret )
458         self.privkey = ecdsa.ecdsa.Private_key( self.pubkey, secret )
459         self.secret = secret
460
461     def get_public_key(self, compressed=True):
462         return point_to_ser(self.pubkey.point, compressed).encode('hex')
463
464     def sign_message(self, message, compressed, address):
465         private_key = ecdsa.SigningKey.from_secret_exponent( self.secret, curve = SECP256k1 )
466         public_key = private_key.get_verifying_key()
467         signature = private_key.sign_digest_deterministic( Hash( msg_magic(message) ), hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_string )
468         assert public_key.verify_digest( signature, Hash( msg_magic(message) ), sigdecode = ecdsa.util.sigdecode_string)
469         for i in range(4):
470             sig = base64.b64encode( chr(27 + i + (4 if compressed else 0)) + signature )
471             try:
472                 self.verify_message( address, sig, message)
473                 return sig
474             except Exception:
475                 continue
476         else:
477             raise Exception("error: cannot sign message")
478
479
480     @classmethod
481     def verify_message(self, address, signature, message):
482         sig = base64.b64decode(signature)
483         if len(sig) != 65: raise Exception("Wrong encoding")
484
485         nV = ord(sig[0])
486         if nV < 27 or nV >= 35:
487             raise Exception("Bad encoding")
488         if nV >= 31:
489             compressed = True
490             nV -= 4
491         else:
492             compressed = False
493
494         recid = nV - 27
495         h = Hash( msg_magic(message) )
496         public_key = MyVerifyingKey.from_signature( sig[1:], recid, h, curve = SECP256k1 )
497
498         # check public key
499         public_key.verify_digest( sig[1:], h, sigdecode = ecdsa.util.sigdecode_string)
500
501         # check that we get the original signing address
502         addr = public_key_to_bc_address( point_to_ser(public_key.pubkey.point, compressed) )
503         if address != addr:
504             raise Exception("Bad signature")
505
506
507     # ecies encryption/decryption methods; aes-256-cbc is used as the cipher; hmac-sha256 is used as the mac
508
509     @classmethod
510     def encrypt_message(self, message, pubkey):
511
512         pk = ser_to_point(pubkey)
513         if not ecdsa.ecdsa.point_is_valid(generator_secp256k1, pk.x(), pk.y()):
514             raise Exception('invalid pubkey')
515
516         ephemeral_exponent = number_to_string(ecdsa.util.randrange(pow(2,256)), generator_secp256k1.order())
517         ephemeral = EC_KEY(ephemeral_exponent)
518
519         ecdh_key = (pk * ephemeral.privkey.secret_multiplier).x()
520         ecdh_key = ('%064x' % ecdh_key).decode('hex')
521         key = hashlib.sha512(ecdh_key).digest()
522         key_e, key_m = key[:32], key[32:]
523
524         iv_ciphertext = aes.encryptData(key_e, message)
525
526         ephemeral_pubkey = ephemeral.get_public_key(compressed=True).decode('hex')
527         encrypted = 'BIE1' + ephemeral_pubkey + iv_ciphertext
528         mac = hmac.new(key_m, encrypted, hashlib.sha256).digest()
529
530         return base64.b64encode(encrypted + mac)
531
532
533     def decrypt_message(self, encrypted):
534
535         encrypted = base64.b64decode(encrypted)
536
537         if len(encrypted) < 85:
538             raise Exception('invalid ciphertext: length')
539
540         magic = encrypted[:4]
541         ephemeral_pubkey = encrypted[4:37]
542         iv_ciphertext = encrypted[37:-32]
543         mac = encrypted[-32:]
544
545         if magic != 'BIE1':
546             raise Exception('invalid ciphertext: invalid magic bytes')
547
548         try:
549             ephemeral_pubkey = ser_to_point(ephemeral_pubkey)
550         except AssertionError, e:
551             raise Exception('invalid ciphertext: invalid ephemeral pubkey')
552
553         if not ecdsa.ecdsa.point_is_valid(generator_secp256k1, ephemeral_pubkey.x(), ephemeral_pubkey.y()):
554             raise Exception('invalid ciphertext: invalid ephemeral pubkey')
555
556         ecdh_key = (ephemeral_pubkey * self.privkey.secret_multiplier).x()
557         ecdh_key = ('%064x' % ecdh_key).decode('hex')
558         key = hashlib.sha512(ecdh_key).digest()
559         key_e, key_m = key[:32], key[32:]
560         if mac != hmac.new(key_m, encrypted[:-32], hashlib.sha256).digest():
561             raise Exception('invalid ciphertext: invalid mac')
562
563         return aes.decryptData(key_e, iv_ciphertext)
564
565
566 ###################################### BIP32 ##############################
567
568 random_seed = lambda n: "%032x"%ecdsa.util.randrange( pow(2,n) )
569 BIP32_PRIME = 0x80000000
570
571
572 def get_pubkeys_from_secret(secret):
573     # public key
574     private_key = ecdsa.SigningKey.from_string( secret, curve = SECP256k1 )
575     public_key = private_key.get_verifying_key()
576     K = public_key.to_string()
577     K_compressed = GetPubKey(public_key.pubkey,True)
578     return K, K_compressed
579
580
581 # Child private key derivation function (from master private key)
582 # k = master private key (32 bytes)
583 # c = master chain code (extra entropy for key derivation) (32 bytes)
584 # n = the index of the key we want to derive. (only 32 bits will be used)
585 # If n is negative (i.e. the 32nd bit is set), the resulting private key's
586 #  corresponding public key can NOT be determined without the master private key.
587 # However, if n is positive, the resulting private key's corresponding
588 #  public key can be determined without the master private key.
589 def CKD_priv(k, c, n):
590     is_prime = n & BIP32_PRIME
591     return _CKD_priv(k, c, rev_hex(int_to_hex(n,4)).decode('hex'), is_prime)
592
593 def _CKD_priv(k, c, s, is_prime):
594     import hmac
595     from ecdsa.util import string_to_number, number_to_string
596     order = generator_secp256k1.order()
597     keypair = EC_KEY(k)
598     cK = GetPubKey(keypair.pubkey,True)
599     data = chr(0) + k + s if is_prime else cK + s
600     I = hmac.new(c, data, hashlib.sha512).digest()
601     k_n = number_to_string( (string_to_number(I[0:32]) + string_to_number(k)) % order , order )
602     c_n = I[32:]
603     return k_n, c_n
604
605 # Child public key derivation function (from public key only)
606 # K = master public key
607 # c = master chain code
608 # n = index of key we want to derive
609 # This function allows us to find the nth public key, as long as n is
610 #  non-negative. If n is negative, we need the master private key to find it.
611 def CKD_pub(cK, c, n):
612     if n & BIP32_PRIME: raise
613     return _CKD_pub(cK, c, rev_hex(int_to_hex(n,4)).decode('hex'))
614
615 # helper function, callable with arbitrary string
616 def _CKD_pub(cK, c, s):
617     import hmac
618     from ecdsa.util import string_to_number, number_to_string
619     order = generator_secp256k1.order()
620     I = hmac.new(c, cK + s, hashlib.sha512).digest()
621     curve = SECP256k1
622     pubkey_point = string_to_number(I[0:32])*curve.generator + ser_to_point(cK)
623     public_key = ecdsa.VerifyingKey.from_public_point( pubkey_point, curve = SECP256k1 )
624     c_n = I[32:]
625     cK_n = GetPubKey(public_key.pubkey,True)
626     return cK_n, c_n
627
628
629
630 def deserialize_xkey(xkey):
631     xkey = DecodeBase58Check(xkey)
632     assert len(xkey) == 78
633     assert xkey[0:4].encode('hex') in ["0488ade4", "0488b21e"]
634     depth = ord(xkey[4])
635     fingerprint = xkey[5:9]
636     child_number = xkey[9:13]
637     c = xkey[13:13+32]
638     if xkey[0:4].encode('hex') == "0488ade4":
639         K_or_k = xkey[13+33:]
640     else:
641         K_or_k = xkey[13+32:]
642     return depth, fingerprint, child_number, c, K_or_k
643
644
645
646 def bip32_root(seed):
647     import hmac
648     seed = seed.decode('hex')
649     I = hmac.new("Bitcoin seed", seed, hashlib.sha512).digest()
650     master_k = I[0:32]
651     master_c = I[32:]
652     K, cK = get_pubkeys_from_secret(master_k)
653     xprv = ("0488ADE4" + "00" + "00000000" + "00000000").decode("hex") + master_c + chr(0) + master_k
654     xpub = ("0488B21E" + "00" + "00000000" + "00000000").decode("hex") + master_c + cK
655     return EncodeBase58Check(xprv), EncodeBase58Check(xpub)
656
657
658
659 def bip32_private_derivation(xprv, branch, sequence):
660     depth, fingerprint, child_number, c, k = deserialize_xkey(xprv)
661     assert sequence.startswith(branch)
662     sequence = sequence[len(branch):]
663     for n in sequence.split('/'):
664         if n == '': continue
665         i = int(n[:-1]) + BIP32_PRIME if n[-1] == "'" else int(n)
666         parent_k = k
667         k, c = CKD_priv(k, c, i)
668         depth += 1
669
670     _, parent_cK = get_pubkeys_from_secret(parent_k)
671     fingerprint = hash_160(parent_cK)[0:4]
672     child_number = ("%08X"%i).decode('hex')
673     K, cK = get_pubkeys_from_secret(k)
674     xprv = "0488ADE4".decode('hex') + chr(depth) + fingerprint + child_number + c + chr(0) + k
675     xpub = "0488B21E".decode('hex') + chr(depth) + fingerprint + child_number + c + cK
676     return EncodeBase58Check(xprv), EncodeBase58Check(xpub)
677
678
679
680 def bip32_public_derivation(xpub, branch, sequence):
681     depth, fingerprint, child_number, c, cK = deserialize_xkey(xpub)
682     assert sequence.startswith(branch)
683     sequence = sequence[len(branch):]
684     for n in sequence.split('/'):
685         if n == '': continue
686         i = int(n)
687         parent_cK = cK
688         cK, c = CKD_pub(cK, c, i)
689         depth += 1
690
691     fingerprint = hash_160(parent_cK)[0:4]
692     child_number = ("%08X"%i).decode('hex')
693     xpub = "0488B21E".decode('hex') + chr(depth) + fingerprint + child_number + c + cK
694     return EncodeBase58Check(xpub)
695
696
697
698
699 def bip32_private_key(sequence, k, chain):
700     for i in sequence:
701         k, chain = CKD_priv(k, chain, i)
702     return SecretToASecret(k, True)
703
704
705
706
707