@btc-vision/bitcoin 7.0.0-alpha.2 → 7.0.0-alpha.4
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/chunks/WorkerSigningPool.sequential-DHha7j0b.js +113 -0
- package/browser/ecc/context.d.ts +22 -21
- 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 +3 -3
- package/browser/index.d.ts.map +1 -1
- package/browser/index.js +5790 -4295
- package/browser/io/index.d.ts +0 -1
- package/browser/io/index.d.ts.map +1 -1
- package/browser/payments/p2tr.d.ts.map +1 -1
- package/browser/psbt/types.d.ts +2 -68
- package/browser/psbt/types.d.ts.map +1 -1
- package/browser/psbt.d.ts +9 -11
- package/browser/psbt.d.ts.map +1 -1
- package/browser/types.d.ts +1 -1
- package/browser/types.d.ts.map +1 -1
- package/browser/workers/WorkerSigningPool.d.ts +6 -0
- package/browser/workers/WorkerSigningPool.d.ts.map +1 -1
- package/browser/workers/WorkerSigningPool.node.d.ts +6 -0
- package/browser/workers/WorkerSigningPool.node.d.ts.map +1 -1
- package/browser/workers/WorkerSigningPool.sequential.d.ts +69 -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.d.ts +2 -2
- package/browser/workers/index.d.ts.map +1 -1
- package/browser/workers/index.react-native.d.ts +28 -0
- package/browser/workers/index.react-native.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 +12 -0
- package/browser/workers/types.d.ts.map +1 -1
- package/build/ecc/context.d.ts +22 -21
- package/build/ecc/context.d.ts.map +1 -1
- package/build/ecc/context.js +19 -114
- 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 +4 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -1
- package/build/index.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/payments/p2tr.d.ts.map +1 -1
- package/build/payments/p2tr.js +2 -3
- package/build/payments/p2tr.js.map +1 -1
- package/build/psbt/types.d.ts +2 -68
- package/build/psbt/types.d.ts.map +1 -1
- package/build/psbt.d.ts +9 -11
- package/build/psbt.d.ts.map +1 -1
- package/build/psbt.js +38 -53
- package/build/psbt.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/build/types.d.ts +1 -1
- package/build/types.d.ts.map +1 -1
- package/build/types.js +2 -16
- package/build/types.js.map +1 -1
- package/build/workers/WorkerSigningPool.d.ts +6 -0
- package/build/workers/WorkerSigningPool.d.ts.map +1 -1
- package/build/workers/WorkerSigningPool.js +8 -0
- package/build/workers/WorkerSigningPool.js.map +1 -1
- package/build/workers/WorkerSigningPool.node.d.ts +6 -0
- package/build/workers/WorkerSigningPool.node.d.ts.map +1 -1
- package/build/workers/WorkerSigningPool.node.js +9 -2
- package/build/workers/WorkerSigningPool.node.js.map +1 -1
- package/build/workers/WorkerSigningPool.sequential.d.ts +78 -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 +388 -0
- package/build/workers/WorkerSigningPool.worklet.js.map +1 -0
- package/build/workers/index.d.ts +2 -2
- package/build/workers/index.d.ts.map +1 -1
- package/build/workers/index.js +9 -0
- package/build/workers/index.js.map +1 -1
- 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/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 +12 -0
- package/build/workers/types.d.ts.map +1 -1
- package/package.json +14 -4
- package/src/ecc/context.ts +26 -147
- package/src/ecc/index.ts +2 -2
- package/src/ecc/types.ts +7 -138
- package/src/env.ts +237 -0
- package/src/index.ts +2 -4
- package/src/io/index.ts +0 -3
- package/src/payments/p2tr.ts +2 -2
- package/src/psbt/types.ts +2 -84
- package/src/psbt.ts +63 -121
- package/src/types.ts +5 -28
- package/src/workers/WorkerSigningPool.node.ts +10 -2
- package/src/workers/WorkerSigningPool.sequential.ts +190 -0
- package/src/workers/WorkerSigningPool.ts +9 -0
- package/src/workers/WorkerSigningPool.worklet.ts +519 -0
- package/src/workers/index.react-native.ts +110 -0
- package/src/workers/index.ts +10 -1
- package/src/workers/psbt-parallel.ts +8 -8
- package/src/workers/types.ts +16 -0
- package/test/env.spec.ts +418 -0
- package/test/workers-pool.spec.ts +43 -0
- package/test/workers-sequential.spec.ts +669 -0
- package/test/workers-worklet.spec.ts +500 -0
- 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/io/MemoryPool.ts +0 -343
package/src/psbt.ts
CHANGED
|
@@ -10,7 +10,6 @@ import type {
|
|
|
10
10
|
import { checkForInput, checkForOutput, Psbt as PsbtBase } from 'bip174';
|
|
11
11
|
import { clone, equals, fromBase64, fromHex, toHex } from './io/index.js';
|
|
12
12
|
|
|
13
|
-
import type { BIP32Interface } from '@btc-vision/bip32';
|
|
14
13
|
import { fromOutputScript, toOutputScript } from './address.js';
|
|
15
14
|
import { bitcoin as btcNetwork } from './networks.js';
|
|
16
15
|
import * as payments from './payments/index.js';
|
|
@@ -41,7 +40,6 @@ import type {
|
|
|
41
40
|
PsbtTxInput,
|
|
42
41
|
PsbtTxOutput,
|
|
43
42
|
Signer,
|
|
44
|
-
SignerAlternative,
|
|
45
43
|
SignerAsync,
|
|
46
44
|
TaprootHashCheckSigner,
|
|
47
45
|
ValidateSigFunction,
|
|
@@ -67,7 +65,6 @@ import {
|
|
|
67
65
|
} from './psbt/validation.js';
|
|
68
66
|
import { checkInvalidP2WSH, classifyScript, getMeaningfulScript, range } from './psbt/utils.js';
|
|
69
67
|
import { witnessStackToScriptWitness } from './psbt/psbtutils.js';
|
|
70
|
-
import type { UniversalSigner } from '@btc-vision/ecpair';
|
|
71
68
|
|
|
72
69
|
// Re-export types from the types module
|
|
73
70
|
export type {
|
|
@@ -84,7 +81,6 @@ export type {
|
|
|
84
81
|
PsbtOutputExtendedScript,
|
|
85
82
|
HDSigner,
|
|
86
83
|
HDSignerAsync,
|
|
87
|
-
SignerAlternative,
|
|
88
84
|
Signer,
|
|
89
85
|
SignerAsync,
|
|
90
86
|
TaprootHashCheckSigner,
|
|
@@ -649,7 +645,7 @@ export class Psbt {
|
|
|
649
645
|
}
|
|
650
646
|
|
|
651
647
|
public signAllInputs(
|
|
652
|
-
keyPair: Signer |
|
|
648
|
+
keyPair: Signer | HDSigner,
|
|
653
649
|
sighashTypes?: number[],
|
|
654
650
|
): this {
|
|
655
651
|
if (!keyPair || !keyPair.publicKey) throw new Error('Need Signer to sign input');
|
|
@@ -670,7 +666,7 @@ export class Psbt {
|
|
|
670
666
|
}
|
|
671
667
|
|
|
672
668
|
public async signAllInputsAsync(
|
|
673
|
-
keyPair: Signer |
|
|
669
|
+
keyPair: Signer | SignerAsync | HDSigner | HDSignerAsync,
|
|
674
670
|
sighashTypes?: number[],
|
|
675
671
|
): Promise<void> {
|
|
676
672
|
if (!keyPair || !keyPair.publicKey) throw new Error('Need Signer to sign input');
|
|
@@ -697,7 +693,7 @@ export class Psbt {
|
|
|
697
693
|
|
|
698
694
|
public signInput(
|
|
699
695
|
inputIndex: number,
|
|
700
|
-
keyPair: Signer |
|
|
696
|
+
keyPair: Signer | HDSigner,
|
|
701
697
|
sighashTypes?: number[],
|
|
702
698
|
): this {
|
|
703
699
|
if (!keyPair || !keyPair.publicKey) {
|
|
@@ -714,7 +710,7 @@ export class Psbt {
|
|
|
714
710
|
|
|
715
711
|
public signTaprootInput(
|
|
716
712
|
inputIndex: number,
|
|
717
|
-
keyPair: Signer |
|
|
713
|
+
keyPair: Signer | HDSigner,
|
|
718
714
|
tapLeafHashToSign?: Uint8Array,
|
|
719
715
|
sighashTypes?: number[],
|
|
720
716
|
): this {
|
|
@@ -736,63 +732,45 @@ export class Psbt {
|
|
|
736
732
|
throw new Error(`Input #${inputIndex} is not of type Taproot.`);
|
|
737
733
|
}
|
|
738
734
|
|
|
739
|
-
public signInputAsync(
|
|
735
|
+
public async signInputAsync(
|
|
740
736
|
inputIndex: number,
|
|
741
|
-
keyPair:
|
|
742
|
-
| Signer
|
|
743
|
-
| SignerAlternative
|
|
744
|
-
| SignerAsync
|
|
745
|
-
| HDSigner
|
|
746
|
-
| HDSignerAsync
|
|
747
|
-
| BIP32Interface
|
|
748
|
-
| UniversalSigner,
|
|
737
|
+
keyPair: Signer | SignerAsync | HDSigner | HDSignerAsync,
|
|
749
738
|
sighashTypes?: number[],
|
|
750
739
|
): Promise<void> {
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
return this.#signInputAsync(inputIndex, keyPair, sighashTypes);
|
|
765
|
-
});
|
|
740
|
+
if (!keyPair || !keyPair.publicKey) throw new Error('Need Signer to sign input');
|
|
741
|
+
|
|
742
|
+
const input = checkForInput(this.data.inputs, inputIndex);
|
|
743
|
+
if (isTaprootInput(input))
|
|
744
|
+
return this.#signTaprootInputAsync(
|
|
745
|
+
inputIndex,
|
|
746
|
+
input,
|
|
747
|
+
keyPair,
|
|
748
|
+
undefined,
|
|
749
|
+
sighashTypes,
|
|
750
|
+
);
|
|
751
|
+
|
|
752
|
+
return this.#signInputAsync(inputIndex, keyPair, sighashTypes);
|
|
766
753
|
}
|
|
767
754
|
|
|
768
|
-
public signTaprootInputAsync(
|
|
755
|
+
public async signTaprootInputAsync(
|
|
769
756
|
inputIndex: number,
|
|
770
|
-
keyPair:
|
|
771
|
-
| Signer
|
|
772
|
-
| SignerAlternative
|
|
773
|
-
| SignerAsync
|
|
774
|
-
| HDSigner
|
|
775
|
-
| HDSignerAsync
|
|
776
|
-
| BIP32Interface
|
|
777
|
-
| UniversalSigner,
|
|
757
|
+
keyPair: Signer | SignerAsync | HDSigner | HDSignerAsync,
|
|
778
758
|
tapLeafHash?: Uint8Array,
|
|
779
759
|
sighashTypes?: number[],
|
|
780
760
|
): Promise<void> {
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
throw new Error(`Input #${inputIndex} is not of type Taproot.`);
|
|
795
|
-
});
|
|
761
|
+
if (!keyPair || !keyPair.publicKey) throw new Error('Need Signer to sign input');
|
|
762
|
+
|
|
763
|
+
const input = checkForInput(this.data.inputs, inputIndex);
|
|
764
|
+
if (isTaprootInput(input))
|
|
765
|
+
return this.#signTaprootInputAsync(
|
|
766
|
+
inputIndex,
|
|
767
|
+
input,
|
|
768
|
+
keyPair,
|
|
769
|
+
tapLeafHash,
|
|
770
|
+
sighashTypes,
|
|
771
|
+
);
|
|
772
|
+
|
|
773
|
+
throw new Error(`Input #${inputIndex} is not of type Taproot.`);
|
|
796
774
|
}
|
|
797
775
|
|
|
798
776
|
public toBuffer(): Uint8Array {
|
|
@@ -872,15 +850,7 @@ export class Psbt {
|
|
|
872
850
|
public checkTaprootHashesForSig(
|
|
873
851
|
inputIndex: number,
|
|
874
852
|
input: PsbtInput,
|
|
875
|
-
keyPair:
|
|
876
|
-
| Signer
|
|
877
|
-
| SignerAlternative
|
|
878
|
-
| SignerAsync
|
|
879
|
-
| HDSigner
|
|
880
|
-
| HDSignerAsync
|
|
881
|
-
| TaprootHashCheckSigner
|
|
882
|
-
| BIP32Interface
|
|
883
|
-
| UniversalSigner,
|
|
853
|
+
keyPair: Signer | SignerAsync | HDSigner | HDSignerAsync | TaprootHashCheckSigner,
|
|
884
854
|
tapLeafHashToSign?: Uint8Array,
|
|
885
855
|
allowedSighashTypes?: number[],
|
|
886
856
|
): { hash: MessageHash; leafHash?: Bytes32 }[] {
|
|
@@ -1064,7 +1034,7 @@ export class Psbt {
|
|
|
1064
1034
|
|
|
1065
1035
|
#signInput(
|
|
1066
1036
|
inputIndex: number,
|
|
1067
|
-
keyPair: Signer |
|
|
1037
|
+
keyPair: Signer | HDSigner,
|
|
1068
1038
|
sighashTypes: number[] = [Transaction.SIGHASH_ALL],
|
|
1069
1039
|
): this {
|
|
1070
1040
|
const pubkey =
|
|
@@ -1098,7 +1068,7 @@ export class Psbt {
|
|
|
1098
1068
|
#signTaprootInput(
|
|
1099
1069
|
inputIndex: number,
|
|
1100
1070
|
input: PsbtInput,
|
|
1101
|
-
keyPair: Signer |
|
|
1071
|
+
keyPair: Signer | HDSigner,
|
|
1102
1072
|
tapLeafHashToSign?: Uint8Array,
|
|
1103
1073
|
allowedSighashTypes: number[] = [Transaction.SIGHASH_DEFAULT],
|
|
1104
1074
|
): this {
|
|
@@ -1153,16 +1123,9 @@ export class Psbt {
|
|
|
1153
1123
|
return this;
|
|
1154
1124
|
}
|
|
1155
1125
|
|
|
1156
|
-
#signInputAsync(
|
|
1126
|
+
async #signInputAsync(
|
|
1157
1127
|
inputIndex: number,
|
|
1158
|
-
keyPair:
|
|
1159
|
-
| Signer
|
|
1160
|
-
| SignerAlternative
|
|
1161
|
-
| SignerAsync
|
|
1162
|
-
| HDSigner
|
|
1163
|
-
| HDSignerAsync
|
|
1164
|
-
| BIP32Interface
|
|
1165
|
-
| UniversalSigner,
|
|
1128
|
+
keyPair: Signer | SignerAsync | HDSigner | HDSignerAsync,
|
|
1166
1129
|
sighashTypes: number[] = [Transaction.SIGHASH_ALL],
|
|
1167
1130
|
): Promise<void> {
|
|
1168
1131
|
const pubkey =
|
|
@@ -1177,31 +1140,23 @@ export class Psbt {
|
|
|
1177
1140
|
sighashTypes,
|
|
1178
1141
|
);
|
|
1179
1142
|
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1143
|
+
const signature = await keyPair.sign(hash);
|
|
1144
|
+
const sig = signature instanceof Uint8Array ? signature : new Uint8Array(signature);
|
|
1145
|
+
const partialSig = [
|
|
1146
|
+
{
|
|
1147
|
+
pubkey,
|
|
1148
|
+
signature: bscript.signature.encode(sig, sighashType),
|
|
1149
|
+
},
|
|
1150
|
+
];
|
|
1188
1151
|
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
});
|
|
1152
|
+
this.data.updateInput(inputIndex, { partialSig });
|
|
1153
|
+
this.#cache.hasSignatures = true;
|
|
1192
1154
|
}
|
|
1193
1155
|
|
|
1194
1156
|
async #signTaprootInputAsync(
|
|
1195
1157
|
inputIndex: number,
|
|
1196
1158
|
input: PsbtInput,
|
|
1197
|
-
keyPair:
|
|
1198
|
-
| Signer
|
|
1199
|
-
| SignerAlternative
|
|
1200
|
-
| SignerAsync
|
|
1201
|
-
| HDSigner
|
|
1202
|
-
| HDSignerAsync
|
|
1203
|
-
| BIP32Interface
|
|
1204
|
-
| UniversalSigner,
|
|
1159
|
+
keyPair: Signer | SignerAsync | HDSigner | HDSignerAsync,
|
|
1205
1160
|
tapLeafHash?: Uint8Array,
|
|
1206
1161
|
sighashTypes: number[] = [Transaction.SIGHASH_DEFAULT],
|
|
1207
1162
|
): Promise<void> {
|
|
@@ -1225,42 +1180,29 @@ export class Psbt {
|
|
|
1225
1180
|
keyPair.signSchnorr as (hash: MessageHash) => SchnorrSignature | Promise<SchnorrSignature>
|
|
1226
1181
|
).bind(keyPair);
|
|
1227
1182
|
|
|
1228
|
-
|
|
1229
|
-
const signaturePromises: Promise<TapSignatureResult>[] = [];
|
|
1230
|
-
|
|
1231
|
-
const tapKeyHash = hashesForSig.filter((h) => !h.leafHash)[0];
|
|
1183
|
+
const tapKeyHash = hashesForSig.find((h) => !h.leafHash);
|
|
1232
1184
|
if (tapKeyHash) {
|
|
1233
|
-
const
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
});
|
|
1238
|
-
signaturePromises.push(tapKeySigPromise);
|
|
1185
|
+
const sig = await signSchnorr(tapKeyHash.hash);
|
|
1186
|
+
const tapKeySig = serializeTaprootSignature(sig, input.sighashType);
|
|
1187
|
+
this.data.updateInput(inputIndex, { tapKeySig });
|
|
1188
|
+
this.#cache.hasSignatures = true;
|
|
1239
1189
|
}
|
|
1240
1190
|
|
|
1241
1191
|
const tapScriptHashes = hashesForSig.filter(
|
|
1242
1192
|
(h): h is typeof h & { leafHash: Bytes32 } => !!h.leafHash,
|
|
1243
1193
|
);
|
|
1244
1194
|
if (tapScriptHashes.length) {
|
|
1245
|
-
const
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
{
|
|
1195
|
+
const tapScriptSigs = await Promise.all(
|
|
1196
|
+
tapScriptHashes.map(async (tsh) => {
|
|
1197
|
+
const signature = await signSchnorr(tsh.hash);
|
|
1198
|
+
return {
|
|
1250
1199
|
pubkey: toXOnly(pubkey),
|
|
1251
1200
|
signature: serializeTaprootSignature(signature, input.sighashType),
|
|
1252
1201
|
leafHash: tsh.leafHash,
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
});
|
|
1258
|
-
signaturePromises.push(...tapScriptSigPromises);
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
const results = await Promise.all(signaturePromises);
|
|
1262
|
-
for (const v of results) {
|
|
1263
|
-
this.data.updateInput(inputIndex, v as PsbtInputUpdate);
|
|
1202
|
+
} as TapScriptSig;
|
|
1203
|
+
}),
|
|
1204
|
+
);
|
|
1205
|
+
this.data.updateInput(inputIndex, { tapScriptSig: tapScriptSigs });
|
|
1264
1206
|
this.#cache.hasSignatures = true;
|
|
1265
1207
|
}
|
|
1266
1208
|
}
|
package/src/types.ts
CHANGED
|
@@ -17,10 +17,6 @@ import type {
|
|
|
17
17
|
XOnlyPublicKey,
|
|
18
18
|
} from './branded.js';
|
|
19
19
|
|
|
20
|
-
// ============================================================================
|
|
21
|
-
// Branded Types (re-exported from branded.ts to avoid circular dependencies)
|
|
22
|
-
// ============================================================================
|
|
23
|
-
|
|
24
20
|
export type {
|
|
25
21
|
Bytes32,
|
|
26
22
|
Bytes20,
|
|
@@ -34,22 +30,15 @@ export type {
|
|
|
34
30
|
Script,
|
|
35
31
|
} from './branded.js';
|
|
36
32
|
|
|
37
|
-
// ============================================================================
|
|
38
|
-
// Constants
|
|
39
|
-
// ============================================================================
|
|
40
|
-
|
|
41
33
|
/** @internal Do not mutate */
|
|
42
34
|
const EC_P = fromHex('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f');
|
|
35
|
+
|
|
43
36
|
/** @internal Do not mutate — secp256k1 curve order */
|
|
44
37
|
const EC_N = fromHex('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141');
|
|
45
38
|
|
|
46
39
|
export const SATOSHI_MAX = 21n * 10n ** 14n;
|
|
47
40
|
export const TAPLEAF_VERSION_MASK = 0xfe;
|
|
48
41
|
|
|
49
|
-
// ============================================================================
|
|
50
|
-
// Type Guards
|
|
51
|
-
// ============================================================================
|
|
52
|
-
|
|
53
42
|
export function isUInt8(value: unknown): value is number {
|
|
54
43
|
return typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 0xff;
|
|
55
44
|
}
|
|
@@ -96,8 +85,7 @@ export function isBytes20(value: unknown): value is Bytes20 {
|
|
|
96
85
|
export function isXOnlyPublicKey(value: unknown): value is XOnlyPublicKey {
|
|
97
86
|
if (!(value instanceof Uint8Array) || value.length !== 32) return false;
|
|
98
87
|
if (isZero(value)) return false;
|
|
99
|
-
|
|
100
|
-
return true;
|
|
88
|
+
return compare(value, EC_P) < 0;
|
|
101
89
|
}
|
|
102
90
|
|
|
103
91
|
export function isPoint(value: unknown): value is PublicKey {
|
|
@@ -130,8 +118,7 @@ export function isSatoshi(value: unknown): value is Satoshi {
|
|
|
130
118
|
export function isPrivateKey(value: unknown): value is PrivateKey {
|
|
131
119
|
if (!(value instanceof Uint8Array) || value.length !== 32) return false;
|
|
132
120
|
if (isZero(value)) return false;
|
|
133
|
-
|
|
134
|
-
return true;
|
|
121
|
+
return compare(value, EC_N) < 0;
|
|
135
122
|
}
|
|
136
123
|
|
|
137
124
|
export function isSchnorrSignature(value: unknown): value is SchnorrSignature {
|
|
@@ -146,9 +133,7 @@ export function isScript(value: unknown): value is Script {
|
|
|
146
133
|
return value instanceof Uint8Array;
|
|
147
134
|
}
|
|
148
135
|
|
|
149
|
-
// ============================================================================
|
|
150
136
|
// Taproot Types
|
|
151
|
-
// ============================================================================
|
|
152
137
|
|
|
153
138
|
export interface Tapleaf {
|
|
154
139
|
readonly output: Uint8Array;
|
|
@@ -178,23 +163,17 @@ export function isTaptree(value: unknown): value is Taptree {
|
|
|
178
163
|
return value.every((node: unknown) => isTaptree(node));
|
|
179
164
|
}
|
|
180
165
|
|
|
181
|
-
//
|
|
182
|
-
// ECC Interface (re-exported from ecc/types.ts for backward compatibility)
|
|
183
|
-
// ============================================================================
|
|
166
|
+
// ECC Interface
|
|
184
167
|
|
|
185
|
-
export type { XOnlyPointAddTweakResult, EccLib, Parity } from './ecc/types.js';
|
|
168
|
+
export type { CryptoBackend, XOnlyPointAddTweakResult, EccLib, Parity } from './ecc/types.js';
|
|
186
169
|
|
|
187
|
-
// ============================================================================
|
|
188
170
|
// Stack Types
|
|
189
|
-
// ============================================================================
|
|
190
171
|
|
|
191
172
|
export type StackElement = Uint8Array | number;
|
|
192
173
|
export type Stack = readonly StackElement[];
|
|
193
174
|
export type StackFunction = () => Stack;
|
|
194
175
|
|
|
195
|
-
// ============================================================================
|
|
196
176
|
// Utility Functions
|
|
197
|
-
// ============================================================================
|
|
198
177
|
|
|
199
178
|
export function stacksEqual(a: Uint8Array[], b: Uint8Array[]): boolean {
|
|
200
179
|
if (a.length !== b.length) return false;
|
|
@@ -236,9 +215,7 @@ export function toSatoshi(value: bigint): Satoshi {
|
|
|
236
215
|
return value as Satoshi;
|
|
237
216
|
}
|
|
238
217
|
|
|
239
|
-
// ============================================================================
|
|
240
218
|
// Assertion Helpers
|
|
241
|
-
// ============================================================================
|
|
242
219
|
|
|
243
220
|
export function assertXOnlyPublicKey(
|
|
244
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
|
*
|
|
@@ -384,7 +393,7 @@ export class NodeWorkerSigningPool {
|
|
|
384
393
|
*/
|
|
385
394
|
#createWorkerScript(): string {
|
|
386
395
|
// Node.js worker_threads can directly require/import modules
|
|
387
|
-
|
|
396
|
+
return `
|
|
388
397
|
const { parentPort } = require('worker_threads');
|
|
389
398
|
|
|
390
399
|
/**
|
|
@@ -649,7 +658,6 @@ function handleSignBatch(msg) {
|
|
|
649
658
|
});
|
|
650
659
|
}
|
|
651
660
|
`;
|
|
652
|
-
return workerCode;
|
|
653
661
|
}
|
|
654
662
|
|
|
655
663
|
/**
|
|
@@ -0,0 +1,190 @@
|
|
|
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
|
+
/**
|
|
185
|
+
* Enables `await using pool = ...` syntax.
|
|
186
|
+
*/
|
|
187
|
+
public async [Symbol.asyncDispose](): Promise<void> {
|
|
188
|
+
await this.shutdown();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -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
|
*
|