Skip to content

fix(isBtcAddress): accept 62-character bech32 P2WSH addresses#2775

Open
chatman-media wants to merge 1 commit into
validatorjs:masterfrom
chatman-media:fix/isbtcaddress-p2wsh-bech32-length
Open

fix(isBtcAddress): accept 62-character bech32 P2WSH addresses#2775
chatman-media wants to merge 1 commit into
validatorjs:masterfrom
chatman-media:fix/isbtcaddress-p2wsh-bech32-length

Conversation

@chatman-media

Copy link
Copy Markdown

isBtcAddress rejects valid native SegWit P2WSH addresses (62 characters), including the official BIP-173 test vectors.

Problem

The bech32 pattern caps the data part after the bc1/tb1 prefix at 58 characters:

const bech32 = /^(bc1|tb1|bc1p|tb1p)[ac-hj-np-z02-9]{39,58}$/;

A bech32 address is HRP + 1 + data, where the data part is 1 (witness version) + program (squashed to base32) + 6 (checksum). For a witness-v0 program:

Type Program base32 program chars Data part (1 + prog + 6) Total
P2WPKH 20 bytes ceil(20*8/5) = 32 39 42
P2WSH 32 bytes ceil(32*8/5) = 52 59 62

P2WPKH sits exactly at the lower bound (39) and passes, but P2WSH needs 59 data characters and is cut off by the {39,58} upper bound, so every 62-char v0 address fails. (P2TR/taproot is also 62 chars but only matched today by accident — its 4th char p lets the regex backtrack into the bc1p alternative.)

Reproduction

const validator = require(validator);

// Official BIP-173 P2WSH test vectors:
validator.isBtcAddress(bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3); // false, expected true
validator.isBtcAddress(tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7); // false, expected true

Fix

Bump the upper bound from 58 to 59 so a v0 32-byte (P2WSH) address matches. The upper limit is still enforced — a 60-data-char string is added to the invalid fixtures to guard against regression.

-const bech32 = /^(bc1|tb1|bc1p|tb1p)[ac-hj-np-z02-9]{39,58}$/;
+const bech32 = /^(bc1|tb1|bc1p|tb1p)[ac-hj-np-z02-9]{39,59}$/;

Authoritative source

Tests

Added the two BIP-173 P2WSH vectors to valid and an over-length (60 data chars) string to invalid in test/validators.test.js. The new valid cases fail before the fix and pass after; full suite (npm test) is green with coverage unchanged.

The bech32 regex capped the data part after the bc1/tb1 prefix at 58
characters, but a witness-v0 32-byte program (P2WSH) squashes to 52
base32 chars, giving 1 (witness version) + 52 + 6 (checksum) = 59 data
characters (62 total). As a result valid P2WSH addresses, including the
official BIP-173 test vectors, were rejected. Bump the upper bound from
58 to 59 so v0 32-byte addresses match while the upper length limit is
still enforced.
@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (3d2f4b3) to head (48c9645).

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #2775   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          114       114           
  Lines         2587      2587           
  Branches       656       656           
=========================================
  Hits          2587      2587           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

1 participant