Skip to content

test: add BIP45/BIP67 test vectors and enforce multisig lexicographic… - #35

Open
RiH-137 wants to merge 1 commit into
Swapso-App:dev-branchfrom
RiH-137:test/bip45-multisig-address-vectors
Open

test: add BIP45/BIP67 test vectors and enforce multisig lexicographic…#35
RiH-137 wants to merge 1 commit into
Swapso-App:dev-branchfrom
RiH-137:test/bip45-multisig-address-vectors

Conversation

@RiH-137

@RiH-137 RiH-137 commented Mar 21, 2026

Copy link
Copy Markdown

Description:
This commit implements and tests the strict lexicographical sorting requirement for public keys in multisig address generation in accordance with BIP45 and BIP67.

Changes:

  • Added createMultiSigAddress.ts implementation securely supporting P2SH, P2SH-P2WSH, and P2WSH addresses.
  • Implemented Buffer.compare sorting for public keys prior to address generation to comply with BIP45/BIP67 deterministic multisig.
  • Integrated raw BIP67 vector test cases alongside the bitcoinjs-lib expected derivations in test/createMultiSigAddress.js to ensure the core sorting algorithm generates standard-compliant outputs.
  • Exported the newly created utility in src/helper/utils/index.ts. All 5 verification tests pass flawlessly.

Related Task:

  • Ref: Phase 3 (Multi-Sig) - Test address generation against BIP45 test vectors

Copilot AI review requested due to automatic review settings March 21, 2026 17:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds a multisig address utility that enforces BIP67-style lexicographic pubkey sorting (referenced alongside BIP45), plus tests to validate P2SH / nested SegWit / native SegWit multisig derivations.

Changes:

  • Introduces createMultiSigAddress to generate P2SH, P2SH-P2WSH, and P2WSH multisig addresses with lexicographically sorted pubkeys.
  • Adds Mocha tests including a BIP67 vector to validate sorting and expected address derivations.
  • Exports the new utility via src/helper/utils/index.* barrel files.

Reviewed changes

Copilot reviewed 6 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
package.json Deleted root npm manifest (not referenced in PR description).
package-lock.json Deleted root npm lockfile (not referenced in PR description).
btc-controller/src/helper/utils/createMultiSigAddress.ts New multisig address generator with lexicographic pubkey sorting.
btc-controller/src/helper/utils/createMultiSigAddress.js Compiled JS output for the new multisig utility.
btc-controller/src/helper/utils/createMultiSigAddress.d.ts Type declarations for the new multisig utility.
btc-controller/src/helper/utils/index.ts Re-exports createMultiSigAddress from utils barrel.
btc-controller/src/helper/utils/index.js Compiled barrel update to export createMultiSigAddress.
btc-controller/src/helper/utils/index.d.ts Declaration barrel update to export createMultiSigAddress.
btc-controller/test/createMultiSigAddress.js New test suite covering multisig types + BIP67 sorting vector.
btc-controller/out.txt Added log/error output file (appears accidental).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +22 to +26
}: MultiSigConfig): MultiSigResult {
if (requiredSignatures > publicKeys.length) {
throw new Error('requiredSignatures cannot be greater than number of public keys');
}

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

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

requiredSignatures is only checked against publicKeys.length. This currently allows requiredSignatures <= 0 and multisig sizes beyond Bitcoin script limits (e.g., publicKeys.length > 16), which will cause bitcoinjs.payments.p2ms to throw less clear errors. Add explicit validation for 1 <= requiredSignatures <= publicKeys.length and publicKeys.length <= 16 (and optionally requiredSignatures <= 16) with consistent error messages.

Suggested change
}: MultiSigConfig): MultiSigResult {
if (requiredSignatures > publicKeys.length) {
throw new Error('requiredSignatures cannot be greater than number of public keys');
}
}: MultiSigConfig): MultiSigResult {
// Validate multisig parameters before constructing scripts
if (requiredSignatures < 1) {
throw new Error('requiredSignatures must be at least 1');
}
if (requiredSignatures > publicKeys.length) {
throw new Error('requiredSignatures cannot be greater than number of public keys');
}
if (publicKeys.length < 1) {
throw new Error('At least one public key is required to create a multisig address');
}
if (publicKeys.length > 16) {
throw new Error('Number of public keys in a multisig address cannot exceed 16');
}
if (requiredSignatures > 16) {
throw new Error('requiredSignatures cannot exceed 16');
}

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +12
type?: 'P2SH' | 'P2SH-P2WSH' | 'P2WSH';
}

export interface MultiSigResult {
address: string;
type: string;

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

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

MultiSigResult.type is typed as string, but the function only ever returns the three supported literal values. Consider typing this as the same union as MultiSigConfig['type'] (or a shared MultiSigType alias) so callers get compile-time guarantees and autocomplete.

Suggested change
type?: 'P2SH' | 'P2SH-P2WSH' | 'P2WSH';
}
export interface MultiSigResult {
address: string;
type: string;
type?: MultiSigType;
}
export type MultiSigType = 'P2SH' | 'P2SH-P2WSH' | 'P2WSH';
export interface MultiSigResult {
address: string;
type: MultiSigType;

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +7
const ECPairFactory = require('ecpair').default;
const ecc = require('@bitcoinerlab/secp256k1');
const { createMultiSigAddress } = require('../src/helper/utils/createMultiSigAddress');

const ECPair = ECPairFactory(ecc);

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

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

This test imports ECPair with require('ecpair').default, but elsewhere in this repo tests use a safer pattern (const ECPairFactory = ECPairModule.default || ECPairModule) to handle both CJS and ESM export shapes. Align this test with that pattern to avoid ECPairFactory being undefined in environments where ecpair doesn't expose .default.

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +7
import { createMultiSigAddress } from "./createMultiSigAddress";

export { getNetwork, generateAddress, calcBip32ExtendedKeys, getAddressFromPk };
export { getNetwork, generateAddress, calcBip32ExtendedKeys, getAddressFromPk, createMultiSigAddress };

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

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

This PR also removes the repository-root package.json and package-lock.json, but the PR description is focused on multisig sorting/tests and doesn't mention this packaging change. If the deletion is intentional cleanup, please document the rationale in the PR (and ensure tooling/CI/publishing doesn't rely on root-level npm metadata); otherwise, revert these deletions.

Copilot uses AI. Check for mistakes.
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