Skip to content

Commit 316ea11

Browse files
committed
api: Reject Unicode lookalikes in u5 conversion
The newly supported chars_to_u5 interface must not case-fold Unicode into valid Bech32 symbols. Lower only ASCII characters so lookalikes such as the Kelvin sign remain invalid, matching the normalization boundary enforced elsewhere.
1 parent 7311db8 commit 316ea11

2 files changed

Lines changed: 11 additions & 1 deletion

File tree

‎src/codex32/bech32.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ def bech32_hrp_expand(hrp: str) -> list[int]:
1919
return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp]
2020

2121

22+
def _ascii_lower(value: str) -> str:
23+
"""Lowercase ASCII letters without normalizing Unicode lookalikes."""
24+
return "".join(character.lower() if character.isascii() else character for character in value)
25+
26+
2227
def u5_to_chars(values: list[int] | tuple[int, ...]) -> str:
2328
"""Convert 5-bit values to Bech32 characters."""
2429

@@ -32,7 +37,7 @@ def chars_to_u5(value: str, first_position: int = 1) -> list[int]:
3237
"""Convert Bech32 characters to 5-bit values."""
3338

3439
result: list[int] = []
35-
for index, character in enumerate(value.lower()):
40+
for index, character in enumerate(_ascii_lower(value)):
3641
position = CHARSET.find(character)
3742
if position < 0:
3843
label = "Apostrophe (')" if character == "'" else f"The character {character!r}"

‎tests/test_bech32.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ def test_u5_character_round_trip() -> None:
2828
assert chars_to_u5(CHARSET.upper()) == values
2929

3030

31+
def test_u5_character_conversion_does_not_fold_unicode_lookalikes() -> None:
32+
with pytest.raises(InvalidCharacter, match="K"):
33+
chars_to_u5("K")
34+
35+
3136
@pytest.mark.parametrize("value", (-1, 32))
3237
def test_u5_rejects_out_of_range_values(value: int) -> None:
3338
with pytest.raises(InvalidCharacter):

0 commit comments

Comments
 (0)