@btc-vision/bitcoin 7.0.0-alpha.8 → 7.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/benchmark-compare/BENCHMARK.md +144 -0
- package/benchmark-compare/compare.bench.ts +1024 -0
- package/benchmark-compare/harness.ts +220 -0
- package/benchmark-compare/package.json +18 -0
- package/browser/address.d.ts.map +1 -1
- package/browser/block.d.ts.map +1 -1
- package/browser/chunks/{psbt-parallel-PtTJ19DC.js → psbt-parallel-B-dfm5GZ.js} +2433 -2524
- package/browser/crypto-hashes.d.ts +4 -0
- package/browser/crypto-hashes.d.ts.map +1 -0
- package/browser/crypto-hashes.native.d.ts +4 -0
- package/browser/crypto-hashes.native.d.ts.map +1 -0
- package/browser/crypto.d.ts.map +1 -1
- package/browser/index.d.ts +3 -3
- package/browser/index.d.ts.map +1 -1
- package/browser/index.js +571 -547
- package/browser/io/base58check.d.ts +26 -0
- package/browser/io/base58check.d.ts.map +1 -0
- package/browser/io/base64.d.ts +8 -0
- package/browser/io/base64.d.ts.map +1 -1
- package/browser/io/hex.d.ts.map +1 -1
- package/browser/io/index.d.ts +2 -1
- package/browser/io/index.d.ts.map +1 -1
- package/browser/io/utils.d.ts.map +1 -1
- package/browser/payments/bip341.d.ts.map +1 -1
- package/browser/payments/p2op.d.ts.map +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.map +1 -1
- package/browser/payments/p2wpkh.d.ts.map +1 -1
- package/browser/psbt/PsbtCache.d.ts.map +1 -1
- package/browser/psbt/PsbtSigner.d.ts.map +1 -1
- package/browser/psbt/PsbtTransaction.d.ts +2 -2
- package/browser/psbt/PsbtTransaction.d.ts.map +1 -1
- package/browser/psbt/bip371.d.ts.map +1 -1
- package/browser/psbt.d.ts +1 -1
- package/browser/psbt.d.ts.map +1 -1
- package/browser/react-native-quick-crypto.d.ts +11 -0
- package/browser/script.d.ts.map +1 -1
- package/browser/transaction.d.ts.map +1 -1
- package/browser/workers/WorkerSigningPool.node.d.ts.map +1 -1
- package/browser/workers/WorkerSigningPool.sequential.d.ts.map +1 -1
- package/browser/workers/index.js +5 -5
- package/build/address.d.ts.map +1 -1
- package/build/address.js +19 -12
- package/build/address.js.map +1 -1
- package/build/bech32utils.js.map +1 -1
- package/build/bip66.js +4 -4
- package/build/bip66.js.map +1 -1
- package/build/block.d.ts.map +1 -1
- package/build/block.js +9 -2
- package/build/block.js.map +1 -1
- package/build/crypto-hashes.d.ts +4 -0
- package/build/crypto-hashes.d.ts.map +1 -0
- package/build/crypto-hashes.js +4 -0
- package/build/crypto-hashes.js.map +1 -0
- package/build/crypto-hashes.native.d.ts +4 -0
- package/build/crypto-hashes.native.d.ts.map +1 -0
- package/build/crypto-hashes.native.js +15 -0
- package/build/crypto-hashes.native.js.map +1 -0
- package/build/crypto.d.ts.map +1 -1
- package/build/crypto.js +1 -2
- package/build/crypto.js.map +1 -1
- package/build/env.js.map +1 -1
- package/build/index.d.ts +3 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/io/BinaryReader.js +1 -1
- package/build/io/BinaryReader.js.map +1 -1
- package/build/io/base58check.d.ts +26 -0
- package/build/io/base58check.d.ts.map +1 -0
- package/build/io/base58check.js +32 -0
- package/build/io/base58check.js.map +1 -0
- package/build/io/base64.d.ts +8 -0
- package/build/io/base64.d.ts.map +1 -1
- package/build/io/base64.js +14 -0
- package/build/io/base64.js.map +1 -1
- package/build/io/hex.d.ts.map +1 -1
- package/build/io/hex.js +3 -2
- package/build/io/hex.js.map +1 -1
- package/build/io/index.d.ts +2 -1
- package/build/io/index.d.ts.map +1 -1
- package/build/io/index.js +4 -2
- package/build/io/index.js.map +1 -1
- package/build/io/utils.d.ts.map +1 -1
- package/build/io/utils.js +3 -4
- package/build/io/utils.js.map +1 -1
- package/build/merkle.js.map +1 -1
- package/build/payments/bip341.d.ts.map +1 -1
- package/build/payments/bip341.js +4 -3
- package/build/payments/bip341.js.map +1 -1
- package/build/payments/embed.js.map +1 -1
- package/build/payments/p2ms.js.map +1 -1
- package/build/payments/p2op.d.ts.map +1 -1
- package/build/payments/p2op.js +6 -4
- package/build/payments/p2op.js.map +1 -1
- package/build/payments/p2pk.js.map +1 -1
- package/build/payments/p2pkh.d.ts.map +1 -1
- package/build/payments/p2pkh.js +3 -4
- package/build/payments/p2pkh.js.map +1 -1
- package/build/payments/p2sh.d.ts.map +1 -1
- package/build/payments/p2sh.js +3 -4
- package/build/payments/p2sh.js.map +1 -1
- package/build/payments/p2tr.d.ts.map +1 -1
- package/build/payments/p2tr.js +13 -6
- package/build/payments/p2tr.js.map +1 -1
- package/build/payments/p2wpkh.d.ts.map +1 -1
- package/build/payments/p2wpkh.js +7 -5
- package/build/payments/p2wpkh.js.map +1 -1
- package/build/payments/p2wsh.js.map +1 -1
- package/build/psbt/PsbtCache.d.ts.map +1 -1
- package/build/psbt/PsbtCache.js +8 -4
- package/build/psbt/PsbtCache.js.map +1 -1
- package/build/psbt/PsbtFinalizer.js +14 -8
- package/build/psbt/PsbtFinalizer.js.map +1 -1
- package/build/psbt/PsbtSigner.d.ts.map +1 -1
- package/build/psbt/PsbtSigner.js +3 -2
- package/build/psbt/PsbtSigner.js.map +1 -1
- package/build/psbt/PsbtTransaction.d.ts +2 -2
- package/build/psbt/PsbtTransaction.d.ts.map +1 -1
- package/build/psbt/PsbtTransaction.js.map +1 -1
- package/build/psbt/bip371.d.ts.map +1 -1
- package/build/psbt/bip371.js +4 -3
- package/build/psbt/bip371.js.map +1 -1
- package/build/psbt/utils.js.map +1 -1
- package/build/psbt.d.ts +1 -1
- package/build/psbt.d.ts.map +1 -1
- package/build/psbt.js.map +1 -1
- package/build/push_data.js +1 -1
- package/build/push_data.js.map +1 -1
- package/build/script.d.ts.map +1 -1
- package/build/script.js +4 -3
- package/build/script.js.map +1 -1
- package/build/script_number.js +1 -1
- package/build/script_number.js.map +1 -1
- package/build/script_signature.js.map +1 -1
- package/build/transaction.d.ts.map +1 -1
- package/build/transaction.js +2 -1
- package/build/transaction.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/build/types.js.map +1 -1
- package/build/workers/WorkerSigningPool.js.map +1 -1
- package/build/workers/WorkerSigningPool.node.d.ts.map +1 -1
- package/build/workers/WorkerSigningPool.node.js +25 -3
- package/build/workers/WorkerSigningPool.node.js.map +1 -1
- package/build/workers/WorkerSigningPool.sequential.d.ts.map +1 -1
- package/build/workers/WorkerSigningPool.sequential.js +2 -0
- package/build/workers/WorkerSigningPool.sequential.js.map +1 -1
- package/build/workers/index.js.map +1 -1
- package/build/workers/psbt-parallel.js.map +1 -1
- package/package.json +7 -5
- package/src/address.ts +18 -13
- package/src/bech32utils.ts +3 -3
- package/src/bip66.ts +18 -18
- package/src/block.ts +8 -3
- package/src/crypto-hashes.native.ts +18 -0
- package/src/crypto-hashes.ts +3 -0
- package/src/crypto.ts +1 -2
- package/src/env.ts +10 -8
- package/src/index.ts +4 -0
- package/src/io/BinaryReader.ts +1 -1
- package/src/io/base58check.ts +35 -0
- package/src/io/base64.ts +15 -0
- package/src/io/hex.ts +3 -2
- package/src/io/index.ts +5 -2
- package/src/io/utils.ts +6 -7
- package/src/merkle.ts +3 -3
- package/src/payments/bip341.ts +8 -7
- package/src/payments/embed.ts +1 -1
- package/src/payments/p2ms.ts +2 -2
- package/src/payments/p2op.ts +6 -4
- package/src/payments/p2pk.ts +2 -2
- package/src/payments/p2pkh.ts +7 -8
- package/src/payments/p2sh.ts +8 -9
- package/src/payments/p2tr.ts +24 -17
- package/src/payments/p2wpkh.ts +9 -7
- package/src/payments/p2wsh.ts +3 -3
- package/src/psbt/PsbtCache.ts +14 -11
- package/src/psbt/PsbtFinalizer.ts +17 -11
- package/src/psbt/PsbtSigner.ts +7 -6
- package/src/psbt/PsbtTransaction.ts +2 -2
- package/src/psbt/bip371.ts +4 -3
- package/src/psbt/utils.ts +1 -1
- package/src/psbt.ts +11 -9
- package/src/push_data.ts +5 -5
- package/src/react-native-quick-crypto.d.ts +11 -0
- package/src/script.ts +5 -4
- package/src/script_number.ts +6 -6
- package/src/script_signature.ts +2 -2
- package/src/transaction.ts +15 -14
- package/src/types.ts +1 -1
- package/src/workers/WorkerSigningPool.node.ts +28 -4
- package/src/workers/WorkerSigningPool.sequential.ts +2 -1
- package/src/workers/WorkerSigningPool.ts +3 -3
- package/src/workers/index.ts +1 -1
- package/src/workers/psbt-parallel.ts +3 -3
- package/test/address.spec.ts +1 -0
- package/test/bitcoin.core.spec.ts +9 -2
- package/test/browser/psbt.spec.ts +54 -29
- package/test/browser/workers-signing.spec.ts +8 -8
- package/test/crypto.spec.ts +1 -1
- package/test/env.spec.ts +2 -2
- package/test/integration/_regtest.ts +2 -2
- package/test/integration/blocks.spec.ts +1 -1
- package/test/integration/csv.spec.ts +1 -1
- package/test/integration/payments.spec.ts +2 -2
- package/test/integration/taproot.spec.ts +3 -3
- package/test/integration/transactions.spec.ts +6 -5
- package/test/psbt.spec.ts +49 -25
- package/test/transaction.spec.ts +6 -3
- package/test/workers-pool.spec.ts +5 -5
- package/test/workers-signing.spec.ts +8 -8
- package/test/workers.spec.ts +3 -3
package/src/psbt/PsbtSigner.ts
CHANGED
|
@@ -69,7 +69,8 @@ export class PsbtSigner {
|
|
|
69
69
|
this.#txFromBuffer,
|
|
70
70
|
);
|
|
71
71
|
|
|
72
|
-
const
|
|
72
|
+
const txIn = unsignedTx.ins[inputIndex] as Transaction['ins'][0];
|
|
73
|
+
const prevoutHash = txIn.hash;
|
|
73
74
|
const utxoHash = nonWitnessUtxoTx.getHash();
|
|
74
75
|
|
|
75
76
|
if (!equals(prevoutHash, utxoHash)) {
|
|
@@ -78,8 +79,8 @@ export class PsbtSigner {
|
|
|
78
79
|
);
|
|
79
80
|
}
|
|
80
81
|
|
|
81
|
-
const prevoutIndex =
|
|
82
|
-
prevout = nonWitnessUtxoTx.outs[prevoutIndex]
|
|
82
|
+
const prevoutIndex = txIn.index;
|
|
83
|
+
prevout = nonWitnessUtxoTx.outs[prevoutIndex] as Transaction['outs'][0];
|
|
83
84
|
} else if (input.witnessUtxo) {
|
|
84
85
|
prevout = {
|
|
85
86
|
script: input.witnessUtxo.script as Script,
|
|
@@ -108,7 +109,7 @@ export class PsbtSigner {
|
|
|
108
109
|
if (!p2pkhPayment.output) throw new Error('Unable to create signing script');
|
|
109
110
|
hash = unsignedTx.hashForWitnessV0(
|
|
110
111
|
inputIndex,
|
|
111
|
-
p2pkhPayment.output
|
|
112
|
+
p2pkhPayment.output,
|
|
112
113
|
prevout.value,
|
|
113
114
|
sighashType,
|
|
114
115
|
);
|
|
@@ -198,7 +199,7 @@ export class PsbtSigner {
|
|
|
198
199
|
signingScripts,
|
|
199
200
|
values,
|
|
200
201
|
sighashType,
|
|
201
|
-
tapLeaf.hash
|
|
202
|
+
tapLeaf.hash,
|
|
202
203
|
undefined,
|
|
203
204
|
taprootCache,
|
|
204
205
|
);
|
|
@@ -206,7 +207,7 @@ export class PsbtSigner {
|
|
|
206
207
|
return {
|
|
207
208
|
pubkey: pubkey as PublicKey,
|
|
208
209
|
hash: tapScriptHash,
|
|
209
|
-
leafHash: tapLeaf.hash
|
|
210
|
+
leafHash: tapLeaf.hash,
|
|
210
211
|
};
|
|
211
212
|
});
|
|
212
213
|
|
|
@@ -3,7 +3,7 @@ import { fromHex, reverse } from '../io/index.js';
|
|
|
3
3
|
import { Transaction } from '../transaction.js';
|
|
4
4
|
import type { Bytes32 } from '../types.js';
|
|
5
5
|
import { checkTxEmpty } from './validation.js';
|
|
6
|
-
import type {
|
|
6
|
+
import type { PsbtTxOutput, TransactionInput } from './types.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Empty version-2 transaction with zero inputs and zero outputs.
|
|
@@ -56,7 +56,7 @@ export class PsbtTransaction implements ITransaction {
|
|
|
56
56
|
this.tx.addInput(hash, input.index, input.sequence);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
public addOutput(output:
|
|
59
|
+
public addOutput(output: PsbtTxOutput): void {
|
|
60
60
|
if (
|
|
61
61
|
output.script === undefined ||
|
|
62
62
|
output.value === undefined ||
|
package/src/psbt/bip371.ts
CHANGED
|
@@ -180,10 +180,11 @@ export function tapTreeToList(tree: Taptree): TapLeaf[] {
|
|
|
180
180
|
* @returns the corresponding taptree, or throws an exception if the tree cannot be reconstructed
|
|
181
181
|
*/
|
|
182
182
|
export function tapTreeFromList(leaves: TapLeaf[] = []): Taptree {
|
|
183
|
-
|
|
183
|
+
const firstLeaf = leaves[0];
|
|
184
|
+
if (leaves.length === 1 && firstLeaf && firstLeaf.depth === 0)
|
|
184
185
|
return {
|
|
185
|
-
output: new Uint8Array(
|
|
186
|
-
version:
|
|
186
|
+
output: new Uint8Array(firstLeaf.script),
|
|
187
|
+
version: firstLeaf.leafVersion,
|
|
187
188
|
};
|
|
188
189
|
|
|
189
190
|
return insertLeavesInTree(leaves);
|
package/src/psbt/utils.ts
CHANGED
|
@@ -73,7 +73,7 @@ export function sighashTypeToString(sighashType: number): string {
|
|
|
73
73
|
*/
|
|
74
74
|
export function compressPubkey(pubkey: Uint8Array): Uint8Array {
|
|
75
75
|
if (pubkey.length === 65) {
|
|
76
|
-
const parity = pubkey[64]
|
|
76
|
+
const parity = (pubkey[64] as number) & 1;
|
|
77
77
|
const newKey = new Uint8Array(pubkey.subarray(0, 33));
|
|
78
78
|
newKey[0] = 2 | parity;
|
|
79
79
|
return newKey;
|
package/src/psbt.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
PsbtGlobalUpdate,
|
|
4
4
|
PsbtInput,
|
|
5
5
|
PsbtInputUpdate,
|
|
6
|
+
PsbtOutput,
|
|
6
7
|
PsbtOutputUpdate,
|
|
7
8
|
TapKeySig,
|
|
8
9
|
TapScriptSig,
|
|
@@ -79,6 +80,7 @@ export type {
|
|
|
79
80
|
PsbtInputExtended,
|
|
80
81
|
PsbtOutputExtended,
|
|
81
82
|
PsbtOutputExtendedScript,
|
|
83
|
+
PsbtOutputExtendedAddress,
|
|
82
84
|
HDSigner,
|
|
83
85
|
HDSignerAsync,
|
|
84
86
|
Signer,
|
|
@@ -348,7 +350,7 @@ export class Psbt {
|
|
|
348
350
|
if (this.#cache.tx.ins.length <= inputIndex) {
|
|
349
351
|
throw new Error('Input index too high');
|
|
350
352
|
}
|
|
351
|
-
this.#cache.tx.ins[inputIndex]
|
|
353
|
+
(this.#cache.tx.ins[inputIndex] as { sequence: number }).sequence = sequence;
|
|
352
354
|
this.#cache.invalidate('outputs');
|
|
353
355
|
return this;
|
|
354
356
|
}
|
|
@@ -386,11 +388,11 @@ export class Psbt {
|
|
|
386
388
|
}
|
|
387
389
|
: inputData;
|
|
388
390
|
this.data.addInput(normalizedInputData);
|
|
389
|
-
const txIn = this.#cache.tx.ins[this.#cache.tx.ins.length - 1]
|
|
391
|
+
const txIn = this.#cache.tx.ins[this.#cache.tx.ins.length - 1] as Transaction['ins'][0];
|
|
390
392
|
checkTxInputCache(this.#cache, txIn);
|
|
391
393
|
|
|
392
394
|
const inputIndex = this.data.inputs.length - 1;
|
|
393
|
-
const input = this.data.inputs[inputIndex]
|
|
395
|
+
const input = this.data.inputs[inputIndex] as PsbtInput;
|
|
394
396
|
if (input.nonWitnessUtxo) {
|
|
395
397
|
this.#cache.addNonWitnessTxCache(input, inputIndex, txFromBuffer);
|
|
396
398
|
}
|
|
@@ -558,7 +560,7 @@ export class Psbt {
|
|
|
558
560
|
validator: ValidateSigFunction,
|
|
559
561
|
pubkey?: PublicKey,
|
|
560
562
|
): boolean {
|
|
561
|
-
const input = this.data.inputs[inputIndex]
|
|
563
|
+
const input = this.data.inputs[inputIndex] as PsbtInput;
|
|
562
564
|
if (isTaprootInput(input))
|
|
563
565
|
return this.#validateSignaturesOfTaprootInput(inputIndex, validator, pubkey);
|
|
564
566
|
|
|
@@ -795,7 +797,7 @@ export class Psbt {
|
|
|
795
797
|
|
|
796
798
|
public updateInput(inputIndex: number, updateData: PsbtInputUpdate): this {
|
|
797
799
|
if (updateData.witnessScript) checkInvalidP2WSH(updateData.witnessScript);
|
|
798
|
-
checkTaprootInputFields(this.data.inputs[inputIndex]
|
|
800
|
+
checkTaprootInputFields(this.data.inputs[inputIndex] as PsbtInput, updateData, 'updateInput');
|
|
799
801
|
const normalizedUpdate = updateData.witnessUtxo
|
|
800
802
|
? {
|
|
801
803
|
...updateData,
|
|
@@ -811,7 +813,7 @@ export class Psbt {
|
|
|
811
813
|
this.data.updateInput(inputIndex, normalizedUpdate);
|
|
812
814
|
if (updateData.nonWitnessUtxo) {
|
|
813
815
|
this.#cache.addNonWitnessTxCache(
|
|
814
|
-
this.data.inputs[inputIndex]
|
|
816
|
+
this.data.inputs[inputIndex] as PsbtInput,
|
|
815
817
|
inputIndex,
|
|
816
818
|
txFromBuffer,
|
|
817
819
|
);
|
|
@@ -820,7 +822,7 @@ export class Psbt {
|
|
|
820
822
|
}
|
|
821
823
|
|
|
822
824
|
public updateOutput(outputIndex: number, updateData: PsbtOutputUpdate): this {
|
|
823
|
-
const outputData = this.data.outputs[outputIndex]
|
|
825
|
+
const outputData = this.data.outputs[outputIndex] as PsbtOutput;
|
|
824
826
|
checkTaprootOutputFields(outputData, updateData, 'updateOutput');
|
|
825
827
|
|
|
826
828
|
this.data.updateOutput(outputIndex, updateData);
|
|
@@ -986,7 +988,7 @@ export class Psbt {
|
|
|
986
988
|
validator: ValidateSigFunction,
|
|
987
989
|
pubkey?: PublicKey,
|
|
988
990
|
): boolean {
|
|
989
|
-
const input = this.data.inputs[inputIndex]
|
|
991
|
+
const input = this.data.inputs[inputIndex] as PsbtInput;
|
|
990
992
|
const tapKeySig = input?.tapKeySig;
|
|
991
993
|
const tapScriptSig = input?.tapScriptSig;
|
|
992
994
|
if (!input && !tapKeySig && !(tapScriptSig && !tapScriptSig.length))
|
|
@@ -1049,7 +1051,7 @@ export class Psbt {
|
|
|
1049
1051
|
sighashTypes,
|
|
1050
1052
|
);
|
|
1051
1053
|
|
|
1052
|
-
const sig = keyPair.sign(hash)
|
|
1054
|
+
const sig = keyPair.sign(hash);
|
|
1053
1055
|
const partialSig = [
|
|
1054
1056
|
{
|
|
1055
1057
|
pubkey,
|
package/src/push_data.ts
CHANGED
|
@@ -61,19 +61,19 @@ export function decode(
|
|
|
61
61
|
size: number;
|
|
62
62
|
} | null {
|
|
63
63
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
64
|
-
const opcode = buffer[offset];
|
|
64
|
+
const opcode = buffer[offset] as number;
|
|
65
65
|
let num: number;
|
|
66
66
|
let size: number;
|
|
67
67
|
|
|
68
68
|
// ~6 bit
|
|
69
|
-
if (opcode
|
|
70
|
-
num = opcode
|
|
69
|
+
if (opcode < opcodes.OP_PUSHDATA1) {
|
|
70
|
+
num = opcode;
|
|
71
71
|
size = 1;
|
|
72
72
|
|
|
73
73
|
// 8 bit
|
|
74
74
|
} else if (opcode === opcodes.OP_PUSHDATA1) {
|
|
75
75
|
if (offset + 2 > buffer.length) return null;
|
|
76
|
-
num = buffer[offset + 1]
|
|
76
|
+
num = buffer[offset + 1] as number;
|
|
77
77
|
size = 2;
|
|
78
78
|
|
|
79
79
|
// 16 bit
|
|
@@ -92,7 +92,7 @@ export function decode(
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
return {
|
|
95
|
-
opcode
|
|
95
|
+
opcode,
|
|
96
96
|
number: num,
|
|
97
97
|
size,
|
|
98
98
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare module 'react-native-quick-crypto' {
|
|
2
|
+
interface Hash {
|
|
3
|
+
update(data: Uint8Array | string): Hash;
|
|
4
|
+
digest(): Buffer;
|
|
5
|
+
}
|
|
6
|
+
interface QuickCrypto {
|
|
7
|
+
createHash(algorithm: string): Hash;
|
|
8
|
+
}
|
|
9
|
+
const QuickCrypto: QuickCrypto;
|
|
10
|
+
export default QuickCrypto;
|
|
11
|
+
}
|
package/src/script.ts
CHANGED
|
@@ -41,8 +41,9 @@ export function countNonPushOnlyOPs(value: Stack): number {
|
|
|
41
41
|
function asMinimalOP(buffer: Uint8Array): number | undefined {
|
|
42
42
|
if (buffer.length === 0) return opcodes.OP_0;
|
|
43
43
|
if (buffer.length !== 1) return undefined;
|
|
44
|
-
|
|
45
|
-
if (
|
|
44
|
+
const firstByte = buffer[0] as number;
|
|
45
|
+
if (firstByte >= 1 && firstByte <= 16) return OP_INT_BASE + firstByte;
|
|
46
|
+
if (firstByte === 0x81) return opcodes.OP_1NEGATE;
|
|
46
47
|
return undefined;
|
|
47
48
|
}
|
|
48
49
|
|
|
@@ -129,7 +130,7 @@ export function decompile(buffer: Uint8Array | Stack): Array<number | Uint8Array
|
|
|
129
130
|
let i = 0;
|
|
130
131
|
|
|
131
132
|
while (i < buffer.length) {
|
|
132
|
-
const opcode = buffer[i]
|
|
133
|
+
const opcode = buffer[i] as number;
|
|
133
134
|
|
|
134
135
|
// data chunk
|
|
135
136
|
if (opcode > opcodes.OP_0 && opcode <= opcodes.OP_PUSHDATA4) {
|
|
@@ -248,7 +249,7 @@ export function isCanonicalPubKey(buffer: Uint8Array): boolean {
|
|
|
248
249
|
|
|
249
250
|
export function isCanonicalScriptSignature(buffer: Uint8Array): boolean {
|
|
250
251
|
if (!(buffer instanceof Uint8Array)) return false;
|
|
251
|
-
if (!isDefinedHashType(buffer[buffer.length - 1]
|
|
252
|
+
if (!isDefinedHashType(buffer[buffer.length - 1] as number)) return false;
|
|
252
253
|
|
|
253
254
|
return bip66.check(buffer.subarray(0, -1));
|
|
254
255
|
}
|
package/src/script_number.ts
CHANGED
|
@@ -16,8 +16,8 @@ export function decode(buffer: Buffer, maxLength?: number, minimal?: boolean): n
|
|
|
16
16
|
if (length === 0) return 0;
|
|
17
17
|
if (length > maxLength) throw new TypeError('Script number overflow');
|
|
18
18
|
if (minimal) {
|
|
19
|
-
if ((buffer[length - 1]
|
|
20
|
-
if (length <= 1 || (buffer[length - 2]
|
|
19
|
+
if (((buffer[length - 1] as number) & 0x7f) === 0) {
|
|
20
|
+
if (length <= 1 || ((buffer[length - 2] as number) & 0x80) === 0)
|
|
21
21
|
throw new Error('Non-minimally encoded script number');
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -34,10 +34,10 @@ export function decode(buffer: Buffer, maxLength?: number, minimal?: boolean): n
|
|
|
34
34
|
// 32-bit / 24-bit / 16-bit / 8-bit
|
|
35
35
|
let result = 0;
|
|
36
36
|
for (let i = 0; i < length; ++i) {
|
|
37
|
-
result |= buffer[i]
|
|
37
|
+
result |= (buffer[i] as number) << (8 * i);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
if (buffer[length - 1]
|
|
40
|
+
if ((buffer[length - 1] as number) & 0x80) return -(result & ~(0x80 << (8 * (length - 1))));
|
|
41
41
|
return result;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -62,10 +62,10 @@ export function encode(_number: number): Buffer {
|
|
|
62
62
|
value >>= 8;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
if (buffer[size - 1]
|
|
65
|
+
if ((buffer[size - 1] as number) & 0x80) {
|
|
66
66
|
buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1);
|
|
67
67
|
} else if (negative) {
|
|
68
|
-
buffer[size - 1]
|
|
68
|
+
buffer[size - 1] = (buffer[size - 1] as number) | 0x80;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
return buffer;
|
package/src/script_signature.ts
CHANGED
|
@@ -24,7 +24,7 @@ function toDER(x: Uint8Array): Uint8Array {
|
|
|
24
24
|
while (x[i] === 0) ++i;
|
|
25
25
|
if (i === x.length) return ZERO;
|
|
26
26
|
x = x.subarray(i);
|
|
27
|
-
if (x[0]
|
|
27
|
+
if ((x[0] as number) & 0x80) return concat([ZERO, x]);
|
|
28
28
|
return x;
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -56,7 +56,7 @@ export interface ScriptSignature {
|
|
|
56
56
|
* @throws Error if the hashType is invalid.
|
|
57
57
|
*/
|
|
58
58
|
export function decode(buffer: Uint8Array): ScriptSignature {
|
|
59
|
-
const hashType = buffer[buffer.length - 1]
|
|
59
|
+
const hashType = buffer[buffer.length - 1] as number;
|
|
60
60
|
if (!isDefinedHashType(hashType)) {
|
|
61
61
|
throw new Error(`Invalid hashType ${hashType}`);
|
|
62
62
|
}
|
package/src/transaction.ts
CHANGED
|
@@ -144,7 +144,7 @@ export class Transaction {
|
|
|
144
144
|
|
|
145
145
|
if (hasWitnesses) {
|
|
146
146
|
for (let i = 0; i < vinLen; ++i) {
|
|
147
|
-
tx.ins[i]
|
|
147
|
+
(tx.ins[i] as Transaction['ins'][0]).witness = bufferReader.readVector();
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
// was this pointless?
|
|
@@ -187,7 +187,8 @@ export class Transaction {
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
isCoinbase(): boolean {
|
|
190
|
-
|
|
190
|
+
const firstIn = this.ins[0];
|
|
191
|
+
return this.ins.length === 1 && firstIn !== undefined && Transaction.isCoinbaseHash(firstIn.hash);
|
|
191
192
|
}
|
|
192
193
|
|
|
193
194
|
/**
|
|
@@ -391,8 +392,8 @@ export class Transaction {
|
|
|
391
392
|
|
|
392
393
|
// SIGHASH_ANYONECANPAY: ignore inputs entirely?
|
|
393
394
|
if (hashType & Transaction.SIGHASH_ANYONECANPAY) {
|
|
394
|
-
txTmp.ins = [txTmp.ins[inIndex]
|
|
395
|
-
txTmp.ins[0]
|
|
395
|
+
txTmp.ins = [txTmp.ins[inIndex] as Transaction['ins'][0]];
|
|
396
|
+
(txTmp.ins[0] as Transaction['ins'][0]).script = ourScript;
|
|
396
397
|
|
|
397
398
|
// SIGHASH_ALL: only ignore input scripts
|
|
398
399
|
} else {
|
|
@@ -400,7 +401,7 @@ export class Transaction {
|
|
|
400
401
|
txTmp.ins.forEach((input) => {
|
|
401
402
|
input.script = EMPTY_BYTES;
|
|
402
403
|
});
|
|
403
|
-
txTmp.ins[inIndex]
|
|
404
|
+
(txTmp.ins[inIndex] as Transaction['ins'][0]).script = ourScript;
|
|
404
405
|
}
|
|
405
406
|
|
|
406
407
|
// serialize and hash
|
|
@@ -522,7 +523,7 @@ export class Transaction {
|
|
|
522
523
|
hashOutputs = bcrypto.sha256(bufferWriter.finish());
|
|
523
524
|
}
|
|
524
525
|
} else if (isSingle && inIndex < this.outs.length) {
|
|
525
|
-
const output = this.outs[inIndex]
|
|
526
|
+
const output = this.outs[inIndex] as Transaction['outs'][0];
|
|
526
527
|
|
|
527
528
|
const bufferWriter = new BinaryWriter(8 + varSliceSize(output.script));
|
|
528
529
|
bufferWriter.writeUInt64LE(output.value);
|
|
@@ -558,11 +559,11 @@ export class Transaction {
|
|
|
558
559
|
// Input
|
|
559
560
|
sigMsgWriter.writeUInt8(spendType);
|
|
560
561
|
if (isAnyoneCanPay) {
|
|
561
|
-
const input = this.ins[inIndex]
|
|
562
|
+
const input = this.ins[inIndex] as Transaction['ins'][0];
|
|
562
563
|
sigMsgWriter.writeBytes(input.hash);
|
|
563
564
|
sigMsgWriter.writeUInt32LE(input.index);
|
|
564
|
-
sigMsgWriter.writeUInt64LE(values[inIndex]
|
|
565
|
-
sigMsgWriter.writeVarBytes(prevOutScripts[inIndex]
|
|
565
|
+
sigMsgWriter.writeUInt64LE(values[inIndex] as Satoshi);
|
|
566
|
+
sigMsgWriter.writeVarBytes(prevOutScripts[inIndex] as Uint8Array);
|
|
566
567
|
sigMsgWriter.writeUInt32LE(input.sequence);
|
|
567
568
|
} else {
|
|
568
569
|
sigMsgWriter.writeUInt32LE(inIndex);
|
|
@@ -733,7 +734,7 @@ export class Transaction {
|
|
|
733
734
|
|
|
734
735
|
hashOutputs = bcrypto.hash256(tbuffer);
|
|
735
736
|
} else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && inIndex < this.outs.length) {
|
|
736
|
-
const output = this.outs[inIndex]
|
|
737
|
+
const output = this.outs[inIndex] as Transaction['outs'][0];
|
|
737
738
|
|
|
738
739
|
tbuffer = alloc(8 + varSliceSize(output.script));
|
|
739
740
|
bufferWriter = new BinaryWriter(tbuffer, 0);
|
|
@@ -746,7 +747,7 @@ export class Transaction {
|
|
|
746
747
|
tbuffer = alloc(156 + varSliceSize(prevOutScript));
|
|
747
748
|
bufferWriter = new BinaryWriter(tbuffer, 0);
|
|
748
749
|
|
|
749
|
-
const input = this.ins[inIndex]
|
|
750
|
+
const input = this.ins[inIndex] as Transaction['ins'][0];
|
|
750
751
|
bufferWriter.writeInt32LE(this.version);
|
|
751
752
|
bufferWriter.writeBytes(hashPrevouts);
|
|
752
753
|
bufferWriter.writeBytes(hashSequence);
|
|
@@ -770,7 +771,7 @@ export class Transaction {
|
|
|
770
771
|
getHash(forWitness?: boolean): Bytes32 {
|
|
771
772
|
// wtxid for coinbase is always 32 bytes of 0x00
|
|
772
773
|
if (forWitness && this.isCoinbase()) return new Uint8Array(32) as Bytes32;
|
|
773
|
-
return bcrypto.hash256(this.#toBuffer(undefined, undefined, forWitness))
|
|
774
|
+
return bcrypto.hash256(this.#toBuffer(undefined, undefined, forWitness));
|
|
774
775
|
}
|
|
775
776
|
|
|
776
777
|
/**
|
|
@@ -817,7 +818,7 @@ export class Transaction {
|
|
|
817
818
|
throw new TypeError('Expected Uint8Array for scriptSig');
|
|
818
819
|
}
|
|
819
820
|
|
|
820
|
-
this.ins[index]
|
|
821
|
+
(this.ins[index] as Transaction['ins'][0]).script = scriptSig;
|
|
821
822
|
}
|
|
822
823
|
|
|
823
824
|
/**
|
|
@@ -834,7 +835,7 @@ export class Transaction {
|
|
|
834
835
|
throw new TypeError('Expected array of Uint8Array for witness');
|
|
835
836
|
}
|
|
836
837
|
|
|
837
|
-
this.ins[index]
|
|
838
|
+
(this.ins[index] as Transaction['ins'][0]).witness = witness;
|
|
838
839
|
}
|
|
839
840
|
|
|
840
841
|
/**
|
package/src/types.ts
CHANGED
|
@@ -177,7 +177,7 @@ export type StackFunction = () => Stack;
|
|
|
177
177
|
|
|
178
178
|
export function stacksEqual(a: Uint8Array[], b: Uint8Array[]): boolean {
|
|
179
179
|
if (a.length !== b.length) return false;
|
|
180
|
-
return a.every((x, i) => equals(x, b[i]
|
|
180
|
+
return a.every((x, i) => equals(x, b[i] as Uint8Array));
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
export function toBytes32(value: Uint8Array): Bytes32 {
|
|
@@ -289,7 +289,7 @@ export class NodeWorkerSigningPool {
|
|
|
289
289
|
const taskBatches: SigningTask[][] = Array.from({ length: workerCount }, () => []);
|
|
290
290
|
|
|
291
291
|
for (let i = 0; i < tasks.length; i++) {
|
|
292
|
-
taskBatches[i % workerCount]
|
|
292
|
+
(taskBatches[i % workerCount] as SigningTask[]).push(tasks[i] as SigningTask);
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
// Get private key once
|
|
@@ -784,16 +784,40 @@ function handleSignBatch(msg) {
|
|
|
784
784
|
leafHash: task.leafHash,
|
|
785
785
|
}));
|
|
786
786
|
|
|
787
|
+
// Copy private key for this worker (original shared across workers)
|
|
788
|
+
const workerPrivateKey = new Uint8Array(privateKey);
|
|
789
|
+
|
|
787
790
|
// Create batch message
|
|
788
791
|
const message: BatchSigningMessage = {
|
|
789
792
|
type: 'signBatch',
|
|
790
793
|
batchId,
|
|
791
794
|
tasks: batchTasks,
|
|
792
|
-
privateKey,
|
|
795
|
+
privateKey: workerPrivateKey,
|
|
793
796
|
};
|
|
794
797
|
|
|
795
|
-
//
|
|
796
|
-
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;
|
|
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);
|
|
797
821
|
});
|
|
798
822
|
}
|
|
799
823
|
|
|
@@ -142,7 +142,8 @@ export class SequentialSigningPool {
|
|
|
142
142
|
const key = privateKey as PrivateKey;
|
|
143
143
|
|
|
144
144
|
if (task.signatureType === SignatureType.Schnorr) {
|
|
145
|
-
|
|
145
|
+
if (!ecc.signSchnorr) throw new Error('Schnorr signing not supported');
|
|
146
|
+
signature = ecc.signSchnorr(hash, key);
|
|
146
147
|
} else {
|
|
147
148
|
signature = ecc.sign(hash, key);
|
|
148
149
|
}
|
|
@@ -319,7 +319,7 @@ export class WorkerSigningPool {
|
|
|
319
319
|
const taskBatches: SigningTask[][] = Array.from({ length: workerCount }, () => []);
|
|
320
320
|
|
|
321
321
|
for (let i = 0; i < tasks.length; i++) {
|
|
322
|
-
taskBatches[i % workerCount]
|
|
322
|
+
(taskBatches[i % workerCount] as SigningTask[]).push(tasks[i] as SigningTask);
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
// Get private key once
|
|
@@ -338,7 +338,7 @@ export class WorkerSigningPool {
|
|
|
338
338
|
const errors = new Map<number, string>();
|
|
339
339
|
|
|
340
340
|
for (let i = 0; i < batchResults.length; i++) {
|
|
341
|
-
const result = batchResults[i]
|
|
341
|
+
const result = batchResults[i] as PromiseSettledResult<BatchSigningResultMessage>;
|
|
342
342
|
if (result.status === 'fulfilled') {
|
|
343
343
|
const batchResult = result.value;
|
|
344
344
|
|
|
@@ -365,7 +365,7 @@ export class WorkerSigningPool {
|
|
|
365
365
|
const errorMsg = reason?.message ?? 'Batch signing failed';
|
|
366
366
|
|
|
367
367
|
// Add error for each task in the failed batch
|
|
368
|
-
const failedBatch = taskBatches[i]
|
|
368
|
+
const failedBatch = taskBatches[i] as SigningTask[];
|
|
369
369
|
for (const task of failedBatch) {
|
|
370
370
|
errors.set(task.inputIndex, errorMsg);
|
|
371
371
|
}
|
package/src/workers/index.ts
CHANGED
|
@@ -57,7 +57,7 @@ export * from './index.shared.js';
|
|
|
57
57
|
* @returns 'node' for Node.js, 'browser' for browsers, 'unknown' otherwise
|
|
58
58
|
*/
|
|
59
59
|
export function detectRuntime(): 'node' | 'browser' | 'react-native' | 'unknown' {
|
|
60
|
-
if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
|
|
60
|
+
if (typeof navigator !== 'undefined' && (navigator as {product?: string}).product === 'ReactNative') {
|
|
61
61
|
return 'react-native';
|
|
62
62
|
}
|
|
63
63
|
if (typeof process !== 'undefined' && process.versions?.node) {
|
|
@@ -118,7 +118,7 @@ export async function signPsbtParallel(
|
|
|
118
118
|
pool = poolOrConfig;
|
|
119
119
|
} else {
|
|
120
120
|
const { WorkerSigningPool } = await import('./WorkerSigningPool.js');
|
|
121
|
-
pool = WorkerSigningPool.getInstance(poolOrConfig
|
|
121
|
+
pool = WorkerSigningPool.getInstance(poolOrConfig);
|
|
122
122
|
if (!pool.isPreservingWorkers) {
|
|
123
123
|
shouldShutdown = true;
|
|
124
124
|
}
|
|
@@ -177,7 +177,7 @@ export function prepareSigningTasks(
|
|
|
177
177
|
const pubkey = keyPair.publicKey;
|
|
178
178
|
|
|
179
179
|
for (let i = 0; i < inputs.length; i++) {
|
|
180
|
-
const input = inputs[i]
|
|
180
|
+
const input = inputs[i] as PsbtInput;
|
|
181
181
|
|
|
182
182
|
// Check if this input can be signed with this key
|
|
183
183
|
if (!psbt.inputHasPubkey(i, pubkey as PublicKey)) {
|
|
@@ -285,7 +285,7 @@ export function applySignaturesToPsbt(
|
|
|
285
285
|
const pubkey = keyPair.publicKey;
|
|
286
286
|
|
|
287
287
|
for (const [inputIndex, sigResult] of result.signatures) {
|
|
288
|
-
const input = psbt.data.inputs[inputIndex]
|
|
288
|
+
const input = psbt.data.inputs[inputIndex] as PsbtInput;
|
|
289
289
|
|
|
290
290
|
if (sigResult.signatureType === SignatureType.Schnorr) {
|
|
291
291
|
// Taproot signature
|
package/test/address.spec.ts
CHANGED
|
@@ -66,6 +66,7 @@ describe('address', () => {
|
|
|
66
66
|
assert.strictEqual(actual.version, f.version);
|
|
67
67
|
// Support both bech32 and bech32Opnet prefixes
|
|
68
68
|
const network = NETWORKS[f.network];
|
|
69
|
+
assert.ok(network, `Unknown network: ${f.network}`);
|
|
69
70
|
const validPrefixes = [network.bech32, network.bech32Opnet].filter(Boolean);
|
|
70
71
|
assert.ok(
|
|
71
72
|
validPrefixes.includes(actual.prefix),
|
|
@@ -21,6 +21,7 @@ describe('Bitcoin-core', () => {
|
|
|
21
21
|
const fb58 = f[1];
|
|
22
22
|
|
|
23
23
|
it('can decode ' + fb58, () => {
|
|
24
|
+
assert(fb58 !== undefined);
|
|
24
25
|
const buffer = base58.decode(fb58);
|
|
25
26
|
const actual = toHex(new Uint8Array(buffer));
|
|
26
27
|
|
|
@@ -28,6 +29,7 @@ describe('Bitcoin-core', () => {
|
|
|
28
29
|
});
|
|
29
30
|
|
|
30
31
|
it('can encode ' + fhex, () => {
|
|
32
|
+
assert(fhex !== undefined);
|
|
31
33
|
const buffer = fromHex(fhex);
|
|
32
34
|
const actual = base58.encode(buffer);
|
|
33
35
|
|
|
@@ -78,6 +80,7 @@ describe('Bitcoin-core', () => {
|
|
|
78
80
|
const strng = f[0];
|
|
79
81
|
|
|
80
82
|
it('throws on ' + strng, () => {
|
|
83
|
+
assert(strng !== undefined);
|
|
81
84
|
assert.throws(() => {
|
|
82
85
|
const address = bitcoin.address.fromBase58Check(strng);
|
|
83
86
|
|
|
@@ -113,10 +116,12 @@ describe('Bitcoin-core', () => {
|
|
|
113
116
|
// const verifyFlags = f[2] // TODO: do we need to test this?
|
|
114
117
|
|
|
115
118
|
it('can decode ' + fhex, () => {
|
|
119
|
+
assert(inputs !== undefined);
|
|
116
120
|
const transaction = bitcoin.Transaction.fromHex(fhex as string);
|
|
117
121
|
|
|
118
122
|
transaction.ins.forEach((txIn, i) => {
|
|
119
|
-
const input = inputs[i];
|
|
123
|
+
const input = (inputs as unknown[][])[i];
|
|
124
|
+
assert(input !== undefined);
|
|
120
125
|
|
|
121
126
|
// reverse because test data is reversed
|
|
122
127
|
const prevOutHash = reverseCopy(fromHex(input[0] as string));
|
|
@@ -196,7 +201,9 @@ describe('Bitcoin-core', () => {
|
|
|
196
201
|
if (i === 0) return;
|
|
197
202
|
if (i % 2 !== 0) return;
|
|
198
203
|
|
|
199
|
-
const
|
|
204
|
+
const prev = sigNoncanonical[i - 1];
|
|
205
|
+
assert(prev !== undefined);
|
|
206
|
+
const description = prev.slice(0, -1);
|
|
200
207
|
const buffer = fromHex(hex);
|
|
201
208
|
|
|
202
209
|
it('throws on ' + description, () => {
|