Skip to content

feat: support BIP-322 P2WSH multisig signatures in auth#3637

Open
TaprootFreak wants to merge 2 commits intodevelopfrom
feat/bip322-p2wsh-multisig-auth
Open

feat: support BIP-322 P2WSH multisig signatures in auth#3637
TaprootFreak wants to merge 2 commits intodevelopfrom
feat/bip322-p2wsh-multisig-auth

Conversation

@TaprootFreak
Copy link
Copy Markdown
Collaborator

Summary

  • Adds BIP-322 full signature verification for native P2WSH multisig addresses (bc1q… 62 chars) in the auth flow, so users can sign in with wsh(sortedmulti(t, …)) / wsh(multi(t, …)) wallets.
  • Wired in as a 4th attempt inside crypto.service.ts:verifyBitcoinBased, only when no message-prefix is set (Bitcoin mainnet) and the address passes strict P2WSH detection — existing P2WPKH/P2SH-P2WPKH/P2TR/legacy paths are untouched.
  • Scope intentionally narrow: only standard OP_M … OP_N OP_CHECKMULTISIG witness scripts with SIGHASH_ALL signatures. Miniscript / Taproot scripts / non-standard policies are rejected.

Implementation notes

  • Pure-noble crypto (@noble/curves, @noble/hashes, bech32 — all already in deps), no new packages.
  • BIP-322 simple signature format: base64-encoded witness stack as produced by any wallet that emits BIP-322 simple sigs.
  • BIP-143 sighash construction over the synthetic to_spend / to_sign pair from BIP-322.
  • Pubkey iteration follows the OP_CHECKMULTISIG convention (sigs in script-pubkey order, with replay-of-pk-index after a match).
  • Defensive typeof address !== 'string' guards on the public entry points, matching the precedent in bech32m.service.ts.

Client-side caveat

Sparrow Wallet's Sign/Verify Message dialog does not accept multisig wallets (hard-coded IllegalArgumentException, issue #193). Producing a BIP-322 simple signature for a multisig today requires either Bitcoin Knots signmessage, or building the BIP-322 to_sign PSBT externally and signing it through Sparrow's regular multisig PSBT flow. The backend code here is signing-tool-agnostic.

Test plan

  • bip322-p2wsh.util.spec.ts — 15 tests:
    • 6× P2WSH address detection (incl. testnet / malformed / empty rejection)
    • 3× structural negatives (empty / garbage / wrong address type)
    • 3× synthetic 2-of-3 sortedmulti roundtrip sign+verify (3 message lengths)
    • 1× rejects under-threshold (1 of 2 sigs)
    • 1× rejects sig for different message
    • 1× rejects sig from foreign key not in script
    • it.todo placeholder for a real wallet-produced fixture
  • crypto.service.spec.ts — 67 existing tests still green
  • type check / prettier / eslint
  • End-to-end: register a real 2-of-3 P2WSH multisig at /auth

@TaprootFreak TaprootFreak requested a review from Danswar April 28, 2026 23:12
TaprootFreak added a commit to DFXswiss/btc-wallet that referenced this pull request Apr 28, 2026
Adds a pure verifier mirroring the backend implementation in
DFXswiss/api#3637, exposed both as a standalone function
(verifyBip322Signature) and as MultisigHDWallet.verifyMessage so the
existing Sign/Verify Message screen works symmetrically: a signature
produced by signMessage on one device can be verified on any device
holding the same wallet (or just the address).

Verifier algorithm:
- strict P2WSH address detection (bc1q…, 62 chars, 32-byte program)
- base64 → witness stack (varint-prefixed items)
- last item must be the witness script; sha256 must match the bech32 program
- script must be standard OP_M … OP_N OP_CHECKMULTISIG with 33-byte pubkeys
- exactly M signatures + empty CHECKMULTISIG dummy
- BIP-143 sighash over the synthetic to_spend / to_sign pair
- ECDSA verify each sig against pubkeys in script order, sighash flag 0x01

Adds 7 tests covering: round-trip with signMessage, multiple message
lengths (incl. unicode and 200-char), wrong-message rejection,
wrong-address rejection, PSBT cross-device round-trip verification,
malformed-input handling, and isP2wshAddress detection.
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