/test_framework/segwit_addr.py

https://github.com/bitcoinops/taproot-workshop · Python · 124 lines · 90 code · 19 blank · 15 comment · 47 complexity · 9a5e0c5478bb209c30faadba54de2df4 MD5 · raw file

  1. #!/usr/bin/env python3
  2. # Copyright (c) 2017 Pieter Wuille
  3. # Distributed under the MIT software license, see the accompanying
  4. # file COPYING or http://www.opensource.org/licenses/mit-license.php.
  5. """Reference implementation for Bech32/Bech32m and segwit addresses."""
  6. from enum import Enum
  7. CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
  8. BECH32_CONST = 1
  9. BECH32M_CONST = 0x2bc830a3
  10. class Encoding(Enum):
  11. """Enumeration type to list the various supported encodings."""
  12. BECH32 = 1
  13. BECH32M = 2
  14. def bech32_polymod(values):
  15. """Internal function that computes the Bech32 checksum."""
  16. generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
  17. chk = 1
  18. for value in values:
  19. top = chk >> 25
  20. chk = (chk & 0x1ffffff) << 5 ^ value
  21. for i in range(5):
  22. chk ^= generator[i] if ((top >> i) & 1) else 0
  23. return chk
  24. def bech32_hrp_expand(hrp):
  25. """Expand the HRP into values for checksum computation."""
  26. return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp]
  27. def bech32_verify_checksum(hrp, data):
  28. """Verify a checksum given HRP and converted data characters."""
  29. check = bech32_polymod(bech32_hrp_expand(hrp) + data)
  30. if check == BECH32_CONST:
  31. return Encoding.BECH32
  32. elif check == BECH32M_CONST:
  33. return Encoding.BECH32M
  34. else:
  35. return None
  36. def bech32_create_checksum(encoding, hrp, data):
  37. """Compute the checksum values given HRP and data."""
  38. values = bech32_hrp_expand(hrp) + data
  39. const = BECH32M_CONST if encoding == Encoding.BECH32M else BECH32_CONST
  40. polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ const
  41. return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)]
  42. def bech32_encode(encoding, hrp, data):
  43. """Compute a Bech32 or Bech32m string given HRP and data values."""
  44. combined = data + bech32_create_checksum(encoding, hrp, data)
  45. return hrp + '1' + ''.join([CHARSET[d] for d in combined])
  46. def bech32_decode(bech):
  47. """Validate a Bech32/Bech32m string, and determine HRP and data."""
  48. if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or
  49. (bech.lower() != bech and bech.upper() != bech)):
  50. return (None, None, None)
  51. bech = bech.lower()
  52. pos = bech.rfind('1')
  53. if pos < 1 or pos + 7 > len(bech) or len(bech) > 90:
  54. return (None, None, None)
  55. if not all(x in CHARSET for x in bech[pos+1:]):
  56. return (None, None, None)
  57. hrp = bech[:pos]
  58. data = [CHARSET.find(x) for x in bech[pos+1:]]
  59. encoding = bech32_verify_checksum(hrp, data)
  60. if encoding is None:
  61. return (None, None, None)
  62. return (encoding, hrp, data[:-6])
  63. def convertbits(data, frombits, tobits, pad=True):
  64. """General power-of-2 base conversion."""
  65. acc = 0
  66. bits = 0
  67. ret = []
  68. maxv = (1 << tobits) - 1
  69. max_acc = (1 << (frombits + tobits - 1)) - 1
  70. for value in data:
  71. if value < 0 or (value >> frombits):
  72. return None
  73. acc = ((acc << frombits) | value) & max_acc
  74. bits += frombits
  75. while bits >= tobits:
  76. bits -= tobits
  77. ret.append((acc >> bits) & maxv)
  78. if pad:
  79. if bits:
  80. ret.append((acc << (tobits - bits)) & maxv)
  81. elif bits >= frombits or ((acc << (tobits - bits)) & maxv):
  82. return None
  83. return ret
  84. def decode_segwit_address(hrp, addr):
  85. """Decode a segwit address."""
  86. encoding, hrpgot, data = bech32_decode(addr)
  87. if hrpgot != hrp:
  88. return (None, None)
  89. decoded = convertbits(data[1:], 5, 8, False)
  90. if decoded is None or len(decoded) < 2 or len(decoded) > 40:
  91. return (None, None)
  92. if data[0] > 16:
  93. return (None, None)
  94. if data[0] == 0 and len(decoded) != 20 and len(decoded) != 32:
  95. return (None, None)
  96. if (data[0] == 0 and encoding != Encoding.BECH32) or (data[0] != 0 and encoding != Encoding.BECH32M):
  97. return (None, None)
  98. return (data[0], decoded)
  99. def encode_segwit_address(hrp, witver, witprog):
  100. """Encode a segwit address."""
  101. encoding = Encoding.BECH32 if witver == 0 else Encoding.BECH32M
  102. ret = bech32_encode(encoding, hrp, [witver] + convertbits(witprog, 8, 5))
  103. if decode_segwit_address(hrp, ret) == (None, None):
  104. return None
  105. return ret