Skip to content

Commit 2d8d57a

Browse files
committed
Removed unnecessary check for tapInternalKey for signature validations of taproot inputs
1 parent c151d53 commit 2d8d57a

File tree

3 files changed

+186
-26
lines changed

3 files changed

+186
-26
lines changed

src/cjs/psbt.cjs

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -516,14 +516,14 @@ class Psbt {
516516
throw new Error('Need validator function to validate signatures');
517517
pubkey = pubkey && (0, bip371_js_1.toXOnly)(pubkey);
518518
const allHashses = pubkey
519-
? getTaprootHashesForSig(
519+
? getTaprootHashesForSigValidation(
520520
inputIndex,
521521
input,
522522
this.data.inputs,
523523
pubkey,
524524
this.__CACHE,
525525
)
526-
: getAllTaprootHashesForSig(
526+
: getAllTaprootHashesForSigValidation(
527527
inputIndex,
528528
input,
529529
this.data.inputs,
@@ -900,7 +900,7 @@ class Psbt {
900900
throw new Error(
901901
`Need Schnorr Signer to sign taproot input #${inputIndex}.`,
902902
);
903-
const hashesForSig = getTaprootHashesForSig(
903+
const hashesForSig = getTaprootHashesForSigning(
904904
inputIndex,
905905
input,
906906
this.data.inputs,
@@ -1348,7 +1348,7 @@ function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) {
13481348
hash,
13491349
};
13501350
}
1351-
function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) {
1351+
function getAllTaprootHashesForSigValidation(inputIndex, input, inputs, cache) {
13521352
const allPublicKeys = [];
13531353
if (input.tapInternalKey) {
13541354
const key = getPrevoutTaprootKey(inputIndex, input, cache);
@@ -1361,7 +1361,13 @@ function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) {
13611361
allPublicKeys.push(...tapScriptPubkeys);
13621362
}
13631363
const allHashes = allPublicKeys.map(publicKey =>
1364-
getTaprootHashesForSig(inputIndex, input, inputs, publicKey, cache),
1364+
getTaprootHashesForSigValidation(
1365+
inputIndex,
1366+
input,
1367+
inputs,
1368+
publicKey,
1369+
cache,
1370+
),
13651371
);
13661372
return allHashes.flat();
13671373
}
@@ -1372,7 +1378,7 @@ function getPrevoutTaprootKey(inputIndex, input, cache) {
13721378
function trimTaprootSig(signature) {
13731379
return signature.length === 64 ? signature : signature.subarray(0, 64);
13741380
}
1375-
function getTaprootHashesForSig(
1381+
function getTaprootHashesForSigning(
13761382
inputIndex,
13771383
input,
13781384
inputs,
@@ -1381,17 +1387,64 @@ function getTaprootHashesForSig(
13811387
tapLeafHashToSign,
13821388
allowedSighashTypes,
13831389
) {
1384-
const unsignedTx = cache.__TX;
13851390
const sighashType =
13861391
input.sighashType || transaction_js_1.Transaction.SIGHASH_DEFAULT;
13871392
checkSighashTypeAllowed(sighashType, allowedSighashTypes);
1393+
const keySpend = Boolean(input.tapInternalKey && !tapLeafHashToSign);
1394+
return getTaprootHashesForSig(
1395+
inputIndex,
1396+
input,
1397+
inputs,
1398+
pubkey,
1399+
cache,
1400+
keySpend,
1401+
sighashType,
1402+
tapLeafHashToSign,
1403+
);
1404+
}
1405+
function getTaprootHashesForSigValidation(
1406+
inputIndex,
1407+
input,
1408+
inputs,
1409+
pubkey,
1410+
cache,
1411+
) {
1412+
const sighashType =
1413+
input.sighashType || transaction_js_1.Transaction.SIGHASH_DEFAULT;
1414+
const keySpend = Boolean(input.tapKeySig);
1415+
return getTaprootHashesForSig(
1416+
inputIndex,
1417+
input,
1418+
inputs,
1419+
pubkey,
1420+
cache,
1421+
keySpend,
1422+
sighashType,
1423+
);
1424+
}
1425+
/*
1426+
* This helper method is used for both generating a hash for signing as well for validating;
1427+
* thus depending on context key spend can be detected either with tapInternalKey with no leaves
1428+
* or tapKeySig (note tapKeySig is a signature to the prevout pk, so tapInternalKey is not needed).
1429+
*/
1430+
function getTaprootHashesForSig(
1431+
inputIndex,
1432+
input,
1433+
inputs,
1434+
pubkey,
1435+
cache,
1436+
keySpend,
1437+
sighashType,
1438+
tapLeafHashToSign,
1439+
) {
1440+
const unsignedTx = cache.__TX;
13881441
const prevOuts = inputs.map((i, index) =>
13891442
getScriptAndAmountFromUtxo(index, i, cache),
13901443
);
13911444
const signingScripts = prevOuts.map(o => o.script);
13921445
const values = prevOuts.map(o => o.value);
13931446
const hashes = [];
1394-
if (input.tapInternalKey && !tapLeafHashToSign) {
1447+
if (keySpend) {
13951448
const outputKey =
13961449
getPrevoutTaprootKey(inputIndex, input, cache) || Uint8Array.from([]);
13971450
if (tools.compare((0, bip371_js_1.toXOnly)(pubkey), outputKey) === 0) {

src/esm/psbt.js

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -475,14 +475,14 @@ export class Psbt {
475475
throw new Error('Need validator function to validate signatures');
476476
pubkey = pubkey && toXOnly(pubkey);
477477
const allHashses = pubkey
478-
? getTaprootHashesForSig(
478+
? getTaprootHashesForSigValidation(
479479
inputIndex,
480480
input,
481481
this.data.inputs,
482482
pubkey,
483483
this.__CACHE,
484484
)
485-
: getAllTaprootHashesForSig(
485+
: getAllTaprootHashesForSigValidation(
486486
inputIndex,
487487
input,
488488
this.data.inputs,
@@ -840,7 +840,7 @@ export class Psbt {
840840
throw new Error(
841841
`Need Schnorr Signer to sign taproot input #${inputIndex}.`,
842842
);
843-
const hashesForSig = getTaprootHashesForSig(
843+
const hashesForSig = getTaprootHashesForSigning(
844844
inputIndex,
845845
input,
846846
this.data.inputs,
@@ -1274,7 +1274,7 @@ function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) {
12741274
hash,
12751275
};
12761276
}
1277-
function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) {
1277+
function getAllTaprootHashesForSigValidation(inputIndex, input, inputs, cache) {
12781278
const allPublicKeys = [];
12791279
if (input.tapInternalKey) {
12801280
const key = getPrevoutTaprootKey(inputIndex, input, cache);
@@ -1287,7 +1287,13 @@ function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) {
12871287
allPublicKeys.push(...tapScriptPubkeys);
12881288
}
12891289
const allHashes = allPublicKeys.map(publicKey =>
1290-
getTaprootHashesForSig(inputIndex, input, inputs, publicKey, cache),
1290+
getTaprootHashesForSigValidation(
1291+
inputIndex,
1292+
input,
1293+
inputs,
1294+
publicKey,
1295+
cache,
1296+
),
12911297
);
12921298
return allHashes.flat();
12931299
}
@@ -1298,7 +1304,7 @@ function getPrevoutTaprootKey(inputIndex, input, cache) {
12981304
function trimTaprootSig(signature) {
12991305
return signature.length === 64 ? signature : signature.subarray(0, 64);
13001306
}
1301-
function getTaprootHashesForSig(
1307+
function getTaprootHashesForSigning(
13021308
inputIndex,
13031309
input,
13041310
inputs,
@@ -1307,16 +1313,62 @@ function getTaprootHashesForSig(
13071313
tapLeafHashToSign,
13081314
allowedSighashTypes,
13091315
) {
1310-
const unsignedTx = cache.__TX;
13111316
const sighashType = input.sighashType || Transaction.SIGHASH_DEFAULT;
13121317
checkSighashTypeAllowed(sighashType, allowedSighashTypes);
1318+
const keySpend = Boolean(input.tapInternalKey && !tapLeafHashToSign);
1319+
return getTaprootHashesForSig(
1320+
inputIndex,
1321+
input,
1322+
inputs,
1323+
pubkey,
1324+
cache,
1325+
keySpend,
1326+
sighashType,
1327+
tapLeafHashToSign,
1328+
);
1329+
}
1330+
function getTaprootHashesForSigValidation(
1331+
inputIndex,
1332+
input,
1333+
inputs,
1334+
pubkey,
1335+
cache,
1336+
) {
1337+
const sighashType = input.sighashType || Transaction.SIGHASH_DEFAULT;
1338+
const keySpend = Boolean(input.tapKeySig);
1339+
return getTaprootHashesForSig(
1340+
inputIndex,
1341+
input,
1342+
inputs,
1343+
pubkey,
1344+
cache,
1345+
keySpend,
1346+
sighashType,
1347+
);
1348+
}
1349+
/*
1350+
* This helper method is used for both generating a hash for signing as well for validating;
1351+
* thus depending on context key spend can be detected either with tapInternalKey with no leaves
1352+
* or tapKeySig (note tapKeySig is a signature to the prevout pk, so tapInternalKey is not needed).
1353+
*/
1354+
function getTaprootHashesForSig(
1355+
inputIndex,
1356+
input,
1357+
inputs,
1358+
pubkey,
1359+
cache,
1360+
keySpend,
1361+
sighashType,
1362+
tapLeafHashToSign,
1363+
) {
1364+
const unsignedTx = cache.__TX;
13131365
const prevOuts = inputs.map((i, index) =>
13141366
getScriptAndAmountFromUtxo(index, i, cache),
13151367
);
13161368
const signingScripts = prevOuts.map(o => o.script);
13171369
const values = prevOuts.map(o => o.value);
13181370
const hashes = [];
1319-
if (input.tapInternalKey && !tapLeafHashToSign) {
1371+
if (keySpend) {
13201372
const outputKey =
13211373
getPrevoutTaprootKey(inputIndex, input, cache) || Uint8Array.from([]);
13221374
if (tools.compare(toXOnly(pubkey), outputKey) === 0) {

ts_src/psbt.ts

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -604,14 +604,14 @@ export class Psbt {
604604

605605
pubkey = pubkey && toXOnly(pubkey);
606606
const allHashses = pubkey
607-
? getTaprootHashesForSig(
607+
? getTaprootHashesForSigValidation(
608608
inputIndex,
609609
input,
610610
this.data.inputs,
611611
pubkey,
612612
this.__CACHE,
613613
)
614-
: getAllTaprootHashesForSig(
614+
: getAllTaprootHashesForSigValidation(
615615
inputIndex,
616616
input,
617617
this.data.inputs,
@@ -1056,7 +1056,7 @@ export class Psbt {
10561056
`Need Schnorr Signer to sign taproot input #${inputIndex}.`,
10571057
);
10581058

1059-
const hashesForSig = getTaprootHashesForSig(
1059+
const hashesForSig = getTaprootHashesForSigning(
10601060
inputIndex,
10611061
input,
10621062
this.data.inputs,
@@ -1720,7 +1720,7 @@ function getHashForSig(
17201720
};
17211721
}
17221722

1723-
function getAllTaprootHashesForSig(
1723+
function getAllTaprootHashesForSigValidation(
17241724
inputIndex: number,
17251725
input: PsbtInput,
17261726
inputs: PsbtInput[],
@@ -1742,7 +1742,13 @@ function getAllTaprootHashesForSig(
17421742
}
17431743

17441744
const allHashes = allPublicKeys.map(publicKey =>
1745-
getTaprootHashesForSig(inputIndex, input, inputs, publicKey, cache),
1745+
getTaprootHashesForSigValidation(
1746+
inputIndex,
1747+
input,
1748+
inputs,
1749+
publicKey,
1750+
cache,
1751+
),
17461752
);
17471753

17481754
return allHashes.flat();
@@ -1761,28 +1767,77 @@ function trimTaprootSig(signature: Uint8Array): Uint8Array {
17611767
return signature.length === 64 ? signature : signature.subarray(0, 64);
17621768
}
17631769

1764-
function getTaprootHashesForSig(
1770+
function getTaprootHashesForSigning(
17651771
inputIndex: number,
17661772
input: PsbtInput,
17671773
inputs: PsbtInput[],
17681774
pubkey: Uint8Array,
17691775
cache: PsbtCache,
17701776
tapLeafHashToSign?: Uint8Array,
17711777
allowedSighashTypes?: number[],
1772-
): { pubkey: Uint8Array; hash: Uint8Array; leafHash?: Uint8Array }[] {
1773-
const unsignedTx = cache.__TX;
1774-
1778+
) {
17751779
const sighashType = input.sighashType || Transaction.SIGHASH_DEFAULT;
17761780
checkSighashTypeAllowed(sighashType, allowedSighashTypes);
17771781

1782+
const keySpend = Boolean(input.tapInternalKey && !tapLeafHashToSign);
1783+
1784+
return getTaprootHashesForSig(
1785+
inputIndex,
1786+
input,
1787+
inputs,
1788+
pubkey,
1789+
cache,
1790+
keySpend,
1791+
sighashType,
1792+
tapLeafHashToSign,
1793+
);
1794+
}
1795+
1796+
function getTaprootHashesForSigValidation(
1797+
inputIndex: number,
1798+
input: PsbtInput,
1799+
inputs: PsbtInput[],
1800+
pubkey: Uint8Array,
1801+
cache: PsbtCache,
1802+
) {
1803+
const sighashType = input.sighashType || Transaction.SIGHASH_DEFAULT;
1804+
const keySpend = Boolean(input.tapKeySig);
1805+
return getTaprootHashesForSig(
1806+
inputIndex,
1807+
input,
1808+
inputs,
1809+
pubkey,
1810+
cache,
1811+
keySpend,
1812+
sighashType,
1813+
);
1814+
}
1815+
1816+
/*
1817+
* This helper method is used for both generating a hash for signing as well for validating;
1818+
* thus depending on context key spend can be detected either with tapInternalKey with no leaves
1819+
* or tapKeySig (note tapKeySig is a signature to the prevout pk, so tapInternalKey is not needed).
1820+
*/
1821+
function getTaprootHashesForSig(
1822+
inputIndex: number,
1823+
input: PsbtInput,
1824+
inputs: PsbtInput[],
1825+
pubkey: Uint8Array,
1826+
cache: PsbtCache,
1827+
keySpend: boolean,
1828+
sighashType: number,
1829+
tapLeafHashToSign?: Uint8Array,
1830+
): { pubkey: Uint8Array; hash: Uint8Array; leafHash?: Uint8Array }[] {
1831+
const unsignedTx = cache.__TX;
1832+
17781833
const prevOuts: Output[] = inputs.map((i, index) =>
17791834
getScriptAndAmountFromUtxo(index, i, cache),
17801835
);
17811836
const signingScripts = prevOuts.map(o => o.script);
17821837
const values = prevOuts.map(o => o.value);
17831838

17841839
const hashes = [];
1785-
if (input.tapInternalKey && !tapLeafHashToSign) {
1840+
if (keySpend) {
17861841
const outputKey =
17871842
getPrevoutTaprootKey(inputIndex, input, cache) || Uint8Array.from([]);
17881843
if (tools.compare(toXOnly(pubkey), outputKey) === 0) {

0 commit comments

Comments
 (0)