[WIP] BIP93: Allow other human-readable parts #2320

pull BenWestgate wants to merge 14 commits into bitcoin:master from BenWestgate:bip93-generalize-hrp changing 1 files +373 −219
  1. BenWestgate commented at 7:45 PM on October 1, 2026: contributor

    Summary

    Generalize codex32 so that the human-readable part is not restricted to ms.

    This PR is based on top of behavior neutral #2285.

    BIP-32 master seeds and their shares continue to use ms, while other applications can use their own human-readable parts.

    Changes

    • Specify the human-readable part as in BIP-173 and include it in checksum construction and verification.
    • Rename the inline ms32 helpers to codex32. codex32_encode takes the human-readable part and codex32_decode returns it.
    • Leave master seed lengths to a master seed decoder, as BIP-173 leaves witness program rules to a segwit address decoder.
    • Require all shares in a set to use the same human-readable part.
    • Clarify that the interpolation helpers do not check the valid set conditions.
    • Limit fresh-secret generation to applications that accept every payload.
      • Other applications MAY use rejection sampling on the last share.
    • Do not recommend correcting errors in the human-readable part unless the application specifies how.
    • Update the existing invalid vectors whose interpretation changes when other human-readable parts become valid, and list invalid master seeds separately from invalid codex32 strings.
    • Add test vectors covering:
      • the registered cl human-readable part used by Core Lightning;
      • checksum selection affected by human-readable-part length;
      • an 83-character human-readable part containing 1;
      • the shortest human-readable part with an empty payload;
      • the longest string with each checksum (expanded lengths 93 and 1023);
      • expanded lengths 94 and 95;
      • a checksum computed over an uppercase human-readable part;
      • a human-readable part longer than 83 characters.

    Strings using ms are unchanged.

    Testing

    The codex32 checksum functions were checked against the previous ms32 functions for ms over random data parts, including both checksum variants.

    The new vectors were checked with both the specification's Python code and an independent implementation, python-codex32. They agree except that python-codex32 does not yet enforce the 83-character human-readable-part limit. The empty-payload and longest-string vectors were generated with the specification's codex32_encode and checked with its codex32_decode.

    Refs: #2040, #2258, #2285

  2. BIP93: Separate format and seed sections
    Group the regular and long checksum definitions in the codex32 format
    section. Move the master-seed application profile to the end of the
    specification and keep seed-specific checksum motivation in the
    rationale.
    
    This is a behavior-neutral organization change on top of the #2258
    profile commit.
    eb7bb6c097
  3. BenWestgate referenced this in commit 0bfb24da6c on Oct 1, 2026
  4. in bip-0093.mediawiki:71 in 80a27cf13b
      67 | @@ -68,24 +68,25 @@ efficient to read out loud, write, type or to put into QR codes.</ref> format ca
      68 |  A codex32 string is similar to a bech32 string defined in [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki BIP-0173].
      69 |  It reuses the base-32 character set from BIP-0173, and consists of:
      70 |  
      71 | -* A human-readable part, which is the string "ms" (or "MS").
      72 | -* A separator, which is always "1".
      73 | +* A human-readable part, as specified in BIP-0173. It identifies the application, which can further restrict validity.
    


    BenWestgate commented at 9:26 PM on October 1, 2026:

    Delete the second sentence? Most specifically the application can further restrict payload validity. A BIP-0173 application HRP can define whatever it wants about the data part besides the checksum.

    We additionally keep the codex32 header a normative requirement for all applications.


    BenWestgate commented at 9:36 PM on October 1, 2026:

    as per BIP-0173

    is better than "as specified"

  5. in bip-0093.mediawiki:72 in 80a27cf13b outdated
      67 | @@ -68,24 +68,25 @@ efficient to read out loud, write, type or to put into QR codes.</ref> format ca
      68 |  A codex32 string is similar to a bech32 string defined in [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki BIP-0173].
      69 |  It reuses the base-32 character set from BIP-0173, and consists of:
      70 |  
      71 | -* A human-readable part, which is the string "ms" (or "MS").
      72 | -* A separator, which is always "1".
      73 | +* A human-readable part, as specified in BIP-0173. It identifies the application, which can further restrict validity.
      74 | +* A separator, which is always "1". If the human-readable part contains "1", the last one in the string is the separator.
    


    BenWestgate commented at 9:28 PM on October 1, 2026:

    We probably can remove this sentence since BIP-0173 covers it.

  6. in bip-0093.mediawiki:83 in 80a27cf13b
      82 | +** A payload which is a sequence of up to 73 - 2''n'' bech32 characters, where ''n'' is the length of the human-readable part. (However, see [[#Long_Checksum|Long checksum]] below for an exception to this limit.)
      83 |  ** A checksum which consists of 13 or 15 bech32 characters as described below.
      84 |  
      85 | -See [[#Master_seed_format|Master seed format]] for the payload-length and payload-conversion requirements for BIP-0032 master seeds.
      86 | +BIP-0032 master seeds and their shares use the human-readable part "ms"; see [[#Master_seed_format|Master seed format]] for their other requirements.
      87 | +SatoshiLabs maintains a list of registered codex32 human-readable parts in [https://github.com/satoshilabs/slips/blob/master/slip-0173.md#uses-of-codex32 SLIP-0173].
    


    BenWestgate commented at 9:32 PM on October 1, 2026:

    This sentence feels out of place, it had it's own section right before the appendix in BIP-0173. I prefer it there than here. https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#registered-human-readable-prefixes

  7. in bip-0093.mediawiki:163 in 80a27cf13b
     181 | -        return ms32_create_long_checksum(data)
     182 | -    return ms32_create_regular_checksum(data)
     183 | +def codex32_create_checksum(hrp, data):
     184 | +    if len(bech32_hrp_expand(hrp)) + len(data) + 13 > 93:  # See Long checksum
     185 | +        return codex32_create_long_checksum(hrp, data)
     186 | +    return codex32_create_regular_checksum(hrp, data)
    


    BenWestgate commented at 9:50 PM on October 1, 2026:

    codex32_verify_checksum(hrp, data) and codex32_create_checksum(hrp, data) should own the values = bech32_hrp_expand(hrp) + data expansion and the checksum selection. Repeating it within every primitive makes this code longer to read and harder to review. def codex32_regular_checksum(values): and similar for the other 3.

  8. in bip-0093.mediawiki:200 in 80a27cf13b
     204 | -def ms32_create_long_checksum(data):
     205 | -    values = data
     206 | -    polymod = ms32_long_polymod(values + [0] * 15) ^ MS32_LONG_CONST
     207 | +def codex32_create_long_checksum(hrp, data):
     208 | +    values = bech32_hrp_expand(hrp) + data
     209 | +    polymod = codex32_long_polymod(values + [0] * 15) ^ CODEX32_LONG_CONST
    


    BenWestgate commented at 9:53 PM on October 1, 2026:

    similar, these primitives should accept (values) and not handle the HRP expansion and data.

  9. in bip-0093.mediawiki:210 in 80a27cf13b


    BenWestgate commented at 10:31 PM on October 1, 2026:

    I dislike this formula representation of the maximum payload, if anyone has a better idea, please share.

    Perhaps instead say the maximum string length is 1024 - len(hrp)?

    I disliked it in the regular codex32 specification also.


    BenWestgate commented at 10:31 PM on October 1, 2026:

    I dislike the formula representation.

    It may be cleaner to say maximum string length 1024 - len(hrp). any suggestions?


    BenWestgate commented at 8:42 AM on October 5, 2026:

    This remains unresolved: whether to switch to maximum string length accounting or continue saying the payload length which is mathematically messier but potentially more useful.

  10. in bip-0093.mediawiki:304 in 80a27cf13b
     298 | @@ -291,19 +299,22 @@ There are two ways to create an initial set of ''k'' valid codex32 strings, depe
     299 |  <span id="For_a_fresh_secret"></span><span id="for-a-fresh-secret"></span>
     300 |  '''For a fresh secret'''
     301 |  
     302 | -In the case that the user wishes to generate a fresh secret, the user generates random initial shares, as follows:
     303 | +In the case that the user wishes to generate a fresh secret, the user generates random initial shares, as follows.
     304 | +This requires an application that accepts every payload of the chosen length as a secret, as the master seed format does.
     305 | +An application that does not MAY use rejection sampling instead: retry with a fresh set of shares until the resulting secret qualifies.
    


    BenWestgate commented at 10:35 PM on October 1, 2026:

    this might work better as a ref link to rationale, or placed after the fresh secret instructions so line 302 can remain unchanged.

  11. in bip-0093.mediawiki:307 in 80a27cf13b
     304 | +This requires an application that accepts every payload of the chosen length as a secret, as the master seed format does.
     305 | +An application that does not MAY use rejection sampling instead: retry with a fresh set of shares until the resulting secret qualifies.
     306 |  
     307 | -# Choose a bit size from 128, 160, 192, 224, 256, or 512
     308 | +# Choose the human-readable part of the application and a payload length it accepts
     309 | +#* For a master seed, use <code>ms</code>, choose a bit size ''bitlength'' from 128, 160, 192, 224, 256, or 512, and use a payload of ceil(''bitlength / 5'') characters
    


    BenWestgate commented at 10:37 PM on October 1, 2026:

    nit: arguably doesn't need to be here.

  12. in bip-0093.mediawiki:333 in 80a27cf13b outdated
     328 |  # Choose a threshold value ''k'' between 2 and 9, inclusive
     329 |  # Choose a 4 bech32 character identifier
     330 |  #* We do not define how to choose the identifier, beyond noting that it SHOULD be distinct for every set of shares the user may need to disambiguate
     331 |  # Set the share index to <code>s</code>
     332 |  # Set the payload to a bech32 encoding of the application-specified secret payload bits; for a master seed, follow [[#Master_seed_format|Master seed format]].
     333 |  # Generate a valid checksum in accordance with the Checksum section
    


    BenWestgate commented at 10:40 PM on October 1, 2026:

    This might belong better in "shared secret" we have an "unshared secret" section much earlier.

  13. in bip-0093.mediawiki:408 in 80a27cf13b outdated
     416 | @@ -405,7 +417,11 @@ We define a long checksum to support the maximum seed size because its expanded
     417 |  While we could use the 15 character checksum for both cases, we prefer to keep the strings as short as possible for the more common cases of 128-bit and 256-bit master seeds.
     418 |  Longer strings mean more chances for transcription errors, so shorter strings are better.
     419 |  
     420 | -If the prefix is damaged and a user is guessing that the data might be using this scheme, then the user can enter the available data explicitly using the suspected <code>MS1</code> prefix.
    


    BenWestgate commented at 10:44 PM on October 1, 2026:

    I prefer to keep this sentence. It works for MS and it's harmless to try MS1, where as replacing a damaged private HRP (e.g. xprv) with a guessed public one (e.g. xpub) could broadcast it unintentionally.

  14. BenWestgate commented at 10:46 PM on October 1, 2026: contributor

    Reviewed all through Test vectors

  15. BenWestgate renamed this:
    BIP93: Allow other human-readable parts
    [WIP] BIP93: Allow other human-readable parts
    on Oct 5, 2026
  16. BenWestgate commented at 8:19 AM on October 5, 2026: contributor

    9c5a8d3 LGTM, much better than expanding the hrp everywhere

  17. in bip-0093.mediawiki:71 in 18919894e5 outdated
      67 | @@ -68,7 +68,7 @@ efficient to read out loud, write, type or to put into QR codes.</ref> format ca
      68 |  A codex32 string is similar to a bech32 string defined in [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki BIP-0173].
      69 |  It reuses the base-32 character set from BIP-0173, and consists of:
      70 |  
      71 | -* A human-readable part, as specified in BIP-0173. It identifies the application, which can further restrict validity.
      72 | +* A human-readable part, as specified in BIP-0173. It identifies the application, which may impose additional validity requirements.
    


    BenWestgate commented at 8:25 AM on October 5, 2026:

    This second sentence should be removed. First it doesn't identify the application, it may identify a profile (of an application) but even then, some profiles like ln or the proposed <key origin>xpub use the HRP to show humans data. Removing it allows BIP-173 to remain authoritative here. We have no differences from bip173.

  18. in bip-0093.mediawiki:300 in 18919894e5
     296 | @@ -298,10 +297,10 @@ There are two ways to create an initial set of ''k'' valid codex32 strings, depe
     297 |  
     298 |  In the case that the user wishes to generate a fresh secret, the user generates random initial shares, as follows.
     299 |  This requires an application that accepts every payload of the chosen length as a secret, as the master seed format does.
     300 | -An application that does not MAY use rejection sampling instead: retry with a fresh set of shares until the resulting secret qualifies.
     301 | +If the application does not accept every payload of the chosen length, it MAY use rejection sampling: retry with a fresh set of shares until the resulting secret is valid for the application.
    


    BenWestgate commented at 8:30 AM on October 5, 2026:

    nit: technically only the last share or even only the offending characters of the last share need to be retried with fresh randomness.

  19. in bip-0093.mediawiki:420 in 18919894e5
     416 | @@ -418,7 +417,7 @@ The checksum covers the expanded human-readable part, as in BIP-0173, and the ex
     417 |  Beyond those limits, some errors in the human-readable part cannot be distinguished from errors elsewhere in the string, so counting the expansion keeps the error detection guarantees for the entire string.
     418 |  It also lets implementations select the checksum variant from the string alone, without knowing the application.
     419 |  
     420 | -If the human-readable part is damaged and a user is guessing that the data might be using this scheme, then the user can enter the available data explicitly using the suspected human-readable part.
     421 | +For master seeds, if the human-readable part is damaged, the user can enter the available data explicitly using the suspected <code>MS1</code> prefix.
    


    BenWestgate commented at 8:38 AM on October 5, 2026:

    Use the sentence:

    For master seeds, if the human-readable part is damaged and a user is guessing that the data might be using this scheme, then the user can enter the available data explicitly using the suspected <code>MS1</code> prefix.

  20. BenWestgate commented at 8:38 AM on October 5, 2026: contributor

    Much improved, requesting a couple changes.

  21. jonatack added the label Proposed BIP modification on Oct 18, 2026
  22. jonatack added the label Pending acceptance on Oct 18, 2026
  23. bip93: Remove duplicate explanations
    State common format rules and checksum properties once. Refer to the
    master seed requirements for application-specific validation.
    732b0bfc3d
  24. bip93: Reorganize specification
    Order the specification as format, secret sharing, then master seeds.
    Place shared helpers before their callers and define the interpolation
    data representation once. Preserve existing section links.
    1af7a01338
  25. bip93: Clarify seed-size units
    Use bits for seed sizes and bytes for decoded output. Supported sizes
    are unchanged.
    89b16306d9
  26. bip93: Add revision history
    Add Version 0.2.1 and a changelog. Date earlier revisions by their
    upstream integration dates.
    ecbed1c982
  27. bip93: Allow other human-readable parts
    Specify the human-readable part as in BIP-0173 instead of requiring
    "ms". Master seeds and their shares keep "ms".
    
    Pass the human-readable part to the checksum functions and generalize
    the ms32 helpers in place as codex32 helpers. Results for "ms" are
    unchanged. Master seed decoders still apply the size table.
    
    Require one human-readable part per share set, limit fresh-secret
    generation to applications that accept every payload, and do not
    correct the human-readable part unless its application says how. Add
    vectors for other human-readable parts and the checksum length limits.
    
    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01DNycZ6NQBfYLvTVtgeZWxK
    f2c4d537c6
  28. bip93: Clarify data-part error correction
    State explicitly that the checksum's substitution and erasure correction
    guarantees apply to errors in the data part. This avoids implying the same
    correction guarantees for the human-readable part.
    4f7e175fe4
  29. bip93: Record HRP generalization in changelog
    Bump to 0.3.0, a backward-compatible extension: strings with the
    human-readable part "ms" are unchanged.
    11e1fd6028
  30. bip93: Simplify checksum helper layering abbbfda9de
  31. bip93: Clarify application-specific HRP guidance 0df51422b3
  32. bip93: Clarify generation and damaged HRPs
    Retrying the final initial share preserves already recorded shares while
    resampling the recovered secret. Distinguish a user-supplied application
    prefix from a checksum-verified repair, and clarify variant selection.
    
    Address peer review on #2.
    563e5dc675
  33. bip93: Clarify checksum detection limit e9486927cb
  34. bip93: Add codex32 boundary test vectors
    Add valid codex32 secrets with the shortest human-readable part and an
    empty payload, the longest string with the regular checksum (expanded
    length 93), and the longest string overall (expanded length 1023). Show
    the uppercase form of Test vector 9, and note that Test vector 10 has
    the shortest expanded length that uses the long checksum.
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01DNycZ6NQBfYLvTVtgeZWxK
    7d9d9c5146
  35. bip93: Separate invalid master seed test vectors
    List strings that are invalid codex32 strings under Invalid test
    vectors, and the strings a master seed decoder must reject for its own
    reasons, improper lengths and a human-readable part other than "ms",
    under a new Invalid master seed test vectors section. The vectors are
    unchanged.
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01DNycZ6NQBfYLvTVtgeZWxK
    a71a477d5b
  36. BenWestgate force-pushed on Oct 29, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bips. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-11-03 19:10 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me