did-btcr2-js

ADR 026: Drop bitcoinjs-lib; @scure/btc-signer for Bitcoin Primitives

Status: Accepted

Date: 2026-04-14

Commit: 86e2f2b

Context

@did-btcr2/bitcoin initially used bitcoinjs-lib for PSBT construction, address derivation, transaction signing, and Taproot output construction. As the aggregation work matured and the HTTP transport planning exposed the browser-compat constraint (ADR 019), two issues with bitcoinjs-lib became hard to ignore:

  1. Browser compatibility is inconsistent. bitcoinjs-lib nominally supports browsers but relies on Buffer shims and create-hash / randombytes compatibility packages that produce brittle bundles depending on the bundler and target. The project has a strict “no Node-only APIs in library source” rule; bitcoinjs-lib is closer to “can be made to work” than “works by construction.”
  2. Dependency stack divergence. The rest of the codebase standardized on the @noble/* and @scure/* stack (ADR 019). bitcoinjs-lib brings tiny-secp256k1, its own hash helpers, and transitive deps that overlap with what’s already present. Two parallel crypto stacks mean two audit scopes and two possible points of supply-chain failure.

A drop-in replacement existed: @scure/btc-signer, from the same maintainers as @scure/base / @scure/bip32 / @scure/bip39 that the project already trusts for Bitcoin-adjacent primitives.

Options considered

  1. Keep bitcoinjs-lib. Works today; incurs ongoing bundler pain for browser builds.
  2. Replace with @scure/btc-signer. Unified dependency stack; known to be browser-first; audited and actively maintained.
  3. Roll our own PSBT + Taproot construction. Full control, but unjustified effort for primitives that have well-maintained libraries.

Decision

Option 2. Remove bitcoinjs-lib from @did-btcr2/bitcoin and @did-btcr2/method dependencies. Rewrite PSBT construction, Taproot address derivation, and transaction signing against @scure/btc-signer.

Affected surfaces:

Consequences

Positive

Negative

Explicitly accepted trade-offs

References