Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1#!/usr/bin/env python32# Copyright (c) 2012-present The Bitcoin Core developers3# Distributed under the MIT software license, see the accompanying4# file COPYING or http://www.opensource.org/licenses/mit-license.php.5'''6Generate valid and invalid base58/bech32(m) address and private key test vectors.7'''9from itertools import islice10import os11import random12import sys14sys.path.append(os.path.join(os.path.dirname(__file__), '../../test/functional'))16from test_framework.address import base58_to_byte, byte_to_base58, b58chars # noqa: E40217from test_framework.script import OP_0, OP_1, OP_2, OP_3, OP_16, OP_DUP, OP_EQUAL, OP_EQUALVERIFY, OP_HASH160, OP_CHECKSIG # noqa: E40218from test_framework.segwit_addr import bech32_encode, decode_segwit_address, convertbits, CHARSET, Encoding # noqa: E40220# key types21PUBKEY_ADDRESS = 022SCRIPT_ADDRESS = 523PUBKEY_ADDRESS_TEST = 11124SCRIPT_ADDRESS_TEST = 19625PUBKEY_ADDRESS_REGTEST = 11126SCRIPT_ADDRESS_REGTEST = 19627PRIVKEY = 12828PRIVKEY_TEST = 23929PRIVKEY_REGTEST = 23931# script32pubkey_prefix = (OP_DUP, OP_HASH160, 20)33pubkey_suffix = (OP_EQUALVERIFY, OP_CHECKSIG)34script_prefix = (OP_HASH160, 20)35script_suffix = (OP_EQUAL,)36p2wpkh_prefix = (OP_0, 20)37p2wsh_prefix = (OP_0, 32)38p2tr_prefix = (OP_1, 32)40metadata_keys = ['isPrivkey', 'chain', 'isCompressed', 'tryCaseFlip']41# templates for valid sequences42templates = [43# prefix, payload_size, suffix, metadata, output_prefix, output_suffix44# None = N/A45((PUBKEY_ADDRESS,), 20, (), (False, 'main', None, None), pubkey_prefix, pubkey_suffix),46((SCRIPT_ADDRESS,), 20, (), (False, 'main', None, None), script_prefix, script_suffix),47((PUBKEY_ADDRESS_TEST,), 20, (), (False, 'test', None, None), pubkey_prefix, pubkey_suffix),48((SCRIPT_ADDRESS_TEST,), 20, (), (False, 'test', None, None), script_prefix, script_suffix),49((PUBKEY_ADDRESS_TEST,), 20, (), (False, 'signet', None, None), pubkey_prefix, pubkey_suffix),50((SCRIPT_ADDRESS_TEST,), 20, (), (False, 'signet', None, None), script_prefix, script_suffix),51((PUBKEY_ADDRESS_REGTEST,), 20, (), (False, 'regtest', None, None), pubkey_prefix, pubkey_suffix),52((SCRIPT_ADDRESS_REGTEST,), 20, (), (False, 'regtest', None, None), script_prefix, script_suffix),53((PRIVKEY,), 32, (), (True, 'main', False, None), (), ()),54((PRIVKEY,), 32, (1,), (True, 'main', True, None), (), ()),55((PRIVKEY_TEST,), 32, (), (True, 'test', False, None), (), ()),56((PRIVKEY_TEST,), 32, (1,), (True, 'test', True, None), (), ()),57((PRIVKEY_TEST,), 32, (), (True, 'signet', False, None), (), ()),58((PRIVKEY_TEST,), 32, (1,), (True, 'signet', True, None), (), ()),59((PRIVKEY_REGTEST,), 32, (), (True, 'regtest', False, None), (), ()),60((PRIVKEY_REGTEST,), 32, (1,), (True, 'regtest', True, None), (), ())61]62# templates for valid bech32 sequences63bech32_templates = [64# hrp, version, witprog_size, metadata, encoding, output_prefix65('bc', 0, 20, (False, 'main', None, True), Encoding.BECH32, p2wpkh_prefix),66('bc', 0, 32, (False, 'main', None, True), Encoding.BECH32, p2wsh_prefix),67('bc', 1, 32, (False, 'main', None, True), Encoding.BECH32M, p2tr_prefix),68('bc', 2, 2, (False, 'main', None, True), Encoding.BECH32M, (OP_2, 2)),69('tb', 0, 20, (False, 'test', None, True), Encoding.BECH32, p2wpkh_prefix),70('tb', 0, 32, (False, 'test', None, True), Encoding.BECH32, p2wsh_prefix),71('tb', 1, 32, (False, 'test', None, True), Encoding.BECH32M, p2tr_prefix),72('tb', 3, 16, (False, 'test', None, True), Encoding.BECH32M, (OP_3, 16)),73('tb', 0, 20, (False, 'signet', None, True), Encoding.BECH32, p2wpkh_prefix),74('tb', 0, 32, (False, 'signet', None, True), Encoding.BECH32, p2wsh_prefix),75('tb', 1, 32, (False, 'signet', None, True), Encoding.BECH32M, p2tr_prefix),76('tb', 3, 32, (False, 'signet', None, True), Encoding.BECH32M, (OP_3, 32)),77('bcrt', 0, 20, (False, 'regtest', None, True), Encoding.BECH32, p2wpkh_prefix),78('bcrt', 0, 32, (False, 'regtest', None, True), Encoding.BECH32, p2wsh_prefix),79('bcrt', 1, 32, (False, 'regtest', None, True), Encoding.BECH32M, p2tr_prefix),80('bcrt', 16, 40, (False, 'regtest', None, True), Encoding.BECH32M, (OP_16, 40))81]82# templates for invalid bech32 sequences83bech32_ng_templates = [84# hrp, version, witprog_size, encoding, invalid_bech32, invalid_checksum, invalid_char85('tc', 0, 20, Encoding.BECH32, False, False, False),86('bt', 1, 32, Encoding.BECH32M, False, False, False),87('tb', 17, 32, Encoding.BECH32M, False, False, False),88('bcrt', 3, 1, Encoding.BECH32M, False, False, False),89('bc', 15, 41, Encoding.BECH32M, False, False, False),90('tb', 0, 16, Encoding.BECH32, False, False, False),91('bcrt', 0, 32, Encoding.BECH32, True, False, False),92('bc', 0, 16, Encoding.BECH32, True, False, False),93('tb', 0, 32, Encoding.BECH32, False, True, False),94('bcrt', 0, 20, Encoding.BECH32, False, False, True),95('bc', 0, 20, Encoding.BECH32M, False, False, False),96('tb', 0, 32, Encoding.BECH32M, False, False, False),97('bcrt', 0, 20, Encoding.BECH32M, False, False, False),98('bc', 1, 32, Encoding.BECH32, False, False, False),99('tb', 2, 16, Encoding.BECH32, False, False, False),100('bcrt', 16, 20, Encoding.BECH32, False, False, False),101]103def is_valid(v):104'''Check vector v for validity'''105if len(set(v) - set(b58chars)) > 0:106return is_valid_bech32(v)107try:108payload, version = base58_to_byte(v)109result = bytes([version]) + payload110except ValueError: # thrown if checksum doesn't match111return is_valid_bech32(v)112for template in templates:113prefix = bytearray(template[0])114suffix = bytearray(template[2])115if result.startswith(prefix) and result.endswith(suffix):116if (len(result) - len(prefix) - len(suffix)) == template[1]:117return True118return is_valid_bech32(v)120def is_valid_bech32(v):121'''Check vector v for bech32 validity'''122for hrp in ['bc', 'tb', 'bcrt']:123if decode_segwit_address(hrp, v) != (None, None):124return True125return False127def gen_valid_base58_vector(template):128'''Generate valid base58 vector'''129prefix = bytearray(template[0])130payload = rand_bytes(size=template[1])131suffix = bytearray(template[2])132dst_prefix = bytearray(template[4])133dst_suffix = bytearray(template[5])134assert len(prefix) == 1135rv = byte_to_base58(payload + suffix, prefix[0])136return rv, dst_prefix + payload + dst_suffix138def gen_valid_bech32_vector(template):139'''Generate valid bech32 vector'''140hrp = template[0]141witver = template[1]142witprog = rand_bytes(size=template[2])143encoding = template[4]144dst_prefix = bytearray(template[5])145rv = bech32_encode(encoding, hrp, [witver] + convertbits(witprog, 8, 5))146return rv, dst_prefix + witprog148def gen_valid_vectors():149'''Generate valid test vectors'''150glist = [gen_valid_base58_vector, gen_valid_bech32_vector]151tlist = [templates, bech32_templates]152while True:153for template, valid_vector_generator in [(t, g) for g, l in zip(glist, tlist) for t in l]:154rv, payload = valid_vector_generator(template)155assert is_valid(rv)156metadata = {x: y for x, y in zip(metadata_keys,template[3]) if y is not None}157hexrepr = payload.hex()158yield (rv, hexrepr, metadata)160def gen_invalid_base58_vector(template):161'''Generate possibly invalid vector'''162# kinds of invalid vectors:163# invalid prefix164# invalid payload length165# invalid (randomized) suffix (add random data)166# corrupt checksum167corrupt_prefix = randbool(0.2)168randomize_payload_size = randbool(0.2)169corrupt_suffix = randbool(0.2)171if corrupt_prefix:172prefix = rand_bytes(size=1)173else:174prefix = bytearray(template[0])176if randomize_payload_size:177payload = rand_bytes(size=max(int(random.expovariate(0.5)), 50))178else:179payload = rand_bytes(size=template[1])181if corrupt_suffix:182suffix = rand_bytes(size=len(template[2]))183else:184suffix = bytearray(template[2])186assert len(prefix) == 1187val = byte_to_base58(payload + suffix, prefix[0])188if random.randint(0,10)<1: # line corruption189if randbool(): # add random character to end190val += random.choice(b58chars)191else: # replace random character in the middle192n = random.randint(0, len(val))193val = val[0:n] + random.choice(b58chars) + val[n+1:]195return val197def gen_invalid_bech32_vector(template):198'''Generate possibly invalid bech32 vector'''199no_data = randbool(0.1)200to_upper = randbool(0.1)201hrp = template[0]202witver = template[1]203witprog = rand_bytes(size=template[2])204encoding = template[3]206if no_data:207rv = bech32_encode(encoding, hrp, [])208else:209data = [witver] + convertbits(witprog, 8, 5)210if template[4] and not no_data:211if template[2] % 5 in {2, 4}:212data[-1] |= 1213else:214data.append(0)215rv = bech32_encode(encoding, hrp, data)217if template[5]:218i = len(rv) - random.randrange(1, 7)219rv = rv[:i] + random.choice(CHARSET.replace(rv[i], '')) + rv[i + 1:]220if template[6]:221i = len(hrp) + 1 + random.randrange(0, len(rv) - len(hrp) - 4)222rv = rv[:i] + rv[i:i + 4].upper() + rv[i + 4:]224if to_upper:225rv = rv.swapcase()227return rv229def randbool(p = 0.5):230'''Return True with P(p)'''231return random.random() < p233def rand_bytes(*, size):234return bytearray(random.getrandbits(8) for _ in range(size))236def gen_invalid_vectors():237'''Generate invalid test vectors'''238# start with some manual edge-cases239yield "",240yield "x",241glist = [gen_invalid_base58_vector, gen_invalid_bech32_vector]242tlist = [templates, bech32_ng_templates]243while True:244for template, invalid_vector_generator in [(t, g) for g, l in zip(glist, tlist) for t in l]:245val = invalid_vector_generator(template)246if not is_valid(val):247yield val,249if __name__ == '__main__':250import json
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.