Skip to content

address: reject v2-v16 segwit addresses encoded with bech32 (BIP-350) - #2544

Merged
Roasbeef merged 1 commit into
btcsuite:masterfrom
Lrifton92:fix/bech32-investigation
Jul 22, 2026
Merged

address: reject v2-v16 segwit addresses encoded with bech32 (BIP-350)#2544
Roasbeef merged 1 commit into
btcsuite:masterfrom
Lrifton92:fix/bech32-investigation

Conversation

@Lrifton92

Copy link
Copy Markdown
Contributor

@

Problem

decodeSegWitAddress is written as a full BIP-350 segwit decoder: it accepts witness versions 0 through 16 (rejecting version > 16). BIP-350 requires that witness version 0 uses bech32, and versions 1 through 16 use bech32m. The reference decoder in the BIP rejects any non-zero witness version that is not bech32m:

if (data[0] == 0 and spec != Encoding.BECH32) or (data[0] != 0 and spec != Encoding.BECH32M):
    return (None, None)

The current code only special-cased versions 0 and 1:

// For witness version 1, the bech32m encoding must be used.
if version == 1 && bech32version != bech32.VersionM {

So a witness program with version 2-16 encoded using the legacy bech32 checksum decoded successfully, in violation of the spec and contrary to the BIP-350 reference decoder.

Reproduction

These are official INVALID_ADDRESS vectors from BIP-350. Both decode successfully on current master and are rejected after this change:

  • tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf — witness v2 with bech32 (should require bech32m)
  • BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL — witness v16 with bech32

Fix

Generalize the version == 1 check to version >= 1, matching the BIP-350 reference decode(). Added a regression test (address/bip350_diff_test.go) covering the v2 and v16 invalid vectors; it fails before this change and passes after.

This aligns the internal reference decoder with BIP-350 for the full v0-16 range the function already claims to handle. Versions 2-16 are not yet surfaced through DecodeAddress today, so this is primarily a spec-conformance / forward-compatibility fix rather than a behavior change for callers of the public API.

Verification

  • go build ./... — clean
  • go vet ./... — clean
  • go test ./...ok for the address, address/base58, address/bech32 packages
  • gofmt -l on touched files — clean
    @

@Lrifton92

Copy link
Copy Markdown
Contributor Author

Friendly ping — this is ready for review whenever a maintainer has bandwidth. The change enforces BIP-350 strictly (reject v2-v16 segwit addresses encoded with legacy bech32). Thanks!

@Lrifton92

Copy link
Copy Markdown
Contributor Author

Friendly follow-up — this is still ready for review whenever a maintainer has bandwidth. It strictly enforces BIP-350 (rejecting v2–v16 segwit addresses encoded with bech32 instead of bech32m). Small, self-contained change, no conflicts. Thanks!

@Roasbeef

Copy link
Copy Markdown
Member

Ci run approved!

BIP-350 requires that segregated witness outputs of version 1 through 16
use the bech32m checksum, while only version 0 uses bech32. decodeSegWitAddress
only special-cased versions 0 and 1, so a witness program with version 2-16
encoded using the legacy bech32 checksum decoded successfully, in violation of
the spec and contrary to the BIP-350 reference decoder (which rejects any
non-zero witness version that is not bech32m).

Generalize the version 1 check to cover all versions >= 1, matching the
reference decode() function. Add the relevant BIP-350 INVALID_ADDRESS vectors
(v2 and v16 encoded with bech32) as a regression test; they decoded
successfully before this change and are now rejected.

Signed-off-by: Lrifton92 <Lrifton92@users.noreply.github.com>
@Lrifton92
Lrifton92 force-pushed the fix/bech32-investigation branch from a0ed479 to 27bbee9 Compare July 21, 2026 00:25

@Roasbeef Roasbeef left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🫛

@Roasbeef
Roasbeef merged commit f799c4b into btcsuite:master Jul 22, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants