Skip to content

Commit 1a42dfd

Browse files
committed
Removed unnecessary check for tapInternalKey for signature validations of taproot inputs
1 parent bcf1bf8 commit 1a42dfd

File tree

2 files changed

+128
-20
lines changed

2 files changed

+128
-20
lines changed

src/psbt.js

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -454,14 +454,14 @@ class Psbt {
454454
throw new Error('Need validator function to validate signatures');
455455
pubkey = pubkey && (0, bip371_1.toXOnly)(pubkey);
456456
const allHashses = pubkey
457-
? getTaprootHashesForSig(
457+
? getTaprootHashesForSigValidation(
458458
inputIndex,
459459
input,
460460
this.data.inputs,
461461
pubkey,
462462
this.__CACHE,
463463
)
464-
: getAllTaprootHashesForSig(
464+
: getAllTaprootHashesForSigValidation(
465465
inputIndex,
466466
input,
467467
this.data.inputs,
@@ -836,7 +836,7 @@ class Psbt {
836836
throw new Error(
837837
`Need Schnorr Signer to sign taproot input #${inputIndex}.`,
838838
);
839-
const hashesForSig = getTaprootHashesForSig(
839+
const hashesForSig = getTaprootHashesForSigning(
840840
inputIndex,
841841
input,
842842
this.data.inputs,
@@ -1280,9 +1280,9 @@ function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) {
12801280
hash,
12811281
};
12821282
}
1283-
function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) {
1283+
function getAllTaprootHashesForSigValidation(inputIndex, input, inputs, cache) {
12841284
const allPublicKeys = [];
1285-
if (input.tapInternalKey) {
1285+
if (input.tapKeySig) {
12861286
const key = getPrevoutTaprootKey(inputIndex, input, cache);
12871287
if (key) {
12881288
allPublicKeys.push(key);
@@ -1293,7 +1293,13 @@ function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) {
12931293
allPublicKeys.push(...tapScriptPubkeys);
12941294
}
12951295
const allHashes = allPublicKeys.map(pubicKey =>
1296-
getTaprootHashesForSig(inputIndex, input, inputs, pubicKey, cache),
1296+
getTaprootHashesForSigValidation(
1297+
inputIndex,
1298+
input,
1299+
inputs,
1300+
pubicKey,
1301+
cache,
1302+
),
12971303
);
12981304
return allHashes.flat();
12991305
}
@@ -1304,7 +1310,7 @@ function getPrevoutTaprootKey(inputIndex, input, cache) {
13041310
function trimTaprootSig(signature) {
13051311
return signature.length === 64 ? signature : signature.subarray(0, 64);
13061312
}
1307-
function getTaprootHashesForSig(
1313+
function getTaprootHashesForSigning(
13081314
inputIndex,
13091315
input,
13101316
inputs,
@@ -1313,17 +1319,64 @@ function getTaprootHashesForSig(
13131319
tapLeafHashToSign,
13141320
allowedSighashTypes,
13151321
) {
1316-
const unsignedTx = cache.__TX;
13171322
const sighashType =
13181323
input.sighashType || transaction_1.Transaction.SIGHASH_DEFAULT;
13191324
checkSighashTypeAllowed(sighashType, allowedSighashTypes);
1325+
const keySpend = Boolean(input.tapInternalKey && !tapLeafHashToSign);
1326+
return getTaprootHashesForSig(
1327+
inputIndex,
1328+
input,
1329+
inputs,
1330+
pubkey,
1331+
cache,
1332+
keySpend,
1333+
sighashType,
1334+
tapLeafHashToSign,
1335+
);
1336+
}
1337+
function getTaprootHashesForSigValidation(
1338+
inputIndex,
1339+
input,
1340+
inputs,
1341+
pubkey,
1342+
cache,
1343+
) {
1344+
const sighashType =
1345+
input.sighashType || transaction_1.Transaction.SIGHASH_DEFAULT;
1346+
const keySpend = Boolean(input.tapKeySig);
1347+
return getTaprootHashesForSig(
1348+
inputIndex,
1349+
input,
1350+
inputs,
1351+
pubkey,
1352+
cache,
1353+
keySpend,
1354+
sighashType,
1355+
);
1356+
}
1357+
/*
1358+
* This helper method is used for both generating a hash for signing as well for validating;
1359+
* thus depending on context key spend can be detected either with tapInternalKey with no leaves
1360+
* or tapKeySig (note tapKeySig is a signature to the prevout pk, so tapInternalKey is not needed).
1361+
*/
1362+
function getTaprootHashesForSig(
1363+
inputIndex,
1364+
input,
1365+
inputs,
1366+
pubkey,
1367+
cache,
1368+
keySpend,
1369+
sighashType,
1370+
tapLeafHashToSign,
1371+
) {
1372+
const unsignedTx = cache.__TX;
13201373
const prevOuts = inputs.map((i, index) =>
13211374
getScriptAndAmountFromUtxo(index, i, cache),
13221375
);
13231376
const signingScripts = prevOuts.map(o => o.script);
13241377
const values = prevOuts.map(o => o.value);
13251378
const hashes = [];
1326-
if (input.tapInternalKey && !tapLeafHashToSign) {
1379+
if (keySpend) {
13271380
const outputKey =
13281381
getPrevoutTaprootKey(inputIndex, input, cache) || Buffer.from([]);
13291382
if ((0, bip371_1.toXOnly)(pubkey).equals(outputKey)) {

ts_src/psbt.ts

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -590,14 +590,14 @@ export class Psbt {
590590

591591
pubkey = pubkey && toXOnly(pubkey);
592592
const allHashses = pubkey
593-
? getTaprootHashesForSig(
593+
? getTaprootHashesForSigValidation(
594594
inputIndex,
595595
input,
596596
this.data.inputs,
597597
pubkey,
598598
this.__CACHE,
599599
)
600-
: getAllTaprootHashesForSig(
600+
: getAllTaprootHashesForSigValidation(
601601
inputIndex,
602602
input,
603603
this.data.inputs,
@@ -1040,7 +1040,7 @@ export class Psbt {
10401040
`Need Schnorr Signer to sign taproot input #${inputIndex}.`,
10411041
);
10421042

1043-
const hashesForSig = getTaprootHashesForSig(
1043+
const hashesForSig = getTaprootHashesForSigning(
10441044
inputIndex,
10451045
input,
10461046
this.data.inputs,
@@ -1693,14 +1693,14 @@ function getHashForSig(
16931693
};
16941694
}
16951695

1696-
function getAllTaprootHashesForSig(
1696+
function getAllTaprootHashesForSigValidation(
16971697
inputIndex: number,
16981698
input: PsbtInput,
16991699
inputs: PsbtInput[],
17001700
cache: PsbtCache,
17011701
): { pubkey: Buffer; hash: Buffer; leafHash?: Buffer }[] {
17021702
const allPublicKeys = [];
1703-
if (input.tapInternalKey) {
1703+
if (input.tapKeySig) {
17041704
const key = getPrevoutTaprootKey(inputIndex, input, cache);
17051705
if (key) {
17061706
allPublicKeys.push(key);
@@ -1713,7 +1713,13 @@ function getAllTaprootHashesForSig(
17131713
}
17141714

17151715
const allHashes = allPublicKeys.map(pubicKey =>
1716-
getTaprootHashesForSig(inputIndex, input, inputs, pubicKey, cache),
1716+
getTaprootHashesForSigValidation(
1717+
inputIndex,
1718+
input,
1719+
inputs,
1720+
pubicKey,
1721+
cache,
1722+
),
17171723
);
17181724

17191725
return allHashes.flat();
@@ -1732,28 +1738,77 @@ function trimTaprootSig(signature: Buffer): Buffer {
17321738
return signature.length === 64 ? signature : signature.subarray(0, 64);
17331739
}
17341740

1735-
function getTaprootHashesForSig(
1741+
function getTaprootHashesForSigning(
17361742
inputIndex: number,
17371743
input: PsbtInput,
17381744
inputs: PsbtInput[],
17391745
pubkey: Buffer,
17401746
cache: PsbtCache,
17411747
tapLeafHashToSign?: Buffer,
17421748
allowedSighashTypes?: number[],
1743-
): { pubkey: Buffer; hash: Buffer; leafHash?: Buffer }[] {
1744-
const unsignedTx = cache.__TX;
1745-
1749+
) {
17461750
const sighashType = input.sighashType || Transaction.SIGHASH_DEFAULT;
17471751
checkSighashTypeAllowed(sighashType, allowedSighashTypes);
17481752

1753+
const keySpend = Boolean(input.tapInternalKey && !tapLeafHashToSign);
1754+
1755+
return getTaprootHashesForSig(
1756+
inputIndex,
1757+
input,
1758+
inputs,
1759+
pubkey,
1760+
cache,
1761+
keySpend,
1762+
sighashType,
1763+
tapLeafHashToSign,
1764+
);
1765+
}
1766+
1767+
function getTaprootHashesForSigValidation(
1768+
inputIndex: number,
1769+
input: PsbtInput,
1770+
inputs: PsbtInput[],
1771+
pubkey: Buffer,
1772+
cache: PsbtCache,
1773+
) {
1774+
const sighashType = input.sighashType || Transaction.SIGHASH_DEFAULT;
1775+
const keySpend = Boolean(input.tapKeySig);
1776+
return getTaprootHashesForSig(
1777+
inputIndex,
1778+
input,
1779+
inputs,
1780+
pubkey,
1781+
cache,
1782+
keySpend,
1783+
sighashType,
1784+
);
1785+
}
1786+
1787+
/*
1788+
* This helper method is used for both generating a hash for signing as well for validating;
1789+
* thus depending on context key spend can be detected either with tapInternalKey with no leaves
1790+
* or tapKeySig (note tapKeySig is a signature to the prevout pk, so tapInternalKey is not needed).
1791+
*/
1792+
function getTaprootHashesForSig(
1793+
inputIndex: number,
1794+
input: PsbtInput,
1795+
inputs: PsbtInput[],
1796+
pubkey: Buffer,
1797+
cache: PsbtCache,
1798+
keySpend: boolean,
1799+
sighashType: number,
1800+
tapLeafHashToSign?: Buffer,
1801+
): { pubkey: Buffer; hash: Buffer; leafHash?: Buffer }[] {
1802+
const unsignedTx = cache.__TX;
1803+
17491804
const prevOuts: Output[] = inputs.map((i, index) =>
17501805
getScriptAndAmountFromUtxo(index, i, cache),
17511806
);
17521807
const signingScripts = prevOuts.map(o => o.script);
17531808
const values = prevOuts.map(o => o.value);
17541809

17551810
const hashes = [];
1756-
if (input.tapInternalKey && !tapLeafHashToSign) {
1811+
if (keySpend) {
17571812
const outputKey =
17581813
getPrevoutTaprootKey(inputIndex, input, cache) || Buffer.from([]);
17591814
if (toXOnly(pubkey).equals(outputKey)) {

0 commit comments

Comments
 (0)