@btc-vision/bitcoin 7.0.0-alpha.0 → 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.
- package/README.md +455 -155
- package/browser/address.d.ts +6 -2
- package/browser/address.d.ts.map +1 -1
- package/browser/block.d.ts.map +1 -1
- package/browser/branded.d.ts +3 -14
- package/browser/branded.d.ts.map +1 -1
- package/browser/chunks/psbt-parallel-BBFlkmiv.js +10717 -0
- package/browser/crypto.d.ts +1 -1
- package/browser/ecc/context.d.ts +25 -24
- package/browser/ecc/context.d.ts.map +1 -1
- package/browser/ecc/index.d.ts +1 -1
- package/browser/ecc/index.d.ts.map +1 -1
- package/browser/ecc/types.d.ts +10 -123
- package/browser/ecc/types.d.ts.map +1 -1
- package/browser/env.d.ts +13 -0
- package/browser/env.d.ts.map +1 -0
- package/browser/index.d.ts +7 -7
- package/browser/index.d.ts.map +1 -1
- package/browser/index.js +2497 -11686
- package/browser/io/BinaryReader.d.ts +15 -15
- package/browser/io/BinaryReader.d.ts.map +1 -1
- package/browser/io/BinaryWriter.d.ts +17 -17
- package/browser/io/BinaryWriter.d.ts.map +1 -1
- package/browser/io/hex.d.ts.map +1 -1
- package/browser/io/index.d.ts +0 -1
- package/browser/io/index.d.ts.map +1 -1
- package/browser/opcodes.d.ts +11 -0
- package/browser/opcodes.d.ts.map +1 -1
- package/browser/payments/bip341.d.ts +1 -1
- package/browser/payments/bip341.d.ts.map +1 -1
- package/browser/payments/embed.d.ts +1 -1
- package/browser/payments/embed.d.ts.map +1 -1
- package/browser/payments/p2ms.d.ts.map +1 -1
- package/browser/payments/p2op.d.ts +1 -1
- package/browser/payments/p2op.d.ts.map +1 -1
- package/browser/payments/p2pk.d.ts +1 -1
- package/browser/payments/p2pk.d.ts.map +1 -1
- package/browser/payments/p2pkh.d.ts +1 -1
- package/browser/payments/p2pkh.d.ts.map +1 -1
- package/browser/payments/p2sh.d.ts.map +1 -1
- package/browser/payments/p2tr.d.ts +2 -2
- package/browser/payments/p2tr.d.ts.map +1 -1
- package/browser/payments/p2wpkh.d.ts +1 -1
- package/browser/payments/p2wpkh.d.ts.map +1 -1
- package/browser/payments/p2wsh.d.ts.map +1 -1
- package/browser/payments/types.d.ts +1 -1
- package/browser/payments/types.d.ts.map +1 -1
- package/browser/psbt/PsbtCache.d.ts +54 -0
- package/browser/psbt/PsbtCache.d.ts.map +1 -0
- package/browser/psbt/PsbtFinalizer.d.ts +21 -0
- package/browser/psbt/PsbtFinalizer.d.ts.map +1 -0
- package/browser/psbt/PsbtSigner.d.ts +32 -0
- package/browser/psbt/PsbtSigner.d.ts.map +1 -0
- package/browser/psbt/PsbtTransaction.d.ts +25 -0
- package/browser/psbt/PsbtTransaction.d.ts.map +1 -0
- package/browser/psbt/bip371.d.ts.map +1 -1
- package/browser/psbt/types.d.ts +5 -71
- package/browser/psbt/types.d.ts.map +1 -1
- package/browser/psbt/validation.d.ts +1 -1
- package/browser/psbt/validation.d.ts.map +1 -1
- package/browser/psbt.d.ts +26 -40
- package/browser/psbt.d.ts.map +1 -1
- package/browser/script.d.ts.map +1 -1
- package/browser/transaction.d.ts +4 -4
- package/browser/transaction.d.ts.map +1 -1
- package/browser/types.d.ts +5 -3
- package/browser/types.d.ts.map +1 -1
- package/browser/workers/WorkerSigningPool.d.ts +24 -17
- package/browser/workers/WorkerSigningPool.d.ts.map +1 -1
- package/browser/workers/WorkerSigningPool.node.d.ts +19 -12
- package/browser/workers/WorkerSigningPool.node.d.ts.map +1 -1
- package/browser/workers/WorkerSigningPool.sequential.d.ts +67 -0
- package/browser/workers/WorkerSigningPool.sequential.d.ts.map +1 -0
- package/browser/workers/WorkerSigningPool.worklet.d.ts +64 -0
- package/browser/workers/WorkerSigningPool.worklet.d.ts.map +1 -0
- package/browser/workers/index.browser.d.ts +16 -0
- package/browser/workers/index.browser.d.ts.map +1 -0
- package/browser/workers/index.d.ts +4 -64
- package/browser/workers/index.d.ts.map +1 -1
- package/browser/workers/index.js +28 -0
- package/browser/workers/index.node.d.ts +17 -0
- package/browser/workers/index.node.d.ts.map +1 -0
- package/browser/workers/index.react-native.d.ts +28 -0
- package/browser/workers/index.react-native.d.ts.map +1 -0
- package/browser/workers/index.shared.d.ts +15 -0
- package/browser/workers/index.shared.d.ts.map +1 -0
- package/browser/workers/psbt-parallel.d.ts +2 -3
- package/browser/workers/psbt-parallel.d.ts.map +1 -1
- package/browser/workers/types.d.ts +17 -0
- package/browser/workers/types.d.ts.map +1 -1
- package/build/address.d.ts +6 -2
- package/build/address.d.ts.map +1 -1
- package/build/address.js +32 -19
- package/build/address.js.map +1 -1
- package/build/bech32utils.js.map +1 -1
- package/build/block.d.ts.map +1 -1
- package/build/block.js +2 -4
- package/build/block.js.map +1 -1
- package/build/branded.d.ts +3 -14
- package/build/branded.d.ts.map +1 -1
- package/build/branded.js +0 -5
- package/build/branded.js.map +1 -1
- package/build/crypto.d.ts +1 -1
- package/build/ecc/context.d.ts +25 -24
- package/build/ecc/context.d.ts.map +1 -1
- package/build/ecc/context.js +29 -101
- package/build/ecc/context.js.map +1 -1
- package/build/ecc/index.d.ts +1 -1
- package/build/ecc/index.d.ts.map +1 -1
- package/build/ecc/types.d.ts +7 -126
- package/build/ecc/types.d.ts.map +1 -1
- package/build/ecc/types.js +4 -1
- package/build/ecc/types.js.map +1 -1
- package/build/env.d.ts +13 -0
- package/build/env.d.ts.map +1 -0
- package/build/env.js +198 -0
- package/build/env.js.map +1 -0
- package/build/index.d.ts +8 -7
- package/build/index.d.ts.map +1 -1
- package/build/index.js +9 -7
- package/build/index.js.map +1 -1
- package/build/io/BinaryReader.d.ts +15 -15
- package/build/io/BinaryReader.d.ts.map +1 -1
- package/build/io/BinaryReader.js +17 -17
- package/build/io/BinaryReader.js.map +1 -1
- package/build/io/BinaryWriter.d.ts +17 -17
- package/build/io/BinaryWriter.d.ts.map +1 -1
- package/build/io/BinaryWriter.js +39 -39
- package/build/io/BinaryWriter.js.map +1 -1
- package/build/io/hex.d.ts.map +1 -1
- package/build/io/hex.js +2 -1
- package/build/io/hex.js.map +1 -1
- package/build/io/index.d.ts +0 -1
- package/build/io/index.d.ts.map +1 -1
- package/build/io/index.js +0 -2
- package/build/io/index.js.map +1 -1
- package/build/opcodes.d.ts +11 -0
- package/build/opcodes.d.ts.map +1 -1
- package/build/opcodes.js +19 -4
- package/build/opcodes.js.map +1 -1
- package/build/payments/bip341.d.ts +1 -2
- package/build/payments/bip341.d.ts.map +1 -1
- package/build/payments/bip341.js +1 -2
- package/build/payments/bip341.js.map +1 -1
- package/build/payments/embed.d.ts +1 -1
- package/build/payments/embed.d.ts.map +1 -1
- package/build/payments/embed.js +14 -14
- package/build/payments/embed.js.map +1 -1
- package/build/payments/p2ms.d.ts.map +1 -1
- package/build/payments/p2ms.js +21 -21
- package/build/payments/p2ms.js.map +1 -1
- package/build/payments/p2op.d.ts +1 -1
- package/build/payments/p2op.d.ts.map +1 -1
- package/build/payments/p2op.js +18 -18
- package/build/payments/p2op.js.map +1 -1
- package/build/payments/p2pk.d.ts +1 -1
- package/build/payments/p2pk.d.ts.map +1 -1
- package/build/payments/p2pk.js +17 -17
- package/build/payments/p2pk.js.map +1 -1
- package/build/payments/p2pkh.d.ts +1 -1
- package/build/payments/p2pkh.d.ts.map +1 -1
- package/build/payments/p2pkh.js +20 -20
- package/build/payments/p2pkh.js.map +1 -1
- package/build/payments/p2sh.d.ts.map +1 -1
- package/build/payments/p2sh.js +22 -20
- package/build/payments/p2sh.js.map +1 -1
- package/build/payments/p2tr.d.ts +2 -2
- package/build/payments/p2tr.d.ts.map +1 -1
- package/build/payments/p2tr.js +25 -26
- package/build/payments/p2tr.js.map +1 -1
- package/build/payments/p2wpkh.d.ts +1 -1
- package/build/payments/p2wpkh.d.ts.map +1 -1
- package/build/payments/p2wpkh.js +20 -20
- package/build/payments/p2wpkh.js.map +1 -1
- package/build/payments/p2wsh.d.ts.map +1 -1
- package/build/payments/p2wsh.js +22 -22
- package/build/payments/p2wsh.js.map +1 -1
- package/build/payments/types.d.ts +1 -1
- package/build/payments/types.d.ts.map +1 -1
- package/build/psbt/PsbtCache.d.ts +54 -0
- package/build/psbt/PsbtCache.d.ts.map +1 -0
- package/build/psbt/PsbtCache.js +249 -0
- package/build/psbt/PsbtCache.js.map +1 -0
- package/build/psbt/PsbtFinalizer.d.ts +21 -0
- package/build/psbt/PsbtFinalizer.d.ts.map +1 -0
- package/build/psbt/PsbtFinalizer.js +157 -0
- package/build/psbt/PsbtFinalizer.js.map +1 -0
- package/build/psbt/PsbtSigner.d.ts +32 -0
- package/build/psbt/PsbtSigner.d.ts.map +1 -0
- package/build/psbt/PsbtSigner.js +192 -0
- package/build/psbt/PsbtSigner.js.map +1 -0
- package/build/psbt/PsbtTransaction.d.ts +25 -0
- package/build/psbt/PsbtTransaction.d.ts.map +1 -0
- package/build/psbt/PsbtTransaction.js +61 -0
- package/build/psbt/PsbtTransaction.js.map +1 -0
- package/build/psbt/bip371.d.ts.map +1 -1
- package/build/psbt/bip371.js +6 -2
- package/build/psbt/bip371.js.map +1 -1
- package/build/psbt/psbtutils.js +1 -1
- package/build/psbt/psbtutils.js.map +1 -1
- package/build/psbt/types.d.ts +5 -71
- package/build/psbt/types.d.ts.map +1 -1
- package/build/psbt/validation.d.ts +1 -1
- package/build/psbt/validation.d.ts.map +1 -1
- package/build/psbt/validation.js +1 -1
- package/build/psbt/validation.js.map +1 -1
- package/build/psbt.d.ts +26 -40
- package/build/psbt.d.ts.map +1 -1
- package/build/psbt.js +180 -808
- package/build/psbt.js.map +1 -1
- package/build/script.d.ts.map +1 -1
- package/build/script.js +4 -4
- package/build/script.js.map +1 -1
- package/build/transaction.d.ts +4 -4
- package/build/transaction.d.ts.map +1 -1
- package/build/transaction.js +6 -5
- package/build/transaction.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/build/types.d.ts +5 -3
- package/build/types.d.ts.map +1 -1
- package/build/types.js +14 -25
- package/build/types.js.map +1 -1
- package/build/workers/WorkerSigningPool.d.ts +24 -17
- package/build/workers/WorkerSigningPool.d.ts.map +1 -1
- package/build/workers/WorkerSigningPool.js +36 -25
- package/build/workers/WorkerSigningPool.js.map +1 -1
- package/build/workers/WorkerSigningPool.node.d.ts +19 -12
- package/build/workers/WorkerSigningPool.node.d.ts.map +1 -1
- package/build/workers/WorkerSigningPool.node.js +60 -28
- package/build/workers/WorkerSigningPool.node.js.map +1 -1
- package/build/workers/WorkerSigningPool.sequential.d.ts +76 -0
- package/build/workers/WorkerSigningPool.sequential.d.ts.map +1 -0
- package/build/workers/WorkerSigningPool.sequential.js +160 -0
- package/build/workers/WorkerSigningPool.sequential.js.map +1 -0
- package/build/workers/WorkerSigningPool.worklet.d.ts +79 -0
- package/build/workers/WorkerSigningPool.worklet.d.ts.map +1 -0
- package/build/workers/WorkerSigningPool.worklet.js +390 -0
- package/build/workers/WorkerSigningPool.worklet.js.map +1 -0
- package/build/workers/index.browser.d.ts +24 -0
- package/build/workers/index.browser.d.ts.map +1 -0
- package/build/workers/index.browser.js +30 -0
- package/build/workers/index.browser.js.map +1 -0
- package/build/workers/index.d.ts +6 -18
- package/build/workers/index.d.ts.map +1 -1
- package/build/workers/index.js +12 -14
- package/build/workers/index.js.map +1 -1
- package/build/workers/index.node.d.ts +38 -0
- package/build/workers/index.node.d.ts.map +1 -0
- package/build/workers/index.node.js +45 -0
- package/build/workers/index.node.js.map +1 -0
- package/build/workers/index.react-native.d.ts +28 -0
- package/build/workers/index.react-native.d.ts.map +1 -0
- package/build/workers/index.react-native.js +67 -0
- package/build/workers/index.react-native.js.map +1 -0
- package/build/workers/index.shared.d.ts +15 -0
- package/build/workers/index.shared.d.ts.map +1 -0
- package/build/workers/index.shared.js +20 -0
- package/build/workers/index.shared.js.map +1 -0
- package/build/workers/psbt-parallel.d.ts +2 -3
- package/build/workers/psbt-parallel.d.ts.map +1 -1
- package/build/workers/psbt-parallel.js +4 -4
- package/build/workers/psbt-parallel.js.map +1 -1
- package/build/workers/types.d.ts +17 -0
- package/build/workers/types.d.ts.map +1 -1
- package/build/workers/types.js.map +1 -1
- package/package.json +48 -9
- package/src/address.ts +53 -21
- package/src/bech32utils.ts +3 -3
- package/src/block.ts +17 -10
- package/src/branded.ts +15 -13
- package/src/crypto.ts +1 -1
- package/src/ecc/context.ts +36 -136
- package/src/ecc/index.ts +2 -2
- package/src/ecc/types.ts +7 -145
- package/src/env.ts +239 -0
- package/src/index.ts +57 -22
- package/src/io/BinaryReader.ts +18 -18
- package/src/io/BinaryWriter.ts +43 -43
- package/src/io/hex.ts +2 -1
- package/src/io/index.ts +0 -3
- package/src/opcodes.ts +21 -4
- package/src/payments/bip341.ts +5 -7
- package/src/payments/embed.ts +19 -19
- package/src/payments/p2ms.ts +34 -27
- package/src/payments/p2op.ts +22 -22
- package/src/payments/p2pk.ts +22 -22
- package/src/payments/p2pkh.ts +28 -28
- package/src/payments/p2sh.ts +33 -30
- package/src/payments/p2tr.ts +40 -40
- package/src/payments/p2wpkh.ts +30 -30
- package/src/payments/p2wsh.ts +29 -29
- package/src/payments/types.ts +1 -1
- package/src/psbt/PsbtCache.ts +325 -0
- package/src/psbt/PsbtFinalizer.ts +213 -0
- package/src/psbt/PsbtSigner.ts +302 -0
- package/src/psbt/PsbtTransaction.ts +82 -0
- package/src/psbt/bip371.ts +7 -3
- package/src/psbt/psbtutils.ts +1 -1
- package/src/psbt/types.ts +5 -94
- package/src/psbt/validation.ts +5 -12
- package/src/psbt.ts +376 -1201
- package/src/script.ts +6 -9
- package/src/transaction.ts +19 -15
- package/src/types.ts +33 -45
- package/src/workers/WorkerSigningPool.node.ts +72 -36
- package/src/workers/WorkerSigningPool.sequential.ts +191 -0
- package/src/workers/WorkerSigningPool.ts +48 -39
- package/src/workers/WorkerSigningPool.worklet.ts +522 -0
- package/src/workers/index.browser.ts +34 -0
- package/src/workers/index.node.ts +50 -0
- package/src/workers/index.react-native.ts +110 -0
- package/src/workers/index.shared.ts +58 -0
- package/src/workers/index.ts +14 -65
- package/src/workers/psbt-parallel.ts +8 -13
- package/src/workers/types.ts +26 -1
- package/test/address.spec.ts +2 -2
- package/test/bitcoin.core.spec.ts +5 -2
- package/test/browser/payments.spec.ts +151 -0
- package/test/browser/psbt.spec.ts +1510 -0
- package/test/browser/script.spec.ts +223 -0
- package/test/browser/setup.ts +13 -0
- package/test/browser/workers-signing.spec.ts +537 -0
- package/test/crypto.spec.ts +2 -2
- package/test/env.spec.ts +418 -0
- package/test/fixtures/core/base58_encode_decode.json +12 -48
- package/test/fixtures/core/base58_keys_invalid.json +50 -150
- package/test/fixtures/core/sighash.json +1 -3
- package/test/fixtures/core/tx_valid.json +133 -501
- package/test/fixtures/embed.json +3 -11
- package/test/fixtures/p2ms.json +21 -91
- package/test/fixtures/p2pk.json +5 -24
- package/test/fixtures/p2pkh.json +7 -36
- package/test/fixtures/p2sh.json +8 -54
- package/test/fixtures/p2tr.json +2 -6
- package/test/fixtures/p2wpkh.json +7 -36
- package/test/fixtures/p2wsh.json +14 -59
- package/test/fixtures/psbt.json +2 -6
- package/test/fixtures/script.json +12 -48
- package/test/integration/addresses.spec.ts +11 -5
- package/test/integration/bip32.spec.ts +1 -1
- package/test/integration/cltv.spec.ts +10 -6
- package/test/integration/csv.spec.ts +10 -9
- package/test/integration/payments.spec.ts +8 -4
- package/test/integration/taproot.spec.ts +26 -6
- package/test/integration/transactions.spec.ts +22 -8
- package/test/payments.spec.ts +1 -1
- package/test/payments.utils.ts +1 -1
- package/test/psbt.spec.ts +250 -64
- package/test/script_signature.spec.ts +1 -1
- package/test/transaction.spec.ts +18 -5
- package/test/tsconfig.json +6 -20
- package/test/workers-pool.spec.ts +65 -23
- package/test/workers-sequential.spec.ts +669 -0
- package/test/workers-signing.spec.ts +7 -3
- package/test/workers-worklet.spec.ts +500 -0
- package/test/workers.spec.ts +6 -7
- package/typedoc.json +39 -0
- package/vite.config.browser.ts +31 -6
- package/vitest.config.browser.ts +68 -0
- package/browser/ecpair.d.ts +0 -99
- package/browser/io/MemoryPool.d.ts +0 -220
- package/browser/io/MemoryPool.d.ts.map +0 -1
- package/build/io/MemoryPool.d.ts +0 -220
- package/build/io/MemoryPool.d.ts.map +0 -1
- package/build/io/MemoryPool.js +0 -309
- package/build/io/MemoryPool.js.map +0 -1
- package/src/ecpair.d.ts +0 -99
- package/src/io/MemoryPool.ts +0 -343
- package/test/taproot-cache.spec.ts +0 -694
package/src/script.ts
CHANGED
|
@@ -3,14 +3,15 @@
|
|
|
3
3
|
* @packageDocumentation
|
|
4
4
|
*/
|
|
5
5
|
import * as bip66 from './bip66.js';
|
|
6
|
-
import {
|
|
6
|
+
import { alloc, fromHex, toHex } from './io/index.js';
|
|
7
7
|
import type { Opcodes } from './opcodes.js';
|
|
8
|
-
import {
|
|
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';
|
|
12
|
-
import
|
|
12
|
+
import { isDefinedHashType } from './script_signature.js';
|
|
13
13
|
import type { Script, Stack } from './types.js';
|
|
14
|
+
import * as types from './types.js';
|
|
14
15
|
|
|
15
16
|
const OP_INT_BASE = opcodes.OP_RESERVED; // OP_1 - 1
|
|
16
17
|
export { opcodes };
|
|
@@ -116,9 +117,7 @@ export function compile(chunks: Uint8Array | Stack): Script {
|
|
|
116
117
|
return buffer as Script;
|
|
117
118
|
}
|
|
118
119
|
|
|
119
|
-
export function decompile(
|
|
120
|
-
buffer: Uint8Array | Stack,
|
|
121
|
-
): Array<number | Uint8Array> | null {
|
|
120
|
+
export function decompile(buffer: Uint8Array | Stack): Array<number | Uint8Array> | null {
|
|
122
121
|
// Already decompiled - return as-is
|
|
123
122
|
if (chunksIsArray(buffer)) return buffer as Array<number | Uint8Array>;
|
|
124
123
|
|
|
@@ -192,7 +191,7 @@ export function toASM(chunks: Uint8Array | Stack): string {
|
|
|
192
191
|
}
|
|
193
192
|
|
|
194
193
|
// opcode!
|
|
195
|
-
return
|
|
194
|
+
return getReverseOps()[chunk];
|
|
196
195
|
})
|
|
197
196
|
.join(' ');
|
|
198
197
|
}
|
|
@@ -247,8 +246,6 @@ export function isCanonicalPubKey(buffer: Uint8Array): boolean {
|
|
|
247
246
|
return types.isPoint(buffer);
|
|
248
247
|
}
|
|
249
248
|
|
|
250
|
-
import { isDefinedHashType } from './script_signature.js';
|
|
251
|
-
|
|
252
249
|
export function isCanonicalScriptSignature(buffer: Uint8Array): boolean {
|
|
253
250
|
if (!(buffer instanceof Uint8Array)) return false;
|
|
254
251
|
if (!isDefinedHashType(buffer[buffer.length - 1]!)) return false;
|
package/src/transaction.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { BinaryReader, BinaryWriter,
|
|
1
|
+
import { alloc, BinaryReader, BinaryWriter, fromHex, reverse, toHex, varuint } from './io/index.js';
|
|
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;
|
|
@@ -23,10 +24,8 @@ function vectorSize(someVector: Uint8Array[]): number {
|
|
|
23
24
|
|
|
24
25
|
const EMPTY_BYTES = new Uint8Array(0) as Script;
|
|
25
26
|
const EMPTY_WITNESS: Uint8Array[] = [];
|
|
26
|
-
const ZERO = fromHex(
|
|
27
|
-
|
|
28
|
-
) as Bytes32;
|
|
29
|
-
const ONE = fromHex('0000000000000000000000000000000000000000000000000000000000000001') as Bytes32;
|
|
27
|
+
const ZERO = fromHex('0000000000000000000000000000000000000000000000000000000000000000') as Bytes32;
|
|
28
|
+
const ONE: MessageHash = toMessageHash(fromHex('0000000000000000000000000000000000000000000000000000000000000001'));
|
|
30
29
|
|
|
31
30
|
/** Maximum value for SIGHASH_SINGLE blank outputs (0xFFFFFFFFFFFFFFFF) */
|
|
32
31
|
const BLANK_OUTPUT_VALUE = 0xffffffffffffffffn as Satoshi;
|
|
@@ -330,7 +329,7 @@ export class Transaction {
|
|
|
330
329
|
* @param hashType - Signature hash type
|
|
331
330
|
* @returns 32-byte hash for signing
|
|
332
331
|
*/
|
|
333
|
-
hashForSignature(inIndex: number, prevOutScript: Script, hashType: number):
|
|
332
|
+
hashForSignature(inIndex: number, prevOutScript: Script, hashType: number): MessageHash {
|
|
334
333
|
if (!Number.isInteger(inIndex) || inIndex < 0) {
|
|
335
334
|
throw new TypeError('Expected non-negative integer for inIndex');
|
|
336
335
|
}
|
|
@@ -410,7 +409,7 @@ export class Transaction {
|
|
|
410
409
|
writer.writeInt32LE(hashType);
|
|
411
410
|
txTmp.#toBuffer(buffer, 0, false);
|
|
412
411
|
|
|
413
|
-
return bcrypto.hash256(buffer)
|
|
412
|
+
return toMessageHash(bcrypto.hash256(buffer));
|
|
414
413
|
}
|
|
415
414
|
|
|
416
415
|
/**
|
|
@@ -432,7 +431,7 @@ export class Transaction {
|
|
|
432
431
|
leafHash?: Bytes32,
|
|
433
432
|
annex?: Uint8Array,
|
|
434
433
|
taprootCache?: TaprootHashCache,
|
|
435
|
-
):
|
|
434
|
+
): MessageHash {
|
|
436
435
|
// https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message
|
|
437
436
|
if (!Number.isInteger(inIndex) || inIndex < 0 || inIndex > 0xffffffff) {
|
|
438
437
|
throw new TypeError('Expected unsigned 32-bit integer for inIndex');
|
|
@@ -493,7 +492,9 @@ export class Transaction {
|
|
|
493
492
|
bufferWriter = new BinaryWriter(
|
|
494
493
|
prevOutScripts.map(varSliceSize).reduce((a, b) => a + b),
|
|
495
494
|
);
|
|
496
|
-
prevOutScripts.forEach((prevOutScript) =>
|
|
495
|
+
prevOutScripts.forEach((prevOutScript) =>
|
|
496
|
+
bufferWriter.writeVarBytes(prevOutScript),
|
|
497
|
+
);
|
|
497
498
|
hashScriptPubKeys = bcrypto.sha256(bufferWriter.finish());
|
|
498
499
|
|
|
499
500
|
bufferWriter = new BinaryWriter(4 * this.ins.length);
|
|
@@ -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)
|
|
593
|
+
return toMessageHash(bcrypto.taggedHash('TapSighash', combined));
|
|
593
594
|
}
|
|
594
595
|
|
|
595
596
|
/**
|
|
@@ -600,7 +601,10 @@ export class Transaction {
|
|
|
600
601
|
* @param values - Array of previous output values for all inputs
|
|
601
602
|
* @returns Cache object to pass to hashForWitnessV1
|
|
602
603
|
*/
|
|
603
|
-
getTaprootHashCache(
|
|
604
|
+
getTaprootHashCache(
|
|
605
|
+
prevOutScripts: readonly Script[],
|
|
606
|
+
values: readonly Satoshi[],
|
|
607
|
+
): TaprootHashCache {
|
|
604
608
|
// hashPrevouts
|
|
605
609
|
let bufferWriter = new BinaryWriter(36 * this.ins.length);
|
|
606
610
|
for (const txIn of this.ins) {
|
|
@@ -663,7 +667,7 @@ export class Transaction {
|
|
|
663
667
|
prevOutScript: Script,
|
|
664
668
|
value: Satoshi,
|
|
665
669
|
hashType: number,
|
|
666
|
-
):
|
|
670
|
+
): MessageHash {
|
|
667
671
|
if (!Number.isInteger(inIndex) || inIndex < 0 || inIndex > 0xffffffff) {
|
|
668
672
|
throw new TypeError('Expected unsigned 32-bit integer for inIndex');
|
|
669
673
|
}
|
|
@@ -754,7 +758,7 @@ export class Transaction {
|
|
|
754
758
|
bufferWriter.writeBytes(hashOutputs);
|
|
755
759
|
bufferWriter.writeUInt32LE(this.locktime);
|
|
756
760
|
bufferWriter.writeUInt32LE(hashType);
|
|
757
|
-
return bcrypto.hash256(tbuffer)
|
|
761
|
+
return toMessageHash(bcrypto.hash256(tbuffer));
|
|
758
762
|
}
|
|
759
763
|
|
|
760
764
|
/**
|
|
@@ -766,7 +770,7 @@ export class Transaction {
|
|
|
766
770
|
getHash(forWitness?: boolean): Bytes32 {
|
|
767
771
|
// wtxid for coinbase is always 32 bytes of 0x00
|
|
768
772
|
if (forWitness && this.isCoinbase()) return new Uint8Array(32) as Bytes32;
|
|
769
|
-
return bcrypto.hash256(this.#toBuffer(undefined, undefined, forWitness))
|
|
773
|
+
return bcrypto.hash256(this.#toBuffer(undefined, undefined, forWitness));
|
|
770
774
|
}
|
|
771
775
|
|
|
772
776
|
/**
|
package/src/types.ts
CHANGED
|
@@ -3,11 +3,19 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @packageDocumentation
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
import { compare, equals, fromHex, isZero } from './io/index.js';
|
|
7
|
+
import type {
|
|
8
|
+
Bytes20,
|
|
9
|
+
Bytes32,
|
|
10
|
+
MessageHash,
|
|
11
|
+
PrivateKey,
|
|
12
|
+
PublicKey,
|
|
13
|
+
Satoshi,
|
|
14
|
+
SchnorrSignature,
|
|
15
|
+
Script,
|
|
16
|
+
Signature,
|
|
17
|
+
XOnlyPublicKey,
|
|
18
|
+
} from './branded.js';
|
|
11
19
|
|
|
12
20
|
export type {
|
|
13
21
|
Bytes32,
|
|
@@ -18,42 +26,26 @@ export type {
|
|
|
18
26
|
PrivateKey,
|
|
19
27
|
Signature,
|
|
20
28
|
SchnorrSignature,
|
|
29
|
+
MessageHash,
|
|
21
30
|
Script,
|
|
22
31
|
} from './branded.js';
|
|
23
32
|
|
|
24
|
-
import type { Bytes32, Bytes20, Satoshi, PrivateKey, XOnlyPublicKey, PublicKey, SchnorrSignature, Signature, Script } from './branded.js';
|
|
25
|
-
|
|
26
|
-
// ============================================================================
|
|
27
|
-
// Constants
|
|
28
|
-
// ============================================================================
|
|
29
|
-
|
|
30
33
|
/** @internal Do not mutate */
|
|
31
34
|
const EC_P = fromHex('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f');
|
|
35
|
+
|
|
32
36
|
/** @internal Do not mutate — secp256k1 curve order */
|
|
33
37
|
const EC_N = fromHex('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141');
|
|
34
38
|
|
|
35
39
|
export const SATOSHI_MAX = 21n * 10n ** 14n;
|
|
36
40
|
export const TAPLEAF_VERSION_MASK = 0xfe;
|
|
37
41
|
|
|
38
|
-
// ============================================================================
|
|
39
|
-
// Type Guards
|
|
40
|
-
// ============================================================================
|
|
41
|
-
|
|
42
42
|
export function isUInt8(value: unknown): value is number {
|
|
43
|
-
return (
|
|
44
|
-
typeof value === 'number' &&
|
|
45
|
-
Number.isInteger(value) &&
|
|
46
|
-
value >= 0 &&
|
|
47
|
-
value <= 0xff
|
|
48
|
-
);
|
|
43
|
+
return typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 0xff;
|
|
49
44
|
}
|
|
50
45
|
|
|
51
46
|
export function isUInt32(value: unknown): value is number {
|
|
52
47
|
return (
|
|
53
|
-
typeof value === 'number' &&
|
|
54
|
-
Number.isInteger(value) &&
|
|
55
|
-
value >= 0 &&
|
|
56
|
-
value <= 0xffffffff
|
|
48
|
+
typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 0xffffffff
|
|
57
49
|
);
|
|
58
50
|
}
|
|
59
51
|
|
|
@@ -93,8 +85,7 @@ export function isBytes20(value: unknown): value is Bytes20 {
|
|
|
93
85
|
export function isXOnlyPublicKey(value: unknown): value is XOnlyPublicKey {
|
|
94
86
|
if (!(value instanceof Uint8Array) || value.length !== 32) return false;
|
|
95
87
|
if (isZero(value)) return false;
|
|
96
|
-
|
|
97
|
-
return true;
|
|
88
|
+
return compare(value, EC_P) < 0;
|
|
98
89
|
}
|
|
99
90
|
|
|
100
91
|
export function isPoint(value: unknown): value is PublicKey {
|
|
@@ -127,8 +118,7 @@ export function isSatoshi(value: unknown): value is Satoshi {
|
|
|
127
118
|
export function isPrivateKey(value: unknown): value is PrivateKey {
|
|
128
119
|
if (!(value instanceof Uint8Array) || value.length !== 32) return false;
|
|
129
120
|
if (isZero(value)) return false;
|
|
130
|
-
|
|
131
|
-
return true;
|
|
121
|
+
return compare(value, EC_N) < 0;
|
|
132
122
|
}
|
|
133
123
|
|
|
134
124
|
export function isSchnorrSignature(value: unknown): value is SchnorrSignature {
|
|
@@ -143,9 +133,7 @@ export function isScript(value: unknown): value is Script {
|
|
|
143
133
|
return value instanceof Uint8Array;
|
|
144
134
|
}
|
|
145
135
|
|
|
146
|
-
// ============================================================================
|
|
147
136
|
// Taproot Types
|
|
148
|
-
// ============================================================================
|
|
149
137
|
|
|
150
138
|
export interface Tapleaf {
|
|
151
139
|
readonly output: Uint8Array;
|
|
@@ -175,23 +163,17 @@ export function isTaptree(value: unknown): value is Taptree {
|
|
|
175
163
|
return value.every((node: unknown) => isTaptree(node));
|
|
176
164
|
}
|
|
177
165
|
|
|
178
|
-
//
|
|
179
|
-
// ECC Interface (re-exported from ecc/types.ts for backward compatibility)
|
|
180
|
-
// ============================================================================
|
|
166
|
+
// ECC Interface
|
|
181
167
|
|
|
182
|
-
export type { XOnlyPointAddTweakResult, EccLib, Parity } from './ecc/types.js';
|
|
168
|
+
export type { CryptoBackend, XOnlyPointAddTweakResult, EccLib, Parity } from './ecc/types.js';
|
|
183
169
|
|
|
184
|
-
// ============================================================================
|
|
185
170
|
// Stack Types
|
|
186
|
-
// ============================================================================
|
|
187
171
|
|
|
188
172
|
export type StackElement = Uint8Array | number;
|
|
189
173
|
export type Stack = readonly StackElement[];
|
|
190
174
|
export type StackFunction = () => Stack;
|
|
191
175
|
|
|
192
|
-
// ============================================================================
|
|
193
176
|
// Utility Functions
|
|
194
|
-
// ============================================================================
|
|
195
177
|
|
|
196
178
|
export function stacksEqual(a: Uint8Array[], b: Uint8Array[]): boolean {
|
|
197
179
|
if (a.length !== b.length) return false;
|
|
@@ -205,6 +187,17 @@ export function toBytes32(value: Uint8Array): Bytes32 {
|
|
|
205
187
|
return value;
|
|
206
188
|
}
|
|
207
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
|
+
|
|
208
201
|
export function toBytes20(value: Uint8Array): Bytes20 {
|
|
209
202
|
if (!isBytes20(value)) {
|
|
210
203
|
throw new TypeError(`Expected 20-byte Uint8Array, got ${value.length} bytes`);
|
|
@@ -222,9 +215,7 @@ export function toSatoshi(value: bigint): Satoshi {
|
|
|
222
215
|
return value as Satoshi;
|
|
223
216
|
}
|
|
224
217
|
|
|
225
|
-
// ============================================================================
|
|
226
218
|
// Assertion Helpers
|
|
227
|
-
// ============================================================================
|
|
228
219
|
|
|
229
220
|
export function assertXOnlyPublicKey(
|
|
230
221
|
value: unknown,
|
|
@@ -244,10 +235,7 @@ export function assertXOnlyPublicKey(
|
|
|
244
235
|
}
|
|
245
236
|
}
|
|
246
237
|
|
|
247
|
-
export function assertPrivateKey(
|
|
248
|
-
value: unknown,
|
|
249
|
-
name: string,
|
|
250
|
-
): asserts value is PrivateKey {
|
|
238
|
+
export function assertPrivateKey(value: unknown, name: string): asserts value is PrivateKey {
|
|
251
239
|
if (!(value instanceof Uint8Array)) {
|
|
252
240
|
throw new TypeError(`${name} must be Uint8Array, got ${typeof value}`);
|
|
253
241
|
}
|
|
@@ -7,21 +7,21 @@
|
|
|
7
7
|
* @packageDocumentation
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { isMainThread, Worker } from 'worker_threads';
|
|
11
11
|
import { cpus } from 'os';
|
|
12
12
|
import type {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
BatchSigningMessage,
|
|
14
|
+
BatchSigningResultMessage,
|
|
15
|
+
BatchSigningTask,
|
|
15
16
|
ParallelSignerKeyPair,
|
|
16
17
|
ParallelSigningResult,
|
|
18
|
+
PooledWorker,
|
|
17
19
|
SigningResultMessage,
|
|
20
|
+
SigningTask,
|
|
21
|
+
WorkerPoolConfig,
|
|
18
22
|
WorkerResponse,
|
|
19
|
-
BatchSigningMessage,
|
|
20
|
-
BatchSigningTask,
|
|
21
|
-
BatchSigningResultMessage,
|
|
22
|
-
PooledWorker,
|
|
23
23
|
} from './types.js';
|
|
24
|
-
import {
|
|
24
|
+
import { isBatchResult, isWorkerReady, WorkerState } from './types.js';
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* ECC library types for Node.js worker.
|
|
@@ -163,29 +163,6 @@ export class NodeWorkerSigningPool {
|
|
|
163
163
|
this.#preserveWorkers = this.#config.preserveWorkers;
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
/**
|
|
167
|
-
* Gets the singleton pool instance.
|
|
168
|
-
*
|
|
169
|
-
* @param config - Optional configuration (only used on first call)
|
|
170
|
-
* @returns The singleton pool instance
|
|
171
|
-
*/
|
|
172
|
-
public static getInstance(config?: NodeWorkerPoolConfig): NodeWorkerSigningPool {
|
|
173
|
-
if (!NodeWorkerSigningPool.#instance) {
|
|
174
|
-
NodeWorkerSigningPool.#instance = new NodeWorkerSigningPool(config);
|
|
175
|
-
}
|
|
176
|
-
return NodeWorkerSigningPool.#instance;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Resets the singleton instance (for testing).
|
|
181
|
-
*/
|
|
182
|
-
public static resetInstance(): void {
|
|
183
|
-
if (NodeWorkerSigningPool.#instance) {
|
|
184
|
-
NodeWorkerSigningPool.#instance.shutdown().catch(() => {});
|
|
185
|
-
NodeWorkerSigningPool.#instance = null;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
166
|
/**
|
|
190
167
|
* Number of workers in the pool.
|
|
191
168
|
*/
|
|
@@ -214,6 +191,29 @@ export class NodeWorkerSigningPool {
|
|
|
214
191
|
return this.#preserveWorkers;
|
|
215
192
|
}
|
|
216
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Gets the singleton pool instance.
|
|
196
|
+
*
|
|
197
|
+
* @param config - Optional configuration (only used on first call)
|
|
198
|
+
* @returns The singleton pool instance
|
|
199
|
+
*/
|
|
200
|
+
public static getInstance(config?: NodeWorkerPoolConfig): NodeWorkerSigningPool {
|
|
201
|
+
if (!NodeWorkerSigningPool.#instance) {
|
|
202
|
+
NodeWorkerSigningPool.#instance = new NodeWorkerSigningPool(config);
|
|
203
|
+
}
|
|
204
|
+
return NodeWorkerSigningPool.#instance;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Resets the singleton instance (for testing).
|
|
209
|
+
*/
|
|
210
|
+
public static resetInstance(): void {
|
|
211
|
+
if (NodeWorkerSigningPool.#instance) {
|
|
212
|
+
NodeWorkerSigningPool.#instance.shutdown().catch(() => {});
|
|
213
|
+
NodeWorkerSigningPool.#instance = null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
217
|
/**
|
|
218
218
|
* Enables worker preservation between signing batches.
|
|
219
219
|
*/
|
|
@@ -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
|
-
|
|
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
|
-
//
|
|
784
|
-
worker
|
|
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
|
+
}
|