@btc-vision/bitcoin 6.3.1 → 6.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +4 -0
- package/.gitattributes +2 -0
- package/.nyc_output/6368a5b2-daa5-4821-8ed0-b742d6fc7eab.json +1 -0
- package/.nyc_output/processinfo/6368a5b2-daa5-4821-8ed0-b742d6fc7eab.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -0
- package/.prettierrc.json +12 -0
- package/CHANGELOG.md +403 -0
- package/CONTRIBUTING.md +83 -0
- package/browser/address.d.ts +16 -0
- package/{src → browser}/bip66.d.ts +6 -7
- package/{src → browser}/block.d.ts +29 -30
- package/{src → browser}/bufferutils.d.ts +34 -54
- package/browser/crypto/crypto.d.ts +1 -0
- package/{src → browser}/crypto.d.ts +13 -18
- package/browser/ecc_lib.d.ts +3 -0
- package/browser/hooks/AdvancedSignatureManager.d.ts +16 -0
- package/{src → browser}/hooks/HookedSigner.d.ts +4 -4
- package/browser/hooks/SignatureManager.d.ts +13 -0
- package/browser/index.d.ts +58 -0
- package/browser/index.js +2 -0
- package/browser/index.js.LICENSE.txt +14 -0
- package/browser/merkle.d.ts +1 -0
- package/browser/networks.d.ts +23 -0
- package/{src → browser}/ops.d.ts +126 -126
- package/browser/payments/bip341.d.ts +23 -0
- package/browser/payments/embed.d.ts +2 -0
- package/browser/payments/index.d.ts +41 -0
- package/{src → browser}/payments/lazy.d.ts +2 -2
- package/browser/payments/p2ms.d.ts +2 -0
- package/browser/payments/p2pk.d.ts +2 -0
- package/browser/payments/p2pkh.d.ts +2 -0
- package/browser/payments/p2sh.d.ts +2 -0
- package/browser/payments/p2tr.d.ts +2 -0
- package/browser/payments/p2wpkh.d.ts +2 -0
- package/browser/payments/p2wsh.d.ts +2 -0
- package/browser/psbt/bip371.d.ts +16 -0
- package/browser/psbt/psbtutils.d.ts +26 -0
- package/{src → browser}/psbt.d.ts +167 -238
- package/browser/push_data.d.ts +7 -0
- package/browser/script.d.ts +17 -0
- package/browser/script_number.d.ts +2 -0
- package/browser/script_signature.d.ts +7 -0
- package/{src → browser}/transaction.d.ts +48 -60
- package/{src → browser}/types.d.ts +37 -54
- package/build/address.d.ts +16 -0
- package/build/address.js +148 -0
- package/build/bip66.d.ts +6 -0
- package/build/bip66.js +99 -0
- package/build/block.d.ts +29 -0
- package/build/block.js +181 -0
- package/build/bufferutils.d.ts +34 -0
- package/build/bufferutils.js +141 -0
- package/build/crypto/crypto.d.ts +1 -0
- package/build/crypto/crypto.js +1 -0
- package/build/crypto.d.ts +13 -0
- package/build/crypto.js +87 -0
- package/build/ecc_lib.d.ts +3 -0
- package/build/ecc_lib.js +61 -0
- package/build/hooks/AdvancedSignatureManager.d.ts +16 -0
- package/build/hooks/AdvancedSignatureManager.js +52 -0
- package/build/hooks/HookedSigner.d.ts +4 -0
- package/build/hooks/HookedSigner.js +64 -0
- package/build/hooks/SignatureManager.d.ts +13 -0
- package/build/hooks/SignatureManager.js +45 -0
- package/build/index.d.ts +58 -0
- package/build/index.js +32 -0
- package/build/merkle.d.ts +1 -0
- package/build/merkle.js +19 -0
- package/build/networks.d.ts +23 -0
- package/build/networks.js +121 -0
- package/build/ops.d.ts +126 -0
- package/{src → build}/ops.js +127 -131
- package/build/payments/bip341.d.ts +23 -0
- package/build/payments/bip341.js +82 -0
- package/build/payments/embed.d.ts +2 -0
- package/build/payments/embed.js +39 -0
- package/build/payments/index.d.ts +41 -0
- package/build/payments/index.js +10 -0
- package/build/payments/lazy.d.ts +2 -0
- package/{src → build}/payments/lazy.js +28 -32
- package/build/payments/p2ms.d.ts +2 -0
- package/{src → build}/payments/p2ms.js +128 -158
- package/build/payments/p2pk.d.ts +2 -0
- package/build/payments/p2pk.js +68 -0
- package/build/payments/p2pkh.d.ts +2 -0
- package/build/payments/p2pkh.js +135 -0
- package/build/payments/p2sh.d.ts +2 -0
- package/build/payments/p2sh.js +175 -0
- package/build/payments/p2tr.d.ts +2 -0
- package/build/payments/p2tr.js +254 -0
- package/build/payments/p2wpkh.d.ts +2 -0
- package/build/payments/p2wpkh.js +130 -0
- package/build/payments/p2wsh.d.ts +2 -0
- package/build/payments/p2wsh.js +180 -0
- package/build/psbt/bip371.d.ts +16 -0
- package/build/psbt/bip371.js +246 -0
- package/build/psbt/psbtutils.d.ts +26 -0
- package/build/psbt/psbtutils.js +170 -0
- package/build/psbt.d.ts +167 -0
- package/build/psbt.js +1305 -0
- package/build/push_data.d.ts +7 -0
- package/build/push_data.js +57 -0
- package/build/script.d.ts +17 -0
- package/build/script.js +167 -0
- package/build/script_number.d.ts +2 -0
- package/build/script_number.js +49 -0
- package/build/script_signature.d.ts +7 -0
- package/build/script_signature.js +49 -0
- package/build/transaction.d.ts +48 -0
- package/build/transaction.js +445 -0
- package/build/types.d.ts +37 -0
- package/build/types.js +73 -0
- package/cjs/package.json +3 -0
- package/eslint.config.js +56 -0
- package/gulpfile.js +42 -0
- package/package.json +105 -50
- package/src/{address.js → address.ts} +93 -73
- package/src/{bip66.js → bip66.ts} +23 -19
- package/src/{block.js → block.ts} +114 -105
- package/src/{bufferutils.js → bufferutils.ts} +65 -67
- package/src/crypto/crypto-browser.js +75 -0
- package/src/crypto/crypto.ts +1 -0
- package/src/crypto.ts +108 -0
- package/src/{ecc_lib.js → ecc_lib.ts} +25 -53
- package/src/hooks/{AdvancedSignatureManager.js → AdvancedSignatureManager.ts} +34 -18
- package/src/hooks/HookedSigner.ts +108 -0
- package/src/hooks/{SignatureManager.js → SignatureManager.ts} +26 -14
- package/src/index.ts +86 -0
- package/src/{merkle.js → merkle.ts} +8 -7
- package/src/{networks.js → networks.ts} +44 -29
- package/src/ops.ts +282 -0
- package/src/payments/bip341.ts +140 -0
- package/src/payments/embed.ts +55 -0
- package/src/payments/{index.d.ts → index.ts} +20 -10
- package/src/payments/lazy.ts +28 -0
- package/src/payments/p2ms.ts +150 -0
- package/src/payments/{p2pk.js → p2pk.ts} +32 -29
- package/src/payments/{p2pkh.js → p2pkh.ts} +53 -47
- package/src/payments/{p2sh.js → p2sh.ts} +72 -71
- package/src/payments/{p2tr.js → p2tr.ts} +114 -125
- package/src/payments/{p2wpkh.js → p2wpkh.ts} +51 -56
- package/src/payments/{p2wsh.js → p2wsh.ts} +69 -81
- package/src/psbt/{bip371.js → bip371.ts} +191 -174
- package/src/psbt/psbtutils.ts +299 -0
- package/src/{psbt.js → psbt.ts} +1025 -679
- package/src/{push_data.js → push_data.ts} +35 -21
- package/src/{script.js → script.ts} +93 -77
- package/src/{script_number.js → script_number.ts} +15 -21
- package/src/{script_signature.js → script_signature.ts} +26 -14
- package/src/{transaction.js → transaction.ts} +247 -167
- package/src/types.ts +122 -0
- package/test/address.spec.js +124 -0
- package/test/address.spec.ts +177 -0
- package/test/bitcoin.core.spec.js +170 -0
- package/test/bitcoin.core.spec.ts +234 -0
- package/test/block.spec.js +141 -0
- package/test/block.spec.ts +194 -0
- package/test/bufferutils.spec.js +427 -0
- package/test/bufferutils.spec.ts +513 -0
- package/test/crypto.spec.js +41 -0
- package/test/crypto.spec.ts +55 -0
- package/test/fixtures/address.json +329 -0
- package/test/fixtures/block.json +148 -0
- package/test/fixtures/bufferutils.json +102 -0
- package/test/fixtures/core/README.md +26 -0
- package/test/fixtures/core/base58_encode_decode.json +50 -0
- package/test/fixtures/core/base58_keys_invalid.json +152 -0
- package/test/fixtures/core/base58_keys_valid.json +452 -0
- package/test/fixtures/core/blocks.json +27 -0
- package/test/fixtures/core/sig_canonical.json +7 -0
- package/test/fixtures/core/sig_noncanonical.json +33 -0
- package/test/fixtures/core/sighash.json +3505 -0
- package/test/fixtures/core/tx_valid.json +2023 -0
- package/test/fixtures/crypto.json +43 -0
- package/test/fixtures/ecdsa.json +217 -0
- package/test/fixtures/ecpair.json +141 -0
- package/test/fixtures/embed.json +108 -0
- package/test/fixtures/p2ms.json +434 -0
- package/test/fixtures/p2pk.json +179 -0
- package/test/fixtures/p2pkh.json +276 -0
- package/test/fixtures/p2sh.json +508 -0
- package/test/fixtures/p2tr.json +1198 -0
- package/test/fixtures/p2wpkh.json +290 -0
- package/test/fixtures/p2wsh.json +489 -0
- package/test/fixtures/psbt.json +924 -0
- package/test/fixtures/script.json +465 -0
- package/test/fixtures/script_number.json +225 -0
- package/test/fixtures/signature.json +140 -0
- package/test/fixtures/transaction.json +916 -0
- package/test/integration/_regtest.js +7 -0
- package/test/integration/_regtest.ts +6 -0
- package/test/integration/addresses.spec.js +116 -0
- package/test/integration/addresses.spec.ts +154 -0
- package/test/integration/bip32.spec.js +85 -0
- package/test/integration/bip32.spec.ts +151 -0
- package/test/integration/blocks.spec.js +26 -0
- package/test/integration/blocks.spec.ts +28 -0
- package/test/integration/cltv.spec.js +199 -0
- package/test/integration/cltv.spec.ts +283 -0
- package/test/integration/csv.spec.js +362 -0
- package/test/integration/csv.spec.ts +527 -0
- package/test/integration/payments.spec.js +98 -0
- package/test/integration/payments.spec.ts +135 -0
- package/test/integration/taproot.spec.js +532 -0
- package/test/integration/taproot.spec.ts +707 -0
- package/test/integration/transactions.spec.js +561 -0
- package/test/integration/transactions.spec.ts +769 -0
- package/test/payments.spec.js +97 -0
- package/test/payments.spec.ts +125 -0
- package/test/payments.utils.js +190 -0
- package/test/payments.utils.ts +208 -0
- package/test/psbt.spec.js +1044 -0
- package/test/psbt.spec.ts +1414 -0
- package/test/script.spec.js +151 -0
- package/test/script.spec.ts +210 -0
- package/test/script_number.spec.js +24 -0
- package/test/script_number.spec.ts +29 -0
- package/test/script_signature.spec.js +52 -0
- package/test/script_signature.spec.ts +66 -0
- package/test/transaction.spec.js +269 -0
- package/test/transaction.spec.ts +387 -0
- package/test/ts-node-register.js +5 -0
- package/test/tsconfig.json +45 -0
- package/test/types.spec.js +46 -0
- package/test/types.spec.ts +58 -0
- package/tsconfig.base.json +27 -0
- package/tsconfig.json +19 -0
- package/tsconfig.webpack.json +18 -0
- package/webpack.config.js +79 -0
- package/src/address.d.ts +0 -42
- package/src/crypto.js +0 -128
- package/src/ecc_lib.d.ts +0 -17
- package/src/hooks/AdvancedSignatureManager.d.ts +0 -44
- package/src/hooks/HookedSigner.js +0 -90
- package/src/hooks/SignatureManager.d.ts +0 -35
- package/src/index.d.ts +0 -42
- package/src/index.js +0 -87
- package/src/merkle.d.ts +0 -10
- package/src/networks.d.ts +0 -83
- package/src/payments/bip341.d.ts +0 -49
- package/src/payments/bip341.js +0 -124
- package/src/payments/embed.d.ts +0 -9
- package/src/payments/embed.js +0 -54
- package/src/payments/index.js +0 -69
- package/src/payments/p2ms.d.ts +0 -9
- package/src/payments/p2pk.d.ts +0 -10
- package/src/payments/p2pkh.d.ts +0 -10
- package/src/payments/p2sh.d.ts +0 -10
- package/src/payments/p2tr.d.ts +0 -10
- package/src/payments/p2wpkh.d.ts +0 -10
- package/src/payments/p2wsh.d.ts +0 -10
- package/src/psbt/bip371.d.ts +0 -42
- package/src/psbt/psbtutils.d.ts +0 -64
- package/src/psbt/psbtutils.js +0 -191
- package/src/push_data.d.ts +0 -29
- package/src/script.d.ts +0 -42
- package/src/script_number.d.ts +0 -19
- package/src/script_signature.d.ts +0 -21
- package/src/types.js +0 -106
|
@@ -1,25 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
import {
|
|
2
|
+
PsbtInput,
|
|
3
|
+
PsbtOutput,
|
|
4
|
+
TapInternalKey,
|
|
5
|
+
TapLeaf,
|
|
6
|
+
TapLeafScript,
|
|
7
|
+
TapScriptSig,
|
|
8
|
+
TapTree,
|
|
9
|
+
} from 'bip174/src/lib/interfaces.js';
|
|
10
|
+
import { isTapleaf, isTaptree, Tapleaf, Taptree } from '../types.js';
|
|
11
|
+
|
|
12
|
+
import { Transaction } from '../transaction.js';
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
LEAF_VERSION_TAPSCRIPT,
|
|
16
|
+
MAX_TAPTREE_DEPTH,
|
|
17
|
+
rootHashFromPath,
|
|
18
|
+
tapleafHash,
|
|
19
|
+
tweakKey,
|
|
20
|
+
} from '../payments/bip341.js';
|
|
21
|
+
import { p2tr } from '../payments/p2tr.js';
|
|
22
|
+
import {
|
|
23
|
+
isP2TR,
|
|
24
|
+
pubkeyPositionInScript,
|
|
25
|
+
signatureBlocksAction,
|
|
26
|
+
witnessStackToScriptWitness,
|
|
27
|
+
} from './psbtutils.js';
|
|
28
|
+
|
|
29
|
+
export const toXOnly = (pubKey: Buffer | Uint8Array): Buffer => {
|
|
30
|
+
const buffer = pubKey.length === 32 ? pubKey : pubKey.slice(1, 33);
|
|
31
|
+
|
|
32
|
+
return Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer);
|
|
33
|
+
};
|
|
34
|
+
|
|
23
35
|
/**
|
|
24
36
|
* Default tapscript finalizer. It searches for the `tapLeafHashToFinalize` if provided.
|
|
25
37
|
* Otherwise it will search for the tapleaf that has at least one signature and has the shortest path.
|
|
@@ -29,37 +41,31 @@ exports.toXOnly = toXOnly;
|
|
|
29
41
|
* and will try to build the finalScriptWitness.
|
|
30
42
|
* @returns the finalScriptWitness or throws an exception if no tapleaf found.
|
|
31
43
|
*/
|
|
32
|
-
function tapScriptFinalizer(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
export function tapScriptFinalizer(
|
|
45
|
+
inputIndex: number,
|
|
46
|
+
input: PsbtInput,
|
|
47
|
+
tapLeafHashToFinalize?: Buffer,
|
|
48
|
+
): {
|
|
49
|
+
finalScriptWitness: Buffer | undefined;
|
|
50
|
+
} {
|
|
51
|
+
const tapLeaf = findTapLeafToFinalize(input, inputIndex, tapLeafHashToFinalize);
|
|
52
|
+
|
|
38
53
|
try {
|
|
39
54
|
const sigs = sortSignatures(input, tapLeaf);
|
|
40
|
-
const witness = sigs
|
|
41
|
-
|
|
42
|
-
.concat(tapLeaf.controlBlock);
|
|
43
|
-
return {
|
|
44
|
-
finalScriptWitness: (0, psbtutils_1.witnessStackToScriptWitness)(
|
|
45
|
-
witness,
|
|
46
|
-
),
|
|
47
|
-
};
|
|
55
|
+
const witness = sigs.concat(tapLeaf.script).concat(tapLeaf.controlBlock);
|
|
56
|
+
return { finalScriptWitness: witnessStackToScriptWitness(witness) };
|
|
48
57
|
} catch (err) {
|
|
49
|
-
throw new Error(
|
|
50
|
-
`Can not finalize taproot input #${inputIndex}: ${err}`,
|
|
51
|
-
);
|
|
58
|
+
throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}`);
|
|
52
59
|
}
|
|
53
60
|
}
|
|
54
|
-
|
|
55
|
-
function serializeTaprootSignature(sig, sighashType) {
|
|
56
|
-
const sighashTypeByte = sighashType
|
|
57
|
-
|
|
58
|
-
: Buffer.from([]);
|
|
61
|
+
|
|
62
|
+
export function serializeTaprootSignature(sig: Buffer, sighashType?: number): Buffer {
|
|
63
|
+
const sighashTypeByte = sighashType ? Buffer.from([sighashType!]) : Buffer.from([]);
|
|
64
|
+
|
|
59
65
|
return Buffer.concat([sig, sighashTypeByte]);
|
|
60
66
|
}
|
|
61
|
-
|
|
62
|
-
function isTaprootInput(input) {
|
|
67
|
+
|
|
68
|
+
export function isTaprootInput(input: PsbtInput): boolean {
|
|
63
69
|
return (
|
|
64
70
|
input &&
|
|
65
71
|
!!(
|
|
@@ -67,65 +73,68 @@ function isTaprootInput(input) {
|
|
|
67
73
|
input.tapMerkleRoot ||
|
|
68
74
|
(input.tapLeafScript && input.tapLeafScript.length) ||
|
|
69
75
|
(input.tapBip32Derivation && input.tapBip32Derivation.length) ||
|
|
70
|
-
(input.witnessUtxo &&
|
|
71
|
-
(0, psbtutils_1.isP2TR)(input.witnessUtxo.script))
|
|
76
|
+
(input.witnessUtxo && isP2TR(input.witnessUtxo.script))
|
|
72
77
|
)
|
|
73
78
|
);
|
|
74
79
|
}
|
|
75
|
-
|
|
76
|
-
function isTaprootOutput(output, script) {
|
|
80
|
+
|
|
81
|
+
export function isTaprootOutput(output: PsbtOutput, script?: Buffer): boolean {
|
|
77
82
|
return (
|
|
78
83
|
output &&
|
|
79
84
|
!!(
|
|
80
85
|
output.tapInternalKey ||
|
|
81
86
|
output.tapTree ||
|
|
82
87
|
(output.tapBip32Derivation && output.tapBip32Derivation.length) ||
|
|
83
|
-
(script &&
|
|
88
|
+
(script && isP2TR(script))
|
|
84
89
|
)
|
|
85
90
|
);
|
|
86
91
|
}
|
|
87
|
-
|
|
88
|
-
function checkTaprootInputFields(
|
|
92
|
+
|
|
93
|
+
export function checkTaprootInputFields(
|
|
94
|
+
inputData: PsbtInput,
|
|
95
|
+
newInputData: PsbtInput,
|
|
96
|
+
action: string,
|
|
97
|
+
): void {
|
|
89
98
|
checkMixedTaprootAndNonTaprootInputFields(inputData, newInputData, action);
|
|
90
99
|
checkIfTapLeafInTree(inputData, newInputData, action);
|
|
91
100
|
}
|
|
92
|
-
|
|
93
|
-
function checkTaprootOutputFields(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
);
|
|
101
|
+
|
|
102
|
+
export function checkTaprootOutputFields(
|
|
103
|
+
outputData: PsbtOutput,
|
|
104
|
+
newOutputData: PsbtOutput,
|
|
105
|
+
action: string,
|
|
106
|
+
): void {
|
|
107
|
+
checkMixedTaprootAndNonTaprootOutputFields(outputData, newOutputData, action);
|
|
99
108
|
checkTaprootScriptPubkey(outputData, newOutputData);
|
|
100
109
|
}
|
|
101
|
-
|
|
102
|
-
function checkTaprootScriptPubkey(outputData, newOutputData) {
|
|
110
|
+
|
|
111
|
+
function checkTaprootScriptPubkey(outputData: PsbtOutput, newOutputData: PsbtOutput): void {
|
|
103
112
|
if (!newOutputData.tapTree && !newOutputData.tapInternalKey) return;
|
|
104
|
-
|
|
105
|
-
|
|
113
|
+
|
|
114
|
+
const tapInternalKey = newOutputData.tapInternalKey || outputData.tapInternalKey;
|
|
106
115
|
const tapTree = newOutputData.tapTree || outputData.tapTree;
|
|
116
|
+
|
|
107
117
|
if (tapInternalKey) {
|
|
108
|
-
const { script: scriptPubkey } = outputData;
|
|
118
|
+
const { script: scriptPubkey } = outputData as any;
|
|
109
119
|
const script = getTaprootScripPubkey(tapInternalKey, tapTree);
|
|
110
120
|
if (scriptPubkey && !scriptPubkey.equals(script))
|
|
111
|
-
throw new Error(
|
|
112
|
-
'Error adding output. Script or address missmatch.',
|
|
113
|
-
);
|
|
121
|
+
throw new Error('Error adding output. Script or address missmatch.');
|
|
114
122
|
}
|
|
115
123
|
}
|
|
116
|
-
|
|
124
|
+
|
|
125
|
+
function getTaprootScripPubkey(tapInternalKey: TapInternalKey, tapTree?: TapTree): Buffer {
|
|
117
126
|
const scriptTree = tapTree && tapTreeFromList(tapTree.leaves);
|
|
118
|
-
const { output } =
|
|
127
|
+
const { output } = p2tr({
|
|
119
128
|
internalPubkey: tapInternalKey,
|
|
120
129
|
scriptTree,
|
|
121
130
|
});
|
|
122
|
-
return output
|
|
131
|
+
return output!;
|
|
123
132
|
}
|
|
124
|
-
|
|
133
|
+
|
|
134
|
+
export function tweakInternalPubKey(inputIndex: number, input: PsbtInput): Buffer {
|
|
125
135
|
const tapInternalKey = input.tapInternalKey;
|
|
126
|
-
const outputKey =
|
|
127
|
-
|
|
128
|
-
(0, bip341_1.tweakKey)(tapInternalKey, input.tapMerkleRoot);
|
|
136
|
+
const outputKey = tapInternalKey && tweakKey(tapInternalKey, input.tapMerkleRoot);
|
|
137
|
+
|
|
129
138
|
if (!outputKey)
|
|
130
139
|
throw new Error(
|
|
131
140
|
`Cannot tweak tap internal key for input #${inputIndex}. Public key: ${
|
|
@@ -134,7 +143,7 @@ function tweakInternalPubKey(inputIndex, input) {
|
|
|
134
143
|
);
|
|
135
144
|
return outputKey.x;
|
|
136
145
|
}
|
|
137
|
-
|
|
146
|
+
|
|
138
147
|
/**
|
|
139
148
|
* Convert a binary tree to a BIP371 type list. Each element of the list is (according to BIP371):
|
|
140
149
|
* One or more tuples representing the depth, leaf version, and script for a leaf in the Taproot tree,
|
|
@@ -143,14 +152,12 @@ exports.tweakInternalPubKey = tweakInternalPubKey;
|
|
|
143
152
|
* @param tree the binary tap tree
|
|
144
153
|
* @returns a list of BIP 371 tapleaves
|
|
145
154
|
*/
|
|
146
|
-
function tapTreeToList(tree) {
|
|
147
|
-
if (!
|
|
148
|
-
throw new Error(
|
|
149
|
-
'Cannot convert taptree to tapleaf list. Expecting a tapree structure.',
|
|
150
|
-
);
|
|
155
|
+
export function tapTreeToList(tree: Taptree): TapLeaf[] {
|
|
156
|
+
if (!isTaptree(tree))
|
|
157
|
+
throw new Error('Cannot convert taptree to tapleaf list. Expecting a tapree structure.');
|
|
151
158
|
return _tapTreeToList(tree);
|
|
152
159
|
}
|
|
153
|
-
|
|
160
|
+
|
|
154
161
|
/**
|
|
155
162
|
* Convert a BIP371 TapLeaf list to a TapTree (binary).
|
|
156
163
|
* @param leaves a list of tapleaves where each element of the list is (according to BIP371):
|
|
@@ -159,61 +166,57 @@ exports.tapTreeToList = tapTreeToList;
|
|
|
159
166
|
* the tree is correctly reconstructed.
|
|
160
167
|
* @returns the corresponding taptree, or throws an exception if the tree cannot be reconstructed
|
|
161
168
|
*/
|
|
162
|
-
function tapTreeFromList(leaves = []) {
|
|
169
|
+
export function tapTreeFromList(leaves: TapLeaf[] = []): Taptree {
|
|
163
170
|
if (leaves.length === 1 && leaves[0].depth === 0)
|
|
164
171
|
return {
|
|
165
172
|
output: leaves[0].script,
|
|
166
173
|
version: leaves[0].leafVersion,
|
|
167
174
|
};
|
|
175
|
+
|
|
168
176
|
return insertLeavesInTree(leaves);
|
|
169
177
|
}
|
|
170
|
-
|
|
171
|
-
function checkTaprootInputForSigs(input, action) {
|
|
178
|
+
|
|
179
|
+
export function checkTaprootInputForSigs(input: PsbtInput, action: string): boolean {
|
|
172
180
|
const sigs = extractTaprootSigs(input);
|
|
173
|
-
return sigs.some(sig =>
|
|
174
|
-
(0, psbtutils_1.signatureBlocksAction)(
|
|
175
|
-
sig,
|
|
176
|
-
decodeSchnorrSignature,
|
|
177
|
-
action,
|
|
178
|
-
),
|
|
179
|
-
);
|
|
181
|
+
return sigs.some((sig) => signatureBlocksAction(sig, decodeSchnorrSignature, action));
|
|
180
182
|
}
|
|
181
|
-
|
|
182
|
-
function decodeSchnorrSignature(signature) {
|
|
183
|
+
|
|
184
|
+
function decodeSchnorrSignature(signature: Buffer): {
|
|
185
|
+
signature: Buffer;
|
|
186
|
+
hashType: number;
|
|
187
|
+
} {
|
|
183
188
|
return {
|
|
184
189
|
signature: signature.slice(0, 64),
|
|
185
|
-
hashType:
|
|
186
|
-
signature.slice(64)[0] || transaction_1.Transaction.SIGHASH_DEFAULT,
|
|
190
|
+
hashType: signature.slice(64)[0] || Transaction.SIGHASH_DEFAULT,
|
|
187
191
|
};
|
|
188
192
|
}
|
|
189
|
-
|
|
190
|
-
|
|
193
|
+
|
|
194
|
+
function extractTaprootSigs(input: PsbtInput): Buffer[] {
|
|
195
|
+
const sigs: Buffer[] = [];
|
|
191
196
|
if (input.tapKeySig) sigs.push(input.tapKeySig);
|
|
192
|
-
if (input.tapScriptSig)
|
|
193
|
-
sigs.push(...input.tapScriptSig.map(s => s.signature));
|
|
197
|
+
if (input.tapScriptSig) sigs.push(...input.tapScriptSig.map((s) => s.signature));
|
|
194
198
|
if (!sigs.length) {
|
|
195
|
-
const finalTapKeySig = getTapKeySigFromWitness(
|
|
196
|
-
input.finalScriptWitness,
|
|
197
|
-
);
|
|
199
|
+
const finalTapKeySig = getTapKeySigFromWitness(input.finalScriptWitness);
|
|
198
200
|
if (finalTapKeySig) sigs.push(finalTapKeySig);
|
|
199
201
|
}
|
|
202
|
+
|
|
200
203
|
return sigs;
|
|
201
204
|
}
|
|
202
|
-
|
|
205
|
+
|
|
206
|
+
export function getTapKeySigFromWitness(finalScriptWitness?: Buffer): Buffer | undefined {
|
|
203
207
|
if (!finalScriptWitness) return;
|
|
204
208
|
const witness = finalScriptWitness.slice(2);
|
|
205
209
|
// todo: add schnorr signature validation
|
|
206
210
|
if (witness.length === 64 || witness.length === 65) return witness;
|
|
207
211
|
}
|
|
208
|
-
|
|
209
|
-
function _tapTreeToList(tree, leaves = [], depth = 0) {
|
|
210
|
-
if (depth >
|
|
211
|
-
throw new Error('Max taptree depth exceeded.');
|
|
212
|
+
|
|
213
|
+
function _tapTreeToList(tree: Taptree, leaves: TapLeaf[] = [], depth = 0): TapLeaf[] {
|
|
214
|
+
if (depth > MAX_TAPTREE_DEPTH) throw new Error('Max taptree depth exceeded.');
|
|
212
215
|
if (!tree) return [];
|
|
213
|
-
if (
|
|
216
|
+
if (isTapleaf(tree)) {
|
|
214
217
|
leaves.push({
|
|
215
218
|
depth,
|
|
216
|
-
leafVersion: tree.version ||
|
|
219
|
+
leafVersion: tree.version || LEAF_VERSION_TAPSCRIPT,
|
|
217
220
|
script: tree.output,
|
|
218
221
|
});
|
|
219
222
|
return leaves;
|
|
@@ -222,17 +225,22 @@ function _tapTreeToList(tree, leaves = [], depth = 0) {
|
|
|
222
225
|
if (tree[1]) _tapTreeToList(tree[1], leaves, depth + 1);
|
|
223
226
|
return leaves;
|
|
224
227
|
}
|
|
225
|
-
|
|
226
|
-
|
|
228
|
+
|
|
229
|
+
// Just like Taptree, but it accepts empty branches
|
|
230
|
+
type PartialTaptree = [PartialTaptree | Tapleaf, PartialTaptree | Tapleaf] | Tapleaf | undefined;
|
|
231
|
+
|
|
232
|
+
function insertLeavesInTree(leaves: TapLeaf[]): Taptree {
|
|
233
|
+
let tree: PartialTaptree;
|
|
227
234
|
for (const leaf of leaves) {
|
|
228
235
|
tree = insertLeafInTree(leaf, tree);
|
|
229
236
|
if (!tree) throw new Error(`No room left to insert tapleaf in tree`);
|
|
230
237
|
}
|
|
231
|
-
|
|
238
|
+
|
|
239
|
+
return tree as Taptree;
|
|
232
240
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
241
|
+
|
|
242
|
+
function insertLeafInTree(leaf: TapLeaf, tree?: PartialTaptree, depth = 0): PartialTaptree {
|
|
243
|
+
if (depth > MAX_TAPTREE_DEPTH) throw new Error('Max taptree depth exceeded.');
|
|
236
244
|
if (leaf.depth === depth) {
|
|
237
245
|
if (!tree)
|
|
238
246
|
return {
|
|
@@ -241,50 +249,53 @@ function insertLeafInTree(leaf, tree, depth = 0) {
|
|
|
241
249
|
};
|
|
242
250
|
return;
|
|
243
251
|
}
|
|
244
|
-
|
|
252
|
+
|
|
253
|
+
if (isTapleaf(tree)) return;
|
|
245
254
|
const leftSide = insertLeafInTree(leaf, tree && tree[0], depth + 1);
|
|
246
255
|
if (leftSide) return [leftSide, tree && tree[1]];
|
|
256
|
+
|
|
247
257
|
const rightSide = insertLeafInTree(leaf, tree && tree[1], depth + 1);
|
|
248
258
|
if (rightSide) return [tree && tree[0], rightSide];
|
|
249
259
|
}
|
|
260
|
+
|
|
250
261
|
function checkMixedTaprootAndNonTaprootInputFields(
|
|
251
|
-
inputData,
|
|
252
|
-
newInputData,
|
|
253
|
-
action,
|
|
254
|
-
) {
|
|
255
|
-
const isBadTaprootUpdate =
|
|
256
|
-
|
|
257
|
-
const isBadNonTaprootUpdate =
|
|
258
|
-
hasNonTaprootFields(inputData) && isTaprootInput(newInputData);
|
|
262
|
+
inputData: PsbtOutput,
|
|
263
|
+
newInputData: PsbtInput,
|
|
264
|
+
action: string,
|
|
265
|
+
): void {
|
|
266
|
+
const isBadTaprootUpdate = isTaprootInput(inputData) && hasNonTaprootFields(newInputData);
|
|
267
|
+
const isBadNonTaprootUpdate = hasNonTaprootFields(inputData) && isTaprootInput(newInputData);
|
|
259
268
|
const hasMixedFields =
|
|
260
269
|
inputData === newInputData &&
|
|
261
270
|
isTaprootInput(newInputData) &&
|
|
262
271
|
hasNonTaprootFields(newInputData); // todo: bad? use !===
|
|
272
|
+
|
|
263
273
|
if (isBadTaprootUpdate || isBadNonTaprootUpdate || hasMixedFields)
|
|
264
274
|
throw new Error(
|
|
265
275
|
`Invalid arguments for Psbt.${action}. ` +
|
|
266
276
|
`Cannot use both taproot and non-taproot fields.`,
|
|
267
277
|
);
|
|
268
278
|
}
|
|
279
|
+
|
|
269
280
|
function checkMixedTaprootAndNonTaprootOutputFields(
|
|
270
|
-
inputData,
|
|
271
|
-
newInputData,
|
|
272
|
-
action,
|
|
273
|
-
) {
|
|
274
|
-
const isBadTaprootUpdate =
|
|
275
|
-
|
|
276
|
-
const isBadNonTaprootUpdate =
|
|
277
|
-
hasNonTaprootFields(inputData) && isTaprootOutput(newInputData);
|
|
281
|
+
inputData: PsbtOutput,
|
|
282
|
+
newInputData: PsbtOutput,
|
|
283
|
+
action: string,
|
|
284
|
+
): void {
|
|
285
|
+
const isBadTaprootUpdate = isTaprootOutput(inputData) && hasNonTaprootFields(newInputData);
|
|
286
|
+
const isBadNonTaprootUpdate = hasNonTaprootFields(inputData) && isTaprootOutput(newInputData);
|
|
278
287
|
const hasMixedFields =
|
|
279
288
|
inputData === newInputData &&
|
|
280
289
|
isTaprootOutput(newInputData) &&
|
|
281
290
|
hasNonTaprootFields(newInputData);
|
|
291
|
+
|
|
282
292
|
if (isBadTaprootUpdate || isBadNonTaprootUpdate || hasMixedFields)
|
|
283
293
|
throw new Error(
|
|
284
294
|
`Invalid arguments for Psbt.${action}. ` +
|
|
285
295
|
`Cannot use both taproot and non-taproot fields.`,
|
|
286
296
|
);
|
|
287
297
|
}
|
|
298
|
+
|
|
288
299
|
/**
|
|
289
300
|
* Checks if the tap leaf is part of the tap tree for the given input data.
|
|
290
301
|
* Throws an error if the tap leaf is not part of the tap tree.
|
|
@@ -293,46 +304,43 @@ function checkMixedTaprootAndNonTaprootOutputFields(
|
|
|
293
304
|
* @param action - The action being performed.
|
|
294
305
|
* @throws {Error} - If the tap leaf is not part of the tap tree.
|
|
295
306
|
*/
|
|
296
|
-
function checkIfTapLeafInTree(inputData, newInputData, action) {
|
|
307
|
+
function checkIfTapLeafInTree(inputData: PsbtInput, newInputData: PsbtInput, action: string): void {
|
|
297
308
|
if (newInputData.tapMerkleRoot) {
|
|
298
|
-
const newLeafsInTree = (newInputData.tapLeafScript || []).every(l =>
|
|
309
|
+
const newLeafsInTree = (newInputData.tapLeafScript || []).every((l) =>
|
|
299
310
|
isTapLeafInTree(l, newInputData.tapMerkleRoot),
|
|
300
311
|
);
|
|
301
|
-
const oldLeafsInTree = (inputData.tapLeafScript || []).every(l =>
|
|
312
|
+
const oldLeafsInTree = (inputData.tapLeafScript || []).every((l) =>
|
|
302
313
|
isTapLeafInTree(l, newInputData.tapMerkleRoot),
|
|
303
314
|
);
|
|
304
315
|
if (!newLeafsInTree || !oldLeafsInTree)
|
|
305
|
-
throw new Error(
|
|
306
|
-
`Invalid arguments for Psbt.${action}. Tapleaf not part of taptree.`,
|
|
307
|
-
);
|
|
316
|
+
throw new Error(`Invalid arguments for Psbt.${action}. Tapleaf not part of taptree.`);
|
|
308
317
|
} else if (inputData.tapMerkleRoot) {
|
|
309
|
-
const newLeafsInTree = (newInputData.tapLeafScript || []).every(l =>
|
|
318
|
+
const newLeafsInTree = (newInputData.tapLeafScript || []).every((l) =>
|
|
310
319
|
isTapLeafInTree(l, inputData.tapMerkleRoot),
|
|
311
320
|
);
|
|
312
321
|
if (!newLeafsInTree)
|
|
313
|
-
throw new Error(
|
|
314
|
-
`Invalid arguments for Psbt.${action}. Tapleaf not part of taptree.`,
|
|
315
|
-
);
|
|
322
|
+
throw new Error(`Invalid arguments for Psbt.${action}. Tapleaf not part of taptree.`);
|
|
316
323
|
}
|
|
317
324
|
}
|
|
325
|
+
|
|
318
326
|
/**
|
|
319
327
|
* Checks if a TapLeafScript is present in a Merkle tree.
|
|
320
328
|
* @param tapLeaf The TapLeafScript to check.
|
|
321
329
|
* @param merkleRoot The Merkle root of the tree. If not provided, the function assumes the TapLeafScript is present.
|
|
322
330
|
* @returns A boolean indicating whether the TapLeafScript is present in the tree.
|
|
323
331
|
*/
|
|
324
|
-
function isTapLeafInTree(tapLeaf, merkleRoot) {
|
|
332
|
+
function isTapLeafInTree(tapLeaf: TapLeafScript, merkleRoot?: Buffer): boolean {
|
|
325
333
|
if (!merkleRoot) return true;
|
|
326
|
-
|
|
334
|
+
|
|
335
|
+
const leafHash = tapleafHash({
|
|
327
336
|
output: tapLeaf.script,
|
|
328
337
|
version: tapLeaf.leafVersion,
|
|
329
338
|
});
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
leafHash,
|
|
333
|
-
);
|
|
339
|
+
|
|
340
|
+
const rootHash = rootHashFromPath(tapLeaf.controlBlock, leafHash);
|
|
334
341
|
return rootHash.equals(merkleRoot);
|
|
335
342
|
}
|
|
343
|
+
|
|
336
344
|
/**
|
|
337
345
|
* Sorts the signatures in the input's tapScriptSig array based on their position in the tapLeaf script.
|
|
338
346
|
*
|
|
@@ -340,53 +348,58 @@ function isTapLeafInTree(tapLeaf, merkleRoot) {
|
|
|
340
348
|
* @param tapLeaf - The TapLeafScript object.
|
|
341
349
|
* @returns An array of sorted signatures as Buffers.
|
|
342
350
|
*/
|
|
343
|
-
function sortSignatures(input, tapLeaf) {
|
|
344
|
-
const leafHash =
|
|
351
|
+
function sortSignatures(input: PsbtInput, tapLeaf: TapLeafScript): Buffer[] {
|
|
352
|
+
const leafHash = tapleafHash({
|
|
345
353
|
output: tapLeaf.script,
|
|
346
354
|
version: tapLeaf.leafVersion,
|
|
347
355
|
});
|
|
356
|
+
|
|
348
357
|
return (input.tapScriptSig || [])
|
|
349
|
-
.filter(tss => tss.leafHash.equals(leafHash))
|
|
350
|
-
.map(tss => addPubkeyPositionInScript(tapLeaf.script, tss))
|
|
358
|
+
.filter((tss) => tss.leafHash.equals(leafHash))
|
|
359
|
+
.map((tss) => addPubkeyPositionInScript(tapLeaf.script, tss))
|
|
351
360
|
.sort((t1, t2) => t2.positionInScript - t1.positionInScript)
|
|
352
|
-
.map(t => t.signature);
|
|
361
|
+
.map((t) => t.signature) as Buffer[];
|
|
353
362
|
}
|
|
363
|
+
|
|
354
364
|
/**
|
|
355
365
|
* Adds the position of a public key in a script to a TapScriptSig object.
|
|
356
366
|
* @param script The script in which to find the position of the public key.
|
|
357
367
|
* @param tss The TapScriptSig object to add the position to.
|
|
358
368
|
* @returns A TapScriptSigWitPosition object with the added position.
|
|
359
369
|
*/
|
|
360
|
-
function addPubkeyPositionInScript(script, tss) {
|
|
370
|
+
function addPubkeyPositionInScript(script: Buffer, tss: TapScriptSig): TapScriptSigWitPosition {
|
|
361
371
|
return Object.assign(
|
|
362
372
|
{
|
|
363
|
-
positionInScript: (
|
|
364
|
-
tss.pubkey,
|
|
365
|
-
script,
|
|
366
|
-
),
|
|
373
|
+
positionInScript: pubkeyPositionInScript(tss.pubkey, script),
|
|
367
374
|
},
|
|
368
375
|
tss,
|
|
369
|
-
);
|
|
376
|
+
) as TapScriptSigWitPosition;
|
|
370
377
|
}
|
|
378
|
+
|
|
371
379
|
/**
|
|
372
380
|
* Find tapleaf by hash, or get the signed tapleaf with the shortest path.
|
|
373
381
|
*/
|
|
374
|
-
function findTapLeafToFinalize(
|
|
382
|
+
function findTapLeafToFinalize(
|
|
383
|
+
input: PsbtInput,
|
|
384
|
+
inputIndex: number,
|
|
385
|
+
leafHashToFinalize?: Buffer,
|
|
386
|
+
): TapLeafScript {
|
|
375
387
|
if (!input.tapScriptSig || !input.tapScriptSig.length)
|
|
376
388
|
throw new Error(
|
|
377
389
|
`Can not finalize taproot input #${inputIndex}. No tapleaf script signature provided.`,
|
|
378
390
|
);
|
|
379
391
|
const tapLeaf = (input.tapLeafScript || [])
|
|
380
392
|
.sort((a, b) => a.controlBlock.length - b.controlBlock.length)
|
|
381
|
-
.find(leaf =>
|
|
382
|
-
|
|
383
|
-
);
|
|
393
|
+
.find((leaf) => canFinalizeLeaf(leaf, input.tapScriptSig!, leafHashToFinalize));
|
|
394
|
+
|
|
384
395
|
if (!tapLeaf)
|
|
385
396
|
throw new Error(
|
|
386
397
|
`Can not finalize taproot input #${inputIndex}. Signature for tapleaf script not found.`,
|
|
387
398
|
);
|
|
399
|
+
|
|
388
400
|
return tapLeaf;
|
|
389
401
|
}
|
|
402
|
+
|
|
390
403
|
/**
|
|
391
404
|
* Determines whether a TapLeafScript can be finalized.
|
|
392
405
|
*
|
|
@@ -395,30 +408,34 @@ function findTapLeafToFinalize(input, inputIndex, leafHashToFinalize) {
|
|
|
395
408
|
* @param hash - The optional hash to compare with the leaf hash.
|
|
396
409
|
* @returns A boolean indicating whether the TapLeafScript can be finalized.
|
|
397
410
|
*/
|
|
398
|
-
function canFinalizeLeaf(
|
|
399
|
-
|
|
411
|
+
function canFinalizeLeaf(
|
|
412
|
+
leaf: TapLeafScript,
|
|
413
|
+
tapScriptSig: TapScriptSig[],
|
|
414
|
+
hash?: Buffer,
|
|
415
|
+
): boolean {
|
|
416
|
+
const leafHash = tapleafHash({
|
|
400
417
|
output: leaf.script,
|
|
401
418
|
version: leaf.leafVersion,
|
|
402
419
|
});
|
|
403
420
|
const whiteListedHash = !hash || hash.equals(leafHash);
|
|
404
421
|
return (
|
|
405
|
-
whiteListedHash &&
|
|
406
|
-
tapScriptSig.find(tss => tss.leafHash.equals(leafHash)) !== undefined
|
|
422
|
+
whiteListedHash && tapScriptSig!.find((tss) => tss.leafHash.equals(leafHash)) !== undefined
|
|
407
423
|
);
|
|
408
424
|
}
|
|
425
|
+
|
|
409
426
|
/**
|
|
410
427
|
* Checks if the given PsbtInput or PsbtOutput has non-taproot fields.
|
|
411
428
|
* Non-taproot fields include redeemScript, witnessScript, and bip32Derivation.
|
|
412
429
|
* @param io The PsbtInput or PsbtOutput to check.
|
|
413
430
|
* @returns A boolean indicating whether the given input or output has non-taproot fields.
|
|
414
431
|
*/
|
|
415
|
-
function hasNonTaprootFields(io) {
|
|
432
|
+
function hasNonTaprootFields(io: PsbtInput | PsbtOutput): boolean {
|
|
416
433
|
return (
|
|
417
434
|
io &&
|
|
418
|
-
!!(
|
|
419
|
-
io.redeemScript ||
|
|
420
|
-
io.witnessScript ||
|
|
421
|
-
(io.bip32Derivation && io.bip32Derivation.length)
|
|
422
|
-
)
|
|
435
|
+
!!(io.redeemScript || io.witnessScript || (io.bip32Derivation && io.bip32Derivation.length))
|
|
423
436
|
);
|
|
424
437
|
}
|
|
438
|
+
|
|
439
|
+
interface TapScriptSigWitPosition extends TapScriptSig {
|
|
440
|
+
positionInScript: number;
|
|
441
|
+
}
|