Skip to content

chore: upgrades bitcore-lib to 10.10.7#1033

Open
tuliomir wants to merge 1 commit intomasterfrom
chore/upgrades-bitcore-lib
Open

chore: upgrades bitcore-lib to 10.10.7#1033
tuliomir wants to merge 1 commit intomasterfrom
chore/upgrades-bitcore-lib

Conversation

@tuliomir
Copy link
Copy Markdown
Contributor

@tuliomir tuliomir commented Mar 11, 2026

Summary

  • Upgrades bitcore-lib and bitcore-mnemonic from 8.25.10 to 10.10.7 (latest stable)
  • Fixes intermittent "s must be 32 bytes" error in message signing/verification (bitcore#3860, fixed in PR#3817)
  • Renames the versionGuard patch file to match the new version (patch content unchanged)

The Bug

ECDSA.sign() intermittently produces r or s signature values shorter than 32 bytes because BN (big number) serialization strips leading zeros. When Message.verify() later calls Signature.fromCompact(), it asserts exactly 32 bytes and throws:

Invalid Argument: Error: s must be 32 bytes
  at Signature.fromCompact (bitcore-lib/lib/crypto/signature.js)
  at Message.verify (bitcore-lib/lib/message.js)

This is a ~1-in-256 chance per signature component, making it an intermittent failure that is hard to reproduce deterministically.

The fix (applied in v10.8.9) normalizes r and s through proper buffer round-tripping in the sign() function:

// Before: raw BN values could have < 32 bytes
return new Signature({ s, r, compressed });
// After: ensures consistent 32-byte representation
return new Signature({
  s: BN.fromBuffer(s.toBuffer({ endian }), { endian }),
  r: BN.fromBuffer(r.toBuffer({ endian }), { endian }),
  compressed
});

Why 10.10.7 and not a smaller jump?

  • No intermediate stable releases contain the fix — v8.25.x was the last 8.x release, and the fix landed in v10.8.9.
  • 10.10.7 is the npm latest tag (v11.x is beta), making it the safest stable target.
  • The diff between 10.8.9 and 10.10.7 is minimal — only cosmetic changes (varconst), JSDoc improvements, and a defensive guard in Point prototype patching.

Breaking changes analysis

Every bitcore-lib API used by wallet-lib was verified against the v10 source. Summary:

Change Risk Details
ECDSA restructured from class to standalone functions None ECDSA.sign(hash, privkey) and ECDSA.verify(hash, sig, pubkey) still work identically — both return/accept Signature objects
Network properties now immutable after Networks.add() None Wallet-lib never mutates network properties after creation
networkMaps stores arrays instead of single values Positive Eliminates potential collision between Hathor and Bitcoin network lookups
New Schnorr, TaggedHash crypto exports None Additive only, no existing code affected
Signature class adds isSchnorr support None Backward compatible — set({nhashtype}), toDER(), SIGHASH_ALL unchanged
Message.MAGIC_BYTES monkey-patch None Still a simple writable property on the constructor

All 25+ API entry points used by wallet-lib (HDPrivateKey, HDPublicKey, Address, Script, Message, Mnemonic, encoding, util, etc.) were individually verified to exist with the same signatures in v10.10.7.

What changed in this PR

  1. package.json — bumped bitcore-lib and bitcore-mnemonic to 10.10.7
  2. patches/bitcore-lib+8.25.10.patchpatches/bitcore-lib+10.10.7.patch (renamed, same content — versionGuard bypass)
  3. package-lock.json — regenerated

No source code changes were needed — all wallet-lib code is fully compatible with v10.10.7.

Summary by CodeRabbit

  • Chores
    • Updated dependencies to newer versions for improved stability and maintenance.

@tuliomir tuliomir self-assigned this Mar 11, 2026
@tuliomir tuliomir added the dependencies Pull requests that update a dependency file label Mar 11, 2026
@tuliomir tuliomir moved this from Todo to In Progress (WIP) in Hathor Network Mar 11, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 507fc718-ed8a-470a-b3bb-69f1a9fd59a7

📥 Commits

Reviewing files that changed from the base of the PR and between 088ec8e and c01fac0.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • package.json
  • patches/bitcore-lib+10.10.7.patch

📝 Walkthrough

Walkthrough

Package.json dependency versions are updated for bitcore-lib and bitcore-mnemonic from 8.25.10 to 10.10.7. No changes to scripts, devDependencies, or other configuration fields.

Changes

Cohort / File(s) Summary
Dependency Version Updates
package.json
bitcore-lib and bitcore-mnemonic upgraded from 8.25.10 to 10.10.7

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

🐰 Two libraries hop and bound,
From eight-point-two-five they're skyward found,
To ten-point-ten they make their leap,
Version bumps run bright and deep! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: upgrading bitcore-lib to version 10.10.7, which is the primary focus of this dependency update PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/upgrades-bitcore-lib

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 11, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.82%. Comparing base (088ec8e) to head (c01fac0).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1033   +/-   ##
=======================================
  Coverage   87.82%   87.82%           
=======================================
  Files         114      114           
  Lines        8818     8818           
  Branches     2004     1994   -10     
=======================================
  Hits         7744     7744           
  Misses       1046     1046           
  Partials       28       28           

☔ View full report in Codecov by Sentry.
📢 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.

@tuliomir tuliomir requested a review from r4mmer March 11, 2026 13:28
@tuliomir tuliomir moved this from In Progress (WIP) to In Progress (Done) in Hathor Network Mar 11, 2026
@tuliomir
Copy link
Copy Markdown
Contributor Author

Future consideration: removing the bitcore-lib dependency entirely

This upgrade fixes the immediate bug, but it's worth documenting the long-term options for the team. Bitcore-lib is a heavy, monolithic dependency with some concerning characteristics. Here's a quick overview.

Why consider removing bitcore-lib?

  • Pinned to outdated transitive deps — bitcore-lib 10.10.7 pins bn.js@4.11.8 (latest is 5.2.3) and inherits@2.0.1 (latest is 2.0.4). These are exact pins (=), not ranges.
  • No changelog or release notes — breaking changes between versions can only be discovered by diffing source code across tags in the monorepo.
  • No TypeScript types — the library ships no .d.ts files and there is no @types/bitcore-lib package on DefinitelyTyped. We rely on noImplicitAny: false in tsconfig.
  • Requires a patch — we must patch out the versionGuard on every install to prevent runtime errors when bitcore-mnemonic loads its own bitcore-lib instance.
  • Large unused surface — we use ~7,000 of the library's ~13,000 lines. The Transaction, Block, Script Interpreter, URI, and Unit modules are never touched.

The modern alternative: @noble/* + @scure/*

Paul Miller's ecosystem is the current standard for JS crypto primitives. All libraries are independently audited, zero-dependency, and TypeScript-native:

What we need Current (bitcore) Replacement Audited?
ECDSA + secp256k1 bitcore.crypto.ECDSAelliptic @noble/secp256k1 Yes
SHA-256, HMAC, RIPEMD-160 bitcore.crypto.Hash → Node crypto @noble/hashes Yes
HD key derivation (BIP32) bitcore.HDPrivateKey / HDPublicKey @scure/bip32 Yes
Mnemonic phrases (BIP39) bitcore-mnemonic @scure/bip39 Yes
Base58 / Base58Check bitcore.encoding.Base58bs58 @scure/base Yes

What's left would be ~300-400 lines of custom code for: Hathor Networks config, Address encoding, Message sign/verify, and Script.buildMultisigOut.

Pros of migrating

  • Audited crypto@noble/* and @scure/* have published audit reports; bitcore-lib and elliptic do not
  • Native TypeScript — full type safety without noImplicitAny: false workarounds
  • Smaller bundle@noble/secp256k1 is 5KB vs elliptic at ~90KB
  • No more patches — eliminates the versionGuard hack
  • Active maintenance — noble/scure receive regular updates; bitcore-lib's last meaningful change was cosmetic

Cons / risks of migrating

  • deriveNonCompliantChild() — this is a bitcore-specific BIP32 extension that skips invalid derived keys instead of throwing. @scure/bip32 does not implement this — we'd need to port ~30 lines and verify behavioral parity
  • HDPrivateKey._buffers — tests access internal buffer structures for validation; @scure/bip32 has a different internal representation
  • Address encoding — our custom Hathor address logic and version byte handling are tightly coupled to bitcore's Networks.add() and Address class
  • Effort — estimated at weeks of work, plus extensive regression testing across all wallet operations
  • Risk surface — subtle behavioral differences in edge cases (key derivation, signature encoding) could cause funds-related bugs that only manifest in production

Another option: inline the bitcore source

Instead of migrating to new libraries, we could copy the ~7,000 lines we actually use into the repo directly. This would:

  • ✅ Remove the npm dependency and patch requirement
  • ✅ Let us fix bugs (like #3860) directly
  • ❌ Make us responsible for maintaining 7,000 lines of untyped legacy JS forever
  • ❌ Still depend on elliptic and bn.js@4.11.8 underneath

This is probably the worst option unless we plan to immediately start replacing modules with @noble/* incrementally.

Recommendation

Short term (this PR): upgrade to 10.10.7, fix the bug, move on.

Medium term: if we decide to migrate, the @noble/* + @scure/* path is clearly the better long-term choice over inlining. A good incremental approach would be:

  1. Replace crypto.Hash with @noble/hashes (lowest risk, most isolated)
  2. Replace encoding.Base58 with @scure/base
  3. Replace ECDSA + Signature with @noble/secp256k1
  4. Replace HDPrivateKey/HDPublicKey with @scure/bip32 (highest risk, needs careful testing)
  5. Replace Mnemonic with @scure/bip39
  6. Write custom Address, Networks, Message (~300 lines)
  7. Remove bitcore-lib and bitcore-mnemonic

Each step can be a separate PR with its own test validation.

@r4mmer
Copy link
Copy Markdown
Member

r4mmer commented Mar 12, 2026

I like this but there are other considerations for this update.
All wallets should update their own bitcore-lib version to match, different versions of bitcore-lib will make the wallet-lib's version install as a sub-dependency and then we will have conflicts with the version guard.

I like the idea of not depending on bitcore, if not the noble/* and scure/* we can go into other small libraries with the crypto part and implement our logic on top.

The main important issue is deriveNonCompliantChild, this method exists because bitcore got the first implementation of the derivation wrong, this would make (from what I tested) 0.4% of wallets make a different derivation, which in turn generates different private keys and addresses, all of which are usable but if we change the derivation method we will generate different addresses for these wallets and the funds will be perceived as "lost".

We should create a plan to migrate this usage of deriveNonCompliantChild before we even consider moving out of bitcore-lib.

Obs: 0.4% is aprox. $$1/256$$ wich makes sense because the issue with derivation would only happen when we had a hash with a leading zero.

@tuliomir tuliomir moved this from In Progress (Done) to In Review (WIP) in Hathor Network Mar 12, 2026
@tuliomir tuliomir mentioned this pull request Apr 13, 2026
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file

Projects

Status: In Review (WIP)

Development

Successfully merging this pull request may close these issues.

2 participants