bip388 1.0.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/index.js ADDED
@@ -0,0 +1,1305 @@
1
+ // src/miniscript.ts
2
+ function pk(key) {
3
+ return {
4
+ type: "pk",
5
+ key,
6
+ toString() {
7
+ return `pk(${this.key})`;
8
+ }
9
+ };
10
+ }
11
+ function pkh(key) {
12
+ return {
13
+ type: "pkh",
14
+ key,
15
+ toString() {
16
+ return `pkh(${this.key})`;
17
+ }
18
+ };
19
+ }
20
+ function sha256(hash) {
21
+ validateHash(hash, 64, "sha256");
22
+ return {
23
+ type: "sha256",
24
+ hash,
25
+ toString() {
26
+ return `sha256(${this.hash})`;
27
+ }
28
+ };
29
+ }
30
+ function hash256(hash) {
31
+ validateHash(hash, 64, "hash256");
32
+ return {
33
+ type: "hash256",
34
+ hash,
35
+ toString() {
36
+ return `hash256(${this.hash})`;
37
+ }
38
+ };
39
+ }
40
+ function hash160(hash) {
41
+ validateHash(hash, 40, "hash160");
42
+ return {
43
+ type: "hash160",
44
+ hash,
45
+ toString() {
46
+ return `hash160(${this.hash})`;
47
+ }
48
+ };
49
+ }
50
+ function ripemd160(hash) {
51
+ validateHash(hash, 40, "ripemd160");
52
+ return {
53
+ type: "ripemd160",
54
+ hash,
55
+ toString() {
56
+ return `ripemd160(${this.hash})`;
57
+ }
58
+ };
59
+ }
60
+ function older(blocks) {
61
+ validateTimelock(blocks, "older");
62
+ return {
63
+ type: "older",
64
+ blocks,
65
+ toString() {
66
+ return `older(${this.blocks})`;
67
+ }
68
+ };
69
+ }
70
+ function after(time) {
71
+ validateTimelock(time, "after");
72
+ return {
73
+ type: "after",
74
+ time,
75
+ toString() {
76
+ return `after(${this.time})`;
77
+ }
78
+ };
79
+ }
80
+ function and_v(left, right) {
81
+ return {
82
+ type: "and_v",
83
+ left,
84
+ right,
85
+ toString() {
86
+ return `and_v(${this.left.toString()},${this.right.toString()})`;
87
+ }
88
+ };
89
+ }
90
+ function or_d(left, right) {
91
+ return {
92
+ type: "or_d",
93
+ left,
94
+ right,
95
+ toString() {
96
+ return `or_d(${this.left.toString()},${this.right.toString()})`;
97
+ }
98
+ };
99
+ }
100
+ function or_i(left, right) {
101
+ return {
102
+ type: "or_i",
103
+ left,
104
+ right,
105
+ toString() {
106
+ return `or_i(${this.left.toString()},${this.right.toString()})`;
107
+ }
108
+ };
109
+ }
110
+ function v(inner) {
111
+ return {
112
+ type: "v",
113
+ inner,
114
+ toString() {
115
+ return `v:${this.inner.toString()}`;
116
+ }
117
+ };
118
+ }
119
+ function multi(threshold, keys) {
120
+ validateMultisig(threshold, keys.length, "multi");
121
+ return {
122
+ type: "multi",
123
+ threshold,
124
+ keys,
125
+ toString() {
126
+ return `multi(${this.threshold},${this.keys.join(",")})`;
127
+ }
128
+ };
129
+ }
130
+ function sortedmulti(threshold, keys) {
131
+ validateMultisig(threshold, keys.length, "sortedmulti");
132
+ return {
133
+ type: "sortedmulti",
134
+ threshold,
135
+ keys,
136
+ toString() {
137
+ return `sortedmulti(${this.threshold},${this.keys.join(",")})`;
138
+ }
139
+ };
140
+ }
141
+ function multi_a(threshold, keys) {
142
+ validateMultisig(threshold, keys.length, "multi_a");
143
+ return {
144
+ type: "multi_a",
145
+ threshold,
146
+ keys,
147
+ toString() {
148
+ return `multi_a(${this.threshold},${this.keys.join(",")})`;
149
+ }
150
+ };
151
+ }
152
+ function sortedmulti_a(threshold, keys) {
153
+ validateMultisig(threshold, keys.length, "sortedmulti_a");
154
+ return {
155
+ type: "sortedmulti_a",
156
+ threshold,
157
+ keys,
158
+ toString() {
159
+ return `sortedmulti_a(${this.threshold},${this.keys.join(",")})`;
160
+ }
161
+ };
162
+ }
163
+ function validateHash(hash, expectedLength, name) {
164
+ if (!hash || typeof hash !== "string") {
165
+ throw new Error(`${name} must be a hex string`);
166
+ }
167
+ if (hash.length !== expectedLength) {
168
+ throw new Error(
169
+ `${name} must be ${expectedLength / 2} bytes (${expectedLength} hex chars), got ${hash.length}`
170
+ );
171
+ }
172
+ if (!/^[0-9a-fA-F]+$/.test(hash)) {
173
+ throw new Error(`${name} must be a valid hex string`);
174
+ }
175
+ }
176
+ function validateTimelock(value, name) {
177
+ if (!Number.isInteger(value) || value <= 0) {
178
+ throw new Error(`${name} must be a positive integer`);
179
+ }
180
+ if (value > 2147483647) {
181
+ throw new Error(`${name} exceeds maximum value (2^31-1)`);
182
+ }
183
+ }
184
+ function validateMultisig(threshold, numKeys, name) {
185
+ if (!Number.isInteger(threshold) || threshold <= 0) {
186
+ throw new Error(`${name} threshold must be a positive integer`);
187
+ }
188
+ if (numKeys < 1) {
189
+ throw new Error(`${name} requires at least one key`);
190
+ }
191
+ if (threshold > numKeys) {
192
+ throw new Error(
193
+ `${name} threshold (${threshold}) cannot exceed number of keys (${numKeys})`
194
+ );
195
+ }
196
+ if (numKeys > 20 && (name === "multi" || name === "sortedmulti")) {
197
+ throw new Error(`${name} is limited to 20 keys in SegWit`);
198
+ }
199
+ }
200
+
201
+ // src/bip388.ts
202
+ function keyPlaceholder(index) {
203
+ if (!Number.isInteger(index) || index < 0) {
204
+ throw new Error(`Key index must be a non-negative integer, got: ${index}`);
205
+ }
206
+ return `@${index}/**`;
207
+ }
208
+ function trDescriptor(internalKeyIndex, tree) {
209
+ const internalKey = keyPlaceholder(internalKeyIndex);
210
+ if (!tree) {
211
+ return `tr(${internalKey})`;
212
+ }
213
+ const treeStr = serializeTapTree(tree);
214
+ return `tr(${internalKey},${treeStr})`;
215
+ }
216
+ function wshDescriptor(script) {
217
+ return `wsh(${script.toString()})`;
218
+ }
219
+ function wpkhDescriptor(keyIndex) {
220
+ return `wpkh(${keyPlaceholder(keyIndex)})`;
221
+ }
222
+ function buildTaprootPolicy(internalKeyIndex, tree, options) {
223
+ validatePolicyOptions(options);
224
+ return {
225
+ name: options.name,
226
+ template: trDescriptor(internalKeyIndex, tree),
227
+ keys: options.keys
228
+ };
229
+ }
230
+ function buildSegwitPolicy(script, options) {
231
+ validatePolicyOptions(options);
232
+ return {
233
+ name: options.name,
234
+ template: wshDescriptor(script),
235
+ keys: options.keys
236
+ };
237
+ }
238
+ function formatKeyInfo(info) {
239
+ let result = "";
240
+ if (info.fingerprint || info.originPath) {
241
+ result += "[";
242
+ if (info.fingerprint) {
243
+ result += info.fingerprint;
244
+ }
245
+ if (info.originPath) {
246
+ result += "/" + info.originPath;
247
+ }
248
+ result += "]";
249
+ }
250
+ result += info.xpub;
251
+ return result;
252
+ }
253
+ function bareKey(xpub) {
254
+ return { xpub };
255
+ }
256
+ function validatePolicyOptions(options) {
257
+ if (!options.name || typeof options.name !== "string") {
258
+ throw new Error("Policy name is required");
259
+ }
260
+ if (options.name.length > 64) {
261
+ throw new Error("Policy name should not exceed 64 characters");
262
+ }
263
+ if (!Array.isArray(options.keys) || options.keys.length === 0) {
264
+ throw new Error("At least one key is required");
265
+ }
266
+ }
267
+ function serializeTapTree(tree) {
268
+ if (Array.isArray(tree)) {
269
+ const [left, right] = tree;
270
+ return `{${serializeTapTree(left)},${serializeTapTree(right)}}`;
271
+ }
272
+ return tree.toString();
273
+ }
274
+
275
+ // src/patterns/htlc.ts
276
+ function buildTaprootHtlcPolicy(params) {
277
+ const { name, secretHash, timelock, numsKey, payeeKey, payerKey } = params;
278
+ validateHash2(secretHash, 64, "secretHash");
279
+ validateTimelock2(timelock, "timelock");
280
+ const secretLeaf = and_v(v(sha256(secretHash)), pk(keyPlaceholder(1)));
281
+ const timeoutLeaf = and_v(v(after(timelock)), pk(keyPlaceholder(2)));
282
+ const tree = [secretLeaf, timeoutLeaf];
283
+ return {
284
+ name,
285
+ template: trDescriptor(0, tree),
286
+ keys: [numsKey, payeeKey, payerKey]
287
+ };
288
+ }
289
+ function buildSegwitHtlcPolicy(params) {
290
+ const { name, secretHash, timelock, payeeKey, payerKey } = params;
291
+ validateHash2(secretHash, 64, "secretHash");
292
+ validateTimelock2(timelock, "timelock");
293
+ const secretPath = and_v(v(sha256(secretHash)), pk(keyPlaceholder(0)));
294
+ const timeoutPath = and_v(v(pk(keyPlaceholder(1))), after(timelock));
295
+ const script = or_i(secretPath, timeoutPath);
296
+ return {
297
+ name,
298
+ template: wshDescriptor(script),
299
+ keys: [payeeKey, payerKey]
300
+ };
301
+ }
302
+ function validateHash2(hash, expectedLength, name) {
303
+ if (!hash || typeof hash !== "string") {
304
+ throw new Error(`${name} must be a hex string`);
305
+ }
306
+ if (hash.length !== expectedLength) {
307
+ throw new Error(
308
+ `${name} must be ${expectedLength / 2} bytes (${expectedLength} hex chars), got ${hash.length}`
309
+ );
310
+ }
311
+ if (!/^[0-9a-fA-F]+$/.test(hash)) {
312
+ throw new Error(`${name} must be a valid hex string`);
313
+ }
314
+ }
315
+ function validateTimelock2(value, name) {
316
+ if (!Number.isInteger(value) || value <= 0) {
317
+ throw new Error(`${name} must be a positive integer`);
318
+ }
319
+ if (value > 2147483647) {
320
+ throw new Error(`${name} exceeds maximum value (2^31-1)`);
321
+ }
322
+ }
323
+
324
+ // src/patterns/multisig.ts
325
+ function buildSegwitMultisigPolicy(params) {
326
+ const { name, threshold, keys, sorted = true } = params;
327
+ if (keys.length === 0) {
328
+ throw new Error("At least one key is required");
329
+ }
330
+ const keyPlaceholders = keys.map((_, i) => keyPlaceholder(i));
331
+ const script = sorted ? sortedmulti(threshold, keyPlaceholders) : multi(threshold, keyPlaceholders);
332
+ return {
333
+ name,
334
+ template: wshDescriptor(script),
335
+ keys
336
+ };
337
+ }
338
+ function buildTaprootMultisigPolicy(params) {
339
+ const { name, threshold, keys, sorted = true } = params;
340
+ if (keys.length < 2) {
341
+ throw new Error(
342
+ "Taproot multisig requires at least 2 keys (internal key + script key)"
343
+ );
344
+ }
345
+ const scriptKeyPlaceholders = keys.slice(1).map((_, i) => keyPlaceholder(i + 1));
346
+ const script = sorted ? sortedmulti_a(threshold, scriptKeyPlaceholders) : multi_a(threshold, scriptKeyPlaceholders);
347
+ return {
348
+ name,
349
+ template: trDescriptor(0, script),
350
+ keys
351
+ };
352
+ }
353
+
354
+ // src/scripts/pk.ts
355
+ import { script as bscript, opcodes } from "bitcoinjs-lib";
356
+ function pkScript(pubkey) {
357
+ if (pubkey.length !== 33 && pubkey.length !== 32) {
358
+ throw new Error(
359
+ `Invalid pubkey length: ${pubkey.length} (expected 32 or 33 bytes)`
360
+ );
361
+ }
362
+ return Buffer.from(bscript.compile([pubkey, opcodes.OP_CHECKSIG]));
363
+ }
364
+
365
+ // src/scripts/pkh.ts
366
+ import { script as bscript2, opcodes as opcodes2, crypto } from "bitcoinjs-lib";
367
+ function pkhScript(pubkey) {
368
+ if (pubkey.length !== 33) {
369
+ throw new Error(
370
+ `Invalid pubkey length: ${pubkey.length} (expected 33 bytes for compressed pubkey)`
371
+ );
372
+ }
373
+ const pubkeyHash = crypto.hash160(pubkey);
374
+ return Buffer.from(
375
+ bscript2.compile([
376
+ opcodes2.OP_DUP,
377
+ opcodes2.OP_HASH160,
378
+ pubkeyHash,
379
+ opcodes2.OP_EQUALVERIFY,
380
+ opcodes2.OP_CHECKSIG
381
+ ])
382
+ );
383
+ }
384
+ function pkhScriptFromHash(pubkeyHash) {
385
+ if (pubkeyHash.length !== 20) {
386
+ throw new Error(
387
+ `Invalid pubkey hash length: ${pubkeyHash.length} (expected 20 bytes)`
388
+ );
389
+ }
390
+ return Buffer.from(
391
+ bscript2.compile([
392
+ opcodes2.OP_DUP,
393
+ opcodes2.OP_HASH160,
394
+ pubkeyHash,
395
+ opcodes2.OP_EQUALVERIFY,
396
+ opcodes2.OP_CHECKSIG
397
+ ])
398
+ );
399
+ }
400
+
401
+ // src/scripts/multi.ts
402
+ import { script as bscript3, opcodes as opcodes3 } from "bitcoinjs-lib";
403
+ function encodeScriptInt(n) {
404
+ if (n === 0) return opcodes3.OP_0;
405
+ if (n >= 1 && n <= 16) return opcodes3.OP_1 - 1 + n;
406
+ return Buffer.from(bscript3.number.encode(n));
407
+ }
408
+ function multiScript(threshold, pubkeys, sorted = false) {
409
+ if (threshold <= 0 || !Number.isInteger(threshold)) {
410
+ throw new Error("threshold must be a positive integer");
411
+ }
412
+ if (pubkeys.length === 0) {
413
+ throw new Error("At least one pubkey is required");
414
+ }
415
+ if (threshold > pubkeys.length) {
416
+ throw new Error(
417
+ `threshold (${threshold}) cannot exceed number of pubkeys (${pubkeys.length})`
418
+ );
419
+ }
420
+ if (pubkeys.length > 20) {
421
+ throw new Error("SegWit multisig is limited to 20 keys");
422
+ }
423
+ for (const pk2 of pubkeys) {
424
+ if (pk2.length !== 33) {
425
+ throw new Error(
426
+ `Invalid pubkey length: ${pk2.length} (expected 33 bytes for SegWit)`
427
+ );
428
+ }
429
+ }
430
+ const keys = sorted ? [...pubkeys].sort(Buffer.compare) : pubkeys;
431
+ return Buffer.from(
432
+ bscript3.compile([
433
+ encodeScriptInt(threshold),
434
+ ...keys,
435
+ encodeScriptInt(keys.length),
436
+ opcodes3.OP_CHECKMULTISIG
437
+ ])
438
+ );
439
+ }
440
+ function sortedMultiScript(threshold, pubkeys) {
441
+ return multiScript(threshold, pubkeys, true);
442
+ }
443
+ function bareMultiScript(threshold, pubkeys, sorted = false) {
444
+ if (threshold <= 0 || !Number.isInteger(threshold)) {
445
+ throw new Error("threshold must be a positive integer");
446
+ }
447
+ if (pubkeys.length === 0) {
448
+ throw new Error("At least one pubkey is required");
449
+ }
450
+ if (threshold > pubkeys.length) {
451
+ throw new Error(
452
+ `threshold (${threshold}) cannot exceed number of pubkeys (${pubkeys.length})`
453
+ );
454
+ }
455
+ for (const pk2 of pubkeys) {
456
+ if (pk2.length !== 33 && pk2.length !== 65) {
457
+ throw new Error(
458
+ `Invalid pubkey length: ${pk2.length} (expected 33 or 65 bytes)`
459
+ );
460
+ }
461
+ }
462
+ const keys = sorted ? [...pubkeys].sort(Buffer.compare) : pubkeys;
463
+ return Buffer.from(
464
+ bscript3.compile([
465
+ encodeScriptInt(threshold),
466
+ ...keys,
467
+ encodeScriptInt(keys.length),
468
+ opcodes3.OP_CHECKMULTISIG
469
+ ])
470
+ );
471
+ }
472
+ function sortedBareMultiScript(threshold, pubkeys) {
473
+ return bareMultiScript(threshold, pubkeys, true);
474
+ }
475
+
476
+ // src/scripts/hashlock.ts
477
+ import { script as bscript4, opcodes as opcodes4 } from "bitcoinjs-lib";
478
+ function getHashOpcode(hashType) {
479
+ switch (hashType) {
480
+ case "sha256":
481
+ return opcodes4.OP_SHA256;
482
+ case "hash256":
483
+ return opcodes4.OP_HASH256;
484
+ case "hash160":
485
+ return opcodes4.OP_HASH160;
486
+ case "ripemd160":
487
+ return opcodes4.OP_RIPEMD160;
488
+ }
489
+ }
490
+ function getHashLength(hashType) {
491
+ switch (hashType) {
492
+ case "sha256":
493
+ case "hash256":
494
+ return 32;
495
+ case "hash160":
496
+ case "ripemd160":
497
+ return 20;
498
+ }
499
+ }
500
+ function hashlockScript(hash, pubkey, hashType = "sha256") {
501
+ const expectedLen = getHashLength(hashType);
502
+ if (hash.length !== expectedLen) {
503
+ throw new Error(
504
+ `Invalid hash length for ${hashType}: ${hash.length} (expected ${expectedLen} bytes)`
505
+ );
506
+ }
507
+ if (pubkey.length !== 32 && pubkey.length !== 33) {
508
+ throw new Error(
509
+ `Invalid pubkey length: ${pubkey.length} (expected 32 or 33 bytes)`
510
+ );
511
+ }
512
+ return Buffer.from(
513
+ bscript4.compile([
514
+ // v:sha256(H) - verify wrapper with SIZE check for preimage length
515
+ opcodes4.OP_SIZE,
516
+ bscript4.number.encode(expectedLen),
517
+ opcodes4.OP_EQUALVERIFY,
518
+ // Hash check
519
+ getHashOpcode(hashType),
520
+ hash,
521
+ opcodes4.OP_EQUALVERIFY,
522
+ // pk(K)
523
+ pubkey,
524
+ opcodes4.OP_CHECKSIG
525
+ ])
526
+ );
527
+ }
528
+ function simpleHashlockScript(hash, hashType = "sha256") {
529
+ const expectedLen = getHashLength(hashType);
530
+ if (hash.length !== expectedLen) {
531
+ throw new Error(
532
+ `Invalid hash length for ${hashType}: ${hash.length} (expected ${expectedLen} bytes)`
533
+ );
534
+ }
535
+ return Buffer.from(
536
+ bscript4.compile([
537
+ opcodes4.OP_SIZE,
538
+ bscript4.number.encode(expectedLen),
539
+ opcodes4.OP_EQUALVERIFY,
540
+ getHashOpcode(hashType),
541
+ hash,
542
+ opcodes4.OP_EQUAL
543
+ ])
544
+ );
545
+ }
546
+
547
+ // src/scripts/timelock.ts
548
+ import { script as bscript5, opcodes as opcodes5 } from "bitcoinjs-lib";
549
+ function encodeScriptNumber(n) {
550
+ if (n === 0) {
551
+ return opcodes5.OP_0;
552
+ }
553
+ if (n >= 1 && n <= 16) {
554
+ return opcodes5.OP_1 - 1 + n;
555
+ }
556
+ return Buffer.from(bscript5.number.encode(n));
557
+ }
558
+ function cltvScript(locktime, pubkey, useDrop = false) {
559
+ if (locktime <= 0) {
560
+ throw new Error("locktime must be a positive number");
561
+ }
562
+ if (locktime > 2147483647) {
563
+ throw new Error("locktime exceeds maximum value (2^31-1)");
564
+ }
565
+ if (pubkey.length !== 32 && pubkey.length !== 33) {
566
+ throw new Error(
567
+ `Invalid pubkey length: ${pubkey.length} (expected 32 or 33 bytes)`
568
+ );
569
+ }
570
+ return Buffer.from(
571
+ bscript5.compile([
572
+ encodeScriptNumber(locktime),
573
+ opcodes5.OP_CHECKLOCKTIMEVERIFY,
574
+ useDrop ? opcodes5.OP_DROP : opcodes5.OP_VERIFY,
575
+ pubkey,
576
+ opcodes5.OP_CHECKSIG
577
+ ])
578
+ );
579
+ }
580
+ function csvScript(sequence, pubkey, useDrop = false) {
581
+ if (sequence <= 0) {
582
+ throw new Error("sequence must be a positive number");
583
+ }
584
+ if (sequence > 2147483647) {
585
+ throw new Error("sequence exceeds maximum value (2^31-1)");
586
+ }
587
+ if (pubkey.length !== 32 && pubkey.length !== 33) {
588
+ throw new Error(
589
+ `Invalid pubkey length: ${pubkey.length} (expected 32 or 33 bytes)`
590
+ );
591
+ }
592
+ return Buffer.from(
593
+ bscript5.compile([
594
+ encodeScriptNumber(sequence),
595
+ opcodes5.OP_CHECKSEQUENCEVERIFY,
596
+ useDrop ? opcodes5.OP_DROP : opcodes5.OP_VERIFY,
597
+ pubkey,
598
+ opcodes5.OP_CHECKSIG
599
+ ])
600
+ );
601
+ }
602
+ function simpleCltvScript(locktime) {
603
+ if (locktime <= 0) {
604
+ throw new Error("locktime must be a positive number");
605
+ }
606
+ if (locktime > 2147483647) {
607
+ throw new Error("locktime exceeds maximum value (2^31-1)");
608
+ }
609
+ return Buffer.from(
610
+ bscript5.compile([
611
+ encodeScriptNumber(locktime),
612
+ opcodes5.OP_CHECKLOCKTIMEVERIFY,
613
+ opcodes5.OP_DROP,
614
+ opcodes5.OP_TRUE
615
+ ])
616
+ );
617
+ }
618
+
619
+ // src/keys.ts
620
+ import * as ecc from "@bitcoinerlab/secp256k1";
621
+ import BIP32Factory from "bip32";
622
+ import { networks } from "bitcoinjs-lib";
623
+
624
+ // src/types.ts
625
+ function isXpubKey(key) {
626
+ return "xpub" in key;
627
+ }
628
+ function isRawKey(key) {
629
+ return "pubkey" in key;
630
+ }
631
+
632
+ // src/keys.ts
633
+ var bip32 = BIP32Factory(ecc);
634
+ function getNetwork(name) {
635
+ switch (name) {
636
+ case "mainnet":
637
+ return networks.bitcoin;
638
+ case "testnet":
639
+ return networks.testnet;
640
+ case "regtest":
641
+ return networks.regtest;
642
+ }
643
+ }
644
+ function deriveFromXpub(xpub, change, index, network) {
645
+ const node = bip32.fromBase58(xpub, network);
646
+ return node.derive(change).derive(index);
647
+ }
648
+ function resolveCompressedPubkey(key, network) {
649
+ if (isXpubKey(key)) {
650
+ const net = getNetwork(network);
651
+ const child = deriveFromXpub(
652
+ key.xpub,
653
+ key.change ?? 0,
654
+ key.index ?? 0,
655
+ net
656
+ );
657
+ return Buffer.from(child.publicKey);
658
+ } else {
659
+ return parsePublicKey(key.pubkey);
660
+ }
661
+ }
662
+ function resolveXOnlyPubkey(key, network) {
663
+ const compressed = resolveCompressedPubkey(key, network);
664
+ return toXOnly(compressed);
665
+ }
666
+ function toXOnly(pubkey) {
667
+ if (pubkey.length === 32) {
668
+ return pubkey;
669
+ }
670
+ if (pubkey.length === 33) {
671
+ return pubkey.subarray(1, 33);
672
+ }
673
+ if (pubkey.length === 65) {
674
+ return pubkey.subarray(1, 33);
675
+ }
676
+ throw new Error(`Invalid public key length: ${pubkey.length}`);
677
+ }
678
+ function parsePublicKey(pubkeyHex) {
679
+ const buf = Buffer.from(pubkeyHex, "hex");
680
+ if (buf.length === 33) {
681
+ if (buf[0] !== 2 && buf[0] !== 3) {
682
+ throw new Error("Compressed public key must start with 02 or 03");
683
+ }
684
+ if (!isValidPoint(buf)) {
685
+ throw new Error("Invalid public key: not a valid curve point");
686
+ }
687
+ return buf;
688
+ }
689
+ if (buf.length === 32) {
690
+ const compressed = Buffer.concat([Buffer.from([2]), buf]);
691
+ if (!isValidPoint(compressed)) {
692
+ throw new Error("Invalid x-only public key: not a valid curve point");
693
+ }
694
+ return compressed;
695
+ }
696
+ if (buf.length === 65) {
697
+ if (buf[0] !== 4) {
698
+ throw new Error("Uncompressed public key must start with 04");
699
+ }
700
+ const prefix = (buf[64] & 1) === 0 ? 2 : 3;
701
+ const compressed = Buffer.concat([
702
+ Buffer.from([prefix]),
703
+ buf.subarray(1, 33)
704
+ ]);
705
+ if (!isValidPoint(compressed)) {
706
+ throw new Error("Invalid public key: not a valid curve point");
707
+ }
708
+ return compressed;
709
+ }
710
+ throw new Error(
711
+ `Invalid public key length: ${buf.length} bytes (expected 32, 33, or 65)`
712
+ );
713
+ }
714
+ function isValidPoint(pubkey) {
715
+ try {
716
+ return ecc.isPoint(pubkey);
717
+ } catch {
718
+ return false;
719
+ }
720
+ }
721
+ function toKeyInfo(key) {
722
+ return {
723
+ fingerprint: key.fingerprint,
724
+ originPath: key.originPath,
725
+ xpub: key.xpub
726
+ };
727
+ }
728
+ function extractKeyInfos(keys) {
729
+ const infos = [];
730
+ for (const key of keys) {
731
+ if (!isXpubKey(key)) {
732
+ return null;
733
+ }
734
+ infos.push(toKeyInfo(key));
735
+ }
736
+ return infos;
737
+ }
738
+
739
+ // src/patterns/taproot/htlc.ts
740
+ import * as ecc3 from "@bitcoinerlab/secp256k1";
741
+ import {
742
+ initEccLib,
743
+ payments,
744
+ opcodes as opcodes7,
745
+ script as bscript7
746
+ } from "bitcoinjs-lib";
747
+ import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
748
+
749
+ // src/patterns/taproot/nums.ts
750
+ var NUMS = {
751
+ /** Compressed public key (33 bytes as hex) */
752
+ pubkey: "0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0",
753
+ /** X-only public key (32 bytes as hex) - for taproot internal key */
754
+ xonly: "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0",
755
+ /** X-only as Buffer */
756
+ get xonlyBuffer() {
757
+ return Buffer.from(this.xonly, "hex");
758
+ },
759
+ /** Compressed as Buffer */
760
+ get pubkeyBuffer() {
761
+ return Buffer.from(this.pubkey, "hex");
762
+ },
763
+ /**
764
+ * Get NUMS xpub for a specific network.
765
+ * Constructed with:
766
+ * - Public key: NUMS point
767
+ * - Chain code: 32 zero bytes
768
+ * - Depth/parent/index: all zeros (acts like master key)
769
+ */
770
+ xpub(network) {
771
+ switch (network) {
772
+ case "mainnet":
773
+ return "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6QgnecKFpJFPpdzxKrwoaZoV44qAJewsc4kX9vGaCaBExuvJH57";
774
+ case "testnet":
775
+ case "regtest":
776
+ return "tpubD6NzVbkrYhZ4WLczPJWReQycCJdd6YVWXubbVUFnJ5KgU5MDQrD998ZJLSmaB7GVcCnJSDWprxmrGkJ6SvgQC6QAffVpqSvonXmeizXcrkN";
777
+ }
778
+ }
779
+ };
780
+
781
+ // src/patterns/taproot/script.ts
782
+ import * as ecc2 from "@bitcoinerlab/secp256k1";
783
+ import { crypto as crypto2, script as bscript6 } from "bitcoinjs-lib";
784
+ var LEAF_VERSION = 192;
785
+ function tapLeafHash(script) {
786
+ return Buffer.from(
787
+ crypto2.taggedHash(
788
+ "TapLeaf",
789
+ Buffer.concat([Buffer.from([LEAF_VERSION]), serializeScript(script)])
790
+ )
791
+ );
792
+ }
793
+ function tapBranchHash(left, right) {
794
+ const [first, second] = Buffer.compare(left, right) <= 0 ? [left, right] : [right, left];
795
+ return Buffer.from(
796
+ crypto2.taggedHash("TapBranch", Buffer.concat([first, second]))
797
+ );
798
+ }
799
+ function tapTweak(internalPubkey, merkleRoot) {
800
+ return Buffer.from(
801
+ crypto2.taggedHash("TapTweak", Buffer.concat([internalPubkey, merkleRoot]))
802
+ );
803
+ }
804
+ function serializeScript(script) {
805
+ const len = varintEncode(script.length);
806
+ return Buffer.concat([len, script]);
807
+ }
808
+ function buildControlBlock(internalPubkey, leafVersion, merklePath) {
809
+ const parityByte = leafVersion;
810
+ return Buffer.concat([
811
+ Buffer.from([parityByte]),
812
+ internalPubkey,
813
+ ...merklePath
814
+ ]);
815
+ }
816
+ function varintEncode(n) {
817
+ if (n < 253) {
818
+ const buf = Buffer.allocUnsafe(1);
819
+ buf.writeUInt8(n, 0);
820
+ return buf;
821
+ } else if (n <= 65535) {
822
+ const buf = Buffer.allocUnsafe(3);
823
+ buf.writeUInt8(253, 0);
824
+ buf.writeUInt16LE(n, 1);
825
+ return buf;
826
+ } else if (n <= 4294967295) {
827
+ const buf = Buffer.allocUnsafe(5);
828
+ buf.writeUInt8(254, 0);
829
+ buf.writeUInt32LE(n, 1);
830
+ return buf;
831
+ } else {
832
+ const buf = Buffer.allocUnsafe(9);
833
+ buf.writeUInt8(255, 0);
834
+ buf.writeUInt32LE(n >>> 0, 1);
835
+ buf.writeUInt32LE(n / 4294967296 | 0, 5);
836
+ return buf;
837
+ }
838
+ }
839
+ function encodeScriptNumber2(n) {
840
+ return Buffer.from(bscript6.number.encode(n));
841
+ }
842
+ function buildP2TROutput(outputKey) {
843
+ return Buffer.concat([
844
+ Buffer.from([81, 32]),
845
+ // OP_1, push 32 bytes
846
+ outputKey
847
+ ]);
848
+ }
849
+
850
+ // src/patterns/taproot/htlc.ts
851
+ initEccLib(ecc3);
852
+ function taprootHtlc(params) {
853
+ const { payee, payer, secretHash, timelock, network, name } = params;
854
+ if (!secretHash || secretHash.length !== 64) {
855
+ throw new Error("secretHash must be 32 bytes (64 hex chars)");
856
+ }
857
+ if (timelock <= 0) {
858
+ throw new Error("timelock must be a positive number");
859
+ }
860
+ const payeeXOnly = resolveXOnlyPubkey(payee, network);
861
+ const payerXOnly = resolveXOnlyPubkey(payer, network);
862
+ const hashBuffer = Buffer.from(secretHash, "hex");
863
+ const secretScript = buildHashLockScript(hashBuffer, payeeXOnly);
864
+ const timeoutScript = buildTimelockScript(timelock, payerXOnly);
865
+ const secretLeafHash = tapLeafHash(secretScript);
866
+ const timeoutLeafHash = tapLeafHash(timeoutScript);
867
+ const merkleRoot = tapBranchHash(secretLeafHash, timeoutLeafHash);
868
+ const net = getNetwork(network);
869
+ const numsXpub = NUMS.xpub(network);
870
+ const derivedNums = deriveFromXpub(numsXpub, 0, 0, net);
871
+ const internalPubkey = toXOnly(Buffer.from(derivedNums.publicKey));
872
+ const tweak = tapTweak(internalPubkey, merkleRoot);
873
+ const tweakedKey = ecc3.xOnlyPointAddTweak(internalPubkey, tweak);
874
+ if (!tweakedKey) {
875
+ throw new Error("Failed to tweak internal key");
876
+ }
877
+ const outputKey = Buffer.from(tweakedKey.xOnlyPubkey);
878
+ const scriptPubkey = buildP2TROutput(outputKey);
879
+ const address = payments.p2tr({
880
+ pubkey: outputKey,
881
+ network: net
882
+ }).address;
883
+ const secretControlBlock = buildControlBlock(
884
+ internalPubkey,
885
+ 192 | (tweakedKey.parity ? 1 : 0),
886
+ [timeoutLeafHash]
887
+ // path to sibling
888
+ );
889
+ const timeoutControlBlock = buildControlBlock(
890
+ internalPubkey,
891
+ 192 | (tweakedKey.parity ? 1 : 0),
892
+ [secretLeafHash]
893
+ // path to sibling
894
+ );
895
+ let policy = null;
896
+ if (isXpubKey(payee) && isXpubKey(payer)) {
897
+ policy = buildTaprootHtlcPolicy({
898
+ name: name || "HTLC",
899
+ secretHash,
900
+ timelock,
901
+ numsKey: bareKey(NUMS.xpub(network)),
902
+ payeeKey: toKeyInfo(payee),
903
+ payerKey: toKeyInfo(payer)
904
+ });
905
+ }
906
+ return {
907
+ address,
908
+ scriptPubkey,
909
+ internalPubkey,
910
+ merkleRoot,
911
+ tweak,
912
+ outputKey,
913
+ timelock,
914
+ secretLeaf: {
915
+ script: secretScript,
916
+ hash: secretLeafHash
917
+ },
918
+ timeoutLeaf: {
919
+ script: timeoutScript,
920
+ hash: timeoutLeafHash
921
+ },
922
+ controlBlock(leaf) {
923
+ return leaf === "secret" ? secretControlBlock : timeoutControlBlock;
924
+ },
925
+ witness: {
926
+ secret(signature, preimage) {
927
+ return [signature, preimage, secretScript, secretControlBlock];
928
+ },
929
+ timeout(signature) {
930
+ return [signature, timeoutScript, timeoutControlBlock];
931
+ }
932
+ },
933
+ policy
934
+ };
935
+ }
936
+ function extractSecret(witness, secretHash) {
937
+ if (!witness || witness.length < 4) {
938
+ return null;
939
+ }
940
+ const preimage = witness[1];
941
+ if (preimage.length !== 32) {
942
+ return null;
943
+ }
944
+ if (secretHash) {
945
+ const computed = Buffer.from(sha2562(preimage)).toString("hex");
946
+ if (computed !== secretHash) {
947
+ return null;
948
+ }
949
+ }
950
+ return preimage.toString("hex");
951
+ }
952
+ function buildHashLockScript(hash, pubkey, hashOp = opcodes7.OP_SHA256) {
953
+ return Buffer.from(
954
+ bscript7.compile([
955
+ // v:sha256(H) - verify wrapper adds SIZE check for 32-byte preimage
956
+ opcodes7.OP_SIZE,
957
+ bscript7.number.encode(32),
958
+ // Push number 32
959
+ opcodes7.OP_EQUALVERIFY,
960
+ // sha256(H)
961
+ hashOp,
962
+ hash,
963
+ opcodes7.OP_EQUALVERIFY,
964
+ // pk(K)
965
+ pubkey,
966
+ opcodes7.OP_CHECKSIG
967
+ ])
968
+ );
969
+ }
970
+ function buildTimelockScript(timelock, pubkey) {
971
+ return Buffer.from(
972
+ bscript7.compile([
973
+ encodeScriptNumber2(timelock),
974
+ opcodes7.OP_CHECKLOCKTIMEVERIFY,
975
+ opcodes7.OP_VERIFY,
976
+ pubkey,
977
+ opcodes7.OP_CHECKSIG
978
+ ])
979
+ );
980
+ }
981
+
982
+ // src/patterns/taproot/multisig.ts
983
+ import * as ecc4 from "@bitcoinerlab/secp256k1";
984
+ import {
985
+ initEccLib as initEccLib2,
986
+ payments as payments2,
987
+ opcodes as opcodes8,
988
+ script as bscript8
989
+ } from "bitcoinjs-lib";
990
+ initEccLib2(ecc4);
991
+ function taprootMultisig(params) {
992
+ const { threshold, keys, sorted = true, network, name } = params;
993
+ if (threshold <= 0 || !Number.isInteger(threshold)) {
994
+ throw new Error("threshold must be a positive integer");
995
+ }
996
+ if (keys.length === 0) {
997
+ throw new Error("At least one key is required");
998
+ }
999
+ if (threshold > keys.length) {
1000
+ throw new Error(
1001
+ `threshold (${threshold}) cannot exceed number of keys (${keys.length})`
1002
+ );
1003
+ }
1004
+ const net = getNetwork(network);
1005
+ let pubkeys = keys.map((key) => resolveXOnlyPubkey(key, network));
1006
+ let sortedIndexes = pubkeys.map((_, i) => i);
1007
+ if (sorted) {
1008
+ const indexed = pubkeys.map((pk2, i) => ({ pk: pk2, i }));
1009
+ indexed.sort(
1010
+ (a, b) => Buffer.compare(a.pk, b.pk)
1011
+ );
1012
+ pubkeys = indexed.map((x) => x.pk);
1013
+ sortedIndexes = indexed.map((x) => x.i);
1014
+ }
1015
+ const scriptParts = [];
1016
+ scriptParts.push(pubkeys[0]);
1017
+ scriptParts.push(opcodes8.OP_CHECKSIG);
1018
+ for (let i = 1; i < pubkeys.length; i++) {
1019
+ scriptParts.push(pubkeys[i]);
1020
+ scriptParts.push(opcodes8.OP_CHECKSIGADD);
1021
+ }
1022
+ scriptParts.push(encodeScriptNumber(threshold));
1023
+ scriptParts.push(opcodes8.OP_NUMEQUAL);
1024
+ const multisigScript = Buffer.from(bscript8.compile(scriptParts));
1025
+ const leafHash = tapLeafHash(multisigScript);
1026
+ const internalPubkey = NUMS.xonlyBuffer;
1027
+ const merkleRoot = leafHash;
1028
+ const tweak = tapTweak(internalPubkey, merkleRoot);
1029
+ const tweakedKey = ecc4.xOnlyPointAddTweak(internalPubkey, tweak);
1030
+ if (!tweakedKey) {
1031
+ throw new Error("Failed to tweak internal key");
1032
+ }
1033
+ const outputKey = Buffer.from(tweakedKey.xOnlyPubkey);
1034
+ const scriptPubkey = buildP2TROutput(outputKey);
1035
+ const address = payments2.p2tr({
1036
+ pubkey: outputKey,
1037
+ network: net
1038
+ }).address;
1039
+ const controlBlock = buildControlBlock(
1040
+ internalPubkey,
1041
+ 192 | (tweakedKey.parity ? 1 : 0),
1042
+ []
1043
+ // No sibling for single-leaf tree
1044
+ );
1045
+ let policy = null;
1046
+ const keyInfos = extractKeyInfos(keys);
1047
+ if (keyInfos) {
1048
+ policy = buildTaprootMultisigPolicy({
1049
+ name: name || `${threshold}-of-${keys.length} Taproot Multisig`,
1050
+ threshold,
1051
+ keys: [bareKey(NUMS.xpub(network)), ...keyInfos],
1052
+ sorted
1053
+ });
1054
+ }
1055
+ return {
1056
+ address,
1057
+ scriptPubkey,
1058
+ internalPubkey,
1059
+ merkleRoot,
1060
+ tweak,
1061
+ outputKey,
1062
+ scriptLeaf: {
1063
+ script: multisigScript,
1064
+ hash: leafHash
1065
+ },
1066
+ controlBlock,
1067
+ policy,
1068
+ /**
1069
+ * Build witness stack for script path spend.
1070
+ *
1071
+ * For multi_a, signatures must be provided in the same order as keys appear
1072
+ * in the script. Use empty Buffer for keys that don't sign.
1073
+ *
1074
+ * @param signatures Array of signatures (length must equal number of keys)
1075
+ * Use Buffer.alloc(0) for non-signing keys
1076
+ * @returns Witness stack: [sig1, sig2, ..., sigN, script, control_block]
1077
+ */
1078
+ witness(signatures) {
1079
+ if (signatures.length !== keys.length) {
1080
+ throw new Error(
1081
+ `Expected ${keys.length} signature slots (use empty Buffer for non-signers), got ${signatures.length}`
1082
+ );
1083
+ }
1084
+ const sigCount = signatures.filter((s) => s.length > 0).length;
1085
+ if (sigCount !== threshold) {
1086
+ throw new Error(`Expected ${threshold} signatures, got ${sigCount}`);
1087
+ }
1088
+ const orderedSigs = sorted ? sortedIndexes.map((origIdx) => signatures[origIdx]) : signatures;
1089
+ return [...orderedSigs.reverse(), multisigScript, controlBlock];
1090
+ }
1091
+ };
1092
+ }
1093
+
1094
+ // src/patterns/segwit/htlc.ts
1095
+ import { script as bscript9, opcodes as opcodes9, payments as payments3 } from "bitcoinjs-lib";
1096
+ import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
1097
+ function segwitHtlc(params) {
1098
+ const { payee, payer, secretHash, timelock, network, name } = params;
1099
+ if (!secretHash || secretHash.length !== 64) {
1100
+ throw new Error("secretHash must be 32 bytes (64 hex chars)");
1101
+ }
1102
+ if (timelock <= 0) {
1103
+ throw new Error("timelock must be a positive number");
1104
+ }
1105
+ const payeePubkey = resolveCompressedPubkey(payee, network);
1106
+ const payerPubkey = resolveCompressedPubkey(payer, network);
1107
+ const secretHashBuffer = Buffer.from(secretHash, "hex");
1108
+ const witnessScript = Buffer.from(
1109
+ bscript9.compile([
1110
+ opcodes9.OP_IF,
1111
+ // and_v(v:sha256(H), pk(@0)) - secret path
1112
+ opcodes9.OP_SIZE,
1113
+ bscript9.number.encode(32),
1114
+ opcodes9.OP_EQUALVERIFY,
1115
+ opcodes9.OP_SHA256,
1116
+ secretHashBuffer,
1117
+ opcodes9.OP_EQUALVERIFY,
1118
+ payeePubkey,
1119
+ opcodes9.OP_CHECKSIG,
1120
+ opcodes9.OP_ELSE,
1121
+ // and_v(v:pk(@1), after(N)) - timeout path
1122
+ payerPubkey,
1123
+ opcodes9.OP_CHECKSIGVERIFY,
1124
+ bscript9.number.encode(timelock),
1125
+ opcodes9.OP_CHECKLOCKTIMEVERIFY,
1126
+ opcodes9.OP_ENDIF
1127
+ ])
1128
+ );
1129
+ const net = getNetwork(network);
1130
+ const scriptHash = sha2563(witnessScript);
1131
+ const p2wsh = payments3.p2wsh({
1132
+ redeem: { output: witnessScript, network: net },
1133
+ network: net
1134
+ });
1135
+ if (!p2wsh.address || !p2wsh.output) {
1136
+ throw new Error("Failed to create P2WSH output");
1137
+ }
1138
+ let policy = null;
1139
+ if (isXpubKey(payee) && isXpubKey(payer)) {
1140
+ policy = buildSegwitHtlcPolicy({
1141
+ name: name || "HTLC",
1142
+ secretHash,
1143
+ timelock,
1144
+ payeeKey: toKeyInfo(payee),
1145
+ payerKey: toKeyInfo(payer)
1146
+ });
1147
+ }
1148
+ return {
1149
+ address: p2wsh.address,
1150
+ scriptPubkey: Buffer.from(p2wsh.output),
1151
+ witnessScript,
1152
+ scriptHash: Buffer.from(scriptHash),
1153
+ timelock,
1154
+ witness: {
1155
+ secret(signature, preimage) {
1156
+ return [signature, preimage, Buffer.from([1]), witnessScript];
1157
+ },
1158
+ timeout(signature) {
1159
+ return [signature, Buffer.alloc(0), witnessScript];
1160
+ }
1161
+ },
1162
+ policy
1163
+ };
1164
+ }
1165
+ function extractSecret2(witness, secretHash) {
1166
+ if (!witness || witness.length < 4) {
1167
+ return null;
1168
+ }
1169
+ const preimage = witness[1];
1170
+ if (preimage.length !== 32) {
1171
+ return null;
1172
+ }
1173
+ if (secretHash) {
1174
+ const computed = Buffer.from(sha2563(preimage)).toString("hex");
1175
+ if (computed !== secretHash) {
1176
+ return null;
1177
+ }
1178
+ }
1179
+ return preimage.toString("hex");
1180
+ }
1181
+
1182
+ // src/patterns/segwit/multisig.ts
1183
+ import { payments as payments4 } from "bitcoinjs-lib";
1184
+ import { sha256 as sha2564 } from "@noble/hashes/sha2.js";
1185
+ function segwitMultisig(params) {
1186
+ const { threshold, keys, sorted = true, network, name } = params;
1187
+ if (threshold <= 0 || !Number.isInteger(threshold)) {
1188
+ throw new Error("threshold must be a positive integer");
1189
+ }
1190
+ if (keys.length === 0) {
1191
+ throw new Error("At least one key is required");
1192
+ }
1193
+ if (threshold > keys.length) {
1194
+ throw new Error(
1195
+ `threshold (${threshold}) cannot exceed number of keys (${keys.length})`
1196
+ );
1197
+ }
1198
+ if (keys.length > 20) {
1199
+ throw new Error("SegWit multisig is limited to 20 keys");
1200
+ }
1201
+ const net = getNetwork(network);
1202
+ const pubkeys = keys.map((key) => resolveCompressedPubkey(key, network));
1203
+ const witnessScript = multiScript(threshold, pubkeys, sorted);
1204
+ const scriptHash = sha2564(witnessScript);
1205
+ const p2wsh = payments4.p2wsh({
1206
+ redeem: { output: witnessScript, network: net },
1207
+ network: net
1208
+ });
1209
+ if (!p2wsh.address || !p2wsh.output) {
1210
+ throw new Error("Failed to create P2WSH output");
1211
+ }
1212
+ let policy = null;
1213
+ const keyInfos = extractKeyInfos(keys);
1214
+ if (keyInfos) {
1215
+ policy = buildSegwitMultisigPolicy({
1216
+ name: name || `${threshold}-of-${keys.length} Multisig`,
1217
+ threshold,
1218
+ keys: keyInfos,
1219
+ sorted
1220
+ });
1221
+ }
1222
+ return {
1223
+ address: p2wsh.address,
1224
+ scriptPubkey: Buffer.from(p2wsh.output),
1225
+ witnessScript,
1226
+ scriptHash: Buffer.from(scriptHash),
1227
+ policy,
1228
+ /**
1229
+ * Build witness stack for spending.
1230
+ * @param signatures Array of signatures (must have exactly `threshold` signatures)
1231
+ * @returns Witness stack: [OP_0, sig1, sig2, ..., witnessScript]
1232
+ */
1233
+ witness(signatures) {
1234
+ if (signatures.length !== threshold) {
1235
+ throw new Error(
1236
+ `Expected ${threshold} signatures, got ${signatures.length}`
1237
+ );
1238
+ }
1239
+ return [Buffer.alloc(0), ...signatures, witnessScript];
1240
+ }
1241
+ };
1242
+ }
1243
+ export {
1244
+ NUMS,
1245
+ after,
1246
+ and_v,
1247
+ bareKey,
1248
+ bareMultiScript,
1249
+ buildSegwitHtlcPolicy,
1250
+ buildSegwitMultisigPolicy,
1251
+ buildSegwitPolicy,
1252
+ buildTaprootHtlcPolicy,
1253
+ buildTaprootMultisigPolicy,
1254
+ buildTaprootPolicy,
1255
+ cltvScript,
1256
+ csvScript,
1257
+ deriveFromXpub,
1258
+ encodeScriptInt,
1259
+ encodeScriptNumber,
1260
+ extractKeyInfos,
1261
+ extractSecret2 as extractSegwitSecret,
1262
+ extractSecret as extractTaprootSecret,
1263
+ formatKeyInfo,
1264
+ getNetwork,
1265
+ hash160,
1266
+ hash256,
1267
+ hashlockScript,
1268
+ isRawKey,
1269
+ isValidPoint,
1270
+ isXpubKey,
1271
+ keyPlaceholder,
1272
+ multi,
1273
+ multiScript,
1274
+ multi_a,
1275
+ older,
1276
+ or_d,
1277
+ or_i,
1278
+ parsePublicKey,
1279
+ pk,
1280
+ pkScript,
1281
+ pkh,
1282
+ pkhScript,
1283
+ pkhScriptFromHash,
1284
+ resolveCompressedPubkey,
1285
+ resolveXOnlyPubkey,
1286
+ ripemd160,
1287
+ segwitHtlc,
1288
+ segwitMultisig,
1289
+ sha256,
1290
+ simpleCltvScript,
1291
+ simpleHashlockScript,
1292
+ sortedBareMultiScript,
1293
+ sortedMultiScript,
1294
+ sortedmulti,
1295
+ sortedmulti_a,
1296
+ taprootHtlc,
1297
+ taprootMultisig,
1298
+ toKeyInfo,
1299
+ toXOnly,
1300
+ trDescriptor,
1301
+ v,
1302
+ wpkhDescriptor,
1303
+ wshDescriptor
1304
+ };
1305
+ //# sourceMappingURL=index.js.map