From eaf31ad2be268ba81c8be662d2102c1e898b1dc3 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 10 Jun 2020 10:23:46 -0400 Subject: [PATCH] Merge #19230: [TESTS] Move base58 to own module to break circular dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit c75de5da5fdd3a304f9da3d8a2e0370d1723ddd0 [TESTS] Move base58 to own module to break circular dependency (Pieter Wuille) Pull request description: I encountered difficulties with the test framework in #17977. This fixes them, and I think the change is generally useful. ACKs for top commit: laanwj: Code review ACK c75de5da5fdd3a304f9da3d8a2e0370d1723ddd0 MarcoFalke: ACK c75de5da5fdd3a304f9da3d8a2e0370d1723ddd0 according to --color-moved=dimmed-zebra this is a move-only apart from the imports 👒 Tree-SHA512: 9e0493de3e279074f0c70e92c959b73ae30479ad6f2083a3c6bbf4b0191d65ef94854559a5b7c904f5dadc5e93129ed00f6dc0a8ccce6ba7921cd45f7119f74b --- test/functional/test_framework/address.py | 68 +--------------------- test/functional/test_framework/base58.py | 70 +++++++++++++++++++++++ test/functional/test_framework/key.py | 2 +- test/functional/test_runner.py | 2 +- 4 files changed, 74 insertions(+), 68 deletions(-) create mode 100644 test/functional/test_framework/base58.py diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py index 96bb1d6d5c..441482ca9e 100644 --- a/test/functional/test_framework/address.py +++ b/test/functional/test_framework/address.py @@ -8,61 +8,16 @@ # # This file encodes and decodes BASE58 P2PKH and P2SH addresses # -import unittest -from .script import hash256, hash160, CScript +from .base58 import byte_to_base58 +from .script import hash160, CScript from .util import hex_str_to_bytes -from test_framework.util import assert_equal # Note unlike in bitcoin, this address isn't bech32 since we don't (at this time) support bech32. ADDRESS_BCRT1_UNSPENDABLE = 'yVg3NBUHNEhgDceqwVUjsZHreC5PBHnUo9' ADDRESS_BCRT1_UNSPENDABLE_DESCRIPTOR = 'addr(yVg3NBUHNEhgDceqwVUjsZHreC5PBHnUo9)#e5kt0jtk' ADDRESS_BCRT1_P2SH_OP_TRUE = '8zJctvfrzGZ5s1zQ3kagwyW1DsPYSQ4V2P' -chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' - - -def byte_to_base58(b, version): - result = '' - str = b.hex() - str = chr(version).encode('latin-1').hex() + str - checksum = hash256(hex_str_to_bytes(str)).hex() - str += checksum[:8] - value = int('0x'+str,0) - while value > 0: - result = chars[value % 58] + result - value //= 58 - while (str[:2] == '00'): - result = chars[0] + result - str = str[2:] - return result - - -def base58_to_byte(s, verify_checksum=True): - if not s: - return b'' - n = 0 - for c in s: - n *= 58 - assert c in chars - digit = chars.index(c) - n += digit - h = '%x' % n - if len(h) % 2: - h = '0' + h - res = n.to_bytes((n.bit_length() + 7) // 8, 'big') - pad = 0 - for c in s: - if c == chars[0]: - pad += 1 - else: - break - res = b'\x00' * pad + res - if verify_checksum: - assert_equal(hash256(res[:-4])[:4], res[-4:]) - - return res[1:-4], int(res[0]) - def keyhash_to_p2pkh(hash, main = False): assert len(hash) == 20 @@ -95,22 +50,3 @@ def check_script(script): if (type(script) is bytes or type(script) is CScript): return script assert False - - -class TestFrameworkScript(unittest.TestCase): - def test_base58encodedecode(self): - def check_base58(data, version): - self.assertEqual(base58_to_byte(byte_to_base58(data, version)), (data, version)) - - check_base58(b'\x1f\x8e\xa1p*{\xd4\x94\x1b\xca\tA\xb8R\xc4\xbb\xfe\xdb.\x05', 111) - check_base58(b':\x0b\x05\xf4\xd7\xf6l;\xa7\x00\x9fE50)l\x84\\\xc9\xcf', 111) - check_base58(b'A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 111) - check_base58(b'\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 111) - check_base58(b'\0\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 111) - check_base58(b'\0\0\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 111) - check_base58(b'\x1f\x8e\xa1p*{\xd4\x94\x1b\xca\tA\xb8R\xc4\xbb\xfe\xdb.\x05', 0) - check_base58(b':\x0b\x05\xf4\xd7\xf6l;\xa7\x00\x9fE50)l\x84\\\xc9\xcf', 0) - check_base58(b'A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 0) - check_base58(b'\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 0) - check_base58(b'\0\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 0) - check_base58(b'\0\0\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 0) diff --git a/test/functional/test_framework/base58.py b/test/functional/test_framework/base58.py new file mode 100644 index 0000000000..3dab3569d0 --- /dev/null +++ b/test/functional/test_framework/base58.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# Copyright (c) 2016-2020 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Encode BASE58.""" + +import unittest + +from .messages import hash256 +from .util import hex_str_to_bytes, assert_equal + +chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' + +def byte_to_base58(b, version): + result = '' + str = b.hex() + str = chr(version).encode('latin-1').hex() + str + checksum = hash256(hex_str_to_bytes(str)).hex() + str += checksum[:8] + value = int('0x'+str,0) + while value > 0: + result = chars[value % 58] + result + value //= 58 + while (str[:2] == '00'): + result = chars[0] + result + str = str[2:] + return result + +def base58_to_byte(s, verify_checksum=True): + if not s: + return b'' + n = 0 + for c in s: + n *= 58 + assert c in chars + digit = chars.index(c) + n += digit + h = '%x' % n + if len(h) % 2: + h = '0' + h + res = n.to_bytes((n.bit_length() + 7) // 8, 'big') + pad = 0 + for c in s: + if c == chars[0]: + pad += 1 + else: + break + res = b'\x00' * pad + res + if verify_checksum: + assert_equal(hash256(res[:-4])[:4], res[-4:]) + + return res[1:-4], int(res[0]) + +class TestFrameworkScript(unittest.TestCase): + def test_base58encodedecode(self): + def check_base58(data, version): + self.assertEqual(base58_to_byte(byte_to_base58(data, version)), (data, version)) + + check_base58(b'\x1f\x8e\xa1p*{\xd4\x94\x1b\xca\tA\xb8R\xc4\xbb\xfe\xdb.\x05', 111) + check_base58(b':\x0b\x05\xf4\xd7\xf6l;\xa7\x00\x9fE50)l\x84\\\xc9\xcf', 111) + check_base58(b'A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 111) + check_base58(b'\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 111) + check_base58(b'\0\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 111) + check_base58(b'\0\0\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 111) + check_base58(b'\x1f\x8e\xa1p*{\xd4\x94\x1b\xca\tA\xb8R\xc4\xbb\xfe\xdb.\x05', 0) + check_base58(b':\x0b\x05\xf4\xd7\xf6l;\xa7\x00\x9fE50)l\x84\\\xc9\xcf', 0) + check_base58(b'A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 0) + check_base58(b'\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 0) + check_base58(b'\0\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 0) + check_base58(b'\0\0\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 0) diff --git a/test/functional/test_framework/key.py b/test/functional/test_framework/key.py index 9529198809..4f571d952d 100644 --- a/test/functional/test_framework/key.py +++ b/test/functional/test_framework/key.py @@ -14,7 +14,7 @@ import random import unittest from test_framework.crypto import secp256k1 -from .address import byte_to_base58 +from .base58 import byte_to_base58 # Order of the secp256k1 curve ORDER = secp256k1.GE.ORDER diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 56f0faf9d6..9362afb88c 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -70,7 +70,7 @@ TEST_EXIT_SKIPPED = 77 # List of framework modules containing unit tests. Should be kept in sync with # the output of `git grep unittest.TestCase ./test/functional/test_framework` TEST_FRAMEWORK_MODULES = [ - "address", + "base58", "crypto.bip324_cipher", "blocktools", "crypto.chacha20",