@bitcoinerlab/descriptors-core 3.1.0

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.
Files changed (76) hide show
  1. package/README.md +710 -0
  2. package/dist/adapters/applyPR2137.d.ts +2 -0
  3. package/dist/adapters/applyPR2137.js +150 -0
  4. package/dist/adapters/bitcoinjs.d.ts +8 -0
  5. package/dist/adapters/bitcoinjs.js +36 -0
  6. package/dist/adapters/scure/address.d.ts +2 -0
  7. package/dist/adapters/scure/address.js +50 -0
  8. package/dist/adapters/scure/bip32.d.ts +2 -0
  9. package/dist/adapters/scure/bip32.js +16 -0
  10. package/dist/adapters/scure/common.d.ts +14 -0
  11. package/dist/adapters/scure/common.js +36 -0
  12. package/dist/adapters/scure/ecpair.d.ts +2 -0
  13. package/dist/adapters/scure/ecpair.js +58 -0
  14. package/dist/adapters/scure/payments.d.ts +2 -0
  15. package/dist/adapters/scure/payments.js +216 -0
  16. package/dist/adapters/scure/psbt.d.ts +43 -0
  17. package/dist/adapters/scure/psbt.js +382 -0
  18. package/dist/adapters/scure/script.d.ts +20 -0
  19. package/dist/adapters/scure/script.js +163 -0
  20. package/dist/adapters/scure/transaction.d.ts +2 -0
  21. package/dist/adapters/scure/transaction.js +32 -0
  22. package/dist/adapters/scure.d.ts +6 -0
  23. package/dist/adapters/scure.js +37 -0
  24. package/dist/adapters/scureKeys.d.ts +4 -0
  25. package/dist/adapters/scureKeys.js +135 -0
  26. package/dist/bip174.d.ts +87 -0
  27. package/dist/bip174.js +12 -0
  28. package/dist/bitcoinLib.d.ts +385 -0
  29. package/dist/bitcoinLib.js +19 -0
  30. package/dist/bitcoinjs-lib-internals.d.ts +6 -0
  31. package/dist/bitcoinjs-lib-internals.js +60 -0
  32. package/dist/bitcoinjs.d.ts +12 -0
  33. package/dist/bitcoinjs.js +18 -0
  34. package/dist/checksum.d.ts +6 -0
  35. package/dist/checksum.js +58 -0
  36. package/dist/crypto.d.ts +3 -0
  37. package/dist/crypto.js +79 -0
  38. package/dist/descriptors.d.ts +481 -0
  39. package/dist/descriptors.js +1888 -0
  40. package/dist/index.d.ts +23 -0
  41. package/dist/index.js +87 -0
  42. package/dist/keyExpressions.d.ts +124 -0
  43. package/dist/keyExpressions.js +310 -0
  44. package/dist/keyInterfaces.d.ts +5 -0
  45. package/dist/keyInterfaces.js +50 -0
  46. package/dist/ledger.d.ts +183 -0
  47. package/dist/ledger.js +618 -0
  48. package/dist/miniscript.d.ts +125 -0
  49. package/dist/miniscript.js +310 -0
  50. package/dist/multipath.d.ts +13 -0
  51. package/dist/multipath.js +76 -0
  52. package/dist/networkUtils.d.ts +3 -0
  53. package/dist/networkUtils.js +16 -0
  54. package/dist/networks.d.ts +16 -0
  55. package/dist/networks.js +31 -0
  56. package/dist/parseUtils.d.ts +7 -0
  57. package/dist/parseUtils.js +46 -0
  58. package/dist/psbt.d.ts +40 -0
  59. package/dist/psbt.js +228 -0
  60. package/dist/re.d.ts +31 -0
  61. package/dist/re.js +79 -0
  62. package/dist/resourceLimits.d.ts +28 -0
  63. package/dist/resourceLimits.js +84 -0
  64. package/dist/scriptExpressions.d.ts +95 -0
  65. package/dist/scriptExpressions.js +98 -0
  66. package/dist/scure.d.ts +4 -0
  67. package/dist/scure.js +10 -0
  68. package/dist/signers.d.ts +161 -0
  69. package/dist/signers.js +324 -0
  70. package/dist/tapMiniscript.d.ts +231 -0
  71. package/dist/tapMiniscript.js +524 -0
  72. package/dist/tapTree.d.ts +91 -0
  73. package/dist/tapTree.js +166 -0
  74. package/dist/types.d.ts +296 -0
  75. package/dist/types.js +4 -0
  76. package/package.json +148 -0
package/dist/psbt.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ import type { TapBip32Derivation, TapLeafScript } from './bip174';
2
+ import type { KeyInfo } from './types';
3
+ import type { FinalScriptsFunc, BitcoinLib, PsbtLike, ScureTransactionLike } from './bitcoinLib';
4
+ import type { Network } from './networks';
5
+ export declare function finalScriptsFuncFactory(scriptSatisfaction: Uint8Array, network: Network, payments: BitcoinLib['payments']): FinalScriptsFunc;
6
+ /**
7
+ * Important: Read comments on Output.updatePsbtAsInput regarding not passing txHex
8
+ */
9
+ export declare function addPsbtInput({ psbt, vout, txHex, txId, value, sequence, locktime, keysInfo, scriptPubKey, isSegwit, tapInternalKey, tapLeafScript, tapBip32Derivation, witnessScript, redeemScript, rbf, Transaction }: {
10
+ psbt: PsbtLike;
11
+ vout: number;
12
+ txHex?: string;
13
+ txId?: string;
14
+ value?: bigint;
15
+ sequence: number | undefined;
16
+ locktime: number | undefined;
17
+ keysInfo: KeyInfo[];
18
+ scriptPubKey: Uint8Array;
19
+ isSegwit: boolean;
20
+ /** for taproot **/
21
+ tapInternalKey?: Uint8Array | undefined;
22
+ /** for taproot script-path **/
23
+ tapLeafScript?: TapLeafScript[] | undefined;
24
+ /** for taproot **/
25
+ tapBip32Derivation?: TapBip32Derivation[] | undefined;
26
+ witnessScript: Uint8Array | undefined;
27
+ redeemScript: Uint8Array | undefined;
28
+ rbf: boolean;
29
+ Transaction: BitcoinLib['Transaction'];
30
+ }): number;
31
+ /**
32
+ * Converts a concrete transaction object to this library's internal `PsbtLike`
33
+ * surface.
34
+ *
35
+ * @param psbt - Either a
36
+ * {@link https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/psbt.ts | bitcoinjs-lib `Psbt`}
37
+ * or a {@link https://github.com/paulmillr/scure-btc-signer | `@scure/btc-signer` `Transaction`}.
38
+ * @returns A `PsbtLike` implementation consumed by internal code.
39
+ */
40
+ export declare function toPsbt(psbt: PsbtLike | ScureTransactionLike): PsbtLike;
package/dist/psbt.js ADDED
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ // Copyright (c) 2025 Jose-Luis Landabaso - https://bitcoinerlab.com
3
+ // Distributed under the MIT software license
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.finalScriptsFuncFactory = finalScriptsFuncFactory;
6
+ exports.addPsbtInput = addPsbtInput;
7
+ exports.toPsbt = toPsbt;
8
+ const bitcoinLib_1 = require("./bitcoinLib");
9
+ const uint8array_tools_1 = require("uint8array-tools");
10
+ const bitcoinjs_lib_internals_1 = require("./bitcoinjs-lib-internals");
11
+ function reverseBytes(buffer) {
12
+ if (buffer.length < 1)
13
+ return buffer;
14
+ const copy = Uint8Array.from(buffer);
15
+ let j = copy.length - 1;
16
+ let tmp = 0;
17
+ for (let i = 0; i < copy.length / 2; i++) {
18
+ tmp = copy[i];
19
+ copy[i] = copy[j];
20
+ copy[j] = tmp;
21
+ j--;
22
+ }
23
+ return copy;
24
+ }
25
+ function finalScriptsFuncFactory(scriptSatisfaction, network, payments) {
26
+ /**
27
+ * This function must do two things:
28
+ * 1. Check if the `input` can be finalized. If it can not be finalized, throw.
29
+ * ie. `Can not finalize input #${inputIndex}`
30
+ * 2. Create finalScriptSig and finalScriptWitness.
31
+ */
32
+ const finalScriptsFunc = (_index, _input, lockingScript /*witnessScript or redeemScript*/, isSegwit, isP2SH, _isP2WSH) => {
33
+ let finalScriptWitness;
34
+ let finalScriptSig;
35
+ //p2wsh
36
+ if (isSegwit && !isP2SH) {
37
+ const payment = payments.p2wsh({
38
+ redeem: { input: scriptSatisfaction, output: lockingScript },
39
+ network
40
+ });
41
+ if (!payment.witness)
42
+ throw new Error(`Error: p2wsh failed producing a witness`);
43
+ finalScriptWitness = (0, bitcoinjs_lib_internals_1.witnessStackToScriptWitness)(payment.witness);
44
+ }
45
+ //p2sh-p2wsh
46
+ else if (isSegwit && isP2SH) {
47
+ const payment = payments.p2sh({
48
+ redeem: payments.p2wsh({
49
+ redeem: { input: scriptSatisfaction, output: lockingScript },
50
+ network
51
+ }),
52
+ network
53
+ });
54
+ if (!payment.witness)
55
+ throw new Error(`Error: p2sh-p2wsh failed producing a witness`);
56
+ finalScriptWitness = (0, bitcoinjs_lib_internals_1.witnessStackToScriptWitness)(payment.witness);
57
+ finalScriptSig = payment.input;
58
+ }
59
+ //p2sh
60
+ else {
61
+ finalScriptSig = payments.p2sh({
62
+ redeem: { input: scriptSatisfaction, output: lockingScript },
63
+ network
64
+ }).input;
65
+ }
66
+ return {
67
+ finalScriptWitness,
68
+ finalScriptSig
69
+ };
70
+ };
71
+ return finalScriptsFunc;
72
+ }
73
+ /**
74
+ * Important: Read comments on Output.updatePsbtAsInput regarding not passing txHex
75
+ */
76
+ function addPsbtInput({ psbt, vout, txHex, txId, value, sequence, locktime, keysInfo, scriptPubKey, isSegwit, tapInternalKey, tapLeafScript, tapBip32Derivation, witnessScript, redeemScript, rbf, Transaction }) {
77
+ if (value !== undefined && typeof value !== 'bigint')
78
+ throw new Error(`Error: value must be a bigint`);
79
+ if (value !== undefined && value < 0n)
80
+ throw new Error(`Error: value must be >= 0n`);
81
+ let normalizedValue = value;
82
+ //Some data-sanity checks:
83
+ if (sequence !== undefined && rbf && sequence > 0xfffffffd)
84
+ throw new Error(`Error: incompatible sequence and rbf settings`);
85
+ if (!isSegwit && txHex === undefined)
86
+ throw new Error(`Error: txHex is mandatory for Non-Segwit inputs`);
87
+ if (isSegwit &&
88
+ txHex === undefined &&
89
+ (txId === undefined || value === undefined))
90
+ throw new Error(`Error: pass txHex or txId+value for Segwit inputs`);
91
+ if (txHex !== undefined) {
92
+ const tx = Transaction.fromHex(txHex);
93
+ const out = tx.outs[vout];
94
+ if (!out)
95
+ throw new Error(`Error: tx ${txHex} does not have vout ${vout}`);
96
+ const outputScript = out.script;
97
+ if (!outputScript)
98
+ throw new Error(`Error: could not extract outputScript for txHex ${txHex} and vout ${vout}`);
99
+ if ((0, uint8array_tools_1.compare)(outputScript, scriptPubKey) !== 0)
100
+ throw new Error(`Error: txHex ${txHex} for vout ${vout} does not correspond to scriptPubKey ${scriptPubKey}`);
101
+ if (txId !== undefined) {
102
+ if (tx.getId() !== txId)
103
+ throw new Error(`Error: txId for ${txHex} and vout ${vout} does not correspond to ${txId}`);
104
+ }
105
+ else {
106
+ txId = tx.getId();
107
+ }
108
+ if (normalizedValue !== undefined) {
109
+ if (out.value !== normalizedValue)
110
+ throw new Error(`Error: value for ${txHex} and vout ${vout} does not correspond to ${value}`);
111
+ }
112
+ else {
113
+ normalizedValue = out.value;
114
+ }
115
+ }
116
+ if (txId === undefined || normalizedValue === undefined)
117
+ throw new Error(`Error: txHex+vout required. Alternatively, but ONLY for Segwit inputs, txId+value can also be passed.`);
118
+ if (locktime) {
119
+ if (psbt.locktime && psbt.locktime !== locktime)
120
+ throw new Error(`Error: transaction locktime was already set with a different value: ${locktime} != ${psbt.locktime}`);
121
+ // nLockTime only works if at least one of the transaction inputs has an
122
+ // nSequence value that is below 0xffffffff. Let's make sure that at least
123
+ // this input's sequence < 0xffffffff
124
+ if (sequence === undefined) {
125
+ //NOTE: if sequence is undefined, bitcoinjs-lib uses 0xffffffff as default
126
+ sequence = rbf ? 0xfffffffd : 0xfffffffe;
127
+ }
128
+ else if (sequence > 0xfffffffe) {
129
+ throw new Error(`Error: incompatible sequence: ${sequence} and locktime: ${locktime}`);
130
+ }
131
+ if (sequence === undefined && rbf)
132
+ sequence = 0xfffffffd;
133
+ psbt.setLocktime(locktime);
134
+ }
135
+ else {
136
+ if (sequence === undefined) {
137
+ if (rbf)
138
+ sequence = 0xfffffffd;
139
+ else
140
+ sequence = 0xffffffff;
141
+ }
142
+ }
143
+ const input = {
144
+ hash: reverseBytes((0, uint8array_tools_1.fromHex)(txId)),
145
+ index: vout
146
+ };
147
+ if (txHex !== undefined) {
148
+ input.nonWitnessUtxo = Transaction.fromHex(txHex).toBuffer();
149
+ }
150
+ if (tapInternalKey) {
151
+ //Taproot
152
+ const fallbackTapBip32Derivation = keysInfo
153
+ .filter((keyInfo) => keyInfo.pubkey && keyInfo.masterFingerprint && keyInfo.path)
154
+ .map((keyInfo) => {
155
+ const pubkey = keyInfo.pubkey;
156
+ if (!pubkey)
157
+ throw new Error(`key ${keyInfo.keyExpression} missing pubkey`);
158
+ return {
159
+ masterFingerprint: keyInfo.masterFingerprint,
160
+ pubkey,
161
+ path: keyInfo.path,
162
+ leafHashes: []
163
+ };
164
+ });
165
+ const resolvedTapBip32Derivation = tapBip32Derivation || fallbackTapBip32Derivation;
166
+ if (resolvedTapBip32Derivation.length)
167
+ input.tapBip32Derivation = resolvedTapBip32Derivation;
168
+ input.tapInternalKey = tapInternalKey;
169
+ if (tapLeafScript && tapLeafScript.length > 0)
170
+ input.tapLeafScript = tapLeafScript;
171
+ }
172
+ else {
173
+ const bip32Derivation = keysInfo
174
+ .filter((keyInfo) => keyInfo.pubkey && keyInfo.masterFingerprint && keyInfo.path)
175
+ .map((keyInfo) => {
176
+ const pubkey = keyInfo.pubkey;
177
+ if (!pubkey)
178
+ throw new Error(`key ${keyInfo.keyExpression} missing pubkey`);
179
+ return {
180
+ masterFingerprint: keyInfo.masterFingerprint,
181
+ pubkey,
182
+ path: keyInfo.path
183
+ };
184
+ });
185
+ if (bip32Derivation.length)
186
+ input.bip32Derivation = bip32Derivation;
187
+ }
188
+ if (isSegwit && txHex !== undefined) {
189
+ //There's no need to put both witnessUtxo and nonWitnessUtxo
190
+ input.witnessUtxo = { script: scriptPubKey, value: normalizedValue };
191
+ }
192
+ if (sequence !== undefined)
193
+ input.sequence = sequence;
194
+ if (witnessScript)
195
+ input.witnessScript = witnessScript;
196
+ if (redeemScript)
197
+ input.redeemScript = redeemScript;
198
+ psbt.addInput(input);
199
+ return psbt.data.inputs.length - 1;
200
+ }
201
+ // ─── Type Guards and Converters ─────────────────────────────────────
202
+ /**
203
+ * Converts a concrete transaction object to this library's internal `PsbtLike`
204
+ * surface.
205
+ *
206
+ * @param psbt - Either a
207
+ * {@link https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/psbt.ts | bitcoinjs-lib `Psbt`}
208
+ * or a {@link https://github.com/paulmillr/scure-btc-signer | `@scure/btc-signer` `Transaction`}.
209
+ * @returns A `PsbtLike` implementation consumed by internal code.
210
+ */
211
+ function toPsbt(psbt) {
212
+ if ((0, bitcoinLib_1.isScureTransaction)(psbt)) {
213
+ // Dynamically import scure adapter only when needed
214
+ try {
215
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
216
+ const { wrapScureTransaction } = require('./adapters/scure');
217
+ return wrapScureTransaction(psbt);
218
+ }
219
+ catch (error) {
220
+ throw new Error('Failed to load @scure/btc-signer adapter. ' +
221
+ 'Make sure @scure/btc-signer is installed as a peer dependency. ' +
222
+ 'Original error: ' +
223
+ (error instanceof Error ? error.message : String(error)));
224
+ }
225
+ }
226
+ // Already a bitcoinjs-lib compatible Psbt
227
+ return psbt;
228
+ }
package/dist/re.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ export declare const reOriginPath: string;
2
+ export declare const reMasterFingerprint: string;
3
+ export declare const reOrigin: string;
4
+ export declare const reChecksum: string;
5
+ export declare const reNonSegwitPubKey: string;
6
+ export declare const reSegwitPubKey: string;
7
+ export declare const reTaprootPubKey: string;
8
+ export declare const reWIF: string;
9
+ export declare const reXpub: string;
10
+ export declare const reXprv: string;
11
+ export declare const rePath: string;
12
+ export declare const reXpubKey: string;
13
+ export declare const reXprvKey: string;
14
+ export declare const reNonSegwitKeyExp: string;
15
+ export declare const reSegwitKeyExp: string;
16
+ export declare const reTaprootKeyExp: string;
17
+ export declare const reNonSegwitSortedMulti: string;
18
+ export declare const reSegwitSortedMulti: string;
19
+ export declare const anchorStartAndEnd: (re: string) => string;
20
+ export declare const rePkAnchored: string;
21
+ export declare const reAddrAnchored: string;
22
+ export declare const rePkhAnchored: string;
23
+ export declare const reWpkhAnchored: string;
24
+ export declare const reShWpkhAnchored: string;
25
+ export declare const reTrSingleKeyAnchored: string;
26
+ export declare const reShSortedMultiAnchored: string;
27
+ export declare const reWshSortedMultiAnchored: string;
28
+ export declare const reShWshSortedMultiAnchored: string;
29
+ export declare const reShMiniscriptAnchored: string;
30
+ export declare const reShWshMiniscriptAnchored: string;
31
+ export declare const reWshMiniscriptAnchored: string;
package/dist/re.js ADDED
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ // Copyright (c) 2025 Jose-Luis Landabaso - https://bitcoinerlab.com
3
+ // Distributed under the MIT software license
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.reWshMiniscriptAnchored = exports.reShWshMiniscriptAnchored = exports.reShMiniscriptAnchored = exports.reShWshSortedMultiAnchored = exports.reWshSortedMultiAnchored = exports.reShSortedMultiAnchored = exports.reTrSingleKeyAnchored = exports.reShWpkhAnchored = exports.reWpkhAnchored = exports.rePkhAnchored = exports.reAddrAnchored = exports.rePkAnchored = exports.anchorStartAndEnd = exports.reSegwitSortedMulti = exports.reNonSegwitSortedMulti = exports.reTaprootKeyExp = exports.reSegwitKeyExp = exports.reNonSegwitKeyExp = exports.reXprvKey = exports.reXpubKey = exports.rePath = exports.reXprv = exports.reXpub = exports.reWIF = exports.reTaprootPubKey = exports.reSegwitPubKey = exports.reNonSegwitPubKey = exports.reChecksum = exports.reOrigin = exports.reMasterFingerprint = exports.reOriginPath = void 0;
6
+ const checksum_1 = require("./checksum");
7
+ //Regular expressions cheat sheet:
8
+ //https://www.keycdn.com/support/regex-cheat-sheet
9
+ //hardened characters
10
+ const reHardened = String.raw `(['hH])`;
11
+ //a level is a series of integers followed (optional) by a hardener char
12
+ const reLevel = String.raw `(\d+${reHardened}?)`;
13
+ //a path component is a level followed by a slash "/" char
14
+ const rePathComponent = String.raw `(${reLevel}\/)`;
15
+ //A path formed by a series of path components that can be hardened: /2'/23H/23
16
+ exports.reOriginPath = String.raw `(\/${rePathComponent}*${reLevel})`; //The "*" means: "match 0 or more of the previous"
17
+ //an origin is something like this: [d34db33f/44'/0'/0'] where the path is optional. The fingerPrint is 8 chars hex
18
+ exports.reMasterFingerprint = String.raw `[0-9a-fA-F]{8}`;
19
+ exports.reOrigin = String.raw `(\[${exports.reMasterFingerprint}(${exports.reOriginPath})?\])`;
20
+ exports.reChecksum = String.raw `(#[${checksum_1.CHECKSUM_CHARSET}]{8})`;
21
+ //Something like this: 0252972572d465d016d4c501887b8df303eee3ed602c056b1eb09260dfa0da0ab2
22
+ //as explained here: github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md#reference
23
+ const reCompressedPubKey = String.raw `((02|03)[0-9a-fA-F]{64})`;
24
+ const reUncompressedPubKey = String.raw `(04[0-9a-fA-F]{128})`;
25
+ const reXOnlyPubKey = String.raw `([0-9a-fA-F]{64})`;
26
+ exports.reNonSegwitPubKey = String.raw `(${reCompressedPubKey}|${reUncompressedPubKey})`;
27
+ exports.reSegwitPubKey = String.raw `(${reCompressedPubKey})`;
28
+ exports.reTaprootPubKey = String.raw `(${reCompressedPubKey}|${reXOnlyPubKey})`;
29
+ //https://learnmeabitcoin.com/technical/wif
30
+ //5, K, L for mainnet, 5: uncompressed, {K, L}: compressed
31
+ //c, 9, testnet, c: compressed, 9: uncompressed
32
+ exports.reWIF = String.raw `([5KLc9][1-9A-HJ-NP-Za-km-z]{50,51})`;
33
+ //x for mainnet, t for testnet
34
+ exports.reXpub = String.raw `([xXtT]pub[1-9A-HJ-NP-Za-km-z]{79,108})`;
35
+ exports.reXprv = String.raw `([xXtT]prv[1-9A-HJ-NP-Za-km-z]{79,108})`;
36
+ //reRangeLevel is like reLevel but using a wildcard "*"
37
+ const reRangeLevel = String.raw `(\*(${reHardened})?)`;
38
+ //A path can be finished with stuff like this: /23 or /23h or /* or /*'
39
+ exports.rePath = String.raw `(\/(${rePathComponent})*(${reRangeLevel}|${reLevel}))`;
40
+ //rePath is optional (note the "zero"): Followed by zero or more /NUM or /NUM' path elements to indicate unhardened or hardened derivation steps between the fingerprint and the key or xpub/xprv root that follows
41
+ exports.reXpubKey = String.raw `(${exports.reXpub})(${exports.rePath})?`;
42
+ exports.reXprvKey = String.raw `(${exports.reXprv})(${exports.rePath})?`;
43
+ //actualKey is the keyExpression without optional origin
44
+ const reNonSegwitActualKey = String.raw `(${exports.reXpubKey}|${exports.reXprvKey}|${exports.reNonSegwitPubKey}|${exports.reWIF})`;
45
+ const reSegwitActualKey = String.raw `(${exports.reXpubKey}|${exports.reXprvKey}|${exports.reSegwitPubKey}|${exports.reWIF})`;
46
+ const reTaprootActualKey = String.raw `(${exports.reXpubKey}|${exports.reXprvKey}|${exports.reTaprootPubKey}|${exports.reWIF})`;
47
+ //reOrigin is optional: Optionally, key origin information, consisting of:
48
+ //Matches a key expression: wif, xpub, xprv or pubkey:
49
+ exports.reNonSegwitKeyExp = String.raw `(${exports.reOrigin})?(${reNonSegwitActualKey})`;
50
+ exports.reSegwitKeyExp = String.raw `(${exports.reOrigin})?(${reSegwitActualKey})`;
51
+ exports.reTaprootKeyExp = String.raw `(${exports.reOrigin})?(${reTaprootActualKey})`;
52
+ const rePk = String.raw `pk\((.*?)\)`; //Matches anything. We assert later in the code that the pubkey is valid.
53
+ const reAddr = String.raw `addr\((.*?)\)`; //Matches anything. We assert later in the code that the address is valid.
54
+ const rePkh = String.raw `pkh\(${exports.reNonSegwitKeyExp}\)`;
55
+ const reWpkh = String.raw `wpkh\(${exports.reSegwitKeyExp}\)`;
56
+ const reShWpkh = String.raw `sh\(wpkh\(${exports.reSegwitKeyExp}\)\)`;
57
+ const reTrSingleKey = String.raw `tr\(${exports.reTaprootKeyExp}\)`; // TODO: tr(KEY,TREE) not yet supported. TrSingleKey used for tr(KEY)
58
+ exports.reNonSegwitSortedMulti = String.raw `sortedmulti\(((?:1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20)(?:,${exports.reNonSegwitKeyExp})+)\)`;
59
+ exports.reSegwitSortedMulti = String.raw `sortedmulti\(((?:1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20)(?:,${exports.reSegwitKeyExp})+)\)`;
60
+ const reMiniscript = String.raw `(.*?)`; //Matches anything. We assert later in the code that miniscripts are valid and sane.
61
+ //RegExp makers:
62
+ const makeReSh = (re) => String.raw `sh\(${re}\)`;
63
+ const makeReWsh = (re) => String.raw `wsh\(${re}\)`;
64
+ const makeReShWsh = (re) => makeReSh(makeReWsh(re));
65
+ const anchorStartAndEnd = (re) => String.raw `^${re}$`; //starts and finishes like re (not composable)
66
+ exports.anchorStartAndEnd = anchorStartAndEnd;
67
+ const composeChecksum = (re) => String.raw `${re}(${exports.reChecksum})?`; //it's optional (note the "?")
68
+ exports.rePkAnchored = (0, exports.anchorStartAndEnd)(composeChecksum(rePk));
69
+ exports.reAddrAnchored = (0, exports.anchorStartAndEnd)(composeChecksum(reAddr));
70
+ exports.rePkhAnchored = (0, exports.anchorStartAndEnd)(composeChecksum(rePkh));
71
+ exports.reWpkhAnchored = (0, exports.anchorStartAndEnd)(composeChecksum(reWpkh));
72
+ exports.reShWpkhAnchored = (0, exports.anchorStartAndEnd)(composeChecksum(reShWpkh));
73
+ exports.reTrSingleKeyAnchored = (0, exports.anchorStartAndEnd)(composeChecksum(reTrSingleKey));
74
+ exports.reShSortedMultiAnchored = (0, exports.anchorStartAndEnd)(composeChecksum(makeReSh(exports.reNonSegwitSortedMulti)));
75
+ exports.reWshSortedMultiAnchored = (0, exports.anchorStartAndEnd)(composeChecksum(makeReWsh(exports.reSegwitSortedMulti)));
76
+ exports.reShWshSortedMultiAnchored = (0, exports.anchorStartAndEnd)(composeChecksum(makeReShWsh(exports.reSegwitSortedMulti)));
77
+ exports.reShMiniscriptAnchored = (0, exports.anchorStartAndEnd)(composeChecksum(makeReSh(reMiniscript)));
78
+ exports.reShWshMiniscriptAnchored = (0, exports.anchorStartAndEnd)(composeChecksum(makeReShWsh(reMiniscript)));
79
+ exports.reWshMiniscriptAnchored = (0, exports.anchorStartAndEnd)(composeChecksum(makeReWsh(reMiniscript)));
@@ -0,0 +1,28 @@
1
+ import type { BitcoinLib } from './bitcoinLib';
2
+ import type { Network } from './networks';
3
+ export declare const MAX_SCRIPT_ELEMENT_SIZE = 520;
4
+ export declare const MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600;
5
+ export declare function assertScriptNonPushOnlyOpsLimit({ script, scriptLib }: {
6
+ script: Uint8Array;
7
+ scriptLib: BitcoinLib['script'];
8
+ }): void;
9
+ /**
10
+ * Enforces consensus stack resource limits.
11
+ */
12
+ export declare function assertConsensusStackResourceLimits({ stackItems, stackLabel, stackItemLabel }: {
13
+ stackItems: Uint8Array[];
14
+ stackLabel?: string;
15
+ stackItemLabel?: string;
16
+ }): void;
17
+ export declare function assertWitnessV0SatisfactionResourceLimits({ stackItems }: {
18
+ stackItems: Uint8Array[];
19
+ }): void;
20
+ export declare function assertTaprootScriptPathSatisfactionResourceLimits({ stackItems }: {
21
+ stackItems: Uint8Array[];
22
+ }): void;
23
+ export declare function assertP2shScriptSigStandardSize({ scriptSatisfaction, redeemScript, network, payments }: {
24
+ scriptSatisfaction: Uint8Array;
25
+ redeemScript: Uint8Array;
26
+ network: Network;
27
+ payments: BitcoinLib['payments'];
28
+ }): void;
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ // Copyright (c) 2026 Jose-Luis Landabaso
3
+ // Distributed under the MIT software license
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.MAX_STANDARD_P2WSH_SCRIPT_SIZE = exports.MAX_SCRIPT_ELEMENT_SIZE = void 0;
6
+ exports.assertScriptNonPushOnlyOpsLimit = assertScriptNonPushOnlyOpsLimit;
7
+ exports.assertConsensusStackResourceLimits = assertConsensusStackResourceLimits;
8
+ exports.assertWitnessV0SatisfactionResourceLimits = assertWitnessV0SatisfactionResourceLimits;
9
+ exports.assertTaprootScriptPathSatisfactionResourceLimits = assertTaprootScriptPathSatisfactionResourceLimits;
10
+ exports.assertP2shScriptSigStandardSize = assertP2shScriptSigStandardSize;
11
+ // See Sipa's Miniscript "Resource limitations":
12
+ // https://bitcoin.sipa.be/miniscript/
13
+ // and Bitcoin Core policy/consensus constants.
14
+ //https://github.com/bitcoin/bitcoin/blob/master/src/policy/policy.h
15
+ // Consensus: max number of elements in initial stack (and stack+altstack after
16
+ // each opcode execution).
17
+ const MAX_STACK_SIZE = 1000;
18
+ // Consensus: max size for any stack element is 520 bytes.
19
+ // This is a per-element limit, not a full script-size limit.
20
+ // In legacy P2SH, redeemScript is pushed as a stack element,
21
+ // ( this is why we typically say that the redeemScript cannot be larger than 520 ).
22
+ // But the same per-element rule applies to other stack items as well.
23
+ exports.MAX_SCRIPT_ELEMENT_SIZE = 520;
24
+ // Standardness policy limits.
25
+ // See Sipa's Miniscript "Resource limitations":
26
+ // https://bitcoin.sipa.be/miniscript/
27
+ // and Bitcoin Core policy/consensus constants.
28
+ //https://github.com/bitcoin/bitcoin/blob/master/src/policy/policy.h
29
+ exports.MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600;
30
+ const MAX_STANDARD_P2WSH_STACK_ITEMS = 100;
31
+ const MAX_OPS_PER_SCRIPT = 201;
32
+ const MAX_STANDARD_SCRIPTSIG_SIZE = 1650;
33
+ const MAX_STANDARD_P2WSH_STACK_ITEM_SIZE = 80;
34
+ const MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE = 80;
35
+ function assertScriptNonPushOnlyOpsLimit({ script, scriptLib }) {
36
+ const chunks = scriptLib.decompile(script);
37
+ if (!chunks)
38
+ throw new Error(`Error: could not decompile ${script}`);
39
+ const nonPushOnlyOps = scriptLib.countNonPushOnlyOPs(chunks);
40
+ if (nonPushOnlyOps > MAX_OPS_PER_SCRIPT)
41
+ throw new Error(`Error: too many non-push ops, ${nonPushOnlyOps} non-push ops is larger than ${MAX_OPS_PER_SCRIPT}`);
42
+ }
43
+ /**
44
+ * Enforces consensus stack resource limits.
45
+ */
46
+ function assertConsensusStackResourceLimits({ stackItems, stackLabel = 'stack', stackItemLabel = 'stack item' }) {
47
+ if (stackItems.length > MAX_STACK_SIZE)
48
+ throw new Error(`Error: ${stackLabel} has too many items, ${stackItems.length} is larger than ${MAX_STACK_SIZE}`);
49
+ for (const stackItem of stackItems) {
50
+ if (stackItem.length > exports.MAX_SCRIPT_ELEMENT_SIZE)
51
+ throw new Error(`Error: ${stackItemLabel} is too large, ${stackItem.length} bytes is larger than ${exports.MAX_SCRIPT_ELEMENT_SIZE} bytes`);
52
+ }
53
+ }
54
+ function assertWitnessV0SatisfactionResourceLimits({ stackItems }) {
55
+ assertConsensusStackResourceLimits({ stackItems });
56
+ if (stackItems.length > MAX_STANDARD_P2WSH_STACK_ITEMS)
57
+ throw new Error(`Error: witness stack has too many items, ${stackItems.length} is larger than ${MAX_STANDARD_P2WSH_STACK_ITEMS}`);
58
+ for (const stackItem of stackItems) {
59
+ if (stackItem.length > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE)
60
+ throw new Error(`Error: witness stack item exceeds standard policy, ${stackItem.length} bytes is larger than ${MAX_STANDARD_P2WSH_STACK_ITEM_SIZE} bytes`);
61
+ }
62
+ }
63
+ function assertTaprootScriptPathSatisfactionResourceLimits({ stackItems }) {
64
+ assertConsensusStackResourceLimits({
65
+ stackItems,
66
+ stackLabel: 'taproot script-path stack',
67
+ stackItemLabel: 'taproot script-path stack item'
68
+ });
69
+ // Standardness policy for tapscript (leaf version 0xc0): <= 80 bytes.
70
+ for (const stackItem of stackItems) {
71
+ if (stackItem.length > MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE)
72
+ throw new Error(`Error: taproot script-path stack item exceeds standard policy, ${stackItem.length} bytes is larger than ${MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE} bytes`);
73
+ }
74
+ }
75
+ function assertP2shScriptSigStandardSize({ scriptSatisfaction, redeemScript, network, payments }) {
76
+ const scriptSig = payments.p2sh({
77
+ redeem: { input: scriptSatisfaction, output: redeemScript },
78
+ network
79
+ }).input;
80
+ if (!scriptSig)
81
+ throw new Error(`Error: could not build scriptSig from satisfaction`);
82
+ if (scriptSig.length > MAX_STANDARD_SCRIPTSIG_SIZE)
83
+ throw new Error(`Error: scriptSig is too large, ${scriptSig.length} bytes is larger than ${MAX_STANDARD_SCRIPTSIG_SIZE} bytes`);
84
+ }
@@ -0,0 +1,95 @@
1
+ import type { BIP32InterfaceLike, ScureHDKeyLike } from './bitcoinLib';
2
+ import type { LedgerManager } from './ledger';
3
+ import { type Network } from './networks';
4
+ /** @function */
5
+ export declare const pkhBIP32: ({ masterNode, network, keyPath, account, change, index, isPublic }: {
6
+ masterNode: BIP32InterfaceLike | ScureHDKeyLike;
7
+ /** @default networks.bitcoin */
8
+ network?: Network;
9
+ account: number;
10
+ change?: number | undefined;
11
+ index?: number | undefined | "*";
12
+ keyPath?: string;
13
+ /**
14
+ * Compute an xpub or xprv
15
+ * @default true
16
+ */
17
+ isPublic?: boolean;
18
+ }) => string;
19
+ /** @function */
20
+ export declare const shWpkhBIP32: ({ masterNode, network, keyPath, account, change, index, isPublic }: {
21
+ masterNode: BIP32InterfaceLike | ScureHDKeyLike;
22
+ /** @default networks.bitcoin */
23
+ network?: Network;
24
+ account: number;
25
+ change?: number | undefined;
26
+ index?: number | undefined | "*";
27
+ keyPath?: string;
28
+ /**
29
+ * Compute an xpub or xprv
30
+ * @default true
31
+ */
32
+ isPublic?: boolean;
33
+ }) => string;
34
+ /** @function */
35
+ export declare const wpkhBIP32: ({ masterNode, network, keyPath, account, change, index, isPublic }: {
36
+ masterNode: BIP32InterfaceLike | ScureHDKeyLike;
37
+ /** @default networks.bitcoin */
38
+ network?: Network;
39
+ account: number;
40
+ change?: number | undefined;
41
+ index?: number | undefined | "*";
42
+ keyPath?: string;
43
+ /**
44
+ * Compute an xpub or xprv
45
+ * @default true
46
+ */
47
+ isPublic?: boolean;
48
+ }) => string;
49
+ /** @function */
50
+ export declare const trBIP32: ({ masterNode, network, keyPath, account, change, index, isPublic }: {
51
+ masterNode: BIP32InterfaceLike | ScureHDKeyLike;
52
+ /** @default networks.bitcoin */
53
+ network?: Network;
54
+ account: number;
55
+ change?: number | undefined;
56
+ index?: number | undefined | "*";
57
+ keyPath?: string;
58
+ /**
59
+ * Compute an xpub or xprv
60
+ * @default true
61
+ */
62
+ isPublic?: boolean;
63
+ }) => string;
64
+ /** @function */
65
+ export declare const pkhLedger: ({ ledgerManager, account, keyPath, change, index }: {
66
+ ledgerManager: LedgerManager;
67
+ account: number;
68
+ keyPath?: string;
69
+ change?: number | undefined;
70
+ index?: number | undefined | "*";
71
+ }) => Promise<string>;
72
+ /** @function */
73
+ export declare const shWpkhLedger: ({ ledgerManager, account, keyPath, change, index }: {
74
+ ledgerManager: LedgerManager;
75
+ account: number;
76
+ keyPath?: string;
77
+ change?: number | undefined;
78
+ index?: number | undefined | "*";
79
+ }) => Promise<string>;
80
+ /** @function */
81
+ export declare const wpkhLedger: ({ ledgerManager, account, keyPath, change, index }: {
82
+ ledgerManager: LedgerManager;
83
+ account: number;
84
+ keyPath?: string;
85
+ change?: number | undefined;
86
+ index?: number | undefined | "*";
87
+ }) => Promise<string>;
88
+ /** @function */
89
+ export declare const trLedger: ({ ledgerManager, account, keyPath, change, index }: {
90
+ ledgerManager: LedgerManager;
91
+ account: number;
92
+ keyPath?: string;
93
+ change?: number | undefined;
94
+ index?: number | undefined | "*";
95
+ }) => Promise<string>;