File: test_bech32.py

package info (click to toggle)
python-bitcoinlib 0.12.2-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 1,356 kB
  • sloc: python: 8,212; makefile: 132; sh: 6
file content (98 lines) | stat: -rw-r--r-- 3,968 bytes parent folder | download
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)