From 65fb739584a290c8e8dff35b59def997b5cf7d4d Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Tue, 28 May 2024 12:00:58 +0200 Subject: [PATCH] segwit_addr: bech32 decode without checksum option --- electrum/segwit_addr.py | 17 +++++++++++------ tests/test_bitcoin.py | 7 +++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/electrum/segwit_addr.py b/electrum/segwit_addr.py index 224947086..d94f6277c 100644 --- a/electrum/segwit_addr.py +++ b/electrum/segwit_addr.py @@ -43,6 +43,9 @@ class DecodedBech32(NamedTuple): data: Optional[Sequence[int]] # 5-bit ints +INVALID_BECH32 = DecodedBech32(None, None, None) + + def bech32_polymod(values): """Internal function that computes the Bech32 checksum.""" generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3] @@ -85,26 +88,28 @@ def bech32_encode(encoding: Encoding, hrp: str, data: List[int]) -> str: return hrp + '1' + ''.join([CHARSET[d] for d in combined]) -def bech32_decode(bech: str, *, ignore_long_length=False) -> DecodedBech32: +def bech32_decode(bech: str, *, ignore_long_length=False, with_checksum=True) -> DecodedBech32: """Validate a Bech32/Bech32m string, and determine HRP and data.""" bech_lower = bech.lower() if bech_lower != bech and bech.upper() != bech: - return DecodedBech32(None, None, None) + return INVALID_BECH32 pos = bech.rfind('1') if pos < 1 or pos + 7 > len(bech) or (not ignore_long_length and len(bech) > 90): - return DecodedBech32(None, None, None) + return INVALID_BECH32 # check that HRP only consists of sane ASCII chars if any(ord(x) < 33 or ord(x) > 126 for x in bech[:pos+1]): - return DecodedBech32(None, None, None) + return INVALID_BECH32 bech = bech_lower hrp = bech[:pos] try: data = [CHARSET_INVERSE[x] for x in bech[pos + 1:]] except KeyError: - return DecodedBech32(None, None, None) + return INVALID_BECH32 + if not with_checksum: + return DecodedBech32(encoding=None, hrp=hrp, data=data) encoding = bech32_verify_checksum(hrp, data) if encoding is None: - return DecodedBech32(None, None, None) + return INVALID_BECH32 return DecodedBech32(encoding=encoding, hrp=hrp, data=data[:-6]) diff --git a/tests/test_bitcoin.py b/tests/test_bitcoin.py index 5673dc2fb..78a6b523d 100644 --- a/tests/test_bitcoin.py +++ b/tests/test_bitcoin.py @@ -660,6 +660,13 @@ class Test_bitcoin(ElectrumTestCase): self.assertEqual(DecodedBech32(None, None, None), segwit_addr.bech32_decode('1p2gdwpf')) + # without checksum + bolt12_str = 'lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg' + self.assertEqual(DecodedBech32(None, None, None), + segwit_addr.bech32_decode(bolt12_str, with_checksum=True, ignore_long_length=True)) + self.assertEqual(DecodedBech32(None, 'lno', [1, 0, 1, 16, 30, 16, 18, 0, 1, 8, 11, 4, 2, 27, 17, 0, 12, 21, 28, 6, 2, 27, 11, 16, 13, 17, 18, 18, 0, 25, 3, 5, 14, 13, 17, 23, 4, 26, 11, 16, 14, 17, 20, 22, 30, 27, 16, 18, 2, 9, 1, 4, 30, 19, 2, 20, 4, 0, 24, 19, 4, 8, 3, 9, 13, 25, 18, 7, 10, 28, 27, 20, 14, 9, 20, 22, 10, 28, 24, 22, 4, 4, 1, 14, 29, 17, 25, 4, 11, 21, 21, 23, 26, 11, 6, 11, 6, 0, 28, 0, 23, 30, 31, 2, 20, 13, 18, 8, 25, 21, 29, 9, 8, 9, 18, 19, 30, 22, 21, 3, 8, 3, 22, 28, 29, 8, 15, 18, 16, 13, 20, 6, 12, 6, 8]), + segwit_addr.bech32_decode(bolt12_str, with_checksum=False, ignore_long_length=True)) + class Test_xprv_xpub(ElectrumTestCase):