bitcoin.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #!/usr/bin/env python
  2. #
  3. # MMGen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2016 Philemon <mmgen-py@yandex.com>
  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. bitcoin.py: Bitcoin address/key conversion functions
  20. """
  21. import ecdsa
  22. from binascii import hexlify, unhexlify
  23. from hashlib import sha256
  24. from hashlib import new as hashlib_new
  25. import sys
  26. # From electrum:
  27. # secp256k1, http://www.oid-info.com/get/1.3.132.0.10
  28. _p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2FL
  29. _r = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141L
  30. _b = 0x0000000000000000000000000000000000000000000000000000000000000007L
  31. _a = 0x0000000000000000000000000000000000000000000000000000000000000000L
  32. _Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798L
  33. _Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8L
  34. _curve_secp256k1 = ecdsa.ellipticcurve.CurveFp(_p,_a,_b)
  35. _generator_secp256k1 = ecdsa.ellipticcurve.Point(_curve_secp256k1,_Gx,_Gy,_r)
  36. _oid_secp256k1 = (1,3,132,0,10)
  37. _secp256k1 = ecdsa.curves.Curve('secp256k1',_curve_secp256k1,_generator_secp256k1,_oid_secp256k1)
  38. b58a='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
  39. # From en.bitcoin.it:
  40. # The Base58 encoding used is home made, and has some differences.
  41. # Especially, leading zeroes are kept as single zeroes when conversion
  42. # happens.
  43. #
  44. # Test: 5JbQQTs3cnoYN9vDYaGY6nhQ1DggVsY4FJNBUfEfpSQqrEp3srk
  45. #
  46. # The 'zero address':
  47. # 1111111111111111111114oLvT2 (use step2 = ('0' * 40) to generate)
  48. from mmgen.globalvars import g
  49. def pubhex2hexaddr(pubhex):
  50. step1 = sha256(unhexlify(pubhex)).digest()
  51. return hashlib_new('ripemd160',step1).hexdigest()
  52. def hexaddr2addr(hexaddr,p2sh=False):
  53. # devdoc/ref_transactions.md:
  54. hexaddr2 = ('00','6f','05','c4')[g.testnet+(2*p2sh)] + hexaddr
  55. step1 = sha256(unhexlify(hexaddr2)).digest()
  56. step2 = sha256(step1).hexdigest()
  57. pubkey = hexaddr2 + step2[:8]
  58. lzeroes = (len(hexaddr2) - len(hexaddr2.lstrip('0'))) / 2
  59. return ('1' * lzeroes) + _numtob58(int(pubkey,16))
  60. def verify_addr(addr,verbose=False,return_hex=False):
  61. for vers_num,ldigit in ('00','1'),('05','3'),('6f','mn'),('c4','2'):
  62. if addr[0] not in ldigit: continue
  63. num = _b58tonum(addr)
  64. if num == False: break
  65. addr_hex = '{:050x}'.format(num)
  66. if addr_hex[:2] != vers_num: continue
  67. step1 = sha256(unhexlify(addr_hex[:42])).digest()
  68. step2 = sha256(step1).hexdigest()
  69. if step2[:8] == addr_hex[42:]:
  70. return addr_hex[2:42] if return_hex else True
  71. else:
  72. if verbose: Msg("Invalid checksum in address '%s'" % addr)
  73. break
  74. if verbose: Msg("Invalid address '%s'" % addr)
  75. return False
  76. # Reworked code from here:
  77. def _numtob58(num):
  78. ret = []
  79. while num:
  80. ret.append(b58a[num % 58])
  81. num /= 58
  82. return ''.join(ret)[::-1]
  83. def _b58tonum(b58num):
  84. for i in b58num:
  85. if not i in b58a: return False
  86. return sum([b58a.index(n) * (58**i) for i,n in enumerate(list(b58num[::-1]))])
  87. # The following are MMGen internal (non-Bitcoin) b58 functions
  88. # Drop-in replacements for b64encode() and b64decode():
  89. # (well, not exactly: they yield numeric but not bytewise equivalence)
  90. def b58encode(s):
  91. if s == '': return ''
  92. num = int(hexlify(s),16)
  93. return _numtob58(num)
  94. def b58decode(b58num):
  95. if b58num == '': return ''
  96. # Zap all spaces:
  97. # Use translate() only with str, not unicode
  98. num = _b58tonum(str(b58num).translate(None,' \t\n\r'))
  99. if num == False: return False
  100. out = u'{:x}'.format(num)
  101. return unhexlify(u'0'*(len(out)%2) + out)
  102. # These yield bytewise equivalence in our special cases:
  103. bin_lens = 16,24,32
  104. b58_lens = 22,33,44
  105. def _b58_pad(s,a,b,pad,f,w):
  106. try:
  107. outlen = b[a.index(len(s))]
  108. except:
  109. Msg('_b58_pad() accepts only %s %s bytes long '\
  110. '(input was %s bytes)' % (w,','.join([str(i) for i in a]),len(s)))
  111. return False
  112. out = f(s)
  113. if out == False: return False
  114. return '%s%s' % (pad * (outlen - len(out)), out)
  115. def b58encode_pad(s):
  116. return _b58_pad(s,
  117. a=bin_lens,b=b58_lens,pad='1',f=b58encode,w='binary strings')
  118. def b58decode_pad(s):
  119. return _b58_pad(s,
  120. a=b58_lens,b=bin_lens,pad='\0',f=b58decode,w='base 58 numbers')
  121. # Compressed address support:
  122. def wif2hex(wif):
  123. compressed = wif[0] != ('5','9')[g.testnet]
  124. idx = (66,68)[bool(compressed)]
  125. num = _b58tonum(wif)
  126. if num == False: return False
  127. key = '{:x}'.format(num)
  128. if compressed and key[66:68] != '01': return False
  129. round1 = sha256(unhexlify(key[:idx])).digest()
  130. round2 = sha256(round1).hexdigest()
  131. return key[2:66] if (key[:2] == ('80','ef')[g.testnet] and key[idx:] == round2[:8]) else False
  132. def hex2wif(hexpriv,compressed=False):
  133. step1 = ('80','ef')[g.testnet] + hexpriv + ('','01')[bool(compressed)]
  134. step2 = sha256(unhexlify(step1)).digest()
  135. step3 = sha256(step2).hexdigest()
  136. key = step1 + step3[:8]
  137. return _numtob58(int(key,16))
  138. # devdoc/guide_wallets.md:
  139. # Uncompressed public keys start with 0x04; compressed public keys begin with
  140. # 0x03 or 0x02 depending on whether they're greater or less than the midpoint
  141. # of the curve.
  142. def privnum2pubhex(numpriv,compressed=False):
  143. pko = ecdsa.SigningKey.from_secret_exponent(numpriv,_secp256k1)
  144. # pubkey = 32-byte X coord + 32-byte Y coord (unsigned big-endian)
  145. pubkey = hexlify(pko.get_verifying_key().to_string())
  146. if compressed: # discard Y coord, replace with appropriate version byte
  147. # even Y: <0, odd Y: >0 -- https://bitcointalk.org/index.php?topic=129652.0
  148. p = ('03','02')[pubkey[-1] in '02468ace']
  149. return p+pubkey[:64]
  150. else:
  151. return '04'+pubkey
  152. def privnum2addr(numpriv,compressed=False):
  153. return hexaddr2addr(pubhex2hexaddr(privnum2pubhex(numpriv,compressed)))