From 7604359f650c506dced008ac9a4fc5abebc9b668 Mon Sep 17 00:00:00 2001 From: Sasha Mitchell Date: Sat, 3 Oct 2026 21:32:56 +0700 Subject: [PATCH] Decode a Base58 string of ones as that many zero bytes The digit 1 is zero, and each leading 1 is already a zero byte. Packing the leftover 0 added one extra byte, so '1' decoded as two zero bytes. --- NEWS | 6 ++++++ stdnum/bitcoin.py | 5 +++-- tests/test_bitcoin.doctest | 13 +++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 8eb60b3a..d5ca41b7 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,9 @@ +changes from 2.2 +---------------- + +* Fix Base58 decoding of a Bitcoin address made only of the digit 1. That digit is a zero byte, so a string of them was one byte too long. + + changes from 2.1 to 2.2 ----------------------- diff --git a/stdnum/bitcoin.py b/stdnum/bitcoin.py index 4cf2bd90..6eac7470 100644 --- a/stdnum/bitcoin.py +++ b/stdnum/bitcoin.py @@ -68,10 +68,11 @@ def b58decode(s: str) -> bytes: """Decode a Base58 encoded string to a bytestring.""" value = reduce(lambda a, c: a * 58 + _base58_alphabet.index(c), s, 0) result = b'' - while value >= 256: + # A zero value has no payload bytes. Each leading 1 is already a zero + # byte, so packing the leftover 0 here would add one extra. + while value: value, mod = divmod(value, 256) result = struct.pack('B', mod) + result - result = struct.pack('B', value) + result return struct.pack('B', 0) * (len(s) - len(s.lstrip('1'))) + result diff --git a/tests/test_bitcoin.doctest b/tests/test_bitcoin.doctest index 022bd846..1038619c 100644 --- a/tests/test_bitcoin.doctest +++ b/tests/test_bitcoin.doctest @@ -23,6 +23,19 @@ useful as module documentation. >>> from stdnum import bitcoin +The digit 1 is zero. A string of them is that many zero bytes, and an empty +string is empty. A leftover zero must not add another byte. + +>>> bitcoin.b58decode('1') +b'\x00' +>>> bitcoin.b58decode('11') +b'\x00\x00' +>>> bitcoin.b58decode('2') +b'\x01' +>>> bitcoin.b58decode('') +b'' + + These are found and constructed P2PKH addresses (P2SH addresses are basically the same because they follow the same validation, except that the first digit is a 3).