Skip to content

Commit c7a1bbd

Browse files
Merge pull request #8081 from BitGo/BTC-2866.fix-bip322
feat(abstract-utxo): fix BIP322 sighash type handling with wasm-utxo 1.34.0
2 parents d1b29a1 + b721908 commit c7a1bbd

7 files changed

Lines changed: 73 additions & 9 deletions

File tree

modules/abstract-utxo/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
"@bitgo/utxo-core": "^1.32.0",
6868
"@bitgo/utxo-lib": "^11.20.0",
6969
"@bitgo/utxo-ord": "^1.25.0",
70-
"@bitgo/wasm-utxo": "^1.32.0",
70+
"@bitgo/wasm-utxo": "^1.34.0",
7171
"@types/lodash": "^4.14.121",
7272
"@types/superagent": "4.1.15",
7373
"bignumber.js": "^9.0.2",

modules/abstract-utxo/test/unit/bip322.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import assert from 'assert';
22

33
import * as utxolib from '@bitgo/utxo-lib';
4+
import { bip322 as coreBip322 } from '@bitgo/utxo-core';
45
import { bip322 as wasmBip322, fixedScriptWallet, BIP32, type Triple } from '@bitgo/wasm-utxo';
56

67
import {
@@ -401,4 +402,67 @@ describe('BIP322', function () {
401402
);
402403
});
403404
});
405+
406+
describe('utxolib verification stack - wasm-utxo respects input.sighashType', function () {
407+
// This test verifies that wasm-utxo correctly respects the input.sighashType field
408+
// when creating musig2 partial signatures.
409+
//
410+
// Previously (before fix), wasm-utxo would always create signatures with SIGHASH_DEFAULT (0)
411+
// regardless of the input.sighashType field, causing validation to fail.
412+
//
413+
// Now (after fix), wasm-utxo reads input.sighashType and creates signatures with the
414+
// correct sighash type, allowing validation to succeed.
415+
416+
it('should validate signatures when wasm-utxo respects input.sighashType', function () {
417+
const seed = 'p2trMusig2_sighash_test';
418+
const { xprivs } = createTestWalletKeys(seed);
419+
420+
// Create utxolib RootWalletKeys for utxo-core PSBT construction
421+
const utxolibRootWalletKeys = new utxolib.bitgo.RootWalletKeys(utxolib.testutil.getKeyTriple(seed));
422+
423+
// p2trMusig2 external chain code
424+
const chain = utxolib.bitgo.getExternalChainCode('p2trMusig2');
425+
const index = 0;
426+
const messageText = 'BIP322 sighash test';
427+
428+
// Create BIP322 PSBT using utxo-core
429+
const psbt = coreBip322.createBaseToSignPsbt(utxolibRootWalletKeys, utxolib.networks.bitcoin);
430+
coreBip322.addBip322InputWithChainAndIndex(psbt, messageText, utxolibRootWalletKeys, { chain, index });
431+
432+
// Note: utxo-core sets sighashType: Transaction.SIGHASH_ALL (1) for BIP322 inputs
433+
const SIGHASH_ALL = 1;
434+
assert.strictEqual(psbt.data.inputs[0].sighashType, SIGHASH_ALL);
435+
436+
// Convert to wasm-utxo PSBT for cosigning
437+
const wasmPsbt = fixedScriptWallet.BitGoPsbt.fromBytes(psbt.toBuffer(), 'btc');
438+
439+
// Generate musig2 nonces and sign with wasm-utxo
440+
// wasm-utxo now respects input.sighashType and creates signatures with SIGHASH_ALL
441+
const userKey = BIP32.fromBase58(xprivs[0]);
442+
const bitgoKey = BIP32.fromBase58(xprivs[2]);
443+
444+
wasmPsbt.generateMusig2Nonces(userKey);
445+
wasmPsbt.generateMusig2Nonces(bitgoKey);
446+
wasmPsbt.sign(0, userKey);
447+
wasmPsbt.sign(0, bitgoKey);
448+
449+
// Convert back to utxolib PSBT for validation
450+
const signedPsbt = utxolib.bitgo.createPsbtFromBuffer(
451+
Buffer.from(wasmPsbt.serialize()),
452+
utxolib.networks.bitcoin
453+
);
454+
455+
// Validation should succeed because wasm-utxo now creates signatures
456+
// with the correct sighash type (SIGHASH_ALL) matching input.sighashType
457+
const validationResult = utxolib.bitgo.getSignatureValidationArrayPsbt(signedPsbt, utxolibRootWalletKeys);
458+
459+
// Verify that both user (index 0) and bitgo (index 2) signatures are valid
460+
assert.strictEqual(validationResult.length, 1);
461+
const [inputIndex, sigValidation] = validationResult[0];
462+
assert.strictEqual(inputIndex, 0);
463+
assert.strictEqual(sigValidation[0], true, 'user signature should be valid');
464+
assert.strictEqual(sigValidation[1], false, 'backup signature should not be present');
465+
assert.strictEqual(sigValidation[2], true, 'bitgo signature should be valid');
466+
});
467+
});
404468
});

modules/utxo-bin/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"@bitgo/unspents": "^0.51.0",
3232
"@bitgo/utxo-core": "^1.32.0",
3333
"@bitgo/utxo-lib": "^11.20.0",
34-
"@bitgo/wasm-utxo": "^1.32.0",
34+
"@bitgo/wasm-utxo": "^1.34.0",
3535
"@noble/curves": "1.8.1",
3636
"archy": "^1.0.0",
3737
"bech32": "^2.0.0",

modules/utxo-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
"@bitgo/secp256k1": "^1.10.0",
8282
"@bitgo/unspents": "^0.51.0",
8383
"@bitgo/utxo-lib": "^11.20.0",
84-
"@bitgo/wasm-utxo": "^1.32.0",
84+
"@bitgo/wasm-utxo": "^1.34.0",
8585
"bip174": "npm:@bitgo-forks/bip174@3.1.0-master.4",
8686
"fast-sha256": "^1.3.0"
8787
},

modules/utxo-ord/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"directory": "modules/utxo-ord"
4646
},
4747
"dependencies": {
48-
"@bitgo/wasm-utxo": "^1.32.0"
48+
"@bitgo/wasm-utxo": "^1.34.0"
4949
},
5050
"devDependencies": {
5151
"@bitgo/utxo-lib": "^11.20.0"

modules/utxo-staking/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
"@bitgo/babylonlabs-io-btc-staking-ts": "^3.4.0",
6464
"@bitgo/utxo-core": "^1.32.0",
6565
"@bitgo/utxo-lib": "^11.20.0",
66-
"@bitgo/wasm-utxo": "^1.32.0",
66+
"@bitgo/wasm-utxo": "^1.34.0",
6767
"bip174": "npm:@bitgo-forks/bip174@3.1.0-master.4",
6868
"bip322-js": "^2.0.0",
6969
"bitcoinjs-lib": "^6.1.7",

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -996,10 +996,10 @@
996996
monocle-ts "^2.3.13"
997997
newtype-ts "^0.3.5"
998998

999-
"@bitgo/wasm-utxo@^1.32.0":
1000-
version "1.32.0"
1001-
resolved "https://registry.npmjs.org/@bitgo/wasm-utxo/-/wasm-utxo-1.32.0.tgz#fc7e7803eb584ba8ad16aeb0a2805d6905d287d3"
1002-
integrity sha512-fqUGh8XOrzbPcTxK3lhS9UjqKxx3UaN6L+eS3vocBeWHbQvl6jm9xPPQ+TDkeiUuZdxaj0+7ca4Algt9vyiXHg==
999+
"@bitgo/wasm-utxo@^1.34.0":
1000+
version "1.34.0"
1001+
resolved "https://registry.npmjs.org/@bitgo/wasm-utxo/-/wasm-utxo-1.34.0.tgz#318bcc0a20acc3f35b9547548ea36506beaab237"
1002+
integrity sha512-aJuLQ8fNAWmI213sIwMt9WJfWvsyVAmmyUWnojUdmK2iHwf6tIo4B9gWHoPuWwNYoqc/UJVbK3dDKxnMIUk/bg==
10031003

10041004
"@brandonblack/musig@^0.0.1-alpha.0":
10051005
version "0.0.1-alpha.1"

0 commit comments

Comments
 (0)