From 5f6f7da2a1be473a34a125509413d95475011e6a Mon Sep 17 00:00:00 2001 From: SomberNight Date: Sun, 8 Dec 2019 06:56:19 +0100 Subject: [PATCH] bitcoin.py: base58 address: make sure all public methods test checksum Note: the checksum was already being checked in practically all cases, by the caller. Moved the check here, to the lower level (but still public) method for sanity. --- electrum/bitcoin.py | 7 +++++-- electrum/tests/test_bitcoin.py | 10 ++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/electrum/bitcoin.py b/electrum/bitcoin.py index 06e1c642e..4e65e8b98 100644 --- a/electrum/bitcoin.py +++ b/electrum/bitcoin.py @@ -328,7 +328,9 @@ def hash160_to_b58_address(h160: bytes, addrtype: int) -> str: def b58_address_to_hash160(addr: str) -> Tuple[int, bytes]: addr = to_bytes(addr, 'ascii') - _bytes = base_decode(addr, base=58, length=25) + _bytes = DecodeBase58Check(addr) + if len(_bytes) != 21: + raise Exception(f'expected 21 payload bytes in base58 address. got: {len(_bytes)}') return _bytes[0], _bytes[1:21] @@ -638,12 +640,13 @@ def is_segwit_address(addr: str, *, net=None) -> bool: def is_b58_address(addr: str, *, net=None) -> bool: if net is None: net = constants.net try: + # test length, checksum, encoding: addrtype, h = b58_address_to_hash160(addr) except Exception as e: return False if addrtype not in [net.ADDRTYPE_P2PKH, net.ADDRTYPE_P2SH]: return False - return addr == hash160_to_b58_address(h, addrtype) + return True def is_address(addr: str, *, net=None) -> bool: if net is None: net = constants.net diff --git a/electrum/tests/test_bitcoin.py b/electrum/tests/test_bitcoin.py index e056aeb5b..dac854eea 100644 --- a/electrum/tests/test_bitcoin.py +++ b/electrum/tests/test_bitcoin.py @@ -711,6 +711,16 @@ class Test_keyImport(ElectrumTestCase): self.assertFalse(is_address("not an address")) + def test_is_address_bad_checksums(self): + self.assertTrue(is_address('1819s5TxxbBtuRPr3qYskMVC8sb1pqapWx')) + self.assertFalse(is_address('1819s5TxxbBtuRPr3qYskMVC8sb1pqapWw')) + + self.assertTrue(is_address('3LrjLVnngqnaJeo3BQwMBg34iqYsjZjQUe')) + self.assertFalse(is_address('3LrjLVnngqnaJeo3BQwMBg34iqYsjZjQUd')) + + self.assertTrue(is_address('bc1qxq64lrwt02hm7tu25lr3hm9tgzh58snfe67yt6')) + self.assertFalse(is_address('bc1qxq64lrwt02hm7tu25lr3hm9tgzh58snfe67yt5')) + @needs_test_with_all_ecc_implementations def test_is_private_key(self): for priv_details in self.priv_pub_addr: