Skip to content

Commit e397fcc

Browse files
committed
bip93: use generalized-HRP draft vectors
1 parent 9a05bb3 commit e397fcc

3 files changed

Lines changed: 52 additions & 24 deletions

File tree

‎tests/data/bip93_vectors.py‎

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,31 @@
7979
"codex32_peev": "cl10peevst6cqh0wu7p5ssjyf4z4ez42ks9jlt3zneju9uuypr2hddak6tlqsjhsks4laxts8q",
8080
}
8181

82+
# BIP-93 generalized-HRP draft, bitcoin/bips bip93-generalize-hrp @ 01374bf.
83+
BIP93_GENERAL_HRP = {
84+
"share_a": "test_vector12spana320zyxwvutsrqpnmlkjhgfedca320zyxwvutsrqpnmlkjhgfedca304ppsqh4l7v3dh",
85+
"share_c": "test_vector12spancacdefghjklmnpqrstuvwxyz023acdefghjklmnpqrstuvwxyz023jxmjy7q9xl7d3ul",
86+
"derived_d": "test_vector12spandll4f8jlh4e5vdvuldlfxu2jhdnll4f8jlh4e5vdvuldlfxu2jhdnx3pe3yqzdl7p30y",
87+
"secret_s": "test_vector12spans6xqguzttxkeqnjsjzv4jv3nz5k6xqguzttxkeqnjsjzv4jv3nz5kdf37v5qm2l7l3az",
88+
"valid_83": (
89+
"a83characterlongcodex32humanreadablepartforsecretsharewiththedigit1andthelettersbio"
90+
"10keyss9mfjjk25y05e3nq"
91+
),
92+
"invalid_gap_regular": (
93+
"test_vector12spans6xqguzttxkeqnjsjzv4jv3nz5k6xqguzttxkeqnjsjzv4jv3nz5kp0f0tlr2cxh0t"
94+
),
95+
"invalid_gap_long": (
96+
"test_vector12spans6xqguzttxkeqnjsjzv4jv3nz5k6xqguzttxkeqnjsjzv4jv3nz5c2m7mxmk8s5qecp"
97+
),
98+
"invalid_uppercase_hrp_checksum": (
99+
"CL10PEEVST6CQH0WU7P5SSJYF4Z4EZ42KS9JLT3ZNEJU9UUYPR2HDDAK6TLQS3J5AYX4Y08079"
100+
),
101+
"invalid_84": (
102+
"a84characterslongcodex32humanreadablepartforsecretsharewiththedigit1andthelettersbio"
103+
"10keyss9hqxu3pxsnkdkth"
104+
),
105+
}
106+
82107

83108
VALID_CODEX32 = [
84109
"A12UEL5LLGCHJ4UJCQVHG",
@@ -116,8 +141,6 @@
116141
+ "12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx836hdd09mhkhkhx", # HRP character out of range
117142
"\x80"
118143
+ "12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxlhf5ywnkmk4r3tc", # HRP character out of range
119-
# HRP exceeds 83 characters (also exceeds the overall max length)
120-
"a1003characterslonghumanreadablepartthatcontainsthenumber1,theexcludedcharactersbio,andeveryus-asciicharacterin[33-126]!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~12fauxxru38cppmlpu0t6l",
121144
"y12bfauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxt3y5fewy4gnw2hs", # Invalid data character
122145
"lt12ifauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxjxd0ehq868vm3zl", # Invalid data character
123146
"in12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxvgegljrsvs5w9q", # Too short checksum

‎tests/test_generic_hrp.py‎

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import pytest
99
from _codex32_oracle import oracle_encode
10+
from data.bip93_vectors import BIP93_GENERAL_HRP
1011

1112
from codex32 import (
1213
CorrectionContext,
@@ -18,7 +19,7 @@
1819
recover_secret,
1920
)
2021
from codex32.cli import main, ms_main
21-
from codex32.errors import InvalidLength, MismatchedHrp, MismatchedProfile
22+
from codex32.errors import InvalidChecksum, InvalidLength, MismatchedHrp, MismatchedProfile
2223
from tools._wallet_test_vectors import STUB_FINGERPRINT
2324

2425
UNKNOWN = {
@@ -180,16 +181,31 @@ def fingerprint(_secret: object) -> bytes:
180181
assert _invoke(ms_main, ["share", "d", "--plain"], basis)[0] == 2
181182

182183

183-
def test_83_character_hrp_may_span_printable_ascii() -> None:
184-
pool = [chr(code) for code in range(33, 127) if not chr(code).isupper()]
185-
hrp = "".join(pool[index % len(pool)] for index in range(83))
186-
assert "1" in hrp # the separator is the last "1", so an HRP may contain one
187-
assert parse_codex32(oracle_encode(hrp, "0testsq")).hrp == hrp
184+
def test_bip93_generalized_hrp_share_vectors() -> None:
185+
share_a = parse_codex32(BIP93_GENERAL_HRP["share_a"])
186+
share_c = parse_codex32(BIP93_GENERAL_HRP["share_c"])
187+
assert share_a.hrp == share_c.hrp == "test_vector"
188+
assert recover_secret([share_a, share_c]).text == BIP93_GENERAL_HRP["secret_s"]
189+
assert derive_share([share_a, share_c], "d").text == BIP93_GENERAL_HRP["derived_d"]
188190

189191

190-
def test_hrp_over_83_characters_is_rejected_at_the_bip173_limit() -> None:
191-
within_limit = oracle_encode("z" * 83, "0testsq")
192-
over_limit = oracle_encode("z" * 84, "0testsq")
193-
assert parse_codex32(within_limit).hrp == "z" * 83
192+
def test_bip93_generalized_hrp_boundary_vectors() -> None:
193+
valid = BIP93_GENERAL_HRP["valid_83"]
194+
invalid = BIP93_GENERAL_HRP["invalid_84"]
195+
artifact = parse_codex32(valid)
196+
197+
assert len(artifact.hrp) == 83
198+
assert artifact.hrp == valid.rsplit("1", 1)[0]
199+
with pytest.raises(InvalidLength):
200+
parse_codex32(invalid)
201+
202+
203+
@pytest.mark.parametrize("key", ("invalid_gap_regular", "invalid_gap_long"))
204+
def test_bip93_generalized_hrp_gap_vectors_are_invalid(key: str) -> None:
194205
with pytest.raises(InvalidLength):
195-
parse_codex32(over_limit)
206+
parse_codex32(BIP93_GENERAL_HRP[key])
207+
208+
209+
def test_bip93_generalized_hrp_checksum_uses_lowercase_hrp() -> None:
210+
with pytest.raises(InvalidChecksum):
211+
parse_codex32(BIP93_GENERAL_HRP["invalid_uppercase_hrp_checksum"])

‎tests/test_profiles.py‎

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -118,17 +118,6 @@ def test_expanded_codeword_upper_bound() -> None:
118118
_checksum_for_encoded_length("ms", len(bech32_decode(oversized)[1]))
119119

120120

121-
def test_long_checksum_residue_stays_correct_past_its_period() -> None:
122-
# Probes the polynomial itself with u5 values, not a codex32 string: the
123-
# arithmetic still closes beyond the code's 1023-symbol period, so length is
124-
# what verify() has to enforce, not the residue.
125-
body = bech32_hrp_expand("ms") + [0] * 1100
126-
codeword = body + _CODEX32_LONG.create(body)
127-
assert len(codeword) > 1023
128-
assert _CODEX32_LONG.polymod(codeword) == _CODEX32_LONG.constant
129-
assert _CODEX32_LONG.verify(codeword) is False
130-
131-
132121
def test_checksum_is_verified_before_unknown_hrp_dispatch() -> None:
133122
valid_generic = _oracle_encode("zz", "0tests" + "q" * 26)
134123
artifact = parse_codex32(valid_generic)

0 commit comments

Comments
 (0)