@btc-vision/bitcoin 7.0.0-beta.0 → 7.0.0-beta.1

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 (116) hide show
  1. package/README.md +112 -13
  2. package/benchmark-compare/BENCHMARK.md +74 -59
  3. package/benchmark-compare/compare.bench.ts +249 -96
  4. package/benchmark-compare/harness.ts +23 -25
  5. package/benchmark-compare/package.json +1 -0
  6. package/browser/address.d.ts +4 -4
  7. package/browser/address.d.ts.map +1 -1
  8. package/browser/chunks/{psbt-parallel-B-dfm5GZ.js → psbt-parallel-jZ6QcCnM.js} +3128 -2731
  9. package/browser/index.d.ts +1 -1
  10. package/browser/index.d.ts.map +1 -1
  11. package/browser/index.js +603 -585
  12. package/browser/io/base58check.d.ts +1 -25
  13. package/browser/io/base58check.d.ts.map +1 -1
  14. package/browser/io/base64.d.ts.map +1 -1
  15. package/browser/networks.d.ts +1 -0
  16. package/browser/networks.d.ts.map +1 -1
  17. package/browser/payments/bip341.d.ts +17 -0
  18. package/browser/payments/bip341.d.ts.map +1 -1
  19. package/browser/payments/index.d.ts +3 -2
  20. package/browser/payments/index.d.ts.map +1 -1
  21. package/browser/payments/p2mr.d.ts +169 -0
  22. package/browser/payments/p2mr.d.ts.map +1 -0
  23. package/browser/payments/types.d.ts +11 -1
  24. package/browser/payments/types.d.ts.map +1 -1
  25. package/browser/psbt/bip371.d.ts +30 -0
  26. package/browser/psbt/bip371.d.ts.map +1 -1
  27. package/browser/psbt/psbtutils.d.ts +1 -0
  28. package/browser/psbt/psbtutils.d.ts.map +1 -1
  29. package/browser/psbt.d.ts.map +1 -1
  30. package/browser/workers/index.js +9 -9
  31. package/build/address.d.ts +4 -4
  32. package/build/address.d.ts.map +1 -1
  33. package/build/address.js +11 -1
  34. package/build/address.js.map +1 -1
  35. package/build/index.d.ts +1 -1
  36. package/build/index.d.ts.map +1 -1
  37. package/build/index.js.map +1 -1
  38. package/build/io/base58check.d.ts +1 -25
  39. package/build/io/base58check.d.ts.map +1 -1
  40. package/build/io/base58check.js +1 -31
  41. package/build/io/base58check.js.map +1 -1
  42. package/build/io/base64.d.ts.map +1 -1
  43. package/build/io/base64.js +3 -0
  44. package/build/io/base64.js.map +1 -1
  45. package/build/networks.d.ts +1 -0
  46. package/build/networks.d.ts.map +1 -1
  47. package/build/networks.js +12 -0
  48. package/build/networks.js.map +1 -1
  49. package/build/payments/bip341.d.ts +17 -0
  50. package/build/payments/bip341.d.ts.map +1 -1
  51. package/build/payments/bip341.js +32 -1
  52. package/build/payments/bip341.js.map +1 -1
  53. package/build/payments/index.d.ts +3 -2
  54. package/build/payments/index.d.ts.map +1 -1
  55. package/build/payments/index.js +2 -1
  56. package/build/payments/index.js.map +1 -1
  57. package/build/payments/p2mr.d.ts +178 -0
  58. package/build/payments/p2mr.d.ts.map +1 -0
  59. package/build/payments/p2mr.js +555 -0
  60. package/build/payments/p2mr.js.map +1 -0
  61. package/build/payments/types.d.ts +11 -1
  62. package/build/payments/types.d.ts.map +1 -1
  63. package/build/payments/types.js +1 -0
  64. package/build/payments/types.js.map +1 -1
  65. package/build/psbt/bip371.d.ts +30 -0
  66. package/build/psbt/bip371.d.ts.map +1 -1
  67. package/build/psbt/bip371.js +80 -15
  68. package/build/psbt/bip371.js.map +1 -1
  69. package/build/psbt/psbtutils.d.ts +1 -0
  70. package/build/psbt/psbtutils.d.ts.map +1 -1
  71. package/build/psbt/psbtutils.js +2 -0
  72. package/build/psbt/psbtutils.js.map +1 -1
  73. package/build/psbt.d.ts.map +1 -1
  74. package/build/psbt.js +3 -2
  75. package/build/psbt.js.map +1 -1
  76. package/build/pubkey.js +1 -1
  77. package/build/pubkey.js.map +1 -1
  78. package/build/tsconfig.build.tsbuildinfo +1 -1
  79. package/documentation/README.md +122 -0
  80. package/documentation/address.md +820 -0
  81. package/documentation/block.md +679 -0
  82. package/documentation/crypto.md +461 -0
  83. package/documentation/ecc.md +584 -0
  84. package/documentation/errors.md +656 -0
  85. package/documentation/io.md +942 -0
  86. package/documentation/networks.md +625 -0
  87. package/documentation/p2mr.md +380 -0
  88. package/documentation/payments.md +1485 -0
  89. package/documentation/psbt.md +1400 -0
  90. package/documentation/script.md +730 -0
  91. package/documentation/taproot.md +670 -0
  92. package/documentation/transaction.md +943 -0
  93. package/documentation/types.md +587 -0
  94. package/documentation/workers.md +1007 -0
  95. package/eslint.config.js +3 -0
  96. package/package.json +17 -14
  97. package/src/address.ts +22 -10
  98. package/src/index.ts +1 -0
  99. package/src/io/base58check.ts +1 -35
  100. package/src/io/base64.ts +5 -0
  101. package/src/networks.ts +13 -0
  102. package/src/payments/bip341.ts +36 -1
  103. package/src/payments/index.ts +4 -0
  104. package/src/payments/p2mr.ts +660 -0
  105. package/src/payments/types.ts +12 -0
  106. package/src/psbt/bip371.ts +84 -13
  107. package/src/psbt/psbtutils.ts +2 -0
  108. package/src/psbt.ts +4 -2
  109. package/src/pubkey.ts +1 -1
  110. package/test/bitcoin.core.spec.ts +1 -1
  111. package/test/fixtures/p2mr.json +270 -0
  112. package/test/integration/taproot.spec.ts +7 -3
  113. package/test/opnetTestnet.spec.ts +302 -0
  114. package/test/payments.spec.ts +3 -1
  115. package/test/psbt.spec.ts +297 -2
  116. package/test/tsconfig.json +2 -2
@@ -0,0 +1,730 @@
1
+ # Script - Bitcoin Script Compilation, Decompilation, and Utilities
2
+
3
+ The `script` module provides tools for working with Bitcoin Script: compiling human-readable or structured representations into raw byte buffers, decompiling buffers back into structured chunks, converting to and from ASM notation, validating public keys and signatures within scripts, and encoding/decoding script numbers and script signatures. It also re-exports the full set of Bitcoin opcodes.
4
+
5
+ ## Overview
6
+
7
+ | Concept | Description |
8
+ |---------|-------------|
9
+ | Chunks | An array of opcodes (`number`) and data pushes (`Uint8Array`) representing a script |
10
+ | Compiled script | A `Uint8Array` (branded as `Script`) containing the serialized byte-level encoding |
11
+ | ASM | A space-separated string of opcode names and hex-encoded data pushes |
12
+ | Stack | An array of `Uint8Array` elements extracted from push-only scripts |
13
+ | Script number | A variable-length little-endian signed integer encoding used by Bitcoin Script |
14
+ | Script signature | A DER-encoded ECDSA signature with an appended hash type byte |
15
+
16
+ ### Import
17
+
18
+ ```typescript
19
+ import * as script from '@btc-vision/bitcoin/script';
20
+ // or
21
+ import { script } from '@btc-vision/bitcoin';
22
+
23
+ // Destructured access
24
+ const { compile, decompile, toASM, fromASM, toStack, opcodes } = script;
25
+ const { encode, decode } = script.number; // script number
26
+ const { encode, decode } = script.signature; // script signature
27
+ ```
28
+
29
+ ---
30
+
31
+ ## compile()
32
+
33
+ Converts an array of chunks (opcodes and data buffers) into a single compiled `Script` buffer. If the input is already a `Uint8Array`, it is returned as-is.
34
+
35
+ ```typescript
36
+ function compile(chunks: Uint8Array | Stack): Script;
37
+ ```
38
+
39
+ ### Behavior
40
+
41
+ 1. Each numeric element is written as a single byte (the opcode value).
42
+ 2. Each `Uint8Array` element is written using Bitcoin's push data encoding:
43
+ - Data that can be represented as a minimal opcode (`OP_0`, `OP_1` through `OP_16`, `OP_1NEGATE`) is encoded as a single opcode byte per BIP 62.3 (minimal push policy).
44
+ - Otherwise the appropriate `OP_PUSHDATA` prefix is used followed by the raw bytes.
45
+ 3. Throws `TypeError` if the input is not an array.
46
+ 4. Throws `Error` if the final buffer length does not match the computed size.
47
+
48
+ ### Example
49
+
50
+ ```typescript
51
+ import { script } from '@btc-vision/bitcoin';
52
+ const { compile, opcodes } = script;
53
+
54
+ // P2PKH scriptPubKey: OP_DUP OP_HASH160 <20-byte hash> OP_EQUALVERIFY OP_CHECKSIG
55
+ const pubKeyHash = new Uint8Array(20); // 20-byte public key hash
56
+ const compiled = compile([
57
+ opcodes.OP_DUP,
58
+ opcodes.OP_HASH160,
59
+ pubKeyHash,
60
+ opcodes.OP_EQUALVERIFY,
61
+ opcodes.OP_CHECKSIG,
62
+ ]);
63
+ // compiled is a Uint8Array of length 25
64
+
65
+ // Minimal push: a 1-byte buffer containing 0x05 compiles to OP_5 (a single byte)
66
+ const minimal = compile([new Uint8Array([5])]);
67
+ // minimal[0] === 0x55 (OP_5)
68
+ ```
69
+
70
+ ---
71
+
72
+ ## decompile()
73
+
74
+ Converts a compiled `Uint8Array` buffer back into an array of chunks. If the input is already an array, it is returned as-is.
75
+
76
+ ```typescript
77
+ function decompile(buffer: Uint8Array | Stack): Array<number | Uint8Array> | null;
78
+ ```
79
+
80
+ **Throws** `TypeError` if the input is neither a `Uint8Array` nor an array. Returns `null` if the buffer is malformed (e.g., truncated push data).
81
+
82
+ ### Behavior
83
+
84
+ 1. Iterates through the buffer byte by byte.
85
+ 2. Bytes in the range `0x01`..`0x4e` (`OP_PUSHDATA4`) are treated as push data instructions; the push data prefix is decoded and the corresponding number of bytes are read as a `Uint8Array` chunk.
86
+ 3. Data that can be represented as a minimal opcode is converted to its numeric opcode form.
87
+ 4. All other bytes are treated as opcode numbers.
88
+ 5. Returns `null` if the buffer is malformed (e.g., truncated push data).
89
+
90
+ ### Example
91
+
92
+ ```typescript
93
+ import { script } from '@btc-vision/bitcoin';
94
+ const { decompile, opcodes } = script;
95
+
96
+ const raw = new Uint8Array([0x76, 0xa9, 0x14, ...new Array(20).fill(0), 0x88, 0xac]);
97
+ const chunks = decompile(raw);
98
+ // chunks = [118(OP_DUP), 169(OP_HASH160), Uint8Array(20), 136(OP_EQUALVERIFY), 172(OP_CHECKSIG)]
99
+
100
+ if (chunks !== null) {
101
+ console.log(chunks[0] === opcodes.OP_DUP); // true
102
+ console.log(chunks[1] === opcodes.OP_HASH160); // true
103
+ console.log(chunks[2] instanceof Uint8Array); // true (the 20-byte hash)
104
+ console.log(chunks[3] === opcodes.OP_EQUALVERIFY); // true
105
+ console.log(chunks[4] === opcodes.OP_CHECKSIG); // true
106
+ }
107
+ ```
108
+
109
+ ---
110
+
111
+ ## toASM()
112
+
113
+ Converts chunks (or a compiled buffer) into a human-readable ASM string. Each chunk is separated by a space. Opcodes are rendered by name (e.g., `OP_DUP`), and data pushes are rendered as lowercase hex strings. Minimal data pushes are rendered as their opcode name.
114
+
115
+ ```typescript
116
+ function toASM(chunks: Uint8Array | Stack): string;
117
+ ```
118
+
119
+ **Throws** `Error` if the input `Uint8Array` cannot be decompiled (e.g., truncated push data).
120
+
121
+ ### Example
122
+
123
+ ```typescript
124
+ import { script } from '@btc-vision/bitcoin';
125
+
126
+ const asm = script.toASM(compiledScript);
127
+ // "OP_DUP OP_HASH160 0000000000000000000000000000000000000000 OP_EQUALVERIFY OP_CHECKSIG"
128
+ ```
129
+
130
+ ---
131
+
132
+ ## fromASM()
133
+
134
+ Parses a human-readable ASM string back into a compiled `Script` buffer. Each token is either an opcode name (e.g., `OP_CHECKSIG`) or a hex-encoded data push.
135
+
136
+ ```typescript
137
+ function fromASM(asm: string): Script;
138
+ ```
139
+
140
+ **Throws** `TypeError` if the input is not a string or if any non-opcode token is not a valid hex string.
141
+
142
+ ### Behavior
143
+
144
+ 1. Splits the input string on spaces.
145
+ 2. Tokens matching a known opcode name are converted to the corresponding numeric value.
146
+ 3. All other tokens must be valid hex strings and are converted to `Uint8Array` data pushes.
147
+ 4. The resulting array of chunks is passed through `compile()`.
148
+
149
+ ### Example
150
+
151
+ ```typescript
152
+ import { script } from '@btc-vision/bitcoin';
153
+
154
+ const compiled = script.fromASM('OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG');
155
+ // compiled is a Uint8Array containing the serialized script
156
+
157
+ // Round-trip
158
+ const asm = script.toASM(compiled);
159
+ // "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG"
160
+ ```
161
+
162
+ ---
163
+
164
+ ## toStack()
165
+
166
+ Converts a push-only script (compiled buffer or chunk array) into an array of `Uint8Array` stack elements. This is useful for extracting witness or scriptSig data elements.
167
+
168
+ ```typescript
169
+ function toStack(chunks: Uint8Array | Stack): Uint8Array[];
170
+ ```
171
+
172
+ ### Behavior
173
+
174
+ 1. Decompiles the input if it is a `Uint8Array`.
175
+ 2. Validates that the script is push-only (throws `TypeError` otherwise).
176
+ 3. Converts each chunk:
177
+ - `Uint8Array` chunks are returned as-is.
178
+ - `OP_0` is converted to an empty `Uint8Array`.
179
+ - `OP_1` through `OP_16` are converted to their script number encoding (e.g., `OP_5` becomes a buffer encoding the number 5).
180
+ - `OP_1NEGATE` is converted to the script number encoding of -1.
181
+
182
+ ### Example
183
+
184
+ ```typescript
185
+ import { script } from '@btc-vision/bitcoin';
186
+
187
+ // A push-only script with OP_0 and two data pushes
188
+ const chunks = [script.opcodes.OP_0, new Uint8Array([0xab, 0xcd]), new Uint8Array([0xef])];
189
+ const stack = script.toStack(chunks);
190
+ // stack[0] => Uint8Array(0) (empty buffer for OP_0)
191
+ // stack[1] => Uint8Array([0xab, 0xcd])
192
+ // stack[2] => Uint8Array([0xef])
193
+ ```
194
+
195
+ ---
196
+
197
+ ## isPushOnly()
198
+
199
+ Returns `true` if every element in the chunk array is either a `Uint8Array` data push or a numeric push opcode (`OP_0`, `OP_1`..`OP_16`, `OP_1NEGATE`).
200
+
201
+ ```typescript
202
+ function isPushOnly(value: Stack): boolean;
203
+ ```
204
+
205
+ ### Example
206
+
207
+ ```typescript
208
+ import { script } from '@btc-vision/bitcoin';
209
+ const { opcodes } = script;
210
+
211
+ script.isPushOnly([opcodes.OP_0, new Uint8Array([1, 2, 3])]); // true
212
+ script.isPushOnly([opcodes.OP_DUP, new Uint8Array([1, 2, 3])]); // false (OP_DUP is not a push)
213
+ ```
214
+
215
+ ---
216
+
217
+ ## countNonPushOnlyOPs()
218
+
219
+ Returns the number of elements in the chunk array that are NOT push-only (i.e., opcodes other than `OP_0`, `OP_1`..`OP_16`, `OP_1NEGATE`, and data buffers).
220
+
221
+ ```typescript
222
+ function countNonPushOnlyOPs(value: Stack): number;
223
+ ```
224
+
225
+ ### Example
226
+
227
+ ```typescript
228
+ import { script } from '@btc-vision/bitcoin';
229
+ const { opcodes } = script;
230
+
231
+ const chunks = [opcodes.OP_DUP, opcodes.OP_HASH160, new Uint8Array(20), opcodes.OP_EQUALVERIFY, opcodes.OP_CHECKSIG];
232
+ script.countNonPushOnlyOPs(chunks); // 4 (OP_DUP, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG)
233
+ ```
234
+
235
+ ---
236
+
237
+ ## isCanonicalPubKey()
238
+
239
+ Returns `true` if the buffer is a valid SEC-encoded public key (compressed 33 bytes with `0x02`/`0x03` prefix, or uncompressed 65 bytes with `0x04`/`0x06`/`0x07` prefix). Validates that x and y coordinates are non-zero and less than the secp256k1 field prime.
240
+
241
+ ```typescript
242
+ function isCanonicalPubKey(buffer: Uint8Array): boolean;
243
+ ```
244
+
245
+ ### Accepted formats
246
+
247
+ | Format | Length | Prefix byte |
248
+ |--------|--------|-------------|
249
+ | Compressed | 33 bytes | `0x02` or `0x03` |
250
+ | Uncompressed | 65 bytes | `0x04`, `0x06`, or `0x07` |
251
+
252
+ ### Example
253
+
254
+ ```typescript
255
+ import { script } from '@btc-vision/bitcoin';
256
+
257
+ const compressedKey = new Uint8Array(33);
258
+ compressedKey[0] = 0x02;
259
+ compressedKey[1] = 0x01; // non-zero x coordinate
260
+ script.isCanonicalPubKey(compressedKey); // true (if valid point)
261
+
262
+ script.isCanonicalPubKey(new Uint8Array(20)); // false (wrong length)
263
+ ```
264
+
265
+ ---
266
+
267
+ ## isCanonicalScriptSignature()
268
+
269
+ Returns `true` if the buffer is a valid DER-encoded script signature: a BIP 66-compliant DER signature followed by a valid hash type byte. Valid hash types are `0x01`, `0x02`, `0x03`, `0x81`, `0x82`, `0x83` (SIGHASH_ALL, SIGHASH_NONE, SIGHASH_SINGLE, each optionally OR'd with `0x80` for SIGHASH_ANYONECANPAY).
270
+
271
+ ```typescript
272
+ function isCanonicalScriptSignature(buffer: Uint8Array): boolean;
273
+ ```
274
+
275
+ ### Example
276
+
277
+ ```typescript
278
+ import { script } from '@btc-vision/bitcoin';
279
+
280
+ // A properly DER-encoded signature with SIGHASH_ALL (0x01) appended
281
+ script.isCanonicalScriptSignature(derSignatureWithHashType); // true or false
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Script Number Module (`script.number`)
287
+
288
+ Encodes and decodes integers using Bitcoin Script's variable-length little-endian signed integer format. This encoding is used by arithmetic opcodes (`OP_ADD`, `OP_SUB`, etc.) and locktime checks.
289
+
290
+ ### script.number.decode()
291
+
292
+ ```typescript
293
+ function decode(buffer: Buffer, maxLength?: number, minimal?: boolean): number;
294
+ ```
295
+
296
+ | Parameter | Default | Description |
297
+ |-----------|---------|-------------|
298
+ | `buffer` | -- | The buffer containing the encoded script number |
299
+ | `maxLength` | `4` | Maximum allowed byte length (set to 5 for lock times) |
300
+ | `minimal` | `true` | If `true`, rejects non-minimally-encoded numbers |
301
+
302
+ **Encoding rules:**
303
+ - An empty buffer decodes to `0`.
304
+ - The number is stored in little-endian byte order.
305
+ - The most significant bit of the last byte is the sign bit.
306
+ - If the value's MSB would collide with the sign bit, an extra byte is added.
307
+ - Supports up to 5 bytes (40-bit numbers) for locktime values.
308
+
309
+ ### script.number.encode()
310
+
311
+ ```typescript
312
+ function encode(number: number): Buffer;
313
+ ```
314
+
315
+ Encodes a JavaScript number into a minimally-encoded script number buffer.
316
+
317
+ ### Example
318
+
319
+ ```typescript
320
+ import { script } from '@btc-vision/bitcoin';
321
+
322
+ // Encode
323
+ const buf = script.number.encode(1000);
324
+ // buf => Buffer [0xe8, 0x03]
325
+
326
+ const negBuf = script.number.encode(-1000);
327
+ // negBuf => Buffer [0xe8, 0x83]
328
+
329
+ // Decode
330
+ script.number.decode(Buffer.from([0xe8, 0x03])); // 1000
331
+ script.number.decode(Buffer.from([0xe8, 0x83])); // -1000
332
+ script.number.decode(Buffer.from([])); // 0
333
+
334
+ // 5-byte locktime value
335
+ script.number.decode(Buffer.from([0x01, 0x00, 0x00, 0x00, 0x00]), 5); // 1
336
+ ```
337
+
338
+ ---
339
+
340
+ ## Script Signature Module (`script.signature`)
341
+
342
+ Encodes and decodes ECDSA signatures used in Bitcoin Script. A script signature consists of a DER-encoded signature (BIP 66) followed by a one-byte hash type flag (BIP 62).
343
+
344
+ ### ScriptSignature Interface
345
+
346
+ ```typescript
347
+ interface ScriptSignature {
348
+ signature: Uint8Array; // 64 bytes: 32-byte R + 32-byte S (raw, not DER)
349
+ hashType: number; // one of 0x01, 0x02, 0x03, 0x81, 0x82, 0x83
350
+ }
351
+ ```
352
+
353
+ ### script.signature.decode()
354
+
355
+ ```typescript
356
+ function decode(buffer: Uint8Array): ScriptSignature;
357
+ ```
358
+
359
+ Decodes a DER-encoded script signature (with trailing hash type byte) into a `ScriptSignature` object. The `signature` field in the result is the raw 64-byte `R || S` value (each component zero-padded to 32 bytes).
360
+
361
+ ### script.signature.encode()
362
+
363
+ ```typescript
364
+ function encode(signature: Uint8Array, hashType: number): Uint8Array;
365
+ ```
366
+
367
+ Encodes a raw 64-byte signature and a hash type into a DER-encoded script signature buffer. The `signature` parameter must be exactly 64 bytes. The `hashType` must be a valid BIP 62 hash type.
368
+
369
+ ### Hash Type Values
370
+
371
+ | Constant | Value | Description |
372
+ |----------|-------|-------------|
373
+ | SIGHASH_ALL | `0x01` | Sign all inputs and outputs |
374
+ | SIGHASH_NONE | `0x02` | Sign all inputs, no outputs |
375
+ | SIGHASH_SINGLE | `0x03` | Sign all inputs, only the output at the same index |
376
+ | SIGHASH_ALL \| ANYONECANPAY | `0x81` | Sign only own input, all outputs |
377
+ | SIGHASH_NONE \| ANYONECANPAY | `0x82` | Sign only own input, no outputs |
378
+ | SIGHASH_SINGLE \| ANYONECANPAY | `0x83` | Sign only own input, matching output |
379
+
380
+ ### Example
381
+
382
+ ```typescript
383
+ import { script } from '@btc-vision/bitcoin';
384
+
385
+ // Decode a DER-encoded script signature
386
+ const decoded = script.signature.decode(derEncodedSigWithHashType);
387
+ console.log(decoded.signature.length); // 64 (raw R || S)
388
+ console.log(decoded.hashType); // e.g. 0x01
389
+
390
+ // Encode a raw signature with hash type
391
+ const raw64 = new Uint8Array(64); // 32-byte R + 32-byte S
392
+ const encoded = script.signature.encode(raw64, 0x01);
393
+ // encoded is DER-encoded with 0x01 hash type appended
394
+ ```
395
+
396
+ ---
397
+
398
+ ## Push Data Encoding
399
+
400
+ The push data module handles the variable-length encoding used to push data onto the Bitcoin Script stack. This is used internally by `compile()` and `decompile()`.
401
+
402
+ | Data length | Encoding | Total prefix size |
403
+ |-------------|----------|-------------------|
404
+ | 0 - 75 bytes | Single byte (length = opcode) | 1 byte |
405
+ | 76 - 255 bytes | `OP_PUSHDATA1` + 1-byte length | 2 bytes |
406
+ | 256 - 65535 bytes | `OP_PUSHDATA2` + 2-byte LE length | 3 bytes |
407
+ | 65536+ bytes | `OP_PUSHDATA4` + 4-byte LE length | 5 bytes |
408
+
409
+ ---
410
+
411
+ ## Complete Opcodes Reference
412
+
413
+ All opcodes are available via `script.opcodes` (or imported directly from `@btc-vision/bitcoin`).
414
+
415
+ ```typescript
416
+ import { script } from '@btc-vision/bitcoin';
417
+
418
+ const { opcodes } = script;
419
+ opcodes.OP_CHECKSIG; // 172
420
+
421
+ // Reverse lookup: build a name-by-value map from the opcodes object
422
+ const reverseOps: Record<number, string> = {};
423
+ for (const [name, value] of Object.entries(opcodes)) {
424
+ reverseOps[value as number] = name;
425
+ }
426
+ reverseOps[172]; // "OP_CHECKSIG"
427
+ ```
428
+
429
+ > **Note:** `getReverseOps()` is defined in `src/opcodes.ts` but is NOT re-exported from the main `@btc-vision/bitcoin` entry point. Use the manual reverse-mapping approach above, or import from the opcodes module directly.
430
+
431
+ ### Constants and Push Numbers
432
+
433
+ | Opcode | Decimal | Hex | Description |
434
+ |--------|---------|-----|-------------|
435
+ | `OP_FALSE` / `OP_0` | 0 | `0x00` | Push empty byte array (false) |
436
+ | `OP_PUSHDATA1` | 76 | `0x4c` | Next 1 byte is data length |
437
+ | `OP_PUSHDATA2` | 77 | `0x4d` | Next 2 bytes (LE) are data length |
438
+ | `OP_PUSHDATA4` | 78 | `0x4e` | Next 4 bytes (LE) are data length |
439
+ | `OP_1NEGATE` | 79 | `0x4f` | Push -1 |
440
+ | `OP_RESERVED` | 80 | `0x50` | Reserved (causes script failure if executed) |
441
+ | `OP_TRUE` / `OP_1` | 81 | `0x51` | Push 1 |
442
+ | `OP_2` | 82 | `0x52` | Push 2 |
443
+ | `OP_3` | 83 | `0x53` | Push 3 |
444
+ | `OP_4` | 84 | `0x54` | Push 4 |
445
+ | `OP_5` | 85 | `0x55` | Push 5 |
446
+ | `OP_6` | 86 | `0x56` | Push 6 |
447
+ | `OP_7` | 87 | `0x57` | Push 7 |
448
+ | `OP_8` | 88 | `0x58` | Push 8 |
449
+ | `OP_9` | 89 | `0x59` | Push 9 |
450
+ | `OP_10` | 90 | `0x5a` | Push 10 |
451
+ | `OP_11` | 91 | `0x5b` | Push 11 |
452
+ | `OP_12` | 92 | `0x5c` | Push 12 |
453
+ | `OP_13` | 93 | `0x5d` | Push 13 |
454
+ | `OP_14` | 94 | `0x5e` | Push 14 |
455
+ | `OP_15` | 95 | `0x5f` | Push 15 |
456
+ | `OP_16` | 96 | `0x60` | Push 16 |
457
+
458
+ ### Flow Control
459
+
460
+ | Opcode | Decimal | Hex | Description |
461
+ |--------|---------|-----|-------------|
462
+ | `OP_NOP` | 97 | `0x61` | No operation |
463
+ | `OP_VER` | 98 | `0x62` | Reserved (push protocol version, disabled) |
464
+ | `OP_IF` | 99 | `0x63` | Execute if top stack value is true |
465
+ | `OP_NOTIF` | 100 | `0x64` | Execute if top stack value is false |
466
+ | `OP_VERIF` | 101 | `0x65` | Reserved (always fails) |
467
+ | `OP_VERNOTIF` | 102 | `0x66` | Reserved (always fails) |
468
+ | `OP_ELSE` | 103 | `0x67` | Else branch of OP_IF/OP_NOTIF |
469
+ | `OP_ENDIF` | 104 | `0x68` | End of OP_IF/OP_NOTIF block |
470
+ | `OP_VERIFY` | 105 | `0x69` | Fail if top stack value is false |
471
+ | `OP_RETURN` | 106 | `0x6a` | Mark output as provably unspendable |
472
+
473
+ ### Stack Operations
474
+
475
+ | Opcode | Decimal | Hex | Description |
476
+ |--------|---------|-----|-------------|
477
+ | `OP_TOALTSTACK` | 107 | `0x6b` | Move top item to alt stack |
478
+ | `OP_FROMALTSTACK` | 108 | `0x6c` | Move top item from alt stack |
479
+ | `OP_2DROP` | 109 | `0x6d` | Remove top two items |
480
+ | `OP_2DUP` | 110 | `0x6e` | Duplicate top two items |
481
+ | `OP_3DUP` | 111 | `0x6f` | Duplicate top three items |
482
+ | `OP_2OVER` | 112 | `0x70` | Copy 3rd and 4th items to top |
483
+ | `OP_2ROT` | 113 | `0x71` | Move 5th and 6th items to top |
484
+ | `OP_2SWAP` | 114 | `0x72` | Swap top two pairs |
485
+ | `OP_IFDUP` | 115 | `0x73` | Duplicate top if non-zero |
486
+ | `OP_DEPTH` | 116 | `0x74` | Push stack depth |
487
+ | `OP_DROP` | 117 | `0x75` | Remove top item |
488
+ | `OP_DUP` | 118 | `0x76` | Duplicate top item |
489
+ | `OP_NIP` | 119 | `0x77` | Remove second-to-top item |
490
+ | `OP_OVER` | 120 | `0x78` | Copy second-to-top item to top |
491
+ | `OP_PICK` | 121 | `0x79` | Copy nth item to top |
492
+ | `OP_ROLL` | 122 | `0x7a` | Move nth item to top |
493
+ | `OP_ROT` | 123 | `0x7b` | Rotate top three items |
494
+ | `OP_SWAP` | 124 | `0x7c` | Swap top two items |
495
+ | `OP_TUCK` | 125 | `0x7d` | Copy top item below second |
496
+
497
+ ### Splice Operations (Disabled)
498
+
499
+ | Opcode | Decimal | Hex | Description |
500
+ |--------|---------|-----|-------------|
501
+ | `OP_CAT` | 126 | `0x7e` | Concatenate (disabled) |
502
+ | `OP_SUBSTR` | 127 | `0x7f` | Substring (disabled) |
503
+ | `OP_LEFT` | 128 | `0x80` | Left substring (disabled) |
504
+ | `OP_RIGHT` | 129 | `0x81` | Right substring (disabled) |
505
+ | `OP_SIZE` | 130 | `0x82` | Push string length |
506
+
507
+ ### Bitwise Logic
508
+
509
+ | Opcode | Decimal | Hex | Description |
510
+ |--------|---------|-----|-------------|
511
+ | `OP_INVERT` | 131 | `0x83` | Bitwise NOT (disabled) |
512
+ | `OP_AND` | 132 | `0x84` | Bitwise AND (disabled) |
513
+ | `OP_OR` | 133 | `0x85` | Bitwise OR (disabled) |
514
+ | `OP_XOR` | 134 | `0x86` | Bitwise XOR (disabled) |
515
+ | `OP_EQUAL` | 135 | `0x87` | Push 1 if top two are byte-for-byte equal |
516
+ | `OP_EQUALVERIFY` | 136 | `0x88` | OP_EQUAL then OP_VERIFY |
517
+ | `OP_RESERVED1` | 137 | `0x89` | Reserved (fails if executed) |
518
+ | `OP_RESERVED2` | 138 | `0x8a` | Reserved (fails if executed) |
519
+
520
+ ### Arithmetic
521
+
522
+ | Opcode | Decimal | Hex | Description |
523
+ |--------|---------|-----|-------------|
524
+ | `OP_1ADD` | 139 | `0x8b` | Add 1 |
525
+ | `OP_1SUB` | 140 | `0x8c` | Subtract 1 |
526
+ | `OP_2MUL` | 141 | `0x8d` | Multiply by 2 (disabled) |
527
+ | `OP_2DIV` | 142 | `0x8e` | Divide by 2 (disabled) |
528
+ | `OP_NEGATE` | 143 | `0x8f` | Negate sign |
529
+ | `OP_ABS` | 144 | `0x90` | Absolute value |
530
+ | `OP_NOT` | 145 | `0x91` | Logical NOT (0 becomes 1, else 0) |
531
+ | `OP_0NOTEQUAL` | 146 | `0x92` | Push 0 if input is 0, else 1 |
532
+ | `OP_ADD` | 147 | `0x93` | Add top two items |
533
+ | `OP_SUB` | 148 | `0x94` | Subtract top from second |
534
+ | `OP_MUL` | 149 | `0x95` | Multiply (disabled) |
535
+ | `OP_DIV` | 150 | `0x96` | Divide (disabled) |
536
+ | `OP_MOD` | 151 | `0x97` | Modulo (disabled) |
537
+ | `OP_LSHIFT` | 152 | `0x98` | Left shift (disabled) |
538
+ | `OP_RSHIFT` | 153 | `0x99` | Right shift (disabled) |
539
+ | `OP_BOOLAND` | 154 | `0x9a` | Boolean AND |
540
+ | `OP_BOOLOR` | 155 | `0x9b` | Boolean OR |
541
+ | `OP_NUMEQUAL` | 156 | `0x9c` | Push 1 if numbers are equal |
542
+ | `OP_NUMEQUALVERIFY` | 157 | `0x9d` | OP_NUMEQUAL then OP_VERIFY |
543
+ | `OP_NUMNOTEQUAL` | 158 | `0x9e` | Push 1 if numbers are not equal |
544
+ | `OP_LESSTHAN` | 159 | `0x9f` | Push 1 if a < b |
545
+ | `OP_GREATERTHAN` | 160 | `0xa0` | Push 1 if a > b |
546
+ | `OP_LESSTHANOREQUAL` | 161 | `0xa1` | Push 1 if a <= b |
547
+ | `OP_GREATERTHANOREQUAL` | 162 | `0xa2` | Push 1 if a >= b |
548
+ | `OP_MIN` | 163 | `0xa3` | Push the smaller of two values |
549
+ | `OP_MAX` | 164 | `0xa4` | Push the larger of two values |
550
+ | `OP_WITHIN` | 165 | `0xa5` | Push 1 if x is within [min, max) |
551
+
552
+ ### Cryptographic Operations
553
+
554
+ | Opcode | Decimal | Hex | Description |
555
+ |--------|---------|-----|-------------|
556
+ | `OP_RIPEMD160` | 166 | `0xa6` | RIPEMD-160 hash |
557
+ | `OP_SHA1` | 167 | `0xa7` | SHA-1 hash |
558
+ | `OP_SHA256` | 168 | `0xa8` | SHA-256 hash |
559
+ | `OP_HASH160` | 169 | `0xa9` | SHA-256 then RIPEMD-160 |
560
+ | `OP_HASH256` | 170 | `0xaa` | Double SHA-256 |
561
+ | `OP_CODESEPARATOR` | 171 | `0xab` | Mark beginning of signature-checked script |
562
+ | `OP_CHECKSIG` | 172 | `0xac` | Verify signature against public key |
563
+ | `OP_CHECKSIGVERIFY` | 173 | `0xad` | OP_CHECKSIG then OP_VERIFY |
564
+ | `OP_CHECKMULTISIG` | 174 | `0xae` | Verify m-of-n multisig |
565
+ | `OP_CHECKMULTISIGVERIFY` | 175 | `0xaf` | OP_CHECKMULTISIG then OP_VERIFY |
566
+
567
+ ### Locktime and Expansion
568
+
569
+ | Opcode | Decimal | Hex | Description |
570
+ |--------|---------|-----|-------------|
571
+ | `OP_NOP1` | 176 | `0xb0` | No operation (reserved for expansion) |
572
+ | `OP_NOP2` / `OP_CHECKLOCKTIMEVERIFY` | 177 | `0xb1` | Verify locktime (BIP 65) |
573
+ | `OP_NOP3` / `OP_CHECKSEQUENCEVERIFY` | 178 | `0xb2` | Verify sequence number (BIP 112) |
574
+ | `OP_NOP4` | 179 | `0xb3` | No operation (reserved) |
575
+ | `OP_NOP5` | 180 | `0xb4` | No operation (reserved) |
576
+ | `OP_NOP6` | 181 | `0xb5` | No operation (reserved) |
577
+ | `OP_NOP7` | 182 | `0xb6` | No operation (reserved) |
578
+ | `OP_NOP8` | 183 | `0xb7` | No operation (reserved) |
579
+ | `OP_NOP9` | 184 | `0xb8` | No operation (reserved) |
580
+ | `OP_NOP10` | 185 | `0xb9` | No operation (reserved) |
581
+
582
+ ### Tapscript
583
+
584
+ | Opcode | Decimal | Hex | Description |
585
+ |--------|---------|-----|-------------|
586
+ | `OP_CHECKSIGADD` | 186 | `0xba` | Tapscript: verify signature and increment counter (BIP 342) |
587
+
588
+ ### Template Matching (Internal)
589
+
590
+ | Opcode | Decimal | Hex | Description |
591
+ |--------|---------|-----|-------------|
592
+ | `OP_PUBKEYHASH` | 253 | `0xfd` | Template placeholder for pubkey hash |
593
+ | `OP_PUBKEY` | 254 | `0xfe` | Template placeholder for pubkey |
594
+ | `OP_INVALIDOPCODE` | 255 | `0xff` | Invalid opcode marker |
595
+
596
+ ---
597
+
598
+ ## Code Examples
599
+
600
+ ### Building a P2PKH Script
601
+
602
+ ```typescript
603
+ import { script } from '@btc-vision/bitcoin';
604
+ const { compile, opcodes } = script;
605
+
606
+ // scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
607
+ function buildP2PKH(pubKeyHash: Uint8Array): Uint8Array {
608
+ if (pubKeyHash.length !== 20) throw new Error('Expected 20-byte hash');
609
+ return compile([
610
+ opcodes.OP_DUP,
611
+ opcodes.OP_HASH160,
612
+ pubKeyHash,
613
+ opcodes.OP_EQUALVERIFY,
614
+ opcodes.OP_CHECKSIG,
615
+ ]);
616
+ }
617
+ ```
618
+
619
+ ### Building an OP_RETURN Data Script
620
+
621
+ ```typescript
622
+ import { script } from '@btc-vision/bitcoin';
623
+ const { compile, opcodes } = script;
624
+
625
+ function buildOpReturn(data: Uint8Array): Uint8Array {
626
+ return compile([opcodes.OP_RETURN, data]);
627
+ }
628
+ ```
629
+
630
+ ### Building a CLTV Timelocked Script
631
+
632
+ ```typescript
633
+ import { script } from '@btc-vision/bitcoin';
634
+ const { compile, opcodes, number: scriptNum } = script;
635
+
636
+ function buildTimelocked(locktime: number, pubKeyHash: Uint8Array): Uint8Array {
637
+ return compile([
638
+ scriptNum.encode(locktime),
639
+ opcodes.OP_CHECKLOCKTIMEVERIFY,
640
+ opcodes.OP_DROP,
641
+ opcodes.OP_DUP,
642
+ opcodes.OP_HASH160,
643
+ pubKeyHash,
644
+ opcodes.OP_EQUALVERIFY,
645
+ opcodes.OP_CHECKSIG,
646
+ ]);
647
+ }
648
+ ```
649
+
650
+ ### Parsing and Inspecting a Script
651
+
652
+ ```typescript
653
+ import { script } from '@btc-vision/bitcoin';
654
+ const { decompile, toASM, isPushOnly, countNonPushOnlyOPs, opcodes } = script;
655
+
656
+ function inspectScript(raw: Uint8Array): void {
657
+ // Human-readable form
658
+ console.log('ASM:', toASM(raw));
659
+
660
+ // Structured form
661
+ const chunks = decompile(raw);
662
+ if (!chunks) {
663
+ console.log('Invalid script');
664
+ return;
665
+ }
666
+
667
+ console.log('Chunk count:', chunks.length);
668
+ console.log('Push-only:', isPushOnly(chunks));
669
+ console.log('Non-push opcodes:', countNonPushOnlyOPs(chunks));
670
+
671
+ // Check for specific patterns
672
+ if (chunks[0] === opcodes.OP_DUP && chunks[1] === opcodes.OP_HASH160) {
673
+ console.log('Looks like a P2PKH script');
674
+ }
675
+ if (chunks[0] === opcodes.OP_RETURN) {
676
+ console.log('This is an OP_RETURN output');
677
+ }
678
+ }
679
+ ```
680
+
681
+ ### Round-trip: ASM to Buffer and Back
682
+
683
+ ```typescript
684
+ import { script } from '@btc-vision/bitcoin';
685
+
686
+ const original = 'OP_2 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 OP_2 OP_CHECKMULTISIG';
687
+
688
+ const compiled = script.fromASM(original);
689
+ const restored = script.toASM(compiled);
690
+ console.log(original === restored); // true
691
+ ```
692
+
693
+ ### Validating a Script Signature
694
+
695
+ ```typescript
696
+ import { script } from '@btc-vision/bitcoin';
697
+
698
+ function validateScriptSig(sigBuffer: Uint8Array): boolean {
699
+ if (!script.isCanonicalScriptSignature(sigBuffer)) {
700
+ console.log('Invalid DER signature or hash type');
701
+ return false;
702
+ }
703
+
704
+ const { signature, hashType } = script.signature.decode(sigBuffer);
705
+ console.log('Raw signature (64 bytes):', signature);
706
+ console.log('Hash type:', hashType);
707
+ return true;
708
+ }
709
+ ```
710
+
711
+ ### Working with Script Numbers
712
+
713
+ ```typescript
714
+ import { script } from '@btc-vision/bitcoin';
715
+
716
+ // Encode various values
717
+ script.number.encode(0); // Buffer(0) - empty buffer
718
+ script.number.encode(1); // Buffer [0x01]
719
+ script.number.encode(127); // Buffer [0x7f]
720
+ script.number.encode(128); // Buffer [0x80, 0x00] (extra byte to avoid sign-bit collision)
721
+ script.number.encode(-1); // Buffer [0x81]
722
+ script.number.encode(-128); // Buffer [0x80, 0x80]
723
+
724
+ // Decode with strict minimal encoding (default)
725
+ script.number.decode(Buffer.from([0x7f])); // 127
726
+ script.number.decode(Buffer.from([0x80, 0x00])); // 128
727
+
728
+ // Decode with relaxed minimal check
729
+ script.number.decode(Buffer.from([0x00]), 4, false); // 0 (would throw with minimal=true)
730
+ ```