summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/crypto/workers
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-core/src/crypto/workers')
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/cryptoDispatcher.ts (renamed from packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts)216
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts783
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts19
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/rpcClient.ts90
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts49
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactory.ts123
6 files changed, 158 insertions, 1122 deletions
diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts b/packages/taler-wallet-core/src/crypto/workers/cryptoDispatcher.ts
index ca498bff1..810273cca 100644
--- a/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/cryptoDispatcher.ts
@@ -22,39 +22,10 @@
/**
* Imports.
*/
-import { DenominationRecord, WireFee } from "../../db.js";
-
-import { CryptoWorker } from "./cryptoWorkerInterface.js";
-
-import {
- BlindedDenominationSignature,
- CoinDepositPermission,
- CoinEnvelope,
- PlanchetUnblindInfo,
- RecoupRefreshRequest,
- RecoupRequest,
- UnblindedSignature,
-} from "@gnu-taler/taler-util";
-
-import {
- BenchmarkResult,
- WithdrawalPlanchet,
- PlanchetCreationRequest,
- DepositInfo,
- MakeSyncSignatureRequest,
-} from "@gnu-taler/taler-util";
-
-import * as timer from "../../util/timer.js";
import { Logger } from "@gnu-taler/taler-util";
-import {
- CreateRecoupRefreshReqRequest,
- CreateRecoupReqRequest,
- DerivedRefreshSession,
- DerivedTipPlanchet,
- DeriveRefreshSessionRequest,
- DeriveTipRequest,
- SignTrackTransactionRequest,
-} from "../cryptoTypes.js";
+import * as timer from "../../util/timer.js";
+import { nullCrypto, TalerCryptoInterface } from "../cryptoImplementation.js";
+import { CryptoWorker } from "./cryptoWorkerInterface.js";
const logger = new Logger("cryptoApi.ts");
@@ -80,7 +51,7 @@ interface WorkerState {
interface WorkItem {
operation: string;
- args: any[];
+ req: unknown;
resolve: any;
reject: any;
@@ -122,10 +93,9 @@ export class CryptoApiStoppedError extends Error {
}
/**
- * Crypto API that interfaces manages a background crypto thread
- * for the execution of expensive operations.
+ * Dispatcher for cryptographic operations to underlying crypto workers.
*/
-export class CryptoApi {
+export class CryptoDispatcher {
private nextRpcId = 1;
private workers: WorkerState[];
private workQueues: WorkItem[][];
@@ -191,7 +161,7 @@ export class CryptoApi {
}
const msg: any = {
- args: work.args,
+ req: work.req,
id: work.rpcId,
operation: work.operation,
};
@@ -277,7 +247,16 @@ export class CryptoApi {
currentWorkItem.resolve(msg.data.result);
}
+ cryptoApi: TalerCryptoInterface;
+
constructor(workerFactory: CryptoWorkerFactory) {
+ const fns: any = {};
+ for (const name of Object.keys(nullCrypto)) {
+ fns[name] = (x: any) => this.doRpc(name, 0, x);
+ }
+
+ this.cryptoApi = fns;
+
this.workerFactory = workerFactory;
this.workers = new Array<WorkerState>(workerFactory.getConcurrency());
@@ -298,7 +277,7 @@ export class CryptoApi {
private doRpc<T>(
operation: string,
priority: number,
- ...args: any[]
+ req: unknown,
): Promise<T> {
if (this.stopped) {
throw new CryptoApiStoppedError();
@@ -307,7 +286,7 @@ export class CryptoApi {
const rpcId = this.nextRpcId++;
const workItem: WorkItem = {
operation,
- args,
+ req,
resolve,
reject,
rpcId,
@@ -362,163 +341,4 @@ export class CryptoApi {
});
});
}
-
- createPlanchet(req: PlanchetCreationRequest): Promise<WithdrawalPlanchet> {
- return this.doRpc<WithdrawalPlanchet>("createPlanchet", 1, req);
- }
-
- unblindDenominationSignature(req: {
- planchet: PlanchetUnblindInfo;
- evSig: BlindedDenominationSignature;
- }): Promise<UnblindedSignature> {
- return this.doRpc<UnblindedSignature>(
- "unblindDenominationSignature",
- 1,
- req,
- );
- }
-
- createTipPlanchet(req: DeriveTipRequest): Promise<DerivedTipPlanchet> {
- return this.doRpc<DerivedTipPlanchet>("createTipPlanchet", 1, req);
- }
-
- signTrackTransaction(req: SignTrackTransactionRequest): Promise<string> {
- return this.doRpc<string>("signTrackTransaction", 1, req);
- }
-
- hashString(str: string): Promise<string> {
- return this.doRpc<string>("hashString", 1, str);
- }
-
- hashEncoded(encodedBytes: string): Promise<string> {
- return this.doRpc<string>("hashEncoded", 1, encodedBytes);
- }
-
- isValidDenom(denom: DenominationRecord, masterPub: string): Promise<boolean> {
- return this.doRpc<boolean>("isValidDenom", 2, denom, masterPub);
- }
-
- isValidWireFee(
- type: string,
- wf: WireFee,
- masterPub: string,
- ): Promise<boolean> {
- return this.doRpc<boolean>("isValidWireFee", 2, type, wf, masterPub);
- }
-
- isValidPaymentSignature(
- sig: string,
- contractHash: string,
- merchantPub: string,
- ): Promise<boolean> {
- return this.doRpc<boolean>(
- "isValidPaymentSignature",
- 1,
- sig,
- contractHash,
- merchantPub,
- );
- }
-
- signDepositPermission(
- depositInfo: DepositInfo,
- ): Promise<CoinDepositPermission> {
- return this.doRpc<CoinDepositPermission>(
- "signDepositPermission",
- 3,
- depositInfo,
- );
- }
-
- createEddsaKeypair(): Promise<{ priv: string; pub: string }> {
- return this.doRpc<{ priv: string; pub: string }>("createEddsaKeypair", 1);
- }
-
- eddsaGetPublic(key: string): Promise<{ priv: string; pub: string }> {
- return this.doRpc<{ priv: string; pub: string }>("eddsaGetPublic", 1, key);
- }
-
- rsaUnblind(sig: string, bk: string, pk: string): Promise<string> {
- return this.doRpc<string>("rsaUnblind", 4, sig, bk, pk);
- }
-
- rsaVerify(hm: string, sig: string, pk: string): Promise<boolean> {
- return this.doRpc<boolean>("rsaVerify", 4, hm, sig, pk);
- }
-
- isValidWireAccount(
- versionCurrent: number,
- paytoUri: string,
- sig: string,
- masterPub: string,
- ): Promise<boolean> {
- return this.doRpc<boolean>(
- "isValidWireAccount",
- 4,
- versionCurrent,
- paytoUri,
- sig,
- masterPub,
- );
- }
-
- isValidContractTermsSignature(
- contractTermsHash: string,
- sig: string,
- merchantPub: string,
- ): Promise<boolean> {
- return this.doRpc<boolean>(
- "isValidContractTermsSignature",
- 4,
- contractTermsHash,
- sig,
- merchantPub,
- );
- }
-
- createRecoupRequest(req: CreateRecoupReqRequest): Promise<RecoupRequest> {
- return this.doRpc<RecoupRequest>("createRecoupRequest", 1, req);
- }
-
- createRecoupRefreshRequest(
- req: CreateRecoupRefreshReqRequest,
- ): Promise<RecoupRefreshRequest> {
- return this.doRpc<RecoupRefreshRequest>(
- "createRecoupRefreshRequest",
- 1,
- req,
- );
- }
-
- deriveRefreshSession(
- req: DeriveRefreshSessionRequest,
- ): Promise<DerivedRefreshSession> {
- return this.doRpc<DerivedRefreshSession>("deriveRefreshSession", 4, req);
- }
-
- signCoinLink(
- oldCoinPriv: string,
- newDenomHash: string,
- oldCoinPub: string,
- transferPub: string,
- coinEv: CoinEnvelope,
- ): Promise<string> {
- return this.doRpc<string>(
- "signCoinLink",
- 4,
- oldCoinPriv,
- newDenomHash,
- oldCoinPub,
- transferPub,
- coinEv,
- );
- }
-
- benchmark(repetitions: number): Promise<BenchmarkResult> {
- return this.doRpc<BenchmarkResult>("benchmark", 1, repetitions);
- }
-
- makeSyncSignature(req: MakeSyncSignatureRequest): Promise<string> {
- return this.doRpc<string>("makeSyncSignature", 3, req);
- }
}
diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts b/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts
deleted file mode 100644
index b27067885..000000000
--- a/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts
+++ /dev/null
@@ -1,783 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019-2020 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * Implementation of crypto-related high-level functions for the Taler wallet.
- *
- * @author Florian Dold <dold@taler.net>
- */
-
-/**
- * Imports.
- */
-
-// FIXME: Crypto should not use DB Types!
-import {
- AmountJson,
- Amounts,
- BenchmarkResult,
- buildSigPS,
- CoinDepositPermission,
- CoinEnvelope,
- createEddsaKeyPair,
- createHashContext,
- decodeCrock,
- DenomKeyType,
- DepositInfo,
- eddsaGetPublic,
- eddsaSign,
- eddsaVerify,
- encodeCrock,
- ExchangeProtocolVersion,
- FreshCoin,
- hash,
- HashCodeString,
- hashCoinEv,
- hashCoinEvInner,
- hashDenomPub,
- hashTruncate32,
- keyExchangeEcdheEddsa,
- Logger,
- MakeSyncSignatureRequest,
- PlanchetCreationRequest,
- WithdrawalPlanchet,
- randomBytes,
- RecoupRefreshRequest,
- RecoupRequest,
- RefreshPlanchetInfo,
- rsaBlind,
- rsaUnblind,
- rsaVerify,
- setupRefreshPlanchet,
- setupRefreshTransferPub,
- setupTipPlanchet,
- setupWithdrawPlanchet,
- stringToBytes,
- TalerSignaturePurpose,
- AbsoluteTime,
- BlindedDenominationSignature,
- UnblindedSignature,
- PlanchetUnblindInfo,
- TalerProtocolTimestamp,
-} from "@gnu-taler/taler-util";
-import bigint from "big-integer";
-import { DenominationRecord, WireFee } from "../../db.js";
-import * as timer from "../../util/timer.js";
-import {
- CreateRecoupRefreshReqRequest,
- CreateRecoupReqRequest,
- DerivedRefreshSession,
- DerivedTipPlanchet,
- DeriveRefreshSessionRequest,
- DeriveTipRequest,
- SignTrackTransactionRequest,
-} from "../cryptoTypes.js";
-
-const logger = new Logger("cryptoImplementation.ts");
-
-function amountToBuffer(amount: AmountJson): Uint8Array {
- const buffer = new ArrayBuffer(8 + 4 + 12);
- const dvbuf = new DataView(buffer);
- const u8buf = new Uint8Array(buffer);
- const curr = stringToBytes(amount.currency);
- if (typeof dvbuf.setBigUint64 !== "undefined") {
- dvbuf.setBigUint64(0, BigInt(amount.value));
- } else {
- const arr = bigint(amount.value).toArray(2 ** 8).value;
- let offset = 8 - arr.length;
- for (let i = 0; i < arr.length; i++) {
- dvbuf.setUint8(offset++, arr[i]);
- }
- }
- dvbuf.setUint32(8, amount.fraction);
- u8buf.set(curr, 8 + 4);
-
- return u8buf;
-}
-
-function timestampRoundedToBuffer(ts: TalerProtocolTimestamp): Uint8Array {
- const b = new ArrayBuffer(8);
- const v = new DataView(b);
- // The buffer we sign over represents the timestamp in microseconds.
- if (typeof v.setBigUint64 !== "undefined") {
- const s = BigInt(ts.t_s) * BigInt(1000 * 1000);
- v.setBigUint64(0, s);
- } else {
- const s =
- ts.t_s === "never" ? bigint.zero : bigint(ts.t_s).multiply(1000 * 1000);
- const arr = s.toArray(2 ** 8).value;
- let offset = 8 - arr.length;
- for (let i = 0; i < arr.length; i++) {
- v.setUint8(offset++, arr[i]);
- }
- }
- return new Uint8Array(b);
-}
-
-export interface PrimitiveWorker {
- setupRefreshPlanchet(arg0: {
- transfer_secret: string;
- coin_index: number;
- }): Promise<{
- coin_pub: string;
- coin_priv: string;
- blinding_key: string;
- }>;
- eddsaVerify(req: {
- msg: string;
- sig: string;
- pub: string;
- }): Promise<{ valid: boolean }>;
-
- eddsaSign(req: { msg: string; priv: string }): Promise<{ sig: string }>;
-}
-
-async function myEddsaSign(
- primitiveWorker: PrimitiveWorker | undefined,
- req: { msg: string; priv: string },
-): Promise<{ sig: string }> {
- if (primitiveWorker) {
- return primitiveWorker.eddsaSign(req);
- }
- const sig = eddsaSign(decodeCrock(req.msg), decodeCrock(req.priv));
- return {
- sig: encodeCrock(sig),
- };
-}
-
-export class CryptoImplementation {
- static enableTracing = false;
-
- constructor(private primitiveWorker?: PrimitiveWorker) {}
-
- /**
- * Create a pre-coin of the given denomination to be withdrawn from then given
- * reserve.
- */
- async createPlanchet(
- req: PlanchetCreationRequest,
- ): Promise<WithdrawalPlanchet> {
- const denomPub = req.denomPub;
- if (denomPub.cipher === DenomKeyType.Rsa) {
- const reservePub = decodeCrock(req.reservePub);
- const denomPubRsa = decodeCrock(denomPub.rsa_public_key);
- const derivedPlanchet = setupWithdrawPlanchet(
- decodeCrock(req.secretSeed),
- req.coinIndex,
- );
- const coinPubHash = hash(derivedPlanchet.coinPub);
- const ev = rsaBlind(coinPubHash, derivedPlanchet.bks, denomPubRsa);
- const coinEv: CoinEnvelope = {
- cipher: DenomKeyType.Rsa,
- rsa_blinded_planchet: encodeCrock(ev),
- };
- const amountWithFee = Amounts.add(req.value, req.feeWithdraw).amount;
- const denomPubHash = hashDenomPub(req.denomPub);
- const evHash = hashCoinEv(coinEv, encodeCrock(denomPubHash));
- const withdrawRequest = buildSigPS(
- TalerSignaturePurpose.WALLET_RESERVE_WITHDRAW,
- )
- .put(amountToBuffer(amountWithFee))
- .put(denomPubHash)
- .put(evHash)
- .build();
-
- const sigResult = await myEddsaSign(this.primitiveWorker, {
- msg: encodeCrock(withdrawRequest),
- priv: req.reservePriv,
- });
-
- const planchet: WithdrawalPlanchet = {
- blindingKey: encodeCrock(derivedPlanchet.bks),
- coinEv,
- coinPriv: encodeCrock(derivedPlanchet.coinPriv),
- coinPub: encodeCrock(derivedPlanchet.coinPub),
- coinValue: req.value,
- denomPub,
- denomPubHash: encodeCrock(denomPubHash),
- reservePub: encodeCrock(reservePub),
- withdrawSig: sigResult.sig,
- coinEvHash: encodeCrock(evHash),
- };
- return planchet;
- } else {
- throw Error("unsupported cipher, unable to create planchet");
- }
- }
-
- /**
- * Create a planchet used for tipping, including the private keys.
- */
- createTipPlanchet(req: DeriveTipRequest): DerivedTipPlanchet {
- if (req.denomPub.cipher !== DenomKeyType.Rsa) {
- throw Error(`unsupported cipher (${req.denomPub.cipher})`);
- }
- const fc = setupTipPlanchet(decodeCrock(req.secretSeed), req.planchetIndex);
- const denomPub = decodeCrock(req.denomPub.rsa_public_key);
- const coinPubHash = hash(fc.coinPub);
- const ev = rsaBlind(coinPubHash, fc.bks, denomPub);
- const coinEv = {
- cipher: DenomKeyType.Rsa,
- rsa_blinded_planchet: encodeCrock(ev),
- };
- const tipPlanchet: DerivedTipPlanchet = {
- blindingKey: encodeCrock(fc.bks),
- coinEv,
- coinEvHash: encodeCrock(
- hashCoinEv(coinEv, encodeCrock(hashDenomPub(req.denomPub))),
- ),
- coinPriv: encodeCrock(fc.coinPriv),
- coinPub: encodeCrock(fc.coinPub),
- };
- return tipPlanchet;
- }
-
- signTrackTransaction(req: SignTrackTransactionRequest): string {
- const p = buildSigPS(TalerSignaturePurpose.MERCHANT_TRACK_TRANSACTION)
- .put(decodeCrock(req.contractTermsHash))
- .put(decodeCrock(req.wireHash))
- .put(decodeCrock(req.merchantPub))
- .put(decodeCrock(req.coinPub))
- .build();
- return encodeCrock(eddsaSign(p, decodeCrock(req.merchantPriv)));
- }
-
- /**
- * Create and sign a message to recoup a coin.
- */
- createRecoupRequest(req: CreateRecoupReqRequest): RecoupRequest {
- const p = buildSigPS(TalerSignaturePurpose.WALLET_COIN_RECOUP)
- .put(decodeCrock(req.denomPubHash))
- .put(decodeCrock(req.blindingKey))
- .build();
-
- const coinPriv = decodeCrock(req.coinPriv);
- const coinSig = eddsaSign(p, coinPriv);
- if (req.denomPub.cipher === DenomKeyType.Rsa) {
- const paybackRequest: RecoupRequest = {
- coin_blind_key_secret: req.blindingKey,
- coin_sig: encodeCrock(coinSig),
- denom_pub_hash: req.denomPubHash,
- denom_sig: req.denomSig,
- // FIXME!
- ewv: {
- cipher: "RSA",
- },
- };
- return paybackRequest;
- } else {
- throw new Error();
- }
- }
-
- /**
- * Create and sign a message to recoup a coin.
- */
- createRecoupRefreshRequest(
- req: CreateRecoupRefreshReqRequest,
- ): RecoupRefreshRequest {
- const p = buildSigPS(TalerSignaturePurpose.WALLET_COIN_RECOUP_REFRESH)
- .put(decodeCrock(req.denomPubHash))
- .put(decodeCrock(req.blindingKey))
- .build();
-
- const coinPriv = decodeCrock(req.coinPriv);
- const coinSig = eddsaSign(p, coinPriv);
- if (req.denomPub.cipher === DenomKeyType.Rsa) {
- const recoupRequest: RecoupRefreshRequest = {
- coin_blind_key_secret: req.blindingKey,
- coin_sig: encodeCrock(coinSig),
- denom_pub_hash: req.denomPubHash,
- denom_sig: req.denomSig,
- // FIXME!
- ewv: {
- cipher: "RSA",
- },
- };
- return recoupRequest;
- } else {
- throw new Error();
- }
- }
-
- /**
- * Check if a payment signature is valid.
- */
- isValidPaymentSignature(
- sig: string,
- contractHash: string,
- merchantPub: string,
- ): boolean {
- const p = buildSigPS(TalerSignaturePurpose.MERCHANT_PAYMENT_OK)
- .put(decodeCrock(contractHash))
- .build();
- const sigBytes = decodeCrock(sig);
- const pubBytes = decodeCrock(merchantPub);
- return eddsaVerify(p, sigBytes, pubBytes);
- }
-
- /**
- * Check if a wire fee is correctly signed.
- */
- async isValidWireFee(
- type: string,
- wf: WireFee,
- masterPub: string,
- ): Promise<boolean> {
- const p = buildSigPS(TalerSignaturePurpose.MASTER_WIRE_FEES)
- .put(hash(stringToBytes(type + "\0")))
- .put(timestampRoundedToBuffer(wf.startStamp))
- .put(timestampRoundedToBuffer(wf.endStamp))
- .put(amountToBuffer(wf.wireFee))
- .put(amountToBuffer(wf.closingFee))
- .put(amountToBuffer(wf.wadFee))
- .build();
- const sig = decodeCrock(wf.sig);
- const pub = decodeCrock(masterPub);
- if (this.primitiveWorker) {
- return (
- await this.primitiveWorker.eddsaVerify({
- msg: encodeCrock(p),
- pub: masterPub,
- sig: encodeCrock(sig),
- })
- ).valid;
- }
- return eddsaVerify(p, sig, pub);
- }
-
- /**
- * Check if the signature of a denomination is valid.
- */
- async isValidDenom(
- denom: DenominationRecord,
- masterPub: string,
- ): Promise<boolean> {
- const p = buildSigPS(TalerSignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY)
- .put(decodeCrock(masterPub))
- .put(timestampRoundedToBuffer(denom.stampStart))
- .put(timestampRoundedToBuffer(denom.stampExpireWithdraw))
- .put(timestampRoundedToBuffer(denom.stampExpireDeposit))
- .put(timestampRoundedToBuffer(denom.stampExpireLegal))
- .put(amountToBuffer(denom.value))
- .put(amountToBuffer(denom.feeWithdraw))
- .put(amountToBuffer(denom.feeDeposit))
- .put(amountToBuffer(denom.feeRefresh))
- .put(amountToBuffer(denom.feeRefund))
- .put(decodeCrock(denom.denomPubHash))
- .build();
- const sig = decodeCrock(denom.masterSig);
- const pub = decodeCrock(masterPub);
- const res = eddsaVerify(p, sig, pub);
- return res;
- }
-
- isValidWireAccount(
- versionCurrent: ExchangeProtocolVersion,
- paytoUri: string,
- sig: string,
- masterPub: string,
- ): boolean {
- const paytoHash = hashTruncate32(stringToBytes(paytoUri + "\0"));
- const p = buildSigPS(TalerSignaturePurpose.MASTER_WIRE_DETAILS)
- .put(paytoHash)
- .build();
- return eddsaVerify(p, decodeCrock(sig), decodeCrock(masterPub));
- }
-
- isValidContractTermsSignature(
- contractTermsHash: string,
- sig: string,
- merchantPub: string,
- ): boolean {
- const cthDec = decodeCrock(contractTermsHash);
- const p = buildSigPS(TalerSignaturePurpose.MERCHANT_CONTRACT)
- .put(cthDec)
- .build();
- return eddsaVerify(p, decodeCrock(sig), decodeCrock(merchantPub));
- }
-
- /**
- * Create a new EdDSA key pair.
- */
- createEddsaKeypair(): { priv: string; pub: string } {
- const pair = createEddsaKeyPair();
- return {
- priv: encodeCrock(pair.eddsaPriv),
- pub: encodeCrock(pair.eddsaPub),
- };
- }
-
- eddsaGetPublic(key: string): { priv: string; pub: string } {
- return {
- priv: key,
- pub: encodeCrock(eddsaGetPublic(decodeCrock(key))),
- };
- }
-
- unblindDenominationSignature(req: {
- planchet: PlanchetUnblindInfo;
- evSig: BlindedDenominationSignature;
- }): UnblindedSignature {
- if (req.evSig.cipher === DenomKeyType.Rsa) {
- if (req.planchet.denomPub.cipher !== DenomKeyType.Rsa) {
- throw new Error(
- "planchet cipher does not match blind signature cipher",
- );
- }
- const denomSig = rsaUnblind(
- decodeCrock(req.evSig.blinded_rsa_signature),
- decodeCrock(req.planchet.denomPub.rsa_public_key),
- decodeCrock(req.planchet.blindingKey),
- );
- return {
- cipher: DenomKeyType.Rsa,
- rsa_signature: encodeCrock(denomSig),
- };
- } else {
- throw Error(`unblinding for cipher ${req.evSig.cipher} not implemented`);
- }
- }
-
- /**
- * Unblind a blindly signed value.
- */
- rsaUnblind(blindedSig: string, bk: string, pk: string): string {
- const denomSig = rsaUnblind(
- decodeCrock(blindedSig),
- decodeCrock(pk),
- decodeCrock(bk),
- );
- return encodeCrock(denomSig);
- }
-
- /**
- * Unblind a blindly signed value.
- */
- rsaVerify(hm: string, sig: string, pk: string): boolean {
- return rsaVerify(hash(decodeCrock(hm)), decodeCrock(sig), decodeCrock(pk));
- }
-
- /**
- * Generate updated coins (to store in the database)
- * and deposit permissions for each given coin.
- */
- async signDepositPermission(
- depositInfo: DepositInfo,
- ): Promise<CoinDepositPermission> {
- // FIXME: put extensions here if used
- const hExt = new Uint8Array(64);
- const hAgeCommitment = new Uint8Array(32);
- let d: Uint8Array;
- if (depositInfo.denomKeyType === DenomKeyType.Rsa) {
- d = buildSigPS(TalerSignaturePurpose.WALLET_COIN_DEPOSIT)
- .put(decodeCrock(depositInfo.contractTermsHash))
- .put(hAgeCommitment)
- .put(hExt)
- .put(decodeCrock(depositInfo.wireInfoHash))
- .put(decodeCrock(depositInfo.denomPubHash))
- .put(timestampRoundedToBuffer(depositInfo.timestamp))
- .put(timestampRoundedToBuffer(depositInfo.refundDeadline))
- .put(amountToBuffer(depositInfo.spendAmount))
- .put(amountToBuffer(depositInfo.feeDeposit))
- .put(decodeCrock(depositInfo.merchantPub))
- .build();
- } else {
- throw Error("unsupported exchange protocol version");
- }
- const coinSigRes = await myEddsaSign(this.primitiveWorker, {
- msg: encodeCrock(d),
- priv: depositInfo.coinPriv,
- });
-
- if (depositInfo.denomKeyType === DenomKeyType.Rsa) {
- const s: CoinDepositPermission = {
- coin_pub: depositInfo.coinPub,
- coin_sig: coinSigRes.sig,
- contribution: Amounts.stringify(depositInfo.spendAmount),
- h_denom: depositInfo.denomPubHash,
- exchange_url: depositInfo.exchangeBaseUrl,
- ub_sig: {
- cipher: DenomKeyType.Rsa,
- rsa_signature: depositInfo.denomSig.rsa_signature,
- },
- };
- return s;
- } else {
- throw Error(
- `unsupported denomination cipher (${depositInfo.denomKeyType})`,
- );
- }
- }
-
- async deriveRefreshSession(
- req: DeriveRefreshSessionRequest,
- ): Promise<DerivedRefreshSession> {
- const {
- newCoinDenoms,
- feeRefresh: meltFee,
- kappa,
- meltCoinDenomPubHash,
- meltCoinPriv,
- meltCoinPub,
- sessionSecretSeed: refreshSessionSecretSeed,
- } = req;
-
- const currency = newCoinDenoms[0].value.currency;
- let valueWithFee = Amounts.getZero(currency);
-
- for (const ncd of newCoinDenoms) {
- const t = Amounts.add(ncd.value, ncd.feeWithdraw).amount;
- valueWithFee = Amounts.add(
- valueWithFee,
- Amounts.mult(t, ncd.count).amount,
- ).amount;
- }
-
- // melt fee
- valueWithFee = Amounts.add(valueWithFee, meltFee).amount;
-
- const sessionHc = createHashContext();
-
- const transferPubs: string[] = [];
- const transferPrivs: string[] = [];
-
- const planchetsForGammas: RefreshPlanchetInfo[][] = [];
-
- for (let i = 0; i < kappa; i++) {
- const transferKeyPair = setupRefreshTransferPub(
- decodeCrock(refreshSessionSecretSeed),
- i,
- );
- sessionHc.update(transferKeyPair.ecdhePub);
- transferPrivs.push(encodeCrock(transferKeyPair.ecdhePriv));
- transferPubs.push(encodeCrock(transferKeyPair.ecdhePub));
- }
-
- for (const denomSel of newCoinDenoms) {
- for (let i = 0; i < denomSel.count; i++) {
- if (denomSel.denomPub.cipher === DenomKeyType.Rsa) {
- const denomPubHash = hashDenomPub(denomSel.denomPub);
- sessionHc.update(denomPubHash);
- } else {
- throw new Error();
- }
- }
- }
-
- sessionHc.update(decodeCrock(meltCoinPub));
- sessionHc.update(amountToBuffer(valueWithFee));
-
- for (let i = 0; i < kappa; i++) {
- const planchets: RefreshPlanchetInfo[] = [];
- for (let j = 0; j < newCoinDenoms.length; j++) {
- const denomSel = newCoinDenoms[j];
- for (let k = 0; k < denomSel.count; k++) {
- const coinIndex = planchets.length;
- const transferPriv = decodeCrock(transferPrivs[i]);
- const oldCoinPub = decodeCrock(meltCoinPub);
- const transferSecret = keyExchangeEcdheEddsa(
- transferPriv,
- oldCoinPub,
- );
- let coinPub: Uint8Array;
- let coinPriv: Uint8Array;
- let blindingFactor: Uint8Array;
- // disabled while not implemented in the C code
- if (0 && this.primitiveWorker) {
- const r = await this.primitiveWorker.setupRefreshPlanchet({
- transfer_secret: encodeCrock(transferSecret),
- coin_index: coinIndex,
- });
- coinPub = decodeCrock(r.coin_pub);
- coinPriv = decodeCrock(r.coin_priv);
- blindingFactor = decodeCrock(r.blinding_key);
- } else {
- let fresh: FreshCoin = setupRefreshPlanchet(
- transferSecret,
- coinIndex,
- );
- coinPriv = fresh.coinPriv;
- coinPub = fresh.coinPub;
- blindingFactor = fresh.bks;
- }
- const coinPubHash = hash(coinPub);
- if (denomSel.denomPub.cipher !== DenomKeyType.Rsa) {
- throw Error("unsupported cipher, can't create refresh session");
- }
- const rsaDenomPub = decodeCrock(denomSel.denomPub.rsa_public_key);
- const ev = rsaBlind(coinPubHash, blindingFactor, rsaDenomPub);
- const coinEv: CoinEnvelope = {
- cipher: DenomKeyType.Rsa,
- rsa_blinded_planchet: encodeCrock(ev),
- };
- const coinEvHash = hashCoinEv(
- coinEv,
- encodeCrock(hashDenomPub(denomSel.denomPub)),
- );
- const planchet: RefreshPlanchetInfo = {
- blindingKey: encodeCrock(blindingFactor),
- coinEv,
- coinPriv: encodeCrock(coinPriv),
- coinPub: encodeCrock(coinPub),
- coinEvHash: encodeCrock(coinEvHash),
- };
- planchets.push(planchet);
- hashCoinEvInner(coinEv, sessionHc);
- }
- }
- planchetsForGammas.push(planchets);
- }
-
- const sessionHash = sessionHc.finish();
- let confirmData: Uint8Array;
- // FIXME: fill in age commitment
- const hAgeCommitment = new Uint8Array(32);
- confirmData = buildSigPS(TalerSignaturePurpose.WALLET_COIN_MELT)
- .put(sessionHash)
- .put(decodeCrock(meltCoinDenomPubHash))
- .put(hAgeCommitment)
- .put(amountToBuffer(valueWithFee))
- .put(amountToBuffer(meltFee))
- .build();
-
- const confirmSigResp = await myEddsaSign(this.primitiveWorker, {
- msg: encodeCrock(confirmData),
- priv: meltCoinPriv,
- });
-
- const refreshSession: DerivedRefreshSession = {
- confirmSig: confirmSigResp.sig,
- hash: encodeCrock(sessionHash),
- meltCoinPub: meltCoinPub,
- planchetsForGammas: planchetsForGammas,
- transferPrivs,
- transferPubs,
- meltValueWithFee: valueWithFee,
- };
-
- return refreshSession;
- }
-
- /**
- * Hash a string including the zero terminator.
- */
- hashString(str: string): string {
- const b = stringToBytes(str + "\0");
- return encodeCrock(hash(b));
- }
-
- /**
- * Hash a crockford encoded value.
- */
- hashEncoded(encodedBytes: string): string {
- return encodeCrock(hash(decodeCrock(encodedBytes)));
- }
-
- async signCoinLink(
- oldCoinPriv: string,
- newDenomHash: string,
- oldCoinPub: string,
- transferPub: string,
- coinEv: CoinEnvelope,
- ): Promise<string> {
- const coinEvHash = hashCoinEv(coinEv, newDenomHash);
- // FIXME: fill in
- const hAgeCommitment = new Uint8Array(32);
- const coinLink = buildSigPS(TalerSignaturePurpose.WALLET_COIN_LINK)
- .put(decodeCrock(newDenomHash))
- .put(decodeCrock(transferPub))
- .put(hAgeCommitment)
- .put(coinEvHash)
- .build();
- const sig = await myEddsaSign(this.primitiveWorker, {
- msg: encodeCrock(coinLink),
- priv: oldCoinPriv,
- });
- return sig.sig;
- }
-
- benchmark(repetitions: number): BenchmarkResult {
- let time_hash = BigInt(0);
- for (let i = 0; i < repetitions; i++) {
- const start = timer.performanceNow();
- this.hashString("hello world");
- time_hash += timer.performanceNow() - start;
- }
-
- let time_hash_big = BigInt(0);
- for (let i = 0; i < repetitions; i++) {
- const ba = randomBytes(4096);
- const start = timer.performanceNow();
- hash(ba);
- time_hash_big += timer.performanceNow() - start;
- }
-
- let time_eddsa_create = BigInt(0);
- for (let i = 0; i < repetitions; i++) {
- const start = timer.performanceNow();
- createEddsaKeyPair();
- time_eddsa_create += timer.performanceNow() - start;
- }
-
- let time_eddsa_sign = BigInt(0);
- const p = randomBytes(4096);
-
- const pair = createEddsaKeyPair();
-
- for (let i = 0; i < repetitions; i++) {
- const start = timer.performanceNow();
- eddsaSign(p, pair.eddsaPriv);
- time_eddsa_sign += timer.performanceNow() - start;
- }
-
- const sig = eddsaSign(p, pair.eddsaPriv);
-
- let time_eddsa_verify = BigInt(0);
- for (let i = 0; i < repetitions; i++) {
- const start = timer.performanceNow();
- eddsaVerify(p, sig, pair.eddsaPub);
- time_eddsa_verify += timer.performanceNow() - start;
- }
-
- return {
- repetitions,
- time: {
- hash_small: Number(time_hash),
- hash_big: Number(time_hash_big),
- eddsa_create: Number(time_eddsa_create),
- eddsa_sign: Number(time_eddsa_sign),
- eddsa_verify: Number(time_eddsa_verify),
- },
- };
- }
-
- makeSyncSignature(req: MakeSyncSignatureRequest): string {
- const hNew = decodeCrock(req.newHash);
- let hOld: Uint8Array;
- if (req.oldHash) {
- hOld = decodeCrock(req.oldHash);
- } else {
- hOld = new Uint8Array(64);
- }
- const sigBlob = buildSigPS(TalerSignaturePurpose.SYNC_BACKUP_UPLOAD)
- .put(hOld)
- .put(hNew)
- .build();
- const uploadSig = eddsaSign(sigBlob, decodeCrock(req.accountPriv));
- return encodeCrock(uploadSig);
- }
-}
diff --git a/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts b/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts
index df57635d1..42370fc1b 100644
--- a/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts
@@ -17,11 +17,11 @@
/**
* Imports
*/
-import { CryptoWorkerFactory } from "./cryptoApi.js";
+import { CryptoWorkerFactory } from "./cryptoDispatcher.js";
import { CryptoWorker } from "./cryptoWorkerInterface.js";
import os from "os";
-import { CryptoImplementation } from "./cryptoImplementation.js";
import { Logger } from "@gnu-taler/taler-util";
+import { nativeCryptoR } from "../cryptoImplementation.js";
const logger = new Logger("nodeThreadWorker.ts");
@@ -69,9 +69,9 @@ const workerCode = `
* a message.
*/
export function handleWorkerMessage(msg: any): void {
- const args = msg.args;
- if (!Array.isArray(args)) {
- console.error("args must be array");
+ const req = msg.req;
+ if (typeof req !== "object") {
+ console.error("request must be an object");
return;
}
const id = msg.id;
@@ -86,7 +86,7 @@ export function handleWorkerMessage(msg: any): void {
}
const handleRequest = async (): Promise<void> => {
- const impl = new CryptoImplementation();
+ const impl = nativeCryptoR;
if (!(operation in impl)) {
console.error(`crypto operation '${operation}' not found`);
@@ -94,12 +94,11 @@ export function handleWorkerMessage(msg: any): void {
}
try {
- const result = await (impl as any)[operation](...args);
+ const result = await (impl as any)[operation](impl, req);
// eslint-disable-next-line @typescript-eslint/no-var-requires
const _r = "require";
- const worker_threads: typeof import("worker_threads") = module[_r](
- "worker_threads",
- );
+ const worker_threads: typeof import("worker_threads") =
+ module[_r]("worker_threads");
// const worker_threads = require("worker_threads");
const p = worker_threads.parentPort;
diff --git a/packages/taler-wallet-core/src/crypto/workers/rpcClient.ts b/packages/taler-wallet-core/src/crypto/workers/rpcClient.ts
new file mode 100644
index 000000000..a8df8b4c6
--- /dev/null
+++ b/packages/taler-wallet-core/src/crypto/workers/rpcClient.ts
@@ -0,0 +1,90 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Imports.
+ */
+import { Logger } from "@gnu-taler/taler-util";
+import child_process from "child_process";
+import type internal from "stream";
+import { OpenedPromise, openPromise } from "../../util/promiseUtils.js";
+
+const logger = new Logger("synchronousWorkerFactory.ts");
+
+export class CryptoRpcClient {
+ proc: child_process.ChildProcessByStdio<
+ internal.Writable,
+ internal.Readable,
+ null
+ >;
+ requests: Array<{
+ p: OpenedPromise<any>;
+ req: any;
+ }> = [];
+
+ constructor() {
+ const stdoutChunks: Buffer[] = [];
+ this.proc = child_process.spawn("taler-crypto-worker", {
+ //stdio: ["pipe", "pipe", "inherit"],
+ stdio: ["pipe", "pipe", "inherit"],
+ detached: true,
+ });
+ this.proc.on("close", (): void => {
+ logger.error("child process exited");
+ });
+ (this.proc.stdout as any).unref();
+ (this.proc.stdin as any).unref();
+ this.proc.unref();
+
+ this.proc.stdout.on("data", (x) => {
+ // console.log("got chunk", x.toString("utf-8"));
+ if (x instanceof Buffer) {
+ const nlIndex = x.indexOf("\n");
+ if (nlIndex >= 0) {
+ const before = x.slice(0, nlIndex);
+ const after = x.slice(nlIndex + 1);
+ stdoutChunks.push(after);
+ const str = Buffer.concat([...stdoutChunks, before]).toString(
+ "utf-8",
+ );
+ const req = this.requests.shift();
+ if (!req) {
+ throw Error("request was undefined");
+ }
+ if (this.requests.length === 0) {
+ this.proc.unref();
+ }
+ //logger.info(`got response: ${str}`);
+ req.p.resolve(JSON.parse(str));
+ } else {
+ stdoutChunks.push(x);
+ }
+ } else {
+ throw Error(`unexpected data chunk type (${typeof x})`);
+ }
+ });
+ }
+
+ async queueRequest(req: any): Promise<any> {
+ const p = openPromise<any>();
+ if (this.requests.length === 0) {
+ this.proc.ref();
+ }
+ this.requests.push({ req, p });
+ this.proc.stdin.write(`${JSON.stringify(req)}\n`);
+ return p.promise;
+ }
+}
diff --git a/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts b/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts
index 4d341718e..1d7539ed6 100644
--- a/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts
@@ -16,11 +16,10 @@
import { Logger } from "@gnu-taler/taler-util";
import {
- CryptoImplementation,
- PrimitiveWorker
-} from "./cryptoImplementation.js";
-
-
+ nativeCryptoR,
+ TalerCryptoInterfaceR,
+} from "../cryptoImplementation.js";
+import { CryptoRpcClient } from "./rpcClient.js";
const logger = new Logger("synchronousWorker.ts");
@@ -38,9 +37,33 @@ export class SynchronousCryptoWorker {
*/
onerror: undefined | ((m: any) => void);
- constructor(private primitiveWorker?: PrimitiveWorker) {
+ cryptoImplR: TalerCryptoInterfaceR;
+
+ rpcClient: CryptoRpcClient | undefined;
+
+ constructor() {
this.onerror = undefined;
this.onmessage = undefined;
+
+ this.cryptoImplR = { ...nativeCryptoR };
+
+ if (
+ process.env["TALER_WALLET_RPC_CRYPRO"] ||
+ // Old name
+ process.env["TALER_WALLET_PRIMITIVE_WORKER"]
+ ) {
+ const rpc = (this.rpcClient = new CryptoRpcClient());
+ this.cryptoImplR.eddsaSign = async (_, req) => {
+ logger.trace("making RPC request");
+ return await rpc.queueRequest({
+ op: "eddsa_sign",
+ args: {
+ msg: req.msg,
+ priv: req.priv,
+ },
+ });
+ };
+ }
}
/**
@@ -66,9 +89,9 @@ export class SynchronousCryptoWorker {
private async handleRequest(
operation: string,
id: number,
- args: string[],
+ req: unknown,
): Promise<void> {
- const impl = new CryptoImplementation(this.primitiveWorker);
+ const impl = this.cryptoImplR;
if (!(operation in impl)) {
console.error(`crypto operation '${operation}' not found`);
@@ -77,7 +100,7 @@ export class SynchronousCryptoWorker {
let result: any;
try {
- result = await (impl as any)[operation](...args);
+ result = await (impl as any)[operation](impl, req);
} catch (e) {
logger.error("error during operation", e);
return;
@@ -94,9 +117,9 @@ export class SynchronousCryptoWorker {
* Send a message to the worker thread.
*/
postMessage(msg: any): void {
- const args = msg.args;
- if (!Array.isArray(args)) {
- console.error("args must be array");
+ const req = msg.req;
+ if (typeof req !== "object") {
+ console.error("request must be an object");
return;
}
const id = msg.id;
@@ -110,7 +133,7 @@ export class SynchronousCryptoWorker {
return;
}
- this.handleRequest(operation, id, args).catch((e) => {
+ this.handleRequest(operation, id, req).catch((e) => {
console.error("Error while handling crypto request:", e);
});
}
diff --git a/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactory.ts b/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactory.ts
index ca63c7687..47f58be13 100644
--- a/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactory.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactory.ts
@@ -14,121 +14,13 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import {
- PrimitiveWorker,
-} from "./cryptoImplementation.js";
-
-import { CryptoWorkerFactory } from "./cryptoApi.js";
+/**
+ * Imports.
+ */
+import { CryptoWorkerFactory } from "./cryptoDispatcher.js";
import { CryptoWorker } from "./cryptoWorkerInterface.js";
-
-import child_process from "child_process";
-import type internal from "stream";
-import { OpenedPromise, openPromise } from "../../index.js";
-import { Logger } from "@gnu-taler/taler-util";
import { SynchronousCryptoWorker } from "./synchronousWorker.js";
-const logger = new Logger("synchronousWorkerFactory.ts");
-
-class MyPrimitiveWorker implements PrimitiveWorker {
- proc: child_process.ChildProcessByStdio<
- internal.Writable,
- internal.Readable,
- null
- >;
- requests: Array<{
- p: OpenedPromise<any>;
- req: any;
- }> = [];
-
- constructor() {
- const stdoutChunks: Buffer[] = [];
- this.proc = child_process.spawn("taler-crypto-worker", {
- //stdio: ["pipe", "pipe", "inherit"],
- stdio: ["pipe", "pipe", "inherit"],
- detached: true,
- });
- this.proc.on("close", (): void => {
- logger.error("child process exited");
- });
- (this.proc.stdout as any).unref();
- (this.proc.stdin as any).unref();
- this.proc.unref();
-
- this.proc.stdout.on("data", (x) => {
- // console.log("got chunk", x.toString("utf-8"));
- if (x instanceof Buffer) {
- const nlIndex = x.indexOf("\n");
- if (nlIndex >= 0) {
- const before = x.slice(0, nlIndex);
- const after = x.slice(nlIndex + 1);
- stdoutChunks.push(after);
- const str = Buffer.concat([...stdoutChunks, before]).toString(
- "utf-8",
- );
- const req = this.requests.shift();
- if (!req) {
- throw Error("request was undefined")
- }
- if (this.requests.length === 0) {
- this.proc.unref();
- }
- //logger.info(`got response: ${str}`);
- req.p.resolve(JSON.parse(str));
- } else {
- stdoutChunks.push(x);
- }
- } else {
- throw Error(`unexpected data chunk type (${typeof x})`);
- }
- });
- }
-
- async setupRefreshPlanchet(req: {
- transfer_secret: string;
- coin_index: number;
- }): Promise<{
- coin_pub: string;
- coin_priv: string;
- blinding_key: string;
- }> {
- return this.queueRequest({
- op: "setup_refresh_planchet",
- args: req,
- });
- }
-
- async queueRequest(req: any): Promise<any> {
- const p = openPromise<any>();
- if (this.requests.length === 0) {
- this.proc.ref();
- }
- this.requests.push({ req, p });
- this.proc.stdin.write(`${JSON.stringify(req)}\n`);
- return p.promise;
- }
-
- async eddsaVerify(req: {
- msg: string;
- sig: string;
- pub: string;
- }): Promise<{ valid: boolean }> {
- return this.queueRequest({
- op: "eddsa_verify",
- args: req,
- });
- }
-
- async eddsaSign(req: {
- msg: string;
- priv: string;
- }): Promise<{ sig: string }> {
- return this.queueRequest({
- op: "eddsa_sign",
- args: req,
- });
- }
-}
-
/**
* The synchronous crypto worker produced by this factory doesn't run in the
* background, but actually blocks the caller until the operation is done.
@@ -139,12 +31,7 @@ export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory {
throw Error("cannot make worker, require(...) not defined");
}
- let primitiveWorker;
- if (process.env["TALER_WALLET_PRIMITIVE_WORKER"]) {
- primitiveWorker = new MyPrimitiveWorker();
- }
-
- return new SynchronousCryptoWorker(primitiveWorker);
+ return new SynchronousCryptoWorker();
}
getConcurrency(): number {