Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion modules/abstract-utxo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"@bitgo/utxo-core": "^1.31.0",
"@bitgo/utxo-lib": "^11.19.1",
"@bitgo/utxo-ord": "^1.24.1",
"@bitgo/wasm-utxo": "^1.27.0",
"@bitgo/wasm-utxo": "^1.29.0",
"@types/lodash": "^4.14.121",
"@types/superagent": "4.1.15",
"bignumber.js": "^9.0.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ export class InputSigningError<TNumber extends number | bigint = number> extends
}
}

export class BulkSigningError extends Error {
constructor(public reason: Error | string) {
const reasonMessage = reason instanceof Error ? reason.message : reason;
super(`bulk signing error: ${reasonMessage}`);
}
}

export class TransactionSigningError<TNumber extends number | bigint = number> extends Error {
constructor(signErrors: InputSigningError<TNumber>[], verifyError: InputSigningError<TNumber>[]) {
super(
Expand Down
33 changes: 13 additions & 20 deletions modules/abstract-utxo/src/transaction/fixedScript/signPsbtWasm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import assert from 'assert';
import { BIP32Interface } from '@bitgo/utxo-lib';
import { BIP32, ECPair, fixedScriptWallet } from '@bitgo/wasm-utxo';

import { InputSigningError, TransactionSigningError } from './SigningError';
import { BulkSigningError, InputSigningError, TransactionSigningError } from './SigningError';
import { Musig2Participant } from './musig2';

export type ReplayProtectionKeys = {
Expand All @@ -29,6 +29,7 @@ function hasKeyPathSpendInput(

/**
* Sign all inputs of a PSBT and verify signatures after signing.
* Uses bulk signing for performance (signs all matching inputs in one pass).
* Collects and logs signing errors and verification errors, throws error in the end if any of them failed.
*/
export function signAndVerifyPsbtWasm(
Expand All @@ -38,32 +39,24 @@ export function signAndVerifyPsbtWasm(
replayProtection: ReplayProtectionKeys
): fixedScriptWallet.BitGoPsbt {
const wasmSigner = toWasmBIP32(signerKeychain);
const parsed = tx.parseTransactionWithWalletKeys(rootWalletKeys, replayProtection);

const signErrors: InputSigningError<bigint>[] = [];
// Bulk sign all wallet inputs (ECDSA + MuSig2) - much faster than per-input signing
try {
tx.sign(wasmSigner);
} catch (e) {
throw new BulkSigningError(e);
}

// Verify signatures for all signed inputs (still per-input for granular error reporting)
const parsed = tx.parseTransactionWithWalletKeys(rootWalletKeys, replayProtection);
const verifyErrors: InputSigningError<bigint>[] = [];

// Sign all inputs (skipping replay protection inputs)
parsed.inputs.forEach((input, inputIndex) => {
if (input.scriptType === 'p2shP2pk') {
// Skip replay protection inputs - they are platform signed only
return;
}

const outputId = `${input.previousOutput.txid}:${input.previousOutput.vout}`;
try {
tx.sign(inputIndex, wasmSigner);
} catch (e) {
signErrors.push(new InputSigningError<bigint>(inputIndex, input.scriptType, { id: outputId }, e));
}
});

// Verify signatures for all signed inputs
parsed.inputs.forEach((input, inputIndex) => {
if (input.scriptType === 'p2shP2pk') {
return;
}

const outputId = `${input.previousOutput.txid}:${input.previousOutput.vout}`;
try {
if (!tx.verifySignature(inputIndex, wasmSigner)) {
Expand All @@ -76,8 +69,8 @@ export function signAndVerifyPsbtWasm(
}
});

if (signErrors.length || verifyErrors.length) {
throw new TransactionSigningError(signErrors, verifyErrors);
if (verifyErrors.length) {
throw new TransactionSigningError([], verifyErrors);
}

return tx;
Expand Down
2 changes: 1 addition & 1 deletion modules/utxo-bin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"@bitgo/unspents": "^0.50.14",
"@bitgo/utxo-core": "^1.31.0",
"@bitgo/utxo-lib": "^11.19.1",
"@bitgo/wasm-utxo": "^1.27.0",
"@bitgo/wasm-utxo": "^1.29.0",
"@noble/curves": "1.8.1",
"archy": "^1.0.0",
"bech32": "^2.0.0",
Expand Down
2 changes: 1 addition & 1 deletion modules/utxo-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
"@bitgo/secp256k1": "^1.9.0",
"@bitgo/unspents": "^0.50.14",
"@bitgo/utxo-lib": "^11.19.1",
"@bitgo/wasm-utxo": "^1.27.0",
"@bitgo/wasm-utxo": "^1.29.0",
"bip174": "npm:@bitgo-forks/bip174@3.1.0-master.4",
"fast-sha256": "^1.3.0"
},
Expand Down
2 changes: 1 addition & 1 deletion modules/utxo-ord/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"directory": "modules/utxo-ord"
},
"dependencies": {
"@bitgo/wasm-utxo": "^1.27.0"
"@bitgo/wasm-utxo": "^1.29.0"
},
"devDependencies": {
"@bitgo/utxo-lib": "^11.19.1"
Expand Down
2 changes: 1 addition & 1 deletion modules/utxo-staking/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"@bitgo/babylonlabs-io-btc-staking-ts": "^3.3.0",
"@bitgo/utxo-core": "^1.31.0",
"@bitgo/utxo-lib": "^11.19.1",
"@bitgo/wasm-utxo": "^1.27.0",
"@bitgo/wasm-utxo": "^1.29.0",
"bip174": "npm:@bitgo-forks/bip174@3.1.0-master.4",
"bip322-js": "^2.0.0",
"bitcoinjs-lib": "^6.1.7",
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -996,10 +996,10 @@
monocle-ts "^2.3.13"
newtype-ts "^0.3.5"

"@bitgo/wasm-utxo@^1.27.0":
version "1.27.0"
resolved "https://registry.npmjs.org/@bitgo/wasm-utxo/-/wasm-utxo-1.27.0.tgz#c8ebe108ce8b55d3df70cd3968211a6ef3001bef"
integrity sha512-gX0YemHbSBOKQ/nKaBsZKI3cJzgkrLXFWuMsPJ7t2oDzE3ggfgVF3ulGFsuaQ8WQT4rOsZ7FZz2f+C9mStXAeA==
"@bitgo/wasm-utxo@^1.29.0":
version "1.29.0"
resolved "https://registry.npmjs.org/@bitgo/wasm-utxo/-/wasm-utxo-1.29.0.tgz#75be3668bd972a3ff9aae07aed84916bfceb870d"
integrity sha512-eWYM7/me8bg+oqw6lEVMdmR1eUVuGzOoyKgSm1QAZUe41qR8IjMyyWjtWI1s5XExfAOXnZuSss/8QJEPOjXhzg==

"@brandonblack/musig@^0.0.1-alpha.0":
version "0.0.1-alpha.1"
Expand Down
Loading