@btc-vision/bitcoin 7.0.0-alpha.1 → 7.0.0-alpha.10

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 (290) hide show
  1. package/README.md +455 -155
  2. package/browser/address.d.ts +5 -1
  3. package/browser/address.d.ts.map +1 -1
  4. package/browser/branded.d.ts +3 -14
  5. package/browser/branded.d.ts.map +1 -1
  6. package/browser/chunks/psbt-parallel-BBFlkmiv.js +10717 -0
  7. package/browser/ecc/context.d.ts +22 -21
  8. package/browser/ecc/context.d.ts.map +1 -1
  9. package/browser/ecc/index.d.ts +1 -1
  10. package/browser/ecc/index.d.ts.map +1 -1
  11. package/browser/ecc/types.d.ts +10 -123
  12. package/browser/ecc/types.d.ts.map +1 -1
  13. package/browser/env.d.ts +13 -0
  14. package/browser/env.d.ts.map +1 -0
  15. package/browser/index.d.ts +6 -6
  16. package/browser/index.d.ts.map +1 -1
  17. package/browser/index.js +2602 -11786
  18. package/browser/io/hex.d.ts.map +1 -1
  19. package/browser/io/index.d.ts +0 -1
  20. package/browser/io/index.d.ts.map +1 -1
  21. package/browser/opcodes.d.ts +11 -0
  22. package/browser/opcodes.d.ts.map +1 -1
  23. package/browser/payments/p2tr.d.ts.map +1 -1
  24. package/browser/psbt/PsbtCache.d.ts +54 -0
  25. package/browser/psbt/PsbtCache.d.ts.map +1 -0
  26. package/browser/psbt/PsbtFinalizer.d.ts +21 -0
  27. package/browser/psbt/PsbtFinalizer.d.ts.map +1 -0
  28. package/browser/psbt/PsbtSigner.d.ts +32 -0
  29. package/browser/psbt/PsbtSigner.d.ts.map +1 -0
  30. package/browser/psbt/PsbtTransaction.d.ts +25 -0
  31. package/browser/psbt/PsbtTransaction.d.ts.map +1 -0
  32. package/browser/psbt/types.d.ts +4 -70
  33. package/browser/psbt/types.d.ts.map +1 -1
  34. package/browser/psbt/validation.d.ts +1 -1
  35. package/browser/psbt/validation.d.ts.map +1 -1
  36. package/browser/psbt.d.ts +26 -40
  37. package/browser/psbt.d.ts.map +1 -1
  38. package/browser/script.d.ts.map +1 -1
  39. package/browser/transaction.d.ts +4 -4
  40. package/browser/transaction.d.ts.map +1 -1
  41. package/browser/types.d.ts +5 -3
  42. package/browser/types.d.ts.map +1 -1
  43. package/browser/workers/WorkerSigningPool.d.ts +7 -0
  44. package/browser/workers/WorkerSigningPool.d.ts.map +1 -1
  45. package/browser/workers/WorkerSigningPool.node.d.ts +7 -0
  46. package/browser/workers/WorkerSigningPool.node.d.ts.map +1 -1
  47. package/browser/workers/WorkerSigningPool.sequential.d.ts +67 -0
  48. package/browser/workers/WorkerSigningPool.sequential.d.ts.map +1 -0
  49. package/browser/workers/WorkerSigningPool.worklet.d.ts +64 -0
  50. package/browser/workers/WorkerSigningPool.worklet.d.ts.map +1 -0
  51. package/browser/workers/index.browser.d.ts +16 -0
  52. package/browser/workers/index.browser.d.ts.map +1 -0
  53. package/browser/workers/index.d.ts +4 -64
  54. package/browser/workers/index.d.ts.map +1 -1
  55. package/browser/workers/index.js +28 -0
  56. package/browser/workers/index.node.d.ts +17 -0
  57. package/browser/workers/index.node.d.ts.map +1 -0
  58. package/browser/workers/index.react-native.d.ts +28 -0
  59. package/browser/workers/index.react-native.d.ts.map +1 -0
  60. package/browser/workers/index.shared.d.ts +15 -0
  61. package/browser/workers/index.shared.d.ts.map +1 -0
  62. package/browser/workers/psbt-parallel.d.ts +2 -3
  63. package/browser/workers/psbt-parallel.d.ts.map +1 -1
  64. package/browser/workers/types.d.ts +17 -0
  65. package/browser/workers/types.d.ts.map +1 -1
  66. package/build/address.d.ts +5 -1
  67. package/build/address.d.ts.map +1 -1
  68. package/build/address.js +29 -17
  69. package/build/address.js.map +1 -1
  70. package/build/bech32utils.js.map +1 -1
  71. package/build/block.js.map +1 -1
  72. package/build/branded.d.ts +3 -14
  73. package/build/branded.d.ts.map +1 -1
  74. package/build/branded.js +0 -5
  75. package/build/branded.js.map +1 -1
  76. package/build/ecc/context.d.ts +22 -21
  77. package/build/ecc/context.d.ts.map +1 -1
  78. package/build/ecc/context.js +23 -95
  79. package/build/ecc/context.js.map +1 -1
  80. package/build/ecc/index.d.ts +1 -1
  81. package/build/ecc/index.d.ts.map +1 -1
  82. package/build/ecc/types.d.ts +7 -126
  83. package/build/ecc/types.d.ts.map +1 -1
  84. package/build/ecc/types.js +4 -1
  85. package/build/ecc/types.js.map +1 -1
  86. package/build/env.d.ts +13 -0
  87. package/build/env.d.ts.map +1 -0
  88. package/build/env.js +198 -0
  89. package/build/env.js.map +1 -0
  90. package/build/index.d.ts +7 -6
  91. package/build/index.d.ts.map +1 -1
  92. package/build/index.js +7 -5
  93. package/build/index.js.map +1 -1
  94. package/build/io/hex.d.ts.map +1 -1
  95. package/build/io/hex.js +2 -1
  96. package/build/io/hex.js.map +1 -1
  97. package/build/io/index.d.ts +0 -1
  98. package/build/io/index.d.ts.map +1 -1
  99. package/build/io/index.js +0 -2
  100. package/build/io/index.js.map +1 -1
  101. package/build/opcodes.d.ts +11 -0
  102. package/build/opcodes.d.ts.map +1 -1
  103. package/build/opcodes.js +19 -4
  104. package/build/opcodes.js.map +1 -1
  105. package/build/payments/bip341.js.map +1 -1
  106. package/build/payments/embed.js.map +1 -1
  107. package/build/payments/p2ms.js.map +1 -1
  108. package/build/payments/p2pk.js.map +1 -1
  109. package/build/payments/p2pkh.js.map +1 -1
  110. package/build/payments/p2sh.js.map +1 -1
  111. package/build/payments/p2tr.d.ts.map +1 -1
  112. package/build/payments/p2tr.js +2 -3
  113. package/build/payments/p2tr.js.map +1 -1
  114. package/build/payments/p2wpkh.js.map +1 -1
  115. package/build/payments/p2wsh.js.map +1 -1
  116. package/build/psbt/PsbtCache.d.ts +54 -0
  117. package/build/psbt/PsbtCache.d.ts.map +1 -0
  118. package/build/psbt/PsbtCache.js +249 -0
  119. package/build/psbt/PsbtCache.js.map +1 -0
  120. package/build/psbt/PsbtFinalizer.d.ts +21 -0
  121. package/build/psbt/PsbtFinalizer.d.ts.map +1 -0
  122. package/build/psbt/PsbtFinalizer.js +157 -0
  123. package/build/psbt/PsbtFinalizer.js.map +1 -0
  124. package/build/psbt/PsbtSigner.d.ts +32 -0
  125. package/build/psbt/PsbtSigner.d.ts.map +1 -0
  126. package/build/psbt/PsbtSigner.js +192 -0
  127. package/build/psbt/PsbtSigner.js.map +1 -0
  128. package/build/psbt/PsbtTransaction.d.ts +25 -0
  129. package/build/psbt/PsbtTransaction.d.ts.map +1 -0
  130. package/build/psbt/PsbtTransaction.js +61 -0
  131. package/build/psbt/PsbtTransaction.js.map +1 -0
  132. package/build/psbt/types.d.ts +4 -70
  133. package/build/psbt/types.d.ts.map +1 -1
  134. package/build/psbt/validation.d.ts +1 -1
  135. package/build/psbt/validation.d.ts.map +1 -1
  136. package/build/psbt.d.ts +26 -40
  137. package/build/psbt.d.ts.map +1 -1
  138. package/build/psbt.js +177 -799
  139. package/build/psbt.js.map +1 -1
  140. package/build/script.d.ts.map +1 -1
  141. package/build/script.js +2 -2
  142. package/build/script.js.map +1 -1
  143. package/build/transaction.d.ts +4 -4
  144. package/build/transaction.d.ts.map +1 -1
  145. package/build/transaction.js +5 -4
  146. package/build/transaction.js.map +1 -1
  147. package/build/tsconfig.build.tsbuildinfo +1 -1
  148. package/build/types.d.ts +5 -3
  149. package/build/types.d.ts.map +1 -1
  150. package/build/types.js +11 -16
  151. package/build/types.js.map +1 -1
  152. package/build/workers/WorkerSigningPool.d.ts +7 -0
  153. package/build/workers/WorkerSigningPool.d.ts.map +1 -1
  154. package/build/workers/WorkerSigningPool.js +12 -1
  155. package/build/workers/WorkerSigningPool.js.map +1 -1
  156. package/build/workers/WorkerSigningPool.node.d.ts +7 -0
  157. package/build/workers/WorkerSigningPool.node.d.ts.map +1 -1
  158. package/build/workers/WorkerSigningPool.node.js +37 -5
  159. package/build/workers/WorkerSigningPool.node.js.map +1 -1
  160. package/build/workers/WorkerSigningPool.sequential.d.ts +76 -0
  161. package/build/workers/WorkerSigningPool.sequential.d.ts.map +1 -0
  162. package/build/workers/WorkerSigningPool.sequential.js +160 -0
  163. package/build/workers/WorkerSigningPool.sequential.js.map +1 -0
  164. package/build/workers/WorkerSigningPool.worklet.d.ts +79 -0
  165. package/build/workers/WorkerSigningPool.worklet.d.ts.map +1 -0
  166. package/build/workers/WorkerSigningPool.worklet.js +390 -0
  167. package/build/workers/WorkerSigningPool.worklet.js.map +1 -0
  168. package/build/workers/index.browser.d.ts +24 -0
  169. package/build/workers/index.browser.d.ts.map +1 -0
  170. package/build/workers/index.browser.js +30 -0
  171. package/build/workers/index.browser.js.map +1 -0
  172. package/build/workers/index.d.ts +6 -18
  173. package/build/workers/index.d.ts.map +1 -1
  174. package/build/workers/index.js +12 -14
  175. package/build/workers/index.js.map +1 -1
  176. package/build/workers/index.node.d.ts +38 -0
  177. package/build/workers/index.node.d.ts.map +1 -0
  178. package/build/workers/index.node.js +45 -0
  179. package/build/workers/index.node.js.map +1 -0
  180. package/build/workers/index.react-native.d.ts +28 -0
  181. package/build/workers/index.react-native.d.ts.map +1 -0
  182. package/build/workers/index.react-native.js +67 -0
  183. package/build/workers/index.react-native.js.map +1 -0
  184. package/build/workers/index.shared.d.ts +15 -0
  185. package/build/workers/index.shared.d.ts.map +1 -0
  186. package/build/workers/index.shared.js +20 -0
  187. package/build/workers/index.shared.js.map +1 -0
  188. package/build/workers/psbt-parallel.d.ts +2 -3
  189. package/build/workers/psbt-parallel.d.ts.map +1 -1
  190. package/build/workers/psbt-parallel.js +4 -4
  191. package/build/workers/psbt-parallel.js.map +1 -1
  192. package/build/workers/types.d.ts +17 -0
  193. package/build/workers/types.d.ts.map +1 -1
  194. package/package.json +46 -8
  195. package/src/address.ts +41 -18
  196. package/src/bech32utils.ts +3 -3
  197. package/src/block.ts +2 -2
  198. package/src/branded.ts +15 -13
  199. package/src/ecc/context.ts +30 -133
  200. package/src/ecc/index.ts +2 -2
  201. package/src/ecc/types.ts +7 -138
  202. package/src/env.ts +239 -0
  203. package/src/index.ts +45 -9
  204. package/src/io/hex.ts +2 -1
  205. package/src/io/index.ts +0 -3
  206. package/src/opcodes.ts +21 -4
  207. package/src/payments/bip341.ts +3 -3
  208. package/src/payments/embed.ts +1 -1
  209. package/src/payments/p2ms.ts +2 -2
  210. package/src/payments/p2pk.ts +2 -2
  211. package/src/payments/p2pkh.ts +3 -3
  212. package/src/payments/p2sh.ts +4 -4
  213. package/src/payments/p2tr.ts +9 -9
  214. package/src/payments/p2wpkh.ts +5 -5
  215. package/src/payments/p2wsh.ts +2 -2
  216. package/src/psbt/PsbtCache.ts +325 -0
  217. package/src/psbt/PsbtFinalizer.ts +213 -0
  218. package/src/psbt/PsbtSigner.ts +302 -0
  219. package/src/psbt/PsbtTransaction.ts +82 -0
  220. package/src/psbt/types.ts +4 -86
  221. package/src/psbt/validation.ts +1 -1
  222. package/src/psbt.ts +349 -1198
  223. package/src/script.ts +2 -2
  224. package/src/transaction.ts +10 -9
  225. package/src/types.ts +18 -28
  226. package/src/workers/WorkerSigningPool.node.ts +41 -5
  227. package/src/workers/WorkerSigningPool.sequential.ts +191 -0
  228. package/src/workers/WorkerSigningPool.ts +14 -1
  229. package/src/workers/WorkerSigningPool.worklet.ts +522 -0
  230. package/src/workers/index.browser.ts +34 -0
  231. package/src/workers/index.node.ts +50 -0
  232. package/src/workers/index.react-native.ts +110 -0
  233. package/src/workers/index.shared.ts +58 -0
  234. package/src/workers/index.ts +14 -65
  235. package/src/workers/psbt-parallel.ts +7 -7
  236. package/src/workers/types.ts +21 -0
  237. package/test/address.spec.ts +2 -2
  238. package/test/bitcoin.core.spec.ts +5 -2
  239. package/test/browser/payments.spec.ts +151 -0
  240. package/test/browser/psbt.spec.ts +1510 -0
  241. package/test/browser/script.spec.ts +223 -0
  242. package/test/browser/setup.ts +13 -0
  243. package/test/browser/workers-signing.spec.ts +537 -0
  244. package/test/crypto.spec.ts +2 -2
  245. package/test/env.spec.ts +418 -0
  246. package/test/fixtures/core/base58_encode_decode.json +12 -48
  247. package/test/fixtures/core/base58_keys_invalid.json +50 -150
  248. package/test/fixtures/core/sighash.json +1 -3
  249. package/test/fixtures/core/tx_valid.json +133 -501
  250. package/test/fixtures/embed.json +3 -11
  251. package/test/fixtures/p2ms.json +21 -91
  252. package/test/fixtures/p2pk.json +5 -24
  253. package/test/fixtures/p2pkh.json +7 -36
  254. package/test/fixtures/p2sh.json +8 -54
  255. package/test/fixtures/p2tr.json +2 -6
  256. package/test/fixtures/p2wpkh.json +7 -36
  257. package/test/fixtures/p2wsh.json +14 -59
  258. package/test/fixtures/psbt.json +2 -6
  259. package/test/fixtures/script.json +12 -48
  260. package/test/integration/addresses.spec.ts +11 -5
  261. package/test/integration/bip32.spec.ts +1 -1
  262. package/test/integration/cltv.spec.ts +10 -6
  263. package/test/integration/csv.spec.ts +10 -9
  264. package/test/integration/payments.spec.ts +8 -4
  265. package/test/integration/taproot.spec.ts +26 -6
  266. package/test/integration/transactions.spec.ts +22 -8
  267. package/test/payments.spec.ts +1 -1
  268. package/test/payments.utils.ts +1 -1
  269. package/test/psbt.spec.ts +250 -64
  270. package/test/script_signature.spec.ts +1 -1
  271. package/test/transaction.spec.ts +18 -5
  272. package/test/tsconfig.json +6 -20
  273. package/test/workers-pool.spec.ts +65 -23
  274. package/test/workers-sequential.spec.ts +669 -0
  275. package/test/workers-signing.spec.ts +7 -3
  276. package/test/workers-worklet.spec.ts +500 -0
  277. package/test/workers.spec.ts +6 -7
  278. package/typedoc.json +11 -1
  279. package/vite.config.browser.ts +31 -6
  280. package/vitest.config.browser.ts +68 -0
  281. package/browser/ecpair.d.ts +0 -99
  282. package/browser/io/MemoryPool.d.ts +0 -220
  283. package/browser/io/MemoryPool.d.ts.map +0 -1
  284. package/build/io/MemoryPool.d.ts +0 -220
  285. package/build/io/MemoryPool.d.ts.map +0 -1
  286. package/build/io/MemoryPool.js +0 -309
  287. package/build/io/MemoryPool.js.map +0 -1
  288. package/src/ecpair.d.ts +0 -99
  289. package/src/io/MemoryPool.ts +0 -343
  290. package/test/taproot-cache.spec.ts +0 -694
package/src/script.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  import * as bip66 from './bip66.js';
6
6
  import { alloc, fromHex, toHex } from './io/index.js';
7
7
  import type { Opcodes } from './opcodes.js';
8
- import { opcodes, REVERSE_OPS } from './opcodes.js';
8
+ import { getReverseOps, opcodes } from './opcodes.js';
9
9
  import * as pushdata from './push_data.js';
10
10
  import * as scriptNumber from './script_number.js';
11
11
  import * as scriptSignature from './script_signature.js';
@@ -191,7 +191,7 @@ export function toASM(chunks: Uint8Array | Stack): string {
191
191
  }
192
192
 
193
193
  // opcode!
194
- return REVERSE_OPS[chunk];
194
+ return getReverseOps()[chunk];
195
195
  })
196
196
  .join(' ');
197
197
  }
@@ -2,7 +2,8 @@ import { alloc, BinaryReader, BinaryWriter, fromHex, reverse, toHex, varuint } f
2
2
  import * as bcrypto from './crypto.js';
3
3
  import * as bscript from './script.js';
4
4
  import { opcodes } from './script.js';
5
- import type { Bytes32, Satoshi, Script } from './types.js';
5
+ import type { Bytes32, MessageHash, Satoshi, Script } from './types.js';
6
+ import { toMessageHash } from './types.js';
6
7
 
7
8
  function varSliceSize(someScript: Uint8Array): number {
8
9
  const length = someScript.length;
@@ -24,7 +25,7 @@ function vectorSize(someVector: Uint8Array[]): number {
24
25
  const EMPTY_BYTES = new Uint8Array(0) as Script;
25
26
  const EMPTY_WITNESS: Uint8Array[] = [];
26
27
  const ZERO = fromHex('0000000000000000000000000000000000000000000000000000000000000000') as Bytes32;
27
- const ONE = fromHex('0000000000000000000000000000000000000000000000000000000000000001') as Bytes32;
28
+ const ONE: MessageHash = toMessageHash(fromHex('0000000000000000000000000000000000000000000000000000000000000001'));
28
29
 
29
30
  /** Maximum value for SIGHASH_SINGLE blank outputs (0xFFFFFFFFFFFFFFFF) */
30
31
  const BLANK_OUTPUT_VALUE = 0xffffffffffffffffn as Satoshi;
@@ -328,7 +329,7 @@ export class Transaction {
328
329
  * @param hashType - Signature hash type
329
330
  * @returns 32-byte hash for signing
330
331
  */
331
- hashForSignature(inIndex: number, prevOutScript: Script, hashType: number): Bytes32 {
332
+ hashForSignature(inIndex: number, prevOutScript: Script, hashType: number): MessageHash {
332
333
  if (!Number.isInteger(inIndex) || inIndex < 0) {
333
334
  throw new TypeError('Expected non-negative integer for inIndex');
334
335
  }
@@ -408,7 +409,7 @@ export class Transaction {
408
409
  writer.writeInt32LE(hashType);
409
410
  txTmp.#toBuffer(buffer, 0, false);
410
411
 
411
- return bcrypto.hash256(buffer) as Bytes32;
412
+ return toMessageHash(bcrypto.hash256(buffer));
412
413
  }
413
414
 
414
415
  /**
@@ -430,7 +431,7 @@ export class Transaction {
430
431
  leafHash?: Bytes32,
431
432
  annex?: Uint8Array,
432
433
  taprootCache?: TaprootHashCache,
433
- ): Bytes32 {
434
+ ): MessageHash {
434
435
  // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message
435
436
  if (!Number.isInteger(inIndex) || inIndex < 0 || inIndex > 0xffffffff) {
436
437
  throw new TypeError('Expected unsigned 32-bit integer for inIndex');
@@ -589,7 +590,7 @@ export class Transaction {
589
590
  const combined = new Uint8Array(1 + sigMsg.length);
590
591
  combined.set(prefix);
591
592
  combined.set(sigMsg, 1);
592
- return bcrypto.taggedHash('TapSighash', combined) as Bytes32;
593
+ return toMessageHash(bcrypto.taggedHash('TapSighash', combined));
593
594
  }
594
595
 
595
596
  /**
@@ -666,7 +667,7 @@ export class Transaction {
666
667
  prevOutScript: Script,
667
668
  value: Satoshi,
668
669
  hashType: number,
669
- ): Bytes32 {
670
+ ): MessageHash {
670
671
  if (!Number.isInteger(inIndex) || inIndex < 0 || inIndex > 0xffffffff) {
671
672
  throw new TypeError('Expected unsigned 32-bit integer for inIndex');
672
673
  }
@@ -757,7 +758,7 @@ export class Transaction {
757
758
  bufferWriter.writeBytes(hashOutputs);
758
759
  bufferWriter.writeUInt32LE(this.locktime);
759
760
  bufferWriter.writeUInt32LE(hashType);
760
- return bcrypto.hash256(tbuffer) as Bytes32;
761
+ return toMessageHash(bcrypto.hash256(tbuffer));
761
762
  }
762
763
 
763
764
  /**
@@ -769,7 +770,7 @@ export class Transaction {
769
770
  getHash(forWitness?: boolean): Bytes32 {
770
771
  // wtxid for coinbase is always 32 bytes of 0x00
771
772
  if (forWitness && this.isCoinbase()) return new Uint8Array(32) as Bytes32;
772
- return bcrypto.hash256(this.#toBuffer(undefined, undefined, forWitness)) as Bytes32;
773
+ return bcrypto.hash256(this.#toBuffer(undefined, undefined, forWitness));
773
774
  }
774
775
 
775
776
  /**
package/src/types.ts CHANGED
@@ -7,6 +7,7 @@ import { compare, equals, fromHex, isZero } from './io/index.js';
7
7
  import type {
8
8
  Bytes20,
9
9
  Bytes32,
10
+ MessageHash,
10
11
  PrivateKey,
11
12
  PublicKey,
12
13
  Satoshi,
@@ -16,10 +17,6 @@ import type {
16
17
  XOnlyPublicKey,
17
18
  } from './branded.js';
18
19
 
19
- // ============================================================================
20
- // Branded Types (re-exported from branded.ts to avoid circular dependencies)
21
- // ============================================================================
22
-
23
20
  export type {
24
21
  Bytes32,
25
22
  Bytes20,
@@ -29,25 +26,19 @@ export type {
29
26
  PrivateKey,
30
27
  Signature,
31
28
  SchnorrSignature,
29
+ MessageHash,
32
30
  Script,
33
31
  } from './branded.js';
34
32
 
35
- // ============================================================================
36
- // Constants
37
- // ============================================================================
38
-
39
33
  /** @internal Do not mutate */
40
34
  const EC_P = fromHex('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f');
35
+
41
36
  /** @internal Do not mutate — secp256k1 curve order */
42
37
  const EC_N = fromHex('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141');
43
38
 
44
39
  export const SATOSHI_MAX = 21n * 10n ** 14n;
45
40
  export const TAPLEAF_VERSION_MASK = 0xfe;
46
41
 
47
- // ============================================================================
48
- // Type Guards
49
- // ============================================================================
50
-
51
42
  export function isUInt8(value: unknown): value is number {
52
43
  return typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 0xff;
53
44
  }
@@ -94,8 +85,7 @@ export function isBytes20(value: unknown): value is Bytes20 {
94
85
  export function isXOnlyPublicKey(value: unknown): value is XOnlyPublicKey {
95
86
  if (!(value instanceof Uint8Array) || value.length !== 32) return false;
96
87
  if (isZero(value)) return false;
97
- if (compare(value, EC_P) >= 0) return false;
98
- return true;
88
+ return compare(value, EC_P) < 0;
99
89
  }
100
90
 
101
91
  export function isPoint(value: unknown): value is PublicKey {
@@ -128,8 +118,7 @@ export function isSatoshi(value: unknown): value is Satoshi {
128
118
  export function isPrivateKey(value: unknown): value is PrivateKey {
129
119
  if (!(value instanceof Uint8Array) || value.length !== 32) return false;
130
120
  if (isZero(value)) return false;
131
- if (compare(value, EC_N) >= 0) return false;
132
- return true;
121
+ return compare(value, EC_N) < 0;
133
122
  }
134
123
 
135
124
  export function isSchnorrSignature(value: unknown): value is SchnorrSignature {
@@ -144,9 +133,7 @@ export function isScript(value: unknown): value is Script {
144
133
  return value instanceof Uint8Array;
145
134
  }
146
135
 
147
- // ============================================================================
148
136
  // Taproot Types
149
- // ============================================================================
150
137
 
151
138
  export interface Tapleaf {
152
139
  readonly output: Uint8Array;
@@ -176,23 +163,17 @@ export function isTaptree(value: unknown): value is Taptree {
176
163
  return value.every((node: unknown) => isTaptree(node));
177
164
  }
178
165
 
179
- // ============================================================================
180
- // ECC Interface (re-exported from ecc/types.ts for backward compatibility)
181
- // ============================================================================
166
+ // ECC Interface
182
167
 
183
- export type { XOnlyPointAddTweakResult, EccLib, Parity } from './ecc/types.js';
168
+ export type { CryptoBackend, XOnlyPointAddTweakResult, EccLib, Parity } from './ecc/types.js';
184
169
 
185
- // ============================================================================
186
170
  // Stack Types
187
- // ============================================================================
188
171
 
189
172
  export type StackElement = Uint8Array | number;
190
173
  export type Stack = readonly StackElement[];
191
174
  export type StackFunction = () => Stack;
192
175
 
193
- // ============================================================================
194
176
  // Utility Functions
195
- // ============================================================================
196
177
 
197
178
  export function stacksEqual(a: Uint8Array[], b: Uint8Array[]): boolean {
198
179
  if (a.length !== b.length) return false;
@@ -206,6 +187,17 @@ export function toBytes32(value: Uint8Array): Bytes32 {
206
187
  return value;
207
188
  }
208
189
 
190
+ export function isMessageHash(value: unknown): value is MessageHash {
191
+ return value instanceof Uint8Array && value.length === 32;
192
+ }
193
+
194
+ export function toMessageHash(value: Uint8Array): MessageHash {
195
+ if (!isMessageHash(value)) {
196
+ throw new TypeError(`Expected 32-byte Uint8Array, got ${value.length} bytes`);
197
+ }
198
+ return value;
199
+ }
200
+
209
201
  export function toBytes20(value: Uint8Array): Bytes20 {
210
202
  if (!isBytes20(value)) {
211
203
  throw new TypeError(`Expected 20-byte Uint8Array, got ${value.length} bytes`);
@@ -223,9 +215,7 @@ export function toSatoshi(value: bigint): Satoshi {
223
215
  return value as Satoshi;
224
216
  }
225
217
 
226
- // ============================================================================
227
218
  // Assertion Helpers
228
- // ============================================================================
229
219
 
230
220
  export function assertXOnlyPublicKey(
231
221
  value: unknown,
@@ -353,6 +353,15 @@ export class NodeWorkerSigningPool {
353
353
  }
354
354
  }
355
355
 
356
+ /**
357
+ * Disposes of the pool by shutting down all workers.
358
+ *
359
+ * Enables `await using pool = ...` syntax for automatic cleanup.
360
+ */
361
+ public async [Symbol.asyncDispose](): Promise<void> {
362
+ await this.shutdown();
363
+ }
364
+
356
365
  /**
357
366
  * Shuts down the pool and terminates all workers.
358
367
  *
@@ -378,13 +387,17 @@ export class NodeWorkerSigningPool {
378
387
  this.#shuttingDown = false;
379
388
  }
380
389
 
390
+ public [Symbol.dispose](): void {
391
+ void this.shutdown();
392
+ }
393
+
381
394
  /**
382
395
  * Creates the inline worker script for Node.js worker_threads.
383
396
  * Supports both @noble/secp256k1 (pure JS) and tiny-secp256k1 (WASM).
384
397
  */
385
398
  #createWorkerScript(): string {
386
399
  // Node.js worker_threads can directly require/import modules
387
- const workerCode = `
400
+ return `
388
401
  const { parentPort } = require('worker_threads');
389
402
 
390
403
  /**
@@ -649,7 +662,6 @@ function handleSignBatch(msg) {
649
662
  });
650
663
  }
651
664
  `;
652
- return workerCode;
653
665
  }
654
666
 
655
667
  /**
@@ -772,16 +784,40 @@ function handleSignBatch(msg) {
772
784
  leafHash: task.leafHash,
773
785
  }));
774
786
 
787
+ // Copy private key for this worker (original shared across workers)
788
+ const workerPrivateKey = new Uint8Array(privateKey);
789
+
775
790
  // Create batch message
776
791
  const message: BatchSigningMessage = {
777
792
  type: 'signBatch',
778
793
  batchId,
779
794
  tasks: batchTasks,
780
- privateKey,
795
+ privateKey: workerPrivateKey,
781
796
  };
782
797
 
783
- // Send to worker
784
- worker.worker.postMessage(message);
798
+ // Collect ArrayBuffers for zero-copy transfer.
799
+ // Only transfer buffers unique to this worker batch — NOT publicKey
800
+ // (shared across all worker batches, would detach for other workers).
801
+ const keyBuf = workerPrivateKey.buffer as ArrayBuffer;
802
+ const transferList: ArrayBuffer[] = [keyBuf];
803
+ const seen = new Set<ArrayBuffer>([keyBuf]);
804
+ for (const task of batchTasks) {
805
+ const hashBuf = task.hash.buffer as ArrayBuffer;
806
+ if (!seen.has(hashBuf)) {
807
+ seen.add(hashBuf);
808
+ transferList.push(hashBuf);
809
+ }
810
+ if (task.leafHash) {
811
+ const leafBuf = task.leafHash.buffer as ArrayBuffer;
812
+ if (!seen.has(leafBuf)) {
813
+ seen.add(leafBuf);
814
+ transferList.push(leafBuf);
815
+ }
816
+ }
817
+ }
818
+
819
+ // Send to worker with transfer list (zero-copy)
820
+ worker.worker.postMessage(message, transferList);
785
821
  });
786
822
  }
787
823
 
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Sequential signing pool for environments without worker support (React Native).
3
+ *
4
+ * Signs inputs one-by-one on the main thread using the CryptoBackend
5
+ * from EccContext. Same API shape as WorkerSigningPool so consumers
6
+ * can swap transparently.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+
11
+ import type {
12
+ ParallelSignerKeyPair,
13
+ ParallelSigningResult,
14
+ SigningResultMessage,
15
+ SigningTask,
16
+ WorkerPoolConfig,
17
+ } from './types.js';
18
+ import { SignatureType } from './types.js';
19
+ import { EccContext } from '../ecc/context.js';
20
+ import type { MessageHash, PrivateKey } from '@btc-vision/ecpair';
21
+
22
+ /**
23
+ * Sequential signing pool — signs inputs one-by-one on the main thread.
24
+ *
25
+ * Provides the same public API as WorkerSigningPool but without any
26
+ * threading. Intended for React Native or other environments where
27
+ * Web Workers and worker_threads are unavailable.
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * import { SequentialSigningPool } from '@btc-vision/bitcoin/workers';
32
+ *
33
+ * const pool = SequentialSigningPool.getInstance();
34
+ * const result = await pool.signBatch(tasks, keyPair);
35
+ * ```
36
+ */
37
+ export class SequentialSigningPool {
38
+ static #instance: SequentialSigningPool | null = null;
39
+
40
+ private constructor(_config: WorkerPoolConfig = {}) {
41
+ // Config accepted for API compatibility but not used —
42
+ // sequential pool has no workers to configure.
43
+ }
44
+
45
+ /**
46
+ * Number of workers — always 0 for sequential pool.
47
+ */
48
+ public get workerCount(): number {
49
+ return 0;
50
+ }
51
+
52
+ /**
53
+ * Idle workers — always 0.
54
+ */
55
+ public get idleWorkerCount(): number {
56
+ return 0;
57
+ }
58
+
59
+ /**
60
+ * Busy workers — always 0.
61
+ */
62
+ public get busyWorkerCount(): number {
63
+ return 0;
64
+ }
65
+
66
+ /**
67
+ * Whether workers are preserved — always false (no workers to preserve).
68
+ */
69
+ public get isPreservingWorkers(): boolean {
70
+ return false;
71
+ }
72
+
73
+ /**
74
+ * Gets the singleton instance.
75
+ */
76
+ public static getInstance(config?: WorkerPoolConfig): SequentialSigningPool {
77
+ if (!SequentialSigningPool.#instance) {
78
+ SequentialSigningPool.#instance = new SequentialSigningPool(config);
79
+ }
80
+ return SequentialSigningPool.#instance;
81
+ }
82
+
83
+ /**
84
+ * Resets the singleton instance (for testing).
85
+ */
86
+ public static resetInstance(): void {
87
+ SequentialSigningPool.#instance = null;
88
+ }
89
+
90
+ /**
91
+ * No-op — no workers to preserve.
92
+ */
93
+ public preserveWorkers(): void {
94
+ // No-op: no workers to preserve
95
+ }
96
+
97
+ /**
98
+ * No-op — no workers to release.
99
+ */
100
+ public releaseWorkers(): void {
101
+ // No-op
102
+ }
103
+
104
+ /**
105
+ * No-op — no initialization required.
106
+ */
107
+ public async initialize(): Promise<void> {
108
+ // No-op: nothing to initialize
109
+ }
110
+
111
+ /**
112
+ * Signs tasks sequentially on the main thread.
113
+ */
114
+ // eslint-disable-next-line @typescript-eslint/require-await
115
+ public async signBatch(
116
+ tasks: readonly SigningTask[],
117
+ keyPair: ParallelSignerKeyPair,
118
+ ): Promise<ParallelSigningResult> {
119
+ const startTime = performance.now();
120
+
121
+ if (tasks.length === 0) {
122
+ return {
123
+ success: true,
124
+ signatures: new Map(),
125
+ errors: new Map(),
126
+ durationMs: performance.now() - startTime,
127
+ };
128
+ }
129
+
130
+ const ecc = EccContext.get().lib;
131
+ const privateKey = keyPair.getPrivateKey();
132
+
133
+ const signatures = new Map<number, SigningResultMessage>();
134
+ const errors = new Map<number, string>();
135
+
136
+ try {
137
+ for (const task of tasks) {
138
+ try {
139
+ let signature: Uint8Array;
140
+
141
+ const hash = task.hash as MessageHash;
142
+ const key = privateKey as PrivateKey;
143
+
144
+ if (task.signatureType === SignatureType.Schnorr) {
145
+ signature = ecc.signSchnorr!(hash, key);
146
+ } else {
147
+ signature = ecc.sign(hash, key);
148
+ }
149
+
150
+ signatures.set(task.inputIndex, {
151
+ type: 'result',
152
+ taskId: task.taskId,
153
+ signature,
154
+ inputIndex: task.inputIndex,
155
+ publicKey: keyPair.publicKey,
156
+ signatureType: task.signatureType,
157
+ leafHash: task.leafHash,
158
+ });
159
+ } catch (err: unknown) {
160
+ const message = err instanceof Error ? err.message : 'Signing failed';
161
+ errors.set(task.inputIndex, message);
162
+ }
163
+ }
164
+ } finally {
165
+ // SECURITY: Zero the private key
166
+ privateKey.fill(0);
167
+ }
168
+
169
+ return {
170
+ success: errors.size === 0,
171
+ signatures,
172
+ errors,
173
+ durationMs: performance.now() - startTime,
174
+ };
175
+ }
176
+
177
+ /**
178
+ * No-op — no workers to shut down.
179
+ */
180
+ public async shutdown(): Promise<void> {
181
+ // No-op: nothing to shut down
182
+ }
183
+
184
+ public [Symbol.dispose](): void {
185
+ void this.shutdown();
186
+ }
187
+
188
+ public async [Symbol.asyncDispose](): Promise<void> {
189
+ await this.shutdown();
190
+ }
191
+ }
@@ -42,7 +42,7 @@ import type {
42
42
  WorkerPoolConfig,
43
43
  WorkerResponse,
44
44
  } from './types.js';
45
- import { isBatchResult, isWorkerReady, WorkerState, } from './types.js';
45
+ import { isBatchResult, isWorkerReady, WorkerState } from './types.js';
46
46
  import { createWorkerBlobUrl, revokeWorkerBlobUrl } from './signing-worker.js';
47
47
 
48
48
  /**
@@ -389,6 +389,15 @@ export class WorkerSigningPool {
389
389
  }
390
390
  }
391
391
 
392
+ /**
393
+ * Disposes of the pool by shutting down all workers.
394
+ *
395
+ * Enables `await using pool = ...` syntax for automatic cleanup.
396
+ */
397
+ public async [Symbol.asyncDispose](): Promise<void> {
398
+ await this.shutdown();
399
+ }
400
+
392
401
  /**
393
402
  * Shuts down the pool and terminates all workers.
394
403
  *
@@ -422,6 +431,10 @@ export class WorkerSigningPool {
422
431
  this.#shuttingDown = false;
423
432
  }
424
433
 
434
+ public [Symbol.dispose](): void {
435
+ void this.shutdown();
436
+ }
437
+
425
438
  /**
426
439
  * Creates a new worker and adds it to the pool.
427
440
  */