Skip to content

Commit da0b34d

Browse files
authored
Merge pull request #1932 from bitcoinjs/fix/validate-sigs
Fix: Find hashes WITHOUT leafHash instead
2 parents 5d2ff1c + f8cfd7f commit da0b34d

File tree

6 files changed

+58
-10
lines changed

6 files changed

+58
-10
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 6.1.2
2+
__fixed__
3+
- validateSignaturesOfInput for taproot inputs returned true for invalid signatures in specific cases. (#1932)
4+
15
# 6.1.1
26
__added__
37
- add example using BIP86 vector to verify the sending to and from a BIP86 generated taproot address

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bitcoinjs-lib",
3-
"version": "6.1.1",
3+
"version": "6.1.2",
44
"description": "Client-side Bitcoin JavaScript library",
55
"main": "./src/index.js",
66
"types": "./src/index.d.ts",

src/psbt.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -468,14 +468,16 @@ class Psbt {
468468
this.__CACHE,
469469
);
470470
if (!allHashses.length) throw new Error('No signatures for this pubkey');
471-
const tapKeyHash = allHashses.find(h => !!h.leafHash);
471+
const tapKeyHash = allHashses.find(h => !h.leafHash);
472+
let validationResultCount = 0;
472473
if (tapKeySig && tapKeyHash) {
473474
const isValidTapkeySig = validator(
474475
tapKeyHash.pubkey,
475476
tapKeyHash.hash,
476-
tapKeySig,
477+
trimTaprootSig(tapKeySig),
477478
);
478479
if (!isValidTapkeySig) return false;
480+
validationResultCount++;
479481
}
480482
if (tapScriptSig) {
481483
for (const tapSig of tapScriptSig) {
@@ -484,13 +486,14 @@ class Psbt {
484486
const isValidTapScriptSig = validator(
485487
tapSig.pubkey,
486488
tapSigHash.hash,
487-
tapSig.signature,
489+
trimTaprootSig(tapSig.signature),
488490
);
489491
if (!isValidTapScriptSig) return false;
492+
validationResultCount++;
490493
}
491494
}
492495
}
493-
return true;
496+
return validationResultCount > 0;
494497
}
495498
signAllInputsHD(
496499
hdKeyPair,
@@ -1292,6 +1295,9 @@ function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) {
12921295
);
12931296
return allHashes.flat();
12941297
}
1298+
function trimTaprootSig(signature) {
1299+
return signature.length === 64 ? signature : signature.subarray(1);
1300+
}
12951301
function getTaprootHashesForSig(
12961302
inputIndex,
12971303
input,

test/integration/taproot.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,37 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
598598
});
599599
}
600600
});
601+
602+
it('should fail validating invalid signatures for taproot (See issue #1931)', () => {
603+
const schnorrValidator = (
604+
pubkey: Buffer,
605+
msghash: Buffer,
606+
signature: Buffer,
607+
) => {
608+
return ecc.verifySchnorr(msghash, pubkey, signature);
609+
};
610+
611+
const psbtBase64 =
612+
`cHNidP8BAFICAAAAAe1h73A6zedruNERV6JU7Ty1IlYZh2KO1cBklZqCMEy8AAAAAAD/////ARA
613+
nAAAAAAAAFgAUS0GlfqWSeEWIpwPwrvRIjBbJQroAAAAAAAEA/TgBAQAAAAABAnGJ6st1FIvYLEV
614+
bJMQaZ3HSOJnkw5C+ViCuJYiFEYosAAAAAAD9////xuZd0xArNSaBuElLX3nzjwtZW95O7L/wbz9
615+
4v+v0vuYAAAAAAP3///8CECcAAAAAAAAiUSAVbMSHgwYVdyBgfNy0syr6TMaFOGhFjXJYuQcRLlp
616+
DS8hgBwAAAAAAIlEgthWGz3o2R7WpgjIK52ODoEaA/0HcImSUjVk6agZgghwBQIP9WWErMfeBBYy
617+
uHuSZS7MdXVICtlFgNveDrvuXeQGSZl1gGG6/r3Aw7h9TifGtoA+7JwYBjLMcEG6hbeyQGXIBQNS
618+
qKH1p/NFzO9bxe9vpvBZQIaX5Qa9SY2NfNCgSRNabmX5EiaihWcLC+ALgchm7DUfYrAmi1r4uSI/
619+
YaQ1lq8gAAAAAAQErECcAAAAAAAAiUSAVbMSHgwYVdyBgfNy0syr6TMaFOGhFjXJYuQcRLlpDSwE
620+
DBIMAAAABCEMBQZUpv6e1Hwfpi/PpglkkK/Rx40vZIIHwtJ7dXWFZ5TcZUEelCnfKOAWZ4xWjauY
621+
M2y+JcgFcVsuPzPuiM+z5AH+DARNBlSm/p7UfB+mL8+mCWSQr9HHjS9kggfC0nt1dYVnlNxlQR6U
622+
Kd8o4BZnjFaNq5gzbL4lyAVxWy4/M+6Iz7PkAf4MBFyC6ZCT2zZVrEbkw/T1fyS8eLKQaP2MH6rz
623+
dlMauGvQzLQAA`.replace(/\s+/g, '');
624+
625+
const psbt = bitcoin.Psbt.fromBase64(psbtBase64);
626+
627+
assert(
628+
!psbt.validateSignaturesOfAllInputs(schnorrValidator),
629+
'Should fail validation',
630+
);
631+
});
601632
});
602633

603634
function buildLeafIndexFinalizer(

ts_src/psbt.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -606,14 +606,16 @@ export class Psbt {
606606

607607
if (!allHashses.length) throw new Error('No signatures for this pubkey');
608608

609-
const tapKeyHash = allHashses.find(h => !!h.leafHash);
609+
const tapKeyHash = allHashses.find(h => !h.leafHash);
610+
let validationResultCount = 0;
610611
if (tapKeySig && tapKeyHash) {
611612
const isValidTapkeySig = validator(
612613
tapKeyHash.pubkey,
613614
tapKeyHash.hash,
614-
tapKeySig,
615+
trimTaprootSig(tapKeySig),
615616
);
616617
if (!isValidTapkeySig) return false;
618+
validationResultCount++;
617619
}
618620

619621
if (tapScriptSig) {
@@ -623,14 +625,15 @@ export class Psbt {
623625
const isValidTapScriptSig = validator(
624626
tapSig.pubkey,
625627
tapSigHash.hash,
626-
tapSig.signature,
628+
trimTaprootSig(tapSig.signature),
627629
);
628630
if (!isValidTapScriptSig) return false;
631+
validationResultCount++;
629632
}
630633
}
631634
}
632635

633-
return true;
636+
return validationResultCount > 0;
634637
}
635638

636639
signAllInputsHD(
@@ -1714,6 +1717,10 @@ function getAllTaprootHashesForSig(
17141717
return allHashes.flat();
17151718
}
17161719

1720+
function trimTaprootSig(signature: Buffer): Buffer {
1721+
return signature.length === 64 ? signature : signature.subarray(1);
1722+
}
1723+
17171724
function getTaprootHashesForSig(
17181725
inputIndex: number,
17191726
input: PsbtInput,

0 commit comments

Comments
 (0)