@bitcoinerlab/descriptors 3.0.5 → 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.
package/dist/tapTree.js DELETED
@@ -1,167 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MAX_TAPTREE_DEPTH = void 0;
4
- exports.assertTapTreeDepth = assertTapTreeDepth;
5
- exports.collectTapTreeLeaves = collectTapTreeLeaves;
6
- exports.selectTapLeafCandidates = selectTapLeafCandidates;
7
- exports.parseTapTreeExpression = parseTapTreeExpression;
8
- // NOTE: This uses an internal bitcoinjs-lib module. Consider adding a local wrapper.
9
- const bitcoinjs_lib_internals_1 = require("./bitcoinjs-lib-internals");
10
- const uint8array_tools_1 = require("uint8array-tools");
11
- const parseUtils_1 = require("./parseUtils");
12
- // See BIP341 control block limits and Sipa's Miniscript "Resource limitations":
13
- // https://bitcoin.sipa.be/miniscript/
14
- // Taproot script path depth is encoded in the control block as 32-byte hashes,
15
- // with consensus max depth 128.
16
- exports.MAX_TAPTREE_DEPTH = 128;
17
- function tapTreeMaxDepth(tapTree, depth = 0) {
18
- if ('expression' in tapTree)
19
- return depth;
20
- return Math.max(tapTreeMaxDepth(tapTree.left, depth + 1), tapTreeMaxDepth(tapTree.right, depth + 1));
21
- }
22
- function assertTapTreeDepth(tapTree) {
23
- const maxDepth = tapTreeMaxDepth(tapTree);
24
- if (maxDepth > exports.MAX_TAPTREE_DEPTH)
25
- throw new Error(`Error: taproot tree depth is too large, ${maxDepth} is larger than ${exports.MAX_TAPTREE_DEPTH}`);
26
- }
27
- /**
28
- * Collects taproot leaf metadata with depth from a tree.
29
- * Traversal is left-first, following the order of `{left,right}` in the
30
- * expression so tie-breaks are deterministic.
31
- *
32
- * Example tree:
33
- * ```
34
- * {pk(A),{pk(B),pk(C)}}
35
- * ```
36
- * Visual shape:
37
- * ```
38
- * root
39
- * / \
40
- * pk(A) branch
41
- * / \
42
- * pk(B) pk(C)
43
- * ```
44
- * Collected leaves with depth:
45
- * ```
46
- * [
47
- * { leaf: pk(A), depth: 1 },
48
- * { leaf: pk(B), depth: 2 },
49
- * { leaf: pk(C), depth: 2 }
50
- * ]
51
- * ```
52
- */
53
- function collectTapTreeLeaves(tapTreeInfo) {
54
- const leaves = [];
55
- const walk = (node, depth) => {
56
- if ('expression' in node) {
57
- leaves.push({ leaf: node, depth });
58
- return;
59
- }
60
- walk(node.left, depth + 1);
61
- walk(node.right, depth + 1);
62
- };
63
- walk(tapTreeInfo, 0);
64
- return leaves;
65
- }
66
- function computeTapLeafHash(leaf) {
67
- return (0, bitcoinjs_lib_internals_1.tapleafHash)({ output: leaf.tapScript, version: leaf.version });
68
- }
69
- function normalizeExpressionForMatch(expression) {
70
- return expression.replace(/\s+/g, '');
71
- }
72
- /**
73
- * Resolves taproot leaf candidates based on an optional selector.
74
- *
75
- * If `tapLeaf` is undefined, all leaves are returned for auto-selection.
76
- * If `tapLeaf` is bytes, it is treated as a tapleaf hash and must match
77
- * exactly one leaf.
78
- * If `tapLeaf` is a string, it is treated as a raw taproot leaf expression
79
- * (not expanded). Matching is whitespace-insensitive. If the expression appears
80
- * more than once, this function throws an error.
81
- *
82
- * Example:
83
- * ```
84
- * const candidates = selectTapLeafCandidates({ tapTreeInfo, tapLeaf });
85
- * // tapLeaf can be undefined, bytes (tapleaf hash) or a leaf expression:
86
- * // f.ex.: 'pk(03bb...)'
87
- * ```
88
- */
89
- function selectTapLeafCandidates({ tapTreeInfo, tapLeaf }) {
90
- const leaves = collectTapTreeLeaves(tapTreeInfo).map(({ leaf, depth }) => ({
91
- leaf,
92
- depth,
93
- tapLeafHash: computeTapLeafHash(leaf)
94
- }));
95
- if (tapLeaf === undefined)
96
- return leaves;
97
- if (tapLeaf instanceof Uint8Array) {
98
- const match = leaves.find(entry => (0, uint8array_tools_1.compare)(entry.tapLeafHash, tapLeaf) === 0);
99
- if (!match)
100
- throw new Error(`Error: tapleaf hash not found in tapTreeInfo`);
101
- return [match];
102
- }
103
- const normalizedSelector = normalizeExpressionForMatch(tapLeaf);
104
- const matches = leaves.filter(entry => normalizeExpressionForMatch(entry.leaf.expression) === normalizedSelector);
105
- if (matches.length === 0)
106
- throw new Error(`Error: taproot leaf expression not found in tapTreeInfo: ${tapLeaf}`);
107
- if (matches.length > 1)
108
- throw new Error(`Error: taproot leaf expression is ambiguous in tapTreeInfo: ${tapLeaf}`);
109
- return matches;
110
- }
111
- function tapTreeError(expression) {
112
- return new Error(`Error: invalid taproot tree expression: ${expression}`);
113
- }
114
- /**
115
- * Splits the inner tree expression of a branch into left/right parts.
116
- * The input must be the contents inside `{}` (no outer braces).
117
- * Example: `pk(@0),{pk(@1),pk(@2)}` => left: `pk(@0)`, right: `{pk(@1),pk(@2)}`.
118
- */
119
- function splitTapTreeExpression(expression) {
120
- const result = (0, parseUtils_1.splitTopLevelComma)({ expression, onError: tapTreeError });
121
- if (!result)
122
- throw tapTreeError(expression);
123
- return result;
124
- }
125
- /**
126
- * Parses a single taproot tree node expression.
127
- *
128
- * Note: the field name is intentionally generic (`expression`) because taproot
129
- * leaves can contain either miniscript fragments (e.g. `pk(...)`) or
130
- * descriptor-level script expressions (e.g. `sortedmulti_a(...)`).
131
- * Examples:
132
- * - `pk(@0)` => { expression: 'pk(@0)' }
133
- * - `{pk(@0),pk(@1)}` => { left: { expression: 'pk(@0)' }, right: { expression: 'pk(@1)' } }
134
- * - `{pk(@0),{pk(@1),pk(@2)}}` =>
135
- * {
136
- * left: { expression: 'pk(@0)' },
137
- * right: { left: { expression: 'pk(@1)' }, right: { expression: 'pk(@2)' } }
138
- * }
139
- */
140
- function parseTapTreeNode(expression) {
141
- const trimmedExpression = expression.trim();
142
- if (!trimmedExpression)
143
- throw tapTreeError(expression);
144
- if (trimmedExpression.startsWith('{')) {
145
- if (!trimmedExpression.endsWith('}'))
146
- throw tapTreeError(expression);
147
- const inner = trimmedExpression.slice(1, -1).trim();
148
- if (!inner)
149
- throw tapTreeError(expression);
150
- const { left, right } = splitTapTreeExpression(inner);
151
- return {
152
- left: parseTapTreeNode(left),
153
- right: parseTapTreeNode(right)
154
- };
155
- }
156
- if (trimmedExpression.includes('{') || trimmedExpression.includes('}'))
157
- throw tapTreeError(expression);
158
- return { expression: trimmedExpression };
159
- }
160
- function parseTapTreeExpression(expression) {
161
- const trimmed = expression.trim();
162
- if (!trimmed)
163
- throw tapTreeError(expression);
164
- const tapTree = parseTapTreeNode(trimmed);
165
- assertTapTreeDepth(tapTree);
166
- return tapTree;
167
- }
package/dist/types.d.ts DELETED
@@ -1,238 +0,0 @@
1
- import type { ECPairInterface } from 'ecpair';
2
- import type { BIP32Interface } from 'bip32';
3
- import type { Payment, Network } from 'bitcoinjs-lib';
4
- import type { TapTreeNode, TapTreeInfoNode } from './tapTree';
5
- /**
6
- * Preimage
7
- * See {@link Output}
8
- */
9
- export type Preimage = {
10
- /**
11
- * Use same string expressions as in miniscript. For example: "sha256(cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204)" or "ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e)"
12
- *
13
- * Accepted functions: sha256, hash256, ripemd160, hash160
14
- *
15
- * Digests must be: 64-character HEX for sha256, hash160 or 30-character HEX for ripemd160 or hash160.
16
- */
17
- digest: string;
18
- /**
19
- * Hex encoded preimage. Preimages are always 32 bytes (so, 64 character in hex).
20
- */
21
- preimage: string;
22
- };
23
- export type TimeConstraints = {
24
- nLockTime: number | undefined;
25
- nSequence: number | undefined;
26
- };
27
- /**
28
- * See {@link _Internal_.KeyExpressionParser | KeyExpressionParser}.
29
- */
30
- export type KeyInfo = {
31
- keyExpression: string;
32
- pubkey?: Uint8Array;
33
- ecpair?: ECPairInterface;
34
- bip32?: BIP32Interface;
35
- masterFingerprint?: Uint8Array;
36
- originPath?: string;
37
- keyPath?: string;
38
- path?: string;
39
- };
40
- /**
41
- * An `ExpansionMap` contains destructured information of a descritptor expression.
42
- *
43
- * For example, this descriptor `sh(wsh(andor(pk(0252972572d465d016d4c501887b8df303eee3ed602c056b1eb09260dfa0da0ab2),older(8640),pk([d34db33f/49'/0'/0']tpubDCdxmvzJ5QBjTN8oCjjyT2V58AyZvA1fkmCeZRC75QMoaHcVP2m45Bv3hmnR7ttAwkb2UNYyoXdHVt4gwBqRrJqLUU2JrM43HippxiWpHra/1/2/3/4/*))))` has the following
44
- * `expandedExpression`: `sh(wsh(andor(pk(@0),older(8640),pk(@1))))`
45
- *
46
- * `key`'s are set using this format: `@i`, where `i` is an integer starting from `0` assigned by parsing and retrieving keys from the descriptor from left to right.
47
- *
48
- * For the given example, the `ExpansionMap` is:
49
- *
50
- * ```javascript
51
- * {
52
- * '@0': {
53
- * keyExpression:
54
- * '0252972572d465d016d4c501887b8df303eee3ed602c056b1eb09260dfa0da0ab2'
55
- * },
56
- * '@1': {
57
- * keyExpression:
58
- * "[d34db33f/49'/0'/0']tpubDCdxmvzJ5QBjTN8oCjjyT2V58AyZvA1fkmCeZRC75QMoaHcVP2m45Bv3hmnR7ttAwkb2UNYyoXdHVt4gwBqRrJqLUU2JrM43HippxiWpHra/1/2/3/4/*",
59
- * keyPath: '/1/2/3/4/*',
60
- * originPath: "/49'/0'/0'",
61
- * path: "m/49'/0'/0'/1/2/3/4/*",
62
- * // Other relevant properties of the type `KeyInfo`: `pubkey`, `ecpair` & `bip32` interfaces, `masterFingerprint`, etc.
63
- * }
64
- * }
65
- *```
66
- *
67
- *
68
- */
69
- export type ExpansionMap = {
70
- [key: string]: KeyInfo;
71
- };
72
- /** @ignore */
73
- interface XOnlyPointAddTweakResult {
74
- parity: 1 | 0;
75
- xOnlyPubkey: Uint8Array;
76
- }
77
- /** @ignore */
78
- export interface TinySecp256k1Interface {
79
- isPoint(p: Uint8Array): boolean;
80
- pointCompress(p: Uint8Array, compressed?: boolean): Uint8Array;
81
- isPrivate(d: Uint8Array): boolean;
82
- pointFromScalar(d: Uint8Array, compressed?: boolean): Uint8Array | null;
83
- pointAddScalar(p: Uint8Array, tweak: Uint8Array, compressed?: boolean): Uint8Array | null;
84
- privateAdd(d: Uint8Array, tweak: Uint8Array): Uint8Array | null;
85
- sign(h: Uint8Array, d: Uint8Array, e?: Uint8Array): Uint8Array;
86
- signSchnorr?(h: Uint8Array, d: Uint8Array, e?: Uint8Array): Uint8Array;
87
- verify(h: Uint8Array, Q: Uint8Array, signature: Uint8Array, strict?: boolean): boolean;
88
- verifySchnorr?(h: Uint8Array, Q: Uint8Array, signature: Uint8Array): boolean;
89
- xOnlyPointAddTweak(p: Uint8Array, tweak: Uint8Array): XOnlyPointAddTweakResult | null;
90
- isXOnlyPoint(p: Uint8Array): boolean;
91
- privateNegate(d: Uint8Array): Uint8Array;
92
- }
93
- /**
94
- * `DescriptorsFactory` creates and returns the {@link DescriptorsFactory | `expand()`}
95
- * function that parses a descriptor expression and destructures it
96
- * into its elemental parts. `Expansion` is the type that `expand()` returns.
97
- */
98
- export type Expansion = {
99
- /**
100
- * The corresponding [bitcoinjs-lib Payment](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/payments/index.ts) for the provided expression, if applicable.
101
- */
102
- payment?: Payment;
103
- /**
104
- * The expanded descriptor expression.
105
- * See {@link ExpansionMap ExpansionMap} for a detailed explanation.
106
- */
107
- expandedExpression?: string;
108
- /**
109
- * The extracted miniscript from the expression, if any.
110
- */
111
- miniscript?: string;
112
- /**
113
- * A map of key expressions in the descriptor to their corresponding expanded keys.
114
- * See {@link ExpansionMap ExpansionMap} for a detailed explanation.
115
- */
116
- expansionMap?: ExpansionMap;
117
- /**
118
- * A boolean indicating whether the descriptor uses SegWit.
119
- */
120
- isSegwit?: boolean;
121
- /**
122
- * A boolean indicating whether the descriptor uses Taproot.
123
- */
124
- isTaproot?: boolean;
125
- /**
126
- * The expanded miniscript, if any.
127
- * It corresponds to the `expandedExpression` without the top-level script
128
- * expression.
129
- */
130
- expandedMiniscript?: string;
131
- /**
132
- * The taproot tree expression, if any. Only defined for `tr(KEY, TREE)`.
133
- * Example: `{pk(02aa...),{pk(03bb...),pk(02cc...)}}`.
134
- */
135
- tapTreeExpression?: string;
136
- /**
137
- * The parsed taproot tree, if any. Only defined for `tr(KEY, TREE)`.
138
- * Example:
139
- * ```
140
- * {
141
- * left: { expression: 'pk(02aa...)' },
142
- * right: {
143
- * left: { expression: 'pk(03bb...)' },
144
- * right: { expression: 'pk(02cc...)' }
145
- * }
146
- * }
147
- * ```
148
- */
149
- tapTree?: TapTreeNode;
150
- /**
151
- * The compiled taproot tree metadata, if any. Only defined for `tr(KEY, TREE)`.
152
- * Same as tapTree, but each leaf includes:
153
- * - `expandedExpression`: descriptor-level expanded leaf expression
154
- * - optional `expandedMiniscript`: miniscript-expanded leaf (when applicable)
155
- * - key expansion map
156
- * - compiled tapscript (`tapScript`)
157
- * - leaf version.
158
- *
159
- * Note: `@i` placeholders are scoped per leaf, since each leaf is expanded
160
- * and satisfied independently.
161
- *
162
- * Example:
163
- * ```
164
- * {
165
- * left: {
166
- * expression: 'pk(02aa...)',
167
- * expandedExpression: 'pk(@0)',
168
- * expandedMiniscript: 'pk(@0)',
169
- * expansionMap: ExpansionMap;
170
- * tapScript: Uint8Array;
171
- * version: number;
172
- * },
173
- * right: ....
174
- */
175
- tapTreeInfo?: TapTreeInfoNode;
176
- /**
177
- * The redeem script for the descriptor, if applicable.
178
- */
179
- redeemScript?: Uint8Array;
180
- /**
181
- * The witness script for the descriptor, if applicable.
182
- */
183
- witnessScript?: Uint8Array;
184
- /**
185
- * Whether the descriptor is a ranged-descriptor.
186
- */
187
- isRanged: boolean;
188
- /**
189
- * This is the preferred or authoritative representation of an output
190
- * descriptor expression.
191
- * It removes the checksum and, if it is a ranged-descriptor, it
192
- * particularizes it to its index.
193
- */
194
- canonicalExpression: string;
195
- };
196
- /**
197
- * The {@link DescriptorsFactory | `DescriptorsFactory`} function creates and
198
- * returns the `parseKeyExpression` function, which is an implementation of this
199
- * interface.
200
- *
201
- * It parses and destructures a key expression string (xpub, xprv, pubkey or
202
- * wif) into {@link KeyInfo | `KeyInfo`}.
203
- *
204
- * For example, given this `keyExpression`: `[d34db33f/49'/0'/0']tpubDCdxmvzJ5QBjTN8oCjjyT2V58AyZvA1fkmCeZRC75QMoaHcVP2m45Bv3hmnR7ttAwkb2UNYyoXdHVt4gwBqRrJqLUU2JrM43HippxiWpHra/1/2/3/4/*`, this is the parsed result:
205
- *
206
- * ```javascript
207
- * {
208
- * keyExpression:
209
- * "[d34db33f/49'/0'/0']tpubDCdxmvzJ5QBjTN8oCjjyT2V58AyZvA1fkmCeZRC75QMoaHcVP2m45Bv3hmnR7ttAwkb2UNYyoXdHVt4gwBqRrJqLUU2JrM43HippxiWpHra/1/2/3/4/*",
210
- * keyPath: '/1/2/3/4/*',
211
- * originPath: "/49'/0'/0'",
212
- * path: "m/49'/0'/0'/1/2/3/4/*",
213
- * // Other relevant properties of the type `KeyInfo`: `pubkey`, `ecpair` & `bip32` interfaces, `masterFingerprint`, etc.
214
- * }
215
- * ```
216
- *
217
- * See {@link KeyInfo} for the complete list of elements retrieved by this function.
218
- */
219
- export interface KeyExpressionParser {
220
- (params: {
221
- keyExpression: string;
222
- /**
223
- * Indicates if this key expression belongs to a a SegWit output. When set,
224
- * further checks are done to ensure the public key (if present in the
225
- * expression) is compressed (33 bytes).
226
- */
227
- isSegwit?: boolean;
228
- /**
229
- * Indicates if this key expression belongs to a Taproot output.
230
- * For Taproot, the key must be represented as an x-only public key
231
- * (32 bytes). If a 33-byte compressed pubkey is derived, it is converted to
232
- * its x-only representation.
233
- */
234
- isTaproot?: boolean;
235
- network?: Network;
236
- }): KeyInfo;
237
- }
238
- export {};
package/dist/types.js DELETED
@@ -1,4 +0,0 @@
1
- "use strict";
2
- // Copyright (c) 2023 Jose-Luis Landabaso - https://bitcoinerlab.com
3
- // Distributed under the MIT software license
4
- Object.defineProperty(exports, "__esModule", { value: true });