Skip to content

Commit 13aea8c

Browse files
summraznboiCopilotjunderw
authored
Removed unnecessary check for tapInternalKey for signature validations of taproot inputs (#2270)
* Removed unnecessary check for tapInternalKey for signature validations of taproot inputs * Update ts_src/psbt.ts Co-authored-by: Copilot <[email protected]> * Update ts_src/psbt.ts Co-authored-by: Copilot <[email protected]> * Upgrade setup-node action from v3 to v6 --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Jonathan Underwood <[email protected]>
1 parent c151d53 commit 13aea8c

File tree

4 files changed

+193
-33
lines changed

4 files changed

+193
-33
lines changed

.github/workflows/main_ci.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
steps:
2727
- uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2
2828
- name: Use Node.js ${{ matrix.node-version }}
29-
uses: actions/setup-node@eeb10cff27034e7acf239c5d29f62154018672fd # v3
29+
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
3030
with:
3131
node-version: ${{ matrix.node-version }}
3232
registry-url: https://registry.npmjs.org/
@@ -48,7 +48,7 @@ jobs:
4848
steps:
4949
- uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2
5050
- name: Use Node.js ${{ matrix.node-version }}
51-
uses: actions/setup-node@eeb10cff27034e7acf239c5d29f62154018672fd # v3
51+
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
5252
with:
5353
node-version: ${{ matrix.node-version }}
5454
registry-url: https://registry.npmjs.org/
@@ -65,7 +65,7 @@ jobs:
6565
runs-on: ubuntu-latest
6666
steps:
6767
- uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2
68-
- uses: actions/setup-node@eeb10cff27034e7acf239c5d29f62154018672fd # v3
68+
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
6969
with:
7070
node-version: 'lts/*'
7171
registry-url: https://registry.npmjs.org/
@@ -76,7 +76,7 @@ jobs:
7676
runs-on: ubuntu-latest
7777
steps:
7878
- uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2
79-
- uses: actions/setup-node@eeb10cff27034e7acf239c5d29f62154018672fd # v3
79+
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
8080
with:
8181
node-version: 'lts/*'
8282
registry-url: https://registry.npmjs.org/
@@ -87,7 +87,7 @@ jobs:
8787
runs-on: ubuntu-latest
8888
steps:
8989
- uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2
90-
- uses: actions/setup-node@eeb10cff27034e7acf239c5d29f62154018672fd # v3
90+
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
9191
with:
9292
node-version: 'lts/*'
9393
registry-url: https://registry.npmjs.org/
@@ -98,7 +98,7 @@ jobs:
9898
runs-on: ubuntu-latest
9999
steps:
100100
- uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2
101-
- uses: actions/setup-node@eeb10cff27034e7acf239c5d29f62154018672fd # v3
101+
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
102102
with:
103103
node-version: 'lts/*'
104104
registry-url: https://registry.npmjs.org/
@@ -109,7 +109,7 @@ jobs:
109109
runs-on: ubuntu-latest
110110
steps:
111111
- uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2
112-
- uses: actions/setup-node@eeb10cff27034e7acf239c5d29f62154018672fd # v3
112+
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
113113
with:
114114
node-version: 'lts/*'
115115
registry-url: https://registry.npmjs.org/
@@ -121,7 +121,7 @@ jobs:
121121
runs-on: ubuntu-latest
122122
steps:
123123
- uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2
124-
- uses: actions/setup-node@eeb10cff27034e7acf239c5d29f62154018672fd # v3
124+
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
125125
with:
126126
node-version: 'lts/*'
127127
registry-url: https://registry.npmjs.org/

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) {

0 commit comments

Comments
 (0)