common.py 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. #!/usr/bin/env python3
  2. #
  3. # MMGen Wallet, a terminal-based cryptocurrency wallet
  4. # Copyright (C)2013-2025 The MMGen Project <mmgen@tuta.io>
  5. # Licensed under the GNU General Public License, Version 3:
  6. # https://www.gnu.org/licenses
  7. # Public project repositories:
  8. # https://github.com/mmgen/mmgen-wallet
  9. # https://gitlab.com/mmgen/mmgen-wallet
  10. """
  11. proto.btc.common: Shared Bitcoin functions and constants
  12. """
  13. import hashlib
  14. b58a = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
  15. def hash160(in_bytes): # OP_HASH160
  16. return hashlib.new('ripemd160', hashlib.sha256(in_bytes).digest()).digest()
  17. def hash256(in_bytes): # OP_HASH256
  18. return hashlib.sha256(hashlib.sha256(in_bytes).digest()).digest()
  19. # From en.bitcoin.it:
  20. # The Base58 encoding used is home made, and has some differences.
  21. # Especially, leading zeroes are kept as single zeroes when conversion happens.
  22. # Test: 5JbQQTs3cnoYN9vDYaGY6nhQ1DggVsY4FJNBUfEfpSQqrEp3srk
  23. # The 'zero address':
  24. # 1111111111111111111114oLvT2 (pubkeyhash = '\0'*20)
  25. def b58chk_encode(in_bytes):
  26. lzeroes = len(in_bytes) - len(in_bytes.lstrip(b'\x00'))
  27. def do_enc(n):
  28. while n:
  29. yield b58a[n % 58]
  30. n //= 58
  31. return ('1' * lzeroes) + ''.join(do_enc(int.from_bytes(in_bytes+hash256(in_bytes)[:4], 'big')))[::-1]
  32. def b58chk_decode(s):
  33. lzeroes = len(s) - len(s.lstrip('1'))
  34. res = sum(b58a.index(ch) * 58**n for n, ch in enumerate(s[::-1]))
  35. bl = res.bit_length()
  36. out = b'\x00' * lzeroes + res.to_bytes(bl//8 + bool(bl%8), 'big')
  37. if out[-4:] != hash256(out[:-4])[:4]:
  38. raise ValueError('b58chk_decode(): incorrect checksum')
  39. return out[:-4]