@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
@@ -0,0 +1,23 @@
1
+ export type { Expansion, ExpansionMap, KeyExpressionParser, KeyInfo, Preimage, TimeConstraints } from './types';
2
+ export type { TreeNode, TapTreeNode, TapTreeInfoNode, TapLeaf, TapLeafInfo } from './tapTree';
3
+ export { networks, type Network } from './networks';
4
+ export { DescriptorsFactory, OutputInstance, OutputConstructor } from './descriptors';
5
+ export { DescriptorChecksum as checksum } from './checksum';
6
+ import * as signers from './signers';
7
+ export { signers };
8
+ export { keyExpressionBIP32, keyExpressionLedger } from './keyExpressions';
9
+ import * as scriptExpressions from './scriptExpressions';
10
+ export { scriptExpressions };
11
+ import { LedgerState, getLedgerMasterFingerPrint, getLedgerXpub, registerLedgerWallet, assertLedgerApp, LedgerManager } from './ledger';
12
+ /** @namespace */
13
+ export declare const ledger: {
14
+ /** @function */
15
+ getLedgerMasterFingerPrint: typeof getLedgerMasterFingerPrint;
16
+ /** @function */
17
+ getLedgerXpub: typeof getLedgerXpub;
18
+ /** @function */
19
+ registerLedgerWallet: typeof registerLedgerWallet;
20
+ /** @function */
21
+ assertLedgerApp: typeof assertLedgerApp;
22
+ };
23
+ export type { LedgerState, LedgerManager };
package/dist/index.js ADDED
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ // Copyright (c) 2023 Jose-Luis Landabaso - https://bitcoinerlab.com
3
+ // Distributed under the MIT software license
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
17
+ }) : function(o, v) {
18
+ o["default"] = v;
19
+ });
20
+ var __importStar = (this && this.__importStar) || (function () {
21
+ var ownKeys = function(o) {
22
+ ownKeys = Object.getOwnPropertyNames || function (o) {
23
+ var ar = [];
24
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
25
+ return ar;
26
+ };
27
+ return ownKeys(o);
28
+ };
29
+ return function (mod) {
30
+ if (mod && mod.__esModule) return mod;
31
+ var result = {};
32
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
33
+ __setModuleDefault(result, mod);
34
+ return result;
35
+ };
36
+ })();
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.ledger = exports.scriptExpressions = exports.keyExpressionLedger = exports.keyExpressionBIP32 = exports.signers = exports.checksum = exports.DescriptorsFactory = exports.networks = void 0;
39
+ // Some dependencies (like hash-base) assume process.version exists.
40
+ // In React Native / Hermes, process is defined but version is not.
41
+ // Note: we only polyfill if process already exists but is incomplete.
42
+ // The user is responsible for providing the process polyfill; this is just
43
+ // a small patch for environments (like Hermes) with partial implementations.
44
+ //
45
+ // More information: https://github.com/browserify/hash-base/issues/21#issuecomment-3476608003
46
+ const g = typeof globalThis !== 'undefined'
47
+ ? globalThis
48
+ : typeof global !== 'undefined'
49
+ ? global
50
+ : {};
51
+ if (typeof g.process !== 'undefined' &&
52
+ typeof g.process.version === 'undefined') {
53
+ const isDev = g['__DEV__'] === true ||
54
+ g.process?.env?.['NODE_ENV'] === 'development';
55
+ if (isDev) {
56
+ //only WARN while developing
57
+ console.warn(`[bitcoinerlab/descriptors] Polyfilled process.version (missing in this non-Node environment).
58
+ Learn more: https://github.com/bitcoinerlab/descriptors/blob/main/src/index.ts#L4`);
59
+ }
60
+ // @ts-expect-error Polyfill for environments missing process.version
61
+ global.process.version = '';
62
+ }
63
+ var networks_1 = require("./networks");
64
+ Object.defineProperty(exports, "networks", { enumerable: true, get: function () { return networks_1.networks; } });
65
+ var descriptors_1 = require("./descriptors");
66
+ Object.defineProperty(exports, "DescriptorsFactory", { enumerable: true, get: function () { return descriptors_1.DescriptorsFactory; } });
67
+ var checksum_1 = require("./checksum");
68
+ Object.defineProperty(exports, "checksum", { enumerable: true, get: function () { return checksum_1.DescriptorChecksum; } });
69
+ const signers = __importStar(require("./signers"));
70
+ exports.signers = signers;
71
+ var keyExpressions_1 = require("./keyExpressions");
72
+ Object.defineProperty(exports, "keyExpressionBIP32", { enumerable: true, get: function () { return keyExpressions_1.keyExpressionBIP32; } });
73
+ Object.defineProperty(exports, "keyExpressionLedger", { enumerable: true, get: function () { return keyExpressions_1.keyExpressionLedger; } });
74
+ const scriptExpressions = __importStar(require("./scriptExpressions"));
75
+ exports.scriptExpressions = scriptExpressions;
76
+ const ledger_1 = require("./ledger");
77
+ /** @namespace */
78
+ exports.ledger = {
79
+ /** @function */
80
+ getLedgerMasterFingerPrint: ledger_1.getLedgerMasterFingerPrint,
81
+ /** @function */
82
+ getLedgerXpub: ledger_1.getLedgerXpub,
83
+ /** @function */
84
+ registerLedgerWallet: ledger_1.registerLedgerWallet,
85
+ /** @function */
86
+ assertLedgerApp: ledger_1.assertLedgerApp
87
+ };
@@ -0,0 +1,124 @@
1
+ import type { ECPairAPILike, BIP32APILike, BIP32InterfaceLike, ScureHDKeyLike } from './bitcoinLib';
2
+ import { type Network } from './networks';
3
+ import type { KeyInfo } from './types';
4
+ import { LedgerManager } from './ledger';
5
+ /**
6
+ * Parses a key expression (xpub, xprv, pubkey or wif) into {@link KeyInfo | `KeyInfo`}.
7
+ *
8
+ * For example, given this `keyExpression`: `"[d34db33f/49'/0'/0']tpubDCdxmvzJ5QBjTN8oCjjyT2V58AyZvA1fkmCeZRC75QMoaHcVP2m45Bv3hmnR7ttAwkb2UNYyoXdHVt4gwBqRrJqLUU2JrM43HippxiWpHra/1/2/3/4/*"`, this is its parsed result:
9
+ *
10
+ * ```javascript
11
+ * {
12
+ * keyExpression:
13
+ * "[d34db33f/49'/0'/0']tpubDCdxmvzJ5QBjTN8oCjjyT2V58AyZvA1fkmCeZRC75QMoaHcVP2m45Bv3hmnR7ttAwkb2UNYyoXdHVt4gwBqRrJqLUU2JrM43HippxiWpHra/1/2/3/4/*",
14
+ * keyPath: '/1/2/3/4/*',
15
+ * originPath: "/49'/0'/0'",
16
+ * path: "m/49'/0'/0'/1/2/3/4/*",
17
+ * // Other relevant properties of `KeyInfo`: `pubkey`, `ecpair`, `bip32`,
18
+ * // `privkey`, `xPub`, `xPrv`, `masterFingerprint`, etc.
19
+ * }
20
+ * ```
21
+ */
22
+ export declare function parseKeyExpression({ keyExpression, isSegwit, isTaproot, ECPair, BIP32, network }: {
23
+ keyExpression: string;
24
+ /** @default networks.bitcoin */
25
+ network?: Network;
26
+ /**
27
+ * Indicates if this key expression belongs to a a SegWit output. When set,
28
+ * further checks are done to ensure the public key (if present in the
29
+ * expression) is compressed (33 bytes).
30
+ */
31
+ isSegwit?: boolean;
32
+ /**
33
+ * Indicates if this key expression belongs to a Taproot output. For Taproot,
34
+ * the key must be represented as an x-only public key (32 bytes).
35
+ * If a 33-byte compressed pubkey is derived, it is converted to its x-only
36
+ * representation.
37
+ */
38
+ isTaproot?: boolean;
39
+ ECPair: ECPairAPILike;
40
+ BIP32: BIP32APILike;
41
+ }): KeyInfo;
42
+ /**
43
+ * Constructs a key expression string for a Ledger device from the provided
44
+ * components.
45
+ *
46
+ * This function assists in crafting key expressions tailored for Ledger
47
+ * hardware wallets. It fetches the master fingerprint and xpub for a
48
+ * specified origin path and then combines them with the input parameters.
49
+ *
50
+ * For detailed understanding and examples of terms like `originPath`,
51
+ * `change`, and `keyPath`, refer to the documentation of
52
+ * {@link KeyExpressionParser}, which consists
53
+ * of the reverse procedure.
54
+ *
55
+ * @returns {Promise<string>} - The formed key expression for the Ledger device.
56
+ */
57
+ export declare function keyExpressionLedger({ ledgerManager, originPath, keyPath, change, index }: {
58
+ ledgerManager: LedgerManager;
59
+ originPath: string;
60
+ change?: number | undefined;
61
+ index?: number | undefined | '*';
62
+ keyPath?: string | undefined;
63
+ }): Promise<string>;
64
+ /**
65
+ * Constructs a BIP32 key expression string from its constituent components.
66
+ *
67
+ * This function essentially performs the reverse operation of
68
+ * {@link KeyExpressionParser}. For detailed
69
+ * explanations and examples of the terms used here, refer to
70
+ * {@link KeyExpressionParser}.
71
+ *
72
+ * @param {Object} params - The parameters object.
73
+ * @param {BIP32InterfaceLike | ScureHDKeyLike} params.masterNode - Root HD node.
74
+ * Pass either:
75
+ * - a bitcoinjs {@link https://github.com/bitcoinjs/bip32 | `BIP32`} node, or
76
+ * - a scure {@link https://github.com/paulmillr/scure-bip32 | `HDKey`}.
77
+ * @param {string} params.originPath - Origin path from master, e.g. `"/84'/0'/0'"`.
78
+ * @param {number} [params.change] - Branch index (`0` receive, `1` change).
79
+ * @param {number | '*'} [params.index] - Address index or `*` for ranged descriptors.
80
+ * @param {string} [params.keyPath] - Full suffix path (`/change/index`) alternative to
81
+ * `change` + `index`.
82
+ * @returns {string} Descriptor key expression (e.g. `[f23f9fd2/84'/0'/0']xpub.../0/5`).
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * import * as ecc from '@bitcoinerlab/secp256k1';
87
+ * import { BIP32Factory } from 'bip32';
88
+ * import { keyExpressionBIP32 } from '@bitcoinerlab/descriptors';
89
+ *
90
+ * const BIP32 = BIP32Factory(ecc);
91
+ * const masterNode = BIP32.fromSeed(seedBytes);
92
+ * const keyExp = keyExpressionBIP32({
93
+ * masterNode,
94
+ * originPath: "/84'/0'/0'",
95
+ * change: 0,
96
+ * index: 5
97
+ * });
98
+ * ```
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * import { HDKey } from '@scure/bip32';
103
+ * import { keyExpressionBIP32 } from '@bitcoinerlab/descriptors';
104
+ *
105
+ * const masterNode = HDKey.fromMasterSeed(seedBytes);
106
+ * const keyExp = keyExpressionBIP32({
107
+ * masterNode,
108
+ * originPath: "/84'/0'/0'",
109
+ * keyPath: '/0/*'
110
+ * });
111
+ * ```
112
+ */
113
+ export declare function keyExpressionBIP32({ masterNode, originPath, keyPath, change, index, isPublic }: {
114
+ masterNode: BIP32InterfaceLike | ScureHDKeyLike;
115
+ originPath: string;
116
+ change?: number | undefined;
117
+ index?: number | undefined | '*';
118
+ keyPath?: string | undefined;
119
+ /**
120
+ * Compute an xpub or xprv
121
+ * @default true
122
+ */
123
+ isPublic?: boolean;
124
+ }): string;
@@ -0,0 +1,310 @@
1
+ "use strict";
2
+ // Copyright (c) 2023 Jose-Luis Landabaso - https://bitcoinerlab.com
3
+ // Distributed under the MIT software license
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
17
+ }) : function(o, v) {
18
+ o["default"] = v;
19
+ });
20
+ var __importStar = (this && this.__importStar) || (function () {
21
+ var ownKeys = function(o) {
22
+ ownKeys = Object.getOwnPropertyNames || function (o) {
23
+ var ar = [];
24
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
25
+ return ar;
26
+ };
27
+ return ownKeys(o);
28
+ };
29
+ return function (mod) {
30
+ if (mod && mod.__esModule) return mod;
31
+ var result = {};
32
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
33
+ __setModuleDefault(result, mod);
34
+ return result;
35
+ };
36
+ })();
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.parseKeyExpression = parseKeyExpression;
39
+ exports.keyExpressionLedger = keyExpressionLedger;
40
+ exports.keyExpressionBIP32 = keyExpressionBIP32;
41
+ const networks_1 = require("./networks");
42
+ const ledger_1 = require("./ledger");
43
+ const keyInterfaces_1 = require("./keyInterfaces");
44
+ const uint8array_tools_1 = require("uint8array-tools");
45
+ const RE = __importStar(require("./re"));
46
+ const derivePath = (node, path) => {
47
+ if (typeof path !== 'string') {
48
+ throw new Error(`Error: invalid derivation path ${path}`);
49
+ }
50
+ const parsedPath = path.replaceAll('H', "'").replaceAll('h', "'").slice(1);
51
+ const splitPath = parsedPath.split('/');
52
+ for (const element of splitPath) {
53
+ const unhardened = element.endsWith("'") ? element.slice(0, -1) : element;
54
+ if (!Number.isInteger(Number(unhardened)) ||
55
+ Number(unhardened) >= 0x80000000)
56
+ throw new Error(`Error: BIP 32 path element overflow`);
57
+ }
58
+ return node.derivePath(parsedPath);
59
+ };
60
+ /**
61
+ * Parses a key expression (xpub, xprv, pubkey or wif) into {@link KeyInfo | `KeyInfo`}.
62
+ *
63
+ * For example, given this `keyExpression`: `"[d34db33f/49'/0'/0']tpubDCdxmvzJ5QBjTN8oCjjyT2V58AyZvA1fkmCeZRC75QMoaHcVP2m45Bv3hmnR7ttAwkb2UNYyoXdHVt4gwBqRrJqLUU2JrM43HippxiWpHra/1/2/3/4/*"`, this is its parsed result:
64
+ *
65
+ * ```javascript
66
+ * {
67
+ * keyExpression:
68
+ * "[d34db33f/49'/0'/0']tpubDCdxmvzJ5QBjTN8oCjjyT2V58AyZvA1fkmCeZRC75QMoaHcVP2m45Bv3hmnR7ttAwkb2UNYyoXdHVt4gwBqRrJqLUU2JrM43HippxiWpHra/1/2/3/4/*",
69
+ * keyPath: '/1/2/3/4/*',
70
+ * originPath: "/49'/0'/0'",
71
+ * path: "m/49'/0'/0'/1/2/3/4/*",
72
+ * // Other relevant properties of `KeyInfo`: `pubkey`, `ecpair`, `bip32`,
73
+ * // `privkey`, `xPub`, `xPrv`, `masterFingerprint`, etc.
74
+ * }
75
+ * ```
76
+ */
77
+ function parseKeyExpression({ keyExpression, isSegwit, isTaproot, ECPair, BIP32, network = networks_1.networks.bitcoin }) {
78
+ if (isTaproot && isSegwit !== true)
79
+ throw new Error(`Error: taproot key expressions require isSegwit`);
80
+ let pubkey; //won't be computed for ranged keyExpressions
81
+ let ecpair;
82
+ let bip32;
83
+ let privkey;
84
+ let xPub;
85
+ let xPrv;
86
+ let masterFingerprint;
87
+ let originPath;
88
+ let keyPath;
89
+ let path;
90
+ const isRanged = keyExpression.indexOf('*') !== -1;
91
+ const reKeyExp = isTaproot
92
+ ? RE.reTaprootKeyExp
93
+ : isSegwit
94
+ ? RE.reSegwitKeyExp
95
+ : RE.reNonSegwitKeyExp;
96
+ const rePubKey = isTaproot
97
+ ? RE.reTaprootPubKey
98
+ : isSegwit
99
+ ? RE.reSegwitPubKey
100
+ : RE.reNonSegwitPubKey;
101
+ //Validate the keyExpression:
102
+ const keyExpressions = keyExpression.match(reKeyExp);
103
+ if (keyExpressions === null || keyExpressions[0] !== keyExpression) {
104
+ throw new Error(`Error: expected a keyExpression but got ${keyExpression}`);
105
+ }
106
+ const reOriginAnchoredStart = RegExp(String.raw `^(${RE.reOrigin})?`); //starts with ^origin
107
+ const mOrigin = keyExpression.match(reOriginAnchoredStart);
108
+ if (mOrigin) {
109
+ const bareOrigin = mOrigin[0].replace(/[[\]]/g, ''); //strip the "[" and "]" in [origin]
110
+ const reMasterFingerprintAnchoredStart = String.raw `^(${RE.reMasterFingerprint})`;
111
+ const mMasterFingerprint = bareOrigin.match(reMasterFingerprintAnchoredStart);
112
+ const masterFingerprintHex = mMasterFingerprint
113
+ ? mMasterFingerprint[0]
114
+ : '';
115
+ originPath = bareOrigin.replace(masterFingerprintHex, '');
116
+ if (masterFingerprintHex.length > 0) {
117
+ if (masterFingerprintHex.length !== 8)
118
+ throw new Error(`Error: masterFingerprint ${masterFingerprintHex} invalid for keyExpression: ${keyExpression}`);
119
+ masterFingerprint = (0, uint8array_tools_1.fromHex)(masterFingerprintHex);
120
+ }
121
+ }
122
+ //Remove the origin (if it exists) and store result in actualKey
123
+ const actualKey = keyExpression.replace(reOriginAnchoredStart, '');
124
+ let mPubKey, mWIF, mXpubKey, mXprvKey;
125
+ //match pubkey:
126
+ if ((mPubKey = actualKey.match(RE.anchorStartAndEnd(rePubKey))) !== null) {
127
+ pubkey = (0, uint8array_tools_1.fromHex)(mPubKey[0]);
128
+ if (isTaproot && pubkey.length === 32)
129
+ //convert the xonly point to a compressed point assuming even parity
130
+ pubkey = (0, uint8array_tools_1.concat)([Uint8Array.from([0x02]), pubkey]);
131
+ ecpair = ECPair.fromPublicKey(pubkey, { network });
132
+ //Validate the pubkey (compressed or uncompressed)
133
+ if (!ECPair.isPoint(pubkey) ||
134
+ !(pubkey.length === 33 || pubkey.length === 65)) {
135
+ throw new Error(`Error: invalid pubkey`);
136
+ }
137
+ //Do an extra check in case we know this pubkey refers to a segwit input
138
+ //Taproot x-only keys are converted to 33-byte compressed form above.
139
+ if (typeof isSegwit === 'boolean' &&
140
+ isSegwit &&
141
+ pubkey.length !== 33 //Inside wpkh and wsh, only compressed public keys are permitted.
142
+ ) {
143
+ throw new Error(`Error: invalid pubkey`);
144
+ }
145
+ //match WIF:
146
+ }
147
+ else if ((mWIF = actualKey.match(RE.anchorStartAndEnd(RE.reWIF))) !== null) {
148
+ ecpair = ECPair.fromWIF(mWIF[0], network);
149
+ //fromWIF will throw if the wif is not valid
150
+ pubkey = ecpair.publicKey;
151
+ privkey = ecpair.privateKey;
152
+ //match xpub:
153
+ }
154
+ else if ((mXpubKey = actualKey.match(RE.anchorStartAndEnd(RE.reXpubKey))) !== null) {
155
+ const xPubKey = mXpubKey[0];
156
+ xPub = xPubKey.match(RE.reXpub)?.[0];
157
+ if (!xPub)
158
+ throw new Error(`Error: xpub could not be matched`);
159
+ bip32 = BIP32.fromBase58(xPub, network);
160
+ const mPath = xPubKey.match(RE.rePath);
161
+ if (mPath !== null) {
162
+ keyPath = xPubKey.match(RE.rePath)?.[0];
163
+ if (!keyPath)
164
+ throw new Error(`Error: could not extract a path`);
165
+ //fromBase58 and derivePath will throw if xPub or path are not valid
166
+ if (!isRanged)
167
+ pubkey = derivePath(bip32, keyPath).publicKey;
168
+ }
169
+ else {
170
+ pubkey = bip32.publicKey;
171
+ }
172
+ //match xprv:
173
+ }
174
+ else if ((mXprvKey = actualKey.match(RE.anchorStartAndEnd(RE.reXprvKey))) !== null) {
175
+ const xPrvKey = mXprvKey[0];
176
+ xPrv = xPrvKey.match(RE.reXprv)?.[0];
177
+ if (!xPrv)
178
+ throw new Error(`Error: xprv could not be matched`);
179
+ bip32 = BIP32.fromBase58(xPrv, network);
180
+ xPub = bip32.neutered().toBase58();
181
+ const mPath = xPrvKey.match(RE.rePath);
182
+ if (mPath !== null) {
183
+ keyPath = xPrvKey.match(RE.rePath)?.[0];
184
+ if (!keyPath)
185
+ throw new Error(`Error: could not extract a path`);
186
+ //fromBase58 and derivePath will throw if xPrv or path are not valid
187
+ if (!isRanged)
188
+ pubkey = derivePath(bip32, keyPath).publicKey;
189
+ }
190
+ else {
191
+ pubkey = bip32.publicKey;
192
+ }
193
+ }
194
+ else {
195
+ throw new Error(`Error: could not get pubkey for keyExpression ${keyExpression}`);
196
+ }
197
+ if (originPath || keyPath) {
198
+ path = `m${originPath ?? ''}${keyPath ?? ''}`;
199
+ }
200
+ if (pubkey !== undefined) {
201
+ if (isTaproot) {
202
+ if (pubkey.length !== 33)
203
+ throw new Error(`Error: invalid pubkey`);
204
+ }
205
+ else if (typeof isSegwit === 'boolean' &&
206
+ isSegwit &&
207
+ pubkey.length !== 33) {
208
+ throw new Error(`Error: invalid pubkey`);
209
+ }
210
+ }
211
+ if (pubkey !== undefined && isTaproot && pubkey.length === 33)
212
+ // If we get a 33-byte compressed key, drop the first byte.
213
+ pubkey = pubkey.slice(1, 33);
214
+ return {
215
+ keyExpression,
216
+ ...(pubkey !== undefined ? { pubkey } : {}),
217
+ ...(ecpair !== undefined ? { ecpair } : {}),
218
+ ...(bip32 !== undefined ? { bip32 } : {}),
219
+ ...(privkey !== undefined ? { privkey } : {}),
220
+ ...(xPub !== undefined ? { xPub } : {}),
221
+ ...(xPrv !== undefined ? { xPrv } : {}),
222
+ ...(masterFingerprint !== undefined ? { masterFingerprint } : {}),
223
+ ...(originPath !== undefined && originPath !== '' ? { originPath } : {}),
224
+ ...(keyPath !== undefined && keyPath !== '' ? { keyPath } : {}),
225
+ ...(path !== undefined ? { path } : {})
226
+ };
227
+ }
228
+ function assertChangeIndexKeyPath({ change, index, keyPath }) {
229
+ if (!((change === undefined && index === undefined) ||
230
+ (change !== undefined && index !== undefined)))
231
+ throw new Error(`Error: Pass change and index or neither`);
232
+ if ((change !== undefined) === (keyPath !== undefined))
233
+ throw new Error(`Error: Pass either change and index or a keyPath`);
234
+ }
235
+ async function keyExpressionLedger({ ledgerManager, originPath, keyPath, change, index }) {
236
+ assertChangeIndexKeyPath({ change, index, keyPath });
237
+ const masterFingerprint = await (0, ledger_1.getLedgerMasterFingerPrint)({
238
+ ledgerManager
239
+ });
240
+ const origin = `[${(0, uint8array_tools_1.toHex)(masterFingerprint)}${originPath}]`;
241
+ const xpub = await (0, ledger_1.getLedgerXpub)({ originPath, ledgerManager });
242
+ const keyRoot = `${origin}${xpub}`;
243
+ if (keyPath !== undefined)
244
+ return `${keyRoot}${keyPath}`;
245
+ else
246
+ return `${keyRoot}/${change}/${index}`;
247
+ }
248
+ /**
249
+ * Constructs a BIP32 key expression string from its constituent components.
250
+ *
251
+ * This function essentially performs the reverse operation of
252
+ * {@link KeyExpressionParser}. For detailed
253
+ * explanations and examples of the terms used here, refer to
254
+ * {@link KeyExpressionParser}.
255
+ *
256
+ * @param {Object} params - The parameters object.
257
+ * @param {BIP32InterfaceLike | ScureHDKeyLike} params.masterNode - Root HD node.
258
+ * Pass either:
259
+ * - a bitcoinjs {@link https://github.com/bitcoinjs/bip32 | `BIP32`} node, or
260
+ * - a scure {@link https://github.com/paulmillr/scure-bip32 | `HDKey`}.
261
+ * @param {string} params.originPath - Origin path from master, e.g. `"/84'/0'/0'"`.
262
+ * @param {number} [params.change] - Branch index (`0` receive, `1` change).
263
+ * @param {number | '*'} [params.index] - Address index or `*` for ranged descriptors.
264
+ * @param {string} [params.keyPath] - Full suffix path (`/change/index`) alternative to
265
+ * `change` + `index`.
266
+ * @returns {string} Descriptor key expression (e.g. `[f23f9fd2/84'/0'/0']xpub.../0/5`).
267
+ *
268
+ * @example
269
+ * ```ts
270
+ * import * as ecc from '@bitcoinerlab/secp256k1';
271
+ * import { BIP32Factory } from 'bip32';
272
+ * import { keyExpressionBIP32 } from '@bitcoinerlab/descriptors';
273
+ *
274
+ * const BIP32 = BIP32Factory(ecc);
275
+ * const masterNode = BIP32.fromSeed(seedBytes);
276
+ * const keyExp = keyExpressionBIP32({
277
+ * masterNode,
278
+ * originPath: "/84'/0'/0'",
279
+ * change: 0,
280
+ * index: 5
281
+ * });
282
+ * ```
283
+ *
284
+ * @example
285
+ * ```ts
286
+ * import { HDKey } from '@scure/bip32';
287
+ * import { keyExpressionBIP32 } from '@bitcoinerlab/descriptors';
288
+ *
289
+ * const masterNode = HDKey.fromMasterSeed(seedBytes);
290
+ * const keyExp = keyExpressionBIP32({
291
+ * masterNode,
292
+ * originPath: "/84'/0'/0'",
293
+ * keyPath: '/0/*'
294
+ * });
295
+ * ```
296
+ */
297
+ function keyExpressionBIP32({ masterNode, originPath, keyPath, change, index, isPublic = true }) {
298
+ masterNode = (0, keyInterfaces_1.toBIP32Interface)(masterNode);
299
+ assertChangeIndexKeyPath({ change, index, keyPath });
300
+ const masterFingerprint = masterNode.fingerprint;
301
+ const origin = `[${(0, uint8array_tools_1.toHex)(masterFingerprint)}${originPath}]`;
302
+ const xpub = isPublic
303
+ ? masterNode.derivePath(`m${originPath}`).neutered().toBase58().toString()
304
+ : masterNode.derivePath(`m${originPath}`).toBase58().toString();
305
+ const keyRoot = `${origin}${xpub}`;
306
+ if (keyPath !== undefined)
307
+ return `${keyRoot}${keyPath}`;
308
+ else
309
+ return `${keyRoot}/${change}/${index}`;
310
+ }
@@ -0,0 +1,5 @@
1
+ import { type ECPairInterfaceLike, type BIP32InterfaceLike, type ScureHDKeyLike } from './bitcoinLib';
2
+ /** @internal */
3
+ export declare function toECPairInterface(ecpair: ECPairInterfaceLike | Uint8Array): ECPairInterfaceLike;
4
+ /** @internal */
5
+ export declare function toBIP32Interface(node: BIP32InterfaceLike | ScureHDKeyLike): BIP32InterfaceLike;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ // Copyright (c) 2026 Jose-Luis Landabaso - https://bitcoinerlab.com
3
+ // Distributed under the MIT software license
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.toECPairInterface = toECPairInterface;
6
+ exports.toBIP32Interface = toBIP32Interface;
7
+ function isScureHDKey(node) {
8
+ const candidate = node;
9
+ return (typeof candidate.fingerprint === 'number' &&
10
+ typeof candidate.derive === 'function' &&
11
+ typeof candidate.deriveChild === 'function' &&
12
+ typeof candidate.publicExtendedKey === 'string' &&
13
+ typeof candidate.privateExtendedKey === 'string');
14
+ }
15
+ /** @internal */
16
+ function toECPairInterface(ecpair) {
17
+ if (ecpair instanceof Uint8Array) {
18
+ try {
19
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
20
+ const { wrapScurePrivateKey } = require('./adapters/scureKeys');
21
+ return wrapScurePrivateKey(ecpair);
22
+ }
23
+ catch (error) {
24
+ throw new Error('Failed to load scure key adapter. ' +
25
+ 'Make sure @noble/curves is installed as a peer dependency. ' +
26
+ 'Original error: ' +
27
+ (error instanceof Error ? error.message : String(error)));
28
+ }
29
+ }
30
+ // Already a bitcoinjs-lib compatible ECPairInterface
31
+ return ecpair;
32
+ }
33
+ /** @internal */
34
+ function toBIP32Interface(node) {
35
+ if (isScureHDKey(node)) {
36
+ try {
37
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
38
+ const { wrapScureHDKey } = require('./adapters/scureKeys');
39
+ return wrapScureHDKey(node);
40
+ }
41
+ catch (error) {
42
+ throw new Error('Failed to load scure key adapter. ' +
43
+ 'Make sure @scure/bip32 is installed as a peer dependency. ' +
44
+ 'Original error: ' +
45
+ (error instanceof Error ? error.message : String(error)));
46
+ }
47
+ }
48
+ // Already a bitcoinjs-lib compatible Bip32Interface
49
+ return node;
50
+ }