1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|
# Copyright (C) The python-bitcoinlib developers
#
# This file is part of python-bitcoinlib.
#
# It is subject to the license terms in the LICENSE file found in the top-level
# directory of this distribution.
#
# No part of python-bitcoinlib, including this file, may be copied, modified,
# propagated, or distributed except according to the terms contained in the
# LICENSE file.
import json
import os
import unittest
from binascii import unhexlify
from bitcoin.core.script import CScript, OP_0, OP_1, OP_16
from bitcoin.bech32 import *
from bitcoin.segwit_addr import encode, decode
BECH32_ENCODE_DECODE_JSON = '''
[
["0014751e76e8199196d454941c45d1b3a323f1433bd6", "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4"],
["00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262", "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7"],
["5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6", "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx"],
["6002751e", "BC1SW50QA3JX3S"],
["5210751e76e8199196d454941c45d1b3a323", "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj"],
["0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433", "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy"]
]
'''
BECH32_INVALID = '''
[
["tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty", "Invalid human-readable part"],
["bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", "Invalid checksum"],
["BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", "Invalid witness version"],
["bc1rw5uspcuh", "Invalid program length"],
["bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90", "Invalid program length"],
["BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", "Invalid program length for witness version 0 (per BIP141)"],
["tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7", "Mixed case"],
["bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du", "zero padding of more than 4 bits"],
["tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv", "Non-zero padding in 8-to-5 conversion"],
["bc1gmk9yu", "Empty data section"]
]
'''
def load_test_vectors(name):
test_vectors = {
'bech32_encode_decode': BECH32_ENCODE_DECODE_JSON,
'bech32_invalid': BECH32_INVALID,
}
for testcase in json.loads(test_vectors[name]):
yield testcase
def to_scriptPubKey(witver, witprog):
"""Decoded bech32 address to script"""
return CScript([witver]) + CScript(bytes(witprog))
class Test_bech32(unittest.TestCase):
def op_decode(self, witver):
"""OP encoding to int"""
if witver == OP_0:
return 0
if OP_1 <= witver <= OP_16:
return witver - OP_1 + 1
self.fail('Wrong witver: %d' % witver)
def test_encode_decode(self):
for exp_bin, exp_bech32 in load_test_vectors('bech32_encode_decode'):
exp_bin = unhexlify(exp_bin.encode('utf8'))
witver = self.op_decode(exp_bin[0])
hrp = exp_bech32[:exp_bech32.rindex('1')].lower()
self.assertEqual(exp_bin[1], len(exp_bin[2:]))
act_bech32 = encode(hrp, witver, exp_bin[2:])
act_bin = decode(hrp, exp_bech32)
self.assertEqual(act_bech32.lower(), exp_bech32.lower())
self.assertEqual(to_scriptPubKey(*act_bin), bytes(exp_bin))
class Test_CBech32Data(unittest.TestCase):
def test_from_data(self):
b = CBech32Data.from_bytes(0, unhexlify('751e76e8199196d454941c45d1b3a323f1433bd6'))
self.assertEqual(b.witver, 0)
self.assertEqual(str(b).upper(), 'BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4')
@unittest.skip('Bad JSON string parsing')
def test_invalid_bech32_exception(self):
for invalid in load_test_vectors("bech32_invalid"):
msg = '%r should have raised Bech32Error but did not' % invalid
with self.assertRaises(Bech32Error, msg=msg):
CBech32Data(invalid)
|