Skip to content

Commit 10f629e

Browse files
committed
Merge bitcoin/bitcoin#24576: contrib: testgen: remove redundant base58 implementation
65c49ac test: throw `ValueError` for invalid base58 checksum (Sebastian Falbesoner) 219d2c7 contrib: testgen: use base58 methods from test framework (Sebastian Falbesoner) 605fecf scripted-diff: rename `chars` to `b58chars` in test_framework.address (Sebastian Falbesoner) 11c63e3 contrib: testgen: import OP_* constants from test framework (Sebastian Falbesoner) 7d755bb contrib: testgen: avoid need for manually setting PYTHONPATH (Sebastian Falbesoner) Pull request description: This PR removes the redundant base58 implementation [contrib/testgen/base58.py](https://github.com/bitcoin/bitcoin/blob/master/contrib/testgen/base58.py) for the test generation script `gen_key_io_test_vectors.py` and uses the one from the test framework instead. Additionally, three other cleanups/improvements are done: - import script operator constants `OP_*` from test framework instead of manually defining them - add Python path to test framework directly in the script (via `sys.path.append(...)`) instead of needing the caller to specify `PYTHONPATH=...` on the command line (the same approach is done for the signet miner and the message capture scripts) - rename `chars` to `b58chars` in the test_framework.address module (is more explicit and makes the diff for the base58 replacement smaller) ACKs for top commit: laanwj: Code review ACK 65c49ac Tree-SHA512: 92e1534cc320cd56262bf455de7231c6ec821bfcd0ed58aa5718271ecec1a89df7951bf31527a2306db6398e7f2664d2ff8508200c28163c0b164d3f5aaf8b0e
2 parents d906329 + 65c49ac commit 10f629e

File tree

4 files changed

+30
-148
lines changed

4 files changed

+30
-148
lines changed

contrib/testgen/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ Utilities to generate test vectors for the data-driven Bitcoin tests.
44

55
Usage:
66

7-
PYTHONPATH=../../test/functional/test_framework ./gen_key_io_test_vectors.py valid 70 > ../../src/test/data/key_io_valid.json
8-
PYTHONPATH=../../test/functional/test_framework ./gen_key_io_test_vectors.py invalid 70 > ../../src/test/data/key_io_invalid.json
7+
./gen_key_io_test_vectors.py valid 70 > ../../src/test/data/key_io_valid.json
8+
./gen_key_io_test_vectors.py invalid 70 > ../../src/test/data/key_io_invalid.json

contrib/testgen/base58.py

Lines changed: 0 additions & 115 deletions
This file was deleted.

contrib/testgen/gen_key_io_test_vectors.py

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
#!/usr/bin/env python3
2-
# Copyright (c) 2012-2021 The Bitcoin Core developers
2+
# Copyright (c) 2012-2022 The Bitcoin Core developers
33
# Distributed under the MIT software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
'''
66
Generate valid and invalid base58/bech32(m) address and private key test vectors.
77
88
Usage:
9-
PYTHONPATH=../../test/functional/test_framework ./gen_key_io_test_vectors.py valid 70 > ../../src/test/data/key_io_valid.json
10-
PYTHONPATH=../../test/functional/test_framework ./gen_key_io_test_vectors.py invalid 70 > ../../src/test/data/key_io_invalid.json
9+
./gen_key_io_test_vectors.py valid 70 > ../../src/test/data/key_io_valid.json
10+
./gen_key_io_test_vectors.py invalid 70 > ../../src/test/data/key_io_invalid.json
1111
'''
12-
# 2012 Wladimir J. van der Laan
13-
# Released under MIT License
14-
import os
12+
1513
from itertools import islice
16-
from base58 import b58encode_chk, b58decode_chk, b58chars
14+
import os
1715
import random
18-
from segwit_addr import bech32_encode, decode_segwit_address, convertbits, CHARSET, Encoding
16+
import sys
17+
18+
sys.path.append(os.path.join(os.path.dirname(__file__), '../../test/functional'))
19+
20+
from test_framework.address import base58_to_byte, byte_to_base58, b58chars # noqa: E402
21+
from 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: E402
22+
from test_framework.segwit_addr import bech32_encode, decode_segwit_address, convertbits, CHARSET, Encoding # noqa: E402
1923

2024
# key types
2125
PUBKEY_ADDRESS = 0
@@ -29,16 +33,6 @@
2933
PRIVKEY_REGTEST = 239
3034

3135
# script
32-
OP_0 = 0x00
33-
OP_1 = 0x51
34-
OP_2 = 0x52
35-
OP_3 = 0x53
36-
OP_16 = 0x60
37-
OP_DUP = 0x76
38-
OP_EQUAL = 0x87
39-
OP_EQUALVERIFY = 0x88
40-
OP_HASH160 = 0xa9
41-
OP_CHECKSIG = 0xac
4236
pubkey_prefix = (OP_DUP, OP_HASH160, 20)
4337
pubkey_suffix = (OP_EQUALVERIFY, OP_CHECKSIG)
4438
script_prefix = (OP_HASH160, 20)
@@ -114,8 +108,10 @@ def is_valid(v):
114108
'''Check vector v for validity'''
115109
if len(set(v) - set(b58chars)) > 0:
116110
return is_valid_bech32(v)
117-
result = b58decode_chk(v)
118-
if result is None:
111+
try:
112+
payload, version = base58_to_byte(v)
113+
result = bytes([version]) + payload
114+
except ValueError: # thrown if checksum doesn't match
119115
return is_valid_bech32(v)
120116
for template in templates:
121117
prefix = bytearray(template[0])
@@ -139,7 +135,8 @@ def gen_valid_base58_vector(template):
139135
suffix = bytearray(template[2])
140136
dst_prefix = bytearray(template[4])
141137
dst_suffix = bytearray(template[5])
142-
rv = b58encode_chk(prefix + payload + suffix)
138+
assert len(prefix) == 1
139+
rv = byte_to_base58(payload + suffix, prefix[0])
143140
return rv, dst_prefix + payload + dst_suffix
144141

145142
def gen_valid_bech32_vector(template):
@@ -190,7 +187,8 @@ def gen_invalid_base58_vector(template):
190187
else:
191188
suffix = bytearray(template[2])
192189

193-
val = b58encode_chk(prefix + payload + suffix)
190+
assert len(prefix) == 1
191+
val = byte_to_base58(payload + suffix, prefix[0])
194192
if random.randint(0,10)<1: # line corruption
195193
if randbool(): # add random character to end
196194
val += random.choice(b58chars)
@@ -250,7 +248,6 @@ def gen_invalid_vectors():
250248
yield val,
251249

252250
if __name__ == '__main__':
253-
import sys
254251
import json
255252
iters = {'valid':gen_valid_vectors, 'invalid':gen_invalid_vectors}
256253
try:

test/functional/test_framework/address.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class AddressType(enum.Enum):
3535
legacy = 'legacy' # P2PKH
3636

3737

38-
chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
38+
b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
3939

4040

4141
def create_deterministic_address_bcrt1_p2tr_op_true():
@@ -59,10 +59,10 @@ def byte_to_base58(b, version):
5959
b += hash256(b)[:4] # append checksum
6060
value = int.from_bytes(b, 'big')
6161
while value > 0:
62-
result = chars[value % 58] + result
62+
result = b58chars[value % 58] + result
6363
value //= 58
6464
while b[0] == 0:
65-
result = chars[0] + result
65+
result = b58chars[0] + result
6666
b = b[1:]
6767
return result
6868

@@ -76,23 +76,23 @@ def base58_to_byte(s):
7676
n = 0
7777
for c in s:
7878
n *= 58
79-
assert c in chars
80-
digit = chars.index(c)
79+
assert c in b58chars
80+
digit = b58chars.index(c)
8181
n += digit
8282
h = '%x' % n
8383
if len(h) % 2:
8484
h = '0' + h
8585
res = n.to_bytes((n.bit_length() + 7) // 8, 'big')
8686
pad = 0
8787
for c in s:
88-
if c == chars[0]:
88+
if c == b58chars[0]:
8989
pad += 1
9090
else:
9191
break
9292
res = b'\x00' * pad + res
9393

94-
# Assert if the checksum is invalid
95-
assert_equal(hash256(res[:-4])[:4], res[-4:])
94+
if hash256(res[:-4])[:4] != res[-4:]:
95+
raise ValueError('Invalid Base58Check checksum')
9696

9797
return res[1:-4], int(res[0])
9898

0 commit comments

Comments
 (0)