@bitcoinerlab/descriptors 3.0.5 → 3.0.6

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.
@@ -1,10 +1,10 @@
1
- import type * as Bip341 from 'bitcoinjs-lib/src/cjs/payments/bip341';
2
- import type * as Bip371 from 'bitcoinjs-lib/src/cjs/psbt/bip371';
3
- import type * as PsbtUtils from 'bitcoinjs-lib/src/cjs/psbt/psbtutils';
4
- export declare const findScriptPath: typeof Bip341.findScriptPath;
5
- export declare const tapleafHash: typeof Bip341.tapleafHash;
6
- export declare const tapTweakHash: typeof Bip341.tapTweakHash;
7
- export declare const toHashTree: typeof Bip341.toHashTree;
8
- export declare const tweakKey: typeof Bip341.tweakKey;
9
- export declare const witnessStackToScriptWitness: typeof PsbtUtils.witnessStackToScriptWitness;
10
- export declare const isTaprootInput: typeof Bip371.isTaprootInput;
1
+ import type { PsbtInput } from 'bip174';
2
+ type Tapleaf = {
3
+ output: Uint8Array;
4
+ version?: number;
5
+ };
6
+ export declare function tapleafHash(leaf: Tapleaf): Uint8Array;
7
+ export declare function tapTweakHash(pubKey: Uint8Array, h?: Uint8Array): Uint8Array;
8
+ export declare function witnessStackToScriptWitness(witness: Uint8Array[]): Uint8Array;
9
+ export declare function isTaprootInput(input: PsbtInput | undefined): boolean;
10
+ export {};
@@ -1,50 +1,60 @@
1
1
  "use strict";
2
- /* eslint-disable @typescript-eslint/no-require-imports */
3
2
  /*
4
- * bitcoinjs-lib v7 does not export all the taproot/psbt helpers we need from
5
- * its top-level API, so this module centralizes only the required deep imports.
3
+ * Reimplements a small subset of bitcoinjs-lib internal helpers.
4
+ * Keep this module free of deep imports (for example `bitcoinjs-lib/src/*`)
5
+ * so it works consistently across Node.js, browser bundlers (including
6
+ * CodeSandbox), and React Native/Metro.
6
7
  */
7
8
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.isTaprootInput = exports.witnessStackToScriptWitness = exports.tweakKey = exports.toHashTree = exports.tapTweakHash = exports.tapleafHash = exports.findScriptPath = void 0;
9
- function resolveAbsoluteCjsPath(relativePath) {
10
- try {
11
- const entryPoint = require.resolve('bitcoinjs-lib');
12
- const root = entryPoint.replace(/src[\\/]+cjs[\\/]+index\.cjs$/, '');
13
- if (root === entryPoint)
14
- return undefined;
15
- return `${root}src/cjs/${relativePath}.cjs`;
16
- }
17
- catch (_err) {
18
- void _err;
19
- return undefined;
20
- }
9
+ exports.tapleafHash = tapleafHash;
10
+ exports.tapTweakHash = tapTweakHash;
11
+ exports.witnessStackToScriptWitness = witnessStackToScriptWitness;
12
+ exports.isTaprootInput = isTaprootInput;
13
+ const bitcoinjs_lib_1 = require("bitcoinjs-lib");
14
+ const varuint_bitcoin_1 = require("varuint-bitcoin");
15
+ const uint8array_tools_1 = require("uint8array-tools");
16
+ const TAPROOT_LEAF_VERSION_TAPSCRIPT = 0xc0;
17
+ const OP_1 = 0x51;
18
+ const PUSH_DATA_32 = 0x20;
19
+ function serializeScript(script) {
20
+ const { buffer: encodedLength } = (0, varuint_bitcoin_1.encode)(script.length);
21
+ return (0, uint8array_tools_1.concat)([encodedLength, script]);
21
22
  }
22
- function requireBitcoinJsInternal(relativePath) {
23
- const candidatePaths = [
24
- `bitcoinjs-lib/src/${relativePath}`,
25
- `bitcoinjs-lib/src/cjs/${relativePath}.cjs`
26
- ];
27
- const absoluteCjsPath = resolveAbsoluteCjsPath(relativePath);
28
- if (absoluteCjsPath)
29
- candidatePaths.push(absoluteCjsPath);
30
- let lastError;
31
- for (const modulePath of candidatePaths) {
32
- try {
33
- return require(modulePath);
34
- }
35
- catch (err) {
36
- lastError = err;
37
- }
38
- }
39
- throw lastError;
23
+ function isP2TRScript(script) {
24
+ return (script instanceof Uint8Array &&
25
+ script.length === 34 &&
26
+ script[0] === OP_1 &&
27
+ script[1] === PUSH_DATA_32);
28
+ }
29
+ function tapleafHash(leaf) {
30
+ const version = leaf.version || TAPROOT_LEAF_VERSION_TAPSCRIPT;
31
+ return bitcoinjs_lib_1.crypto.taggedHash('TapLeaf', (0, uint8array_tools_1.concat)([Uint8Array.from([version]), serializeScript(leaf.output)]));
32
+ }
33
+ function tapTweakHash(pubKey, h) {
34
+ return bitcoinjs_lib_1.crypto.taggedHash('TapTweak', (0, uint8array_tools_1.concat)(h ? [pubKey, h] : [pubKey]));
35
+ }
36
+ function witnessStackToScriptWitness(witness) {
37
+ let buffer = new Uint8Array(0);
38
+ const writeSlice = (slice) => {
39
+ buffer = (0, uint8array_tools_1.concat)([buffer, slice]);
40
+ };
41
+ const writeVarInt = (value) => {
42
+ const { buffer: encoded } = (0, varuint_bitcoin_1.encode)(value);
43
+ writeSlice(encoded);
44
+ };
45
+ const writeVarSlice = (slice) => {
46
+ writeVarInt(slice.length);
47
+ writeSlice(slice);
48
+ };
49
+ writeVarInt(witness.length);
50
+ witness.forEach(writeVarSlice);
51
+ return buffer;
52
+ }
53
+ function isTaprootInput(input) {
54
+ return (!!input &&
55
+ !!(input.tapInternalKey ||
56
+ input.tapMerkleRoot ||
57
+ (input.tapLeafScript && input.tapLeafScript.length > 0) ||
58
+ (input.tapBip32Derivation && input.tapBip32Derivation.length > 0) ||
59
+ isP2TRScript(input.witnessUtxo?.script)));
40
60
  }
41
- const bip341 = requireBitcoinJsInternal('payments/bip341');
42
- const bip371 = requireBitcoinJsInternal('psbt/bip371');
43
- const psbtUtils = requireBitcoinJsInternal('psbt/psbtutils');
44
- exports.findScriptPath = bip341.findScriptPath;
45
- exports.tapleafHash = bip341.tapleafHash;
46
- exports.tapTweakHash = bip341.tapTweakHash;
47
- exports.toHashTree = bip341.toHashTree;
48
- exports.tweakKey = bip341.tweakKey;
49
- exports.witnessStackToScriptWitness = psbtUtils.witnessStackToScriptWitness;
50
- exports.isTaprootInput = bip371.isTaprootInput;
@@ -49,7 +49,7 @@ export declare function parseKeyExpression({ keyExpression, isSegwit, isTaproot,
49
49
  *
50
50
  * For detailed understanding and examples of terms like `originPath`,
51
51
  * `change`, and `keyPath`, refer to the documentation of
52
- * {@link _Internal_.KeyExpressionParser | KeyExpressionParser}, which consists
52
+ * {@link KeyExpressionParser}, which consists
53
53
  * of the reverse procedure.
54
54
  *
55
55
  * @returns {string} - The formed key expression for the Ledger device.
@@ -65,9 +65,9 @@ export declare function keyExpressionLedger({ ledgerManager, originPath, keyPath
65
65
  * Constructs a key expression string from its constituent components.
66
66
  *
67
67
  * This function essentially performs the reverse operation of
68
- * {@link _Internal_.KeyExpressionParser | KeyExpressionParser}. For detailed
68
+ * {@link KeyExpressionParser}. For detailed
69
69
  * explanations and examples of the terms used here, refer to
70
- * {@link _Internal_.KeyExpressionParser | KeyExpressionParser}.
70
+ * {@link KeyExpressionParser}.
71
71
  */
72
72
  export declare function keyExpressionBIP32({ masterNode, originPath, keyPath, change, index, isPublic }: {
73
73
  masterNode: BIP32Interface;
@@ -211,7 +211,6 @@ function assertChangeIndexKeyPath({ change, index, keyPath }) {
211
211
  if ((change !== undefined) === (keyPath !== undefined))
212
212
  throw new Error(`Error: Pass either change and index or a keyPath`);
213
213
  }
214
- /** @hidden */
215
214
  async function keyExpressionLedger({ ledgerManager, originPath, keyPath, change, index }) {
216
215
  assertChangeIndexKeyPath({ change, index, keyPath });
217
216
  const masterFingerprint = await (0, ledger_1.getLedgerMasterFingerPrint)({
@@ -229,9 +228,9 @@ async function keyExpressionLedger({ ledgerManager, originPath, keyPath, change,
229
228
  * Constructs a key expression string from its constituent components.
230
229
  *
231
230
  * This function essentially performs the reverse operation of
232
- * {@link _Internal_.KeyExpressionParser | KeyExpressionParser}. For detailed
231
+ * {@link KeyExpressionParser}. For detailed
233
232
  * explanations and examples of the terms used here, refer to
234
- * {@link _Internal_.KeyExpressionParser | KeyExpressionParser}.
233
+ * {@link KeyExpressionParser}.
235
234
  */
236
235
  function keyExpressionBIP32({ masterNode, originPath, keyPath, change, index, isPublic = true }) {
237
236
  assertChangeIndexKeyPath({ change, index, keyPath });
@@ -0,0 +1,17 @@
1
+ export declare const MAX_STACK_SIZE = 1000;
2
+ export declare const MAX_SCRIPT_ELEMENT_SIZE = 520;
3
+ export declare function assertConsensusStackResourceLimits({ stackItems, stackLabel, stackItemLabel }: {
4
+ stackItems: Uint8Array[];
5
+ stackLabel?: string;
6
+ stackItemLabel?: string;
7
+ }): void;
8
+ export declare function assertStandardPolicyStackItemCountLimit({ stackItems, maxStackItems, stackLabel }: {
9
+ stackItems: Uint8Array[];
10
+ maxStackItems: number;
11
+ stackLabel: string;
12
+ }): void;
13
+ export declare function assertStandardPolicyStackItemSizeLimit({ stackItems, maxStackItemSize, stackItemLabel }: {
14
+ stackItems: Uint8Array[];
15
+ maxStackItemSize: number;
16
+ stackItemLabel: string;
17
+ }): void;
@@ -0,0 +1,35 @@
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_SCRIPT_ELEMENT_SIZE = exports.MAX_STACK_SIZE = void 0;
6
+ exports.assertConsensusStackResourceLimits = assertConsensusStackResourceLimits;
7
+ exports.assertStandardPolicyStackItemCountLimit = assertStandardPolicyStackItemCountLimit;
8
+ exports.assertStandardPolicyStackItemSizeLimit = assertStandardPolicyStackItemSizeLimit;
9
+ // See Sipa's Miniscript "Resource limitations":
10
+ // https://bitcoin.sipa.be/miniscript/
11
+ // and Bitcoin Core policy/consensus constants.
12
+ // Consensus: max number of elements in initial stack (and stack+altstack after
13
+ // each opcode execution).
14
+ exports.MAX_STACK_SIZE = 1000;
15
+ // Consensus: max size for any pushed stack element. This is an element limit,
16
+ // not a full script-size limit.
17
+ exports.MAX_SCRIPT_ELEMENT_SIZE = 520;
18
+ function assertConsensusStackResourceLimits({ stackItems, stackLabel = 'stack', stackItemLabel = 'stack item' }) {
19
+ if (stackItems.length > exports.MAX_STACK_SIZE)
20
+ throw new Error(`Error: ${stackLabel} has too many items, ${stackItems.length} is larger than ${exports.MAX_STACK_SIZE}`);
21
+ for (const stackItem of stackItems) {
22
+ if (stackItem.length > exports.MAX_SCRIPT_ELEMENT_SIZE)
23
+ throw new Error(`Error: ${stackItemLabel} is too large, ${stackItem.length} bytes is larger than ${exports.MAX_SCRIPT_ELEMENT_SIZE} bytes`);
24
+ }
25
+ }
26
+ function assertStandardPolicyStackItemCountLimit({ stackItems, maxStackItems, stackLabel }) {
27
+ if (stackItems.length > maxStackItems)
28
+ throw new Error(`Error: ${stackLabel} has too many items, ${stackItems.length} is larger than ${maxStackItems}`);
29
+ }
30
+ function assertStandardPolicyStackItemSizeLimit({ stackItems, maxStackItemSize, stackItemLabel }) {
31
+ for (const stackItem of stackItems) {
32
+ if (stackItem.length > maxStackItemSize)
33
+ throw new Error(`Error: ${stackItemLabel} exceeds standard policy, ${stackItem.length} bytes is larger than ${maxStackItemSize} bytes`);
34
+ }
35
+ }
@@ -2,9 +2,13 @@ import { Network } from 'bitcoinjs-lib';
2
2
  import type { BIP32API } from 'bip32';
3
3
  import type { ECPairAPI } from 'ecpair';
4
4
  import type { PartialSig, TapBip32Derivation } from 'bip174';
5
- import type { Taptree } from 'bitcoinjs-lib/src/cjs/types';
6
5
  import type { ExpansionMap, KeyInfo, Preimage, TimeConstraints } from './types';
7
6
  import type { TapLeafInfo, TapTreeInfoNode, TapTreeNode } from './tapTree';
7
+ type BitcoinJsTapleaf = {
8
+ output: Uint8Array;
9
+ version?: number;
10
+ };
11
+ type Taptree = [Taptree | BitcoinJsTapleaf, Taptree | BitcoinJsTapleaf] | BitcoinJsTapleaf;
8
12
  export type TapLeafExpansionOverride = {
9
13
  expandedExpression: string;
10
14
  expansionMap: ExpansionMap;
@@ -102,7 +106,7 @@ export declare function tapTreeInfoToScriptTree(tapTreeInfo: TapTreeInfoNode): T
102
106
  * - Leaves are returned in deterministic left-first order.
103
107
  * - One metadata entry is returned per leaf.
104
108
  * - `controlBlock.length === 33 + 32 * depth`.
105
- * - Throws if internal key is invalid or merkle path cannot be found.
109
+ * - Throws if internal key is invalid or control block cannot be derived.
106
110
  *
107
111
  * Typical usage:
108
112
  * - Convert this metadata into PSBT `tapLeafScript[]` entries
@@ -213,3 +217,4 @@ export declare function satisfyTapTree({ tapTreeInfo, signatures, preimages, tap
213
217
  tapLeaf?: Uint8Array | string;
214
218
  timeConstraints?: TimeConstraints;
215
219
  }): TaprootLeafSatisfaction;
220
+ export {};
@@ -19,6 +19,7 @@ const miniscript_1 = require("./miniscript");
19
19
  const tapTree_1 = require("./tapTree");
20
20
  const resourceLimits_1 = require("./resourceLimits");
21
21
  const TAPROOT_LEAF_VERSION_TAPSCRIPT = 0xc0;
22
+ const { p2tr } = bitcoinjs_lib_1.payments;
22
23
  function expandTaprootMiniscript({ miniscript, network = bitcoinjs_lib_1.networks.bitcoin, BIP32, ECPair }) {
23
24
  return (0, miniscript_1.expandMiniscript)({
24
25
  miniscript,
@@ -173,7 +174,7 @@ function tapTreeInfoToScriptTree(tapTreeInfo) {
173
174
  * - Leaves are returned in deterministic left-first order.
174
175
  * - One metadata entry is returned per leaf.
175
176
  * - `controlBlock.length === 33 + 32 * depth`.
176
- * - Throws if internal key is invalid or merkle path cannot be found.
177
+ * - Throws if internal key is invalid or control block cannot be derived.
177
178
  *
178
179
  * Typical usage:
179
180
  * - Convert this metadata into PSBT `tapLeafScript[]` entries
@@ -182,10 +183,6 @@ function tapTreeInfoToScriptTree(tapTreeInfo) {
182
183
  function buildTaprootLeafPsbtMetadata({ tapTreeInfo, internalPubkey }) {
183
184
  const normalizedInternalPubkey = normalizeTaprootPubkey(internalPubkey);
184
185
  const scriptTree = tapTreeInfoToScriptTree(tapTreeInfo);
185
- const hashTree = (0, bitcoinjs_lib_internals_1.toHashTree)(scriptTree);
186
- const tweaked = (0, bitcoinjs_lib_internals_1.tweakKey)(normalizedInternalPubkey, hashTree.hash);
187
- if (!tweaked)
188
- throw new Error(`Error: invalid taproot internal pubkey`);
189
186
  return (0, tapTree_1.collectTapTreeLeaves)(tapTreeInfo).map(({ leaf, depth }) => {
190
187
  if (depth > tapTree_1.MAX_TAPTREE_DEPTH)
191
188
  throw new Error(`Error: taproot tree depth is too large, ${depth} is larger than ${tapTree_1.MAX_TAPTREE_DEPTH}`);
@@ -193,19 +190,17 @@ function buildTaprootLeafPsbtMetadata({ tapTreeInfo, internalPubkey }) {
193
190
  output: leaf.tapScript,
194
191
  version: leaf.version
195
192
  });
196
- const merklePath = (0, bitcoinjs_lib_internals_1.findScriptPath)(hashTree, tapLeafHash);
197
- if (!merklePath)
193
+ const payment = p2tr({
194
+ internalPubkey: normalizedInternalPubkey,
195
+ scriptTree,
196
+ redeem: {
197
+ output: leaf.tapScript,
198
+ redeemVersion: leaf.version
199
+ }
200
+ });
201
+ const controlBlock = payment.witness?.[1];
202
+ if (!controlBlock)
198
203
  throw new Error(`Error: could not build controlBlock for taproot leaf ${leaf.expression}`);
199
- // controlBlock[0] packs:
200
- // - leaf version (high bits), and
201
- // - parity of the tweaked output key Q = P + t*G (low bit).
202
- // `normalizedInternalPubkey` is x-only P, so parity is not encoded there.
203
- // BIP341 requires carrying Q parity in controlBlock[0].
204
- const controlBlock = (0, uint8array_tools_1.concat)([
205
- Uint8Array.from([leaf.version | tweaked.parity]),
206
- normalizedInternalPubkey,
207
- ...merklePath
208
- ]);
209
204
  return { leaf, depth, tapLeafHash, controlBlock };
210
205
  });
211
206
  }
package/dist/tapTree.js CHANGED
@@ -5,7 +5,6 @@ exports.assertTapTreeDepth = assertTapTreeDepth;
5
5
  exports.collectTapTreeLeaves = collectTapTreeLeaves;
6
6
  exports.selectTapLeafCandidates = selectTapLeafCandidates;
7
7
  exports.parseTapTreeExpression = parseTapTreeExpression;
8
- // NOTE: This uses an internal bitcoinjs-lib module. Consider adding a local wrapper.
9
8
  const bitcoinjs_lib_internals_1 = require("./bitcoinjs-lib-internals");
10
9
  const uint8array_tools_1 = require("uint8array-tools");
11
10
  const parseUtils_1 = require("./parseUtils");
package/dist/types.d.ts CHANGED
@@ -4,7 +4,7 @@ import type { Payment, Network } from 'bitcoinjs-lib';
4
4
  import type { TapTreeNode, TapTreeInfoNode } from './tapTree';
5
5
  /**
6
6
  * Preimage
7
- * See {@link Output}
7
+ * Preimage material used by descriptor outputs that include hashlocks.
8
8
  */
9
9
  export type Preimage = {
10
10
  /**
@@ -25,7 +25,7 @@ export type TimeConstraints = {
25
25
  nSequence: number | undefined;
26
26
  };
27
27
  /**
28
- * See {@link _Internal_.KeyExpressionParser | KeyExpressionParser}.
28
+ * See {@link KeyExpressionParser}.
29
29
  */
30
30
  export type KeyInfo = {
31
31
  keyExpression: string;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@bitcoinerlab/descriptors",
3
3
  "description": "This library parses and creates Bitcoin Miniscript Descriptors and generates Partially Signed Bitcoin Transactions (PSBTs). It provides PSBT finalizers and signers for single-signature, BIP32 and Hardware Wallets.",
4
4
  "homepage": "https://github.com/bitcoinerlab/descriptors",
5
- "version": "3.0.5",
5
+ "version": "3.0.6",
6
6
  "author": "Jose-Luis Landabaso",
7
7
  "license": "MIT",
8
8
  "repository": {