wallet: crypto worker fixes, better taler-crypto-worker integration
This commit is contained in:
parent
cc18751e72
commit
9d38cb56a6
@ -692,7 +692,7 @@ export interface FreshCoin {
|
|||||||
bks: Uint8Array;
|
bks: Uint8Array;
|
||||||
}
|
}
|
||||||
|
|
||||||
function bufferForUint32(n: number): Uint8Array {
|
export function bufferForUint32(n: number): Uint8Array {
|
||||||
const arrBuf = new ArrayBuffer(4);
|
const arrBuf = new ArrayBuffer(4);
|
||||||
const buf = new Uint8Array(arrBuf);
|
const buf = new Uint8Array(arrBuf);
|
||||||
const dv = new DataView(arrBuf);
|
const dv = new DataView(arrBuf);
|
||||||
@ -700,37 +700,6 @@ function bufferForUint32(n: number): Uint8Array {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setupRefreshPlanchet(
|
|
||||||
transferSecret: Uint8Array,
|
|
||||||
coinNumber: number,
|
|
||||||
): FreshCoin {
|
|
||||||
// See TALER_transfer_secret_to_planchet_secret in C impl
|
|
||||||
const planchetMasterSecret = kdfKw({
|
|
||||||
ikm: transferSecret,
|
|
||||||
outputLength: 32,
|
|
||||||
salt: bufferForUint32(coinNumber),
|
|
||||||
info: stringToBytes("taler-coin-derivation"),
|
|
||||||
});
|
|
||||||
|
|
||||||
const coinPriv = kdfKw({
|
|
||||||
ikm: planchetMasterSecret,
|
|
||||||
outputLength: 32,
|
|
||||||
salt: stringToBytes("coin"),
|
|
||||||
});
|
|
||||||
|
|
||||||
const bks = kdfKw({
|
|
||||||
ikm: planchetMasterSecret,
|
|
||||||
outputLength: 32,
|
|
||||||
salt: stringToBytes("bks"),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
bks,
|
|
||||||
coinPriv,
|
|
||||||
coinPub: eddsaGetPublic(coinPriv),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setupWithdrawPlanchet(
|
export function setupWithdrawPlanchet(
|
||||||
secretSeed: Uint8Array,
|
secretSeed: Uint8Array,
|
||||||
coinNumber: number,
|
coinNumber: number,
|
||||||
@ -786,10 +755,10 @@ export function setupRefreshTransferPub(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param paytoUri
|
* @param paytoUri
|
||||||
* @param salt 16-byte salt
|
* @param salt 16-byte salt
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function hashWire(paytoUri: string, salt: string): string {
|
export function hashWire(paytoUri: string, salt: string): string {
|
||||||
const r = kdf(
|
const r = kdf(
|
||||||
|
@ -64,7 +64,10 @@ import { runBench1 } from "./bench1.js";
|
|||||||
import { runEnv1 } from "./env1.js";
|
import { runEnv1 } from "./env1.js";
|
||||||
import { GlobalTestState, runTestWithState } from "./harness/harness.js";
|
import { GlobalTestState, runTestWithState } from "./harness/harness.js";
|
||||||
import { runBench2 } from "./bench2.js";
|
import { runBench2 } from "./bench2.js";
|
||||||
import { TalerCryptoInterface, TalerCryptoInterfaceR } from "@gnu-taler/taler-wallet-core/src/crypto/cryptoImplementation";
|
import {
|
||||||
|
TalerCryptoInterface,
|
||||||
|
TalerCryptoInterfaceR,
|
||||||
|
} from "@gnu-taler/taler-wallet-core/src/crypto/cryptoImplementation";
|
||||||
|
|
||||||
// This module also serves as the entry point for the crypto
|
// This module also serves as the entry point for the crypto
|
||||||
// thread worker, and thus must expose these two handlers.
|
// thread worker, and thus must expose these two handlers.
|
||||||
@ -75,6 +78,12 @@ export {
|
|||||||
|
|
||||||
const logger = new Logger("taler-wallet-cli.ts");
|
const logger = new Logger("taler-wallet-cli.ts");
|
||||||
|
|
||||||
|
process.on("unhandledRejection", (error: any) => {
|
||||||
|
logger.error("unhandledRejection", error.message);
|
||||||
|
logger.error("stack", error.stack);
|
||||||
|
process.exit(2);
|
||||||
|
});
|
||||||
|
|
||||||
const defaultWalletDbPath = os.homedir + "/" + ".talerwalletdb.json";
|
const defaultWalletDbPath = os.homedir + "/" + ".talerwalletdb.json";
|
||||||
|
|
||||||
function assertUnreachable(x: never): never {
|
function assertUnreachable(x: never): never {
|
||||||
@ -218,6 +227,7 @@ async function withWallet<T>(
|
|||||||
} finally {
|
} finally {
|
||||||
logger.info("operation with wallet finished, stopping");
|
logger.info("operation with wallet finished, stopping");
|
||||||
wallet.stop();
|
wallet.stop();
|
||||||
|
logger.info("stopped wallet");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,13 +260,18 @@ walletCli
|
|||||||
console.error("Invalid JSON");
|
console.error("Invalid JSON");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
const resp = await wallet.ws.handleCoreApiRequest(
|
try {
|
||||||
args.api.operation,
|
const resp = await wallet.ws.handleCoreApiRequest(
|
||||||
"reqid-1",
|
args.api.operation,
|
||||||
requestJson,
|
"reqid-1",
|
||||||
);
|
requestJson,
|
||||||
console.log(JSON.stringify(resp, undefined, 2));
|
);
|
||||||
|
console.log(JSON.stringify(resp, undefined, 2));
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Got exception while handling API request ${e}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
logger.info("finished handling API request");
|
||||||
});
|
});
|
||||||
|
|
||||||
walletCli
|
walletCli
|
||||||
|
@ -42,7 +42,6 @@ import {
|
|||||||
eddsaVerify,
|
eddsaVerify,
|
||||||
encodeCrock,
|
encodeCrock,
|
||||||
ExchangeProtocolVersion,
|
ExchangeProtocolVersion,
|
||||||
FreshCoin,
|
|
||||||
hash,
|
hash,
|
||||||
hashCoinEv,
|
hashCoinEv,
|
||||||
hashCoinEvInner,
|
hashCoinEvInner,
|
||||||
@ -53,14 +52,12 @@ import {
|
|||||||
MakeSyncSignatureRequest,
|
MakeSyncSignatureRequest,
|
||||||
PlanchetCreationRequest,
|
PlanchetCreationRequest,
|
||||||
WithdrawalPlanchet,
|
WithdrawalPlanchet,
|
||||||
randomBytes,
|
|
||||||
RecoupRefreshRequest,
|
RecoupRefreshRequest,
|
||||||
RecoupRequest,
|
RecoupRequest,
|
||||||
RefreshPlanchetInfo,
|
RefreshPlanchetInfo,
|
||||||
rsaBlind,
|
rsaBlind,
|
||||||
rsaUnblind,
|
rsaUnblind,
|
||||||
rsaVerify,
|
rsaVerify,
|
||||||
setupRefreshPlanchet,
|
|
||||||
setupRefreshTransferPub,
|
setupRefreshTransferPub,
|
||||||
setupTipPlanchet,
|
setupTipPlanchet,
|
||||||
setupWithdrawPlanchet,
|
setupWithdrawPlanchet,
|
||||||
@ -70,6 +67,8 @@ import {
|
|||||||
UnblindedSignature,
|
UnblindedSignature,
|
||||||
PlanchetUnblindInfo,
|
PlanchetUnblindInfo,
|
||||||
TalerProtocolTimestamp,
|
TalerProtocolTimestamp,
|
||||||
|
kdfKw,
|
||||||
|
bufferForUint32,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import bigint from "big-integer";
|
import bigint from "big-integer";
|
||||||
import { DenominationRecord, WireFee } from "../db.js";
|
import { DenominationRecord, WireFee } from "../db.js";
|
||||||
@ -141,6 +140,8 @@ export interface TalerCryptoInterface {
|
|||||||
|
|
||||||
rsaVerify(req: RsaVerificationRequest): Promise<ValidationResult>;
|
rsaVerify(req: RsaVerificationRequest): Promise<ValidationResult>;
|
||||||
|
|
||||||
|
rsaBlind(req: RsaBlindRequest): Promise<RsaBlindResponse>;
|
||||||
|
|
||||||
signDepositPermission(
|
signDepositPermission(
|
||||||
depositInfo: DepositInfo,
|
depositInfo: DepositInfo,
|
||||||
): Promise<CoinDepositPermission>;
|
): Promise<CoinDepositPermission>;
|
||||||
@ -154,6 +155,14 @@ export interface TalerCryptoInterface {
|
|||||||
signCoinLink(req: SignCoinLinkRequest): Promise<EddsaSigningResult>;
|
signCoinLink(req: SignCoinLinkRequest): Promise<EddsaSigningResult>;
|
||||||
|
|
||||||
makeSyncSignature(req: MakeSyncSignatureRequest): Promise<EddsaSigningResult>;
|
makeSyncSignature(req: MakeSyncSignatureRequest): Promise<EddsaSigningResult>;
|
||||||
|
|
||||||
|
setupRefreshPlanchet(
|
||||||
|
req: SetupRefreshPlanchetRequest,
|
||||||
|
): Promise<FreshCoinEncoded>;
|
||||||
|
|
||||||
|
keyExchangeEcdheEddsa(
|
||||||
|
req: KeyExchangeEcdheEddsaRequest,
|
||||||
|
): Promise<KeyExchangeResult>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -257,6 +266,19 @@ export const nullCrypto: TalerCryptoInterface = {
|
|||||||
): Promise<EddsaSigningResult> {
|
): Promise<EddsaSigningResult> {
|
||||||
throw new Error("Function not implemented.");
|
throw new Error("Function not implemented.");
|
||||||
},
|
},
|
||||||
|
setupRefreshPlanchet: function (
|
||||||
|
req: SetupRefreshPlanchetRequest,
|
||||||
|
): Promise<FreshCoinEncoded> {
|
||||||
|
throw new Error("Function not implemented.");
|
||||||
|
},
|
||||||
|
rsaBlind: function (req: RsaBlindRequest): Promise<RsaBlindResponse> {
|
||||||
|
throw new Error("Function not implemented.");
|
||||||
|
},
|
||||||
|
keyExchangeEcdheEddsa: function (
|
||||||
|
req: KeyExchangeEcdheEddsaRequest,
|
||||||
|
): Promise<KeyExchangeResult> {
|
||||||
|
throw new Error("Function not implemented.");
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export type WithArg<X> = X extends (req: infer T) => infer R
|
export type WithArg<X> = X extends (req: infer T) => infer R
|
||||||
@ -275,12 +297,23 @@ export interface SignCoinLinkRequest {
|
|||||||
coinEv: CoinEnvelope;
|
coinEv: CoinEnvelope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SetupRefreshPlanchetRequest {
|
||||||
|
transferSecret: string;
|
||||||
|
coinNumber: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface RsaVerificationRequest {
|
export interface RsaVerificationRequest {
|
||||||
hm: string;
|
hm: string;
|
||||||
sig: string;
|
sig: string;
|
||||||
pk: string;
|
pk: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RsaBlindRequest {
|
||||||
|
hm: string;
|
||||||
|
bks: string;
|
||||||
|
pub: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface EddsaSigningResult {
|
export interface EddsaSigningResult {
|
||||||
sig: string;
|
sig: string;
|
||||||
}
|
}
|
||||||
@ -341,16 +374,35 @@ export interface UnblindDenominationSignatureRequest {
|
|||||||
evSig: BlindedDenominationSignature;
|
evSig: BlindedDenominationSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FreshCoinEncoded {
|
||||||
|
coinPub: string;
|
||||||
|
coinPriv: string;
|
||||||
|
bks: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface RsaUnblindRequest {
|
export interface RsaUnblindRequest {
|
||||||
blindedSig: string;
|
blindedSig: string;
|
||||||
bk: string;
|
bk: string;
|
||||||
pk: string;
|
pk: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RsaBlindResponse {
|
||||||
|
blinded: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface RsaUnblindResponse {
|
export interface RsaUnblindResponse {
|
||||||
sig: string;
|
sig: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface KeyExchangeEcdheEddsaRequest {
|
||||||
|
ecdhePriv: string;
|
||||||
|
eddsaPub: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface KeyExchangeResult {
|
||||||
|
h: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const nativeCryptoR: TalerCryptoInterfaceR = {
|
export const nativeCryptoR: TalerCryptoInterfaceR = {
|
||||||
async eddsaSign(
|
async eddsaSign(
|
||||||
tci: TalerCryptoInterfaceR,
|
tci: TalerCryptoInterfaceR,
|
||||||
@ -361,6 +413,53 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async rsaBlind(
|
||||||
|
tci: TalerCryptoInterfaceR,
|
||||||
|
req: RsaBlindRequest,
|
||||||
|
): Promise<RsaBlindResponse> {
|
||||||
|
const res = rsaBlind(
|
||||||
|
decodeCrock(req.hm),
|
||||||
|
decodeCrock(req.bks),
|
||||||
|
decodeCrock(req.pub),
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
blinded: encodeCrock(res),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
async setupRefreshPlanchet(
|
||||||
|
tci: TalerCryptoInterfaceR,
|
||||||
|
req: SetupRefreshPlanchetRequest,
|
||||||
|
): Promise<FreshCoinEncoded> {
|
||||||
|
const transferSecret = decodeCrock(req.transferSecret);
|
||||||
|
const coinNumber = req.coinNumber;
|
||||||
|
// See TALER_transfer_secret_to_planchet_secret in C impl
|
||||||
|
const planchetMasterSecret = kdfKw({
|
||||||
|
ikm: transferSecret,
|
||||||
|
outputLength: 32,
|
||||||
|
salt: bufferForUint32(coinNumber),
|
||||||
|
info: stringToBytes("taler-coin-derivation"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const coinPriv = kdfKw({
|
||||||
|
ikm: planchetMasterSecret,
|
||||||
|
outputLength: 32,
|
||||||
|
salt: stringToBytes("coin"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const bks = kdfKw({
|
||||||
|
ikm: planchetMasterSecret,
|
||||||
|
outputLength: 32,
|
||||||
|
salt: stringToBytes("bks"),
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
bks: encodeCrock(bks),
|
||||||
|
coinPriv: encodeCrock(coinPriv),
|
||||||
|
coinPub: encodeCrock(eddsaGetPublic(coinPriv)),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
async createPlanchet(
|
async createPlanchet(
|
||||||
tci: TalerCryptoInterfaceR,
|
tci: TalerCryptoInterfaceR,
|
||||||
req: PlanchetCreationRequest,
|
req: PlanchetCreationRequest,
|
||||||
@ -374,10 +473,14 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
|
|||||||
req.coinIndex,
|
req.coinIndex,
|
||||||
);
|
);
|
||||||
const coinPubHash = hash(derivedPlanchet.coinPub);
|
const coinPubHash = hash(derivedPlanchet.coinPub);
|
||||||
const ev = rsaBlind(coinPubHash, derivedPlanchet.bks, denomPubRsa);
|
const blindResp = await tci.rsaBlind(tci, {
|
||||||
|
bks: encodeCrock(derivedPlanchet.bks),
|
||||||
|
hm: encodeCrock(coinPubHash),
|
||||||
|
pub: denomPub.rsa_public_key,
|
||||||
|
});
|
||||||
const coinEv: CoinEnvelope = {
|
const coinEv: CoinEnvelope = {
|
||||||
cipher: DenomKeyType.Rsa,
|
cipher: DenomKeyType.Rsa,
|
||||||
rsa_blinded_planchet: encodeCrock(ev),
|
rsa_blinded_planchet: blindResp.blinded,
|
||||||
};
|
};
|
||||||
const amountWithFee = Amounts.add(req.value, req.feeWithdraw).amount;
|
const amountWithFee = Amounts.add(req.value, req.feeWithdraw).amount;
|
||||||
const denomPubHash = hashDenomPub(req.denomPub);
|
const denomPubHash = hashDenomPub(req.denomPub);
|
||||||
@ -423,10 +526,14 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
|
|||||||
const fc = setupTipPlanchet(decodeCrock(req.secretSeed), req.planchetIndex);
|
const fc = setupTipPlanchet(decodeCrock(req.secretSeed), req.planchetIndex);
|
||||||
const denomPub = decodeCrock(req.denomPub.rsa_public_key);
|
const denomPub = decodeCrock(req.denomPub.rsa_public_key);
|
||||||
const coinPubHash = hash(fc.coinPub);
|
const coinPubHash = hash(fc.coinPub);
|
||||||
const ev = rsaBlind(coinPubHash, fc.bks, denomPub);
|
const blindResp = await tci.rsaBlind(tci, {
|
||||||
|
bks: encodeCrock(fc.bks),
|
||||||
|
hm: encodeCrock(coinPubHash),
|
||||||
|
pub: encodeCrock(denomPub),
|
||||||
|
});
|
||||||
const coinEv = {
|
const coinEv = {
|
||||||
cipher: DenomKeyType.Rsa,
|
cipher: DenomKeyType.Rsa,
|
||||||
rsa_blinded_planchet: encodeCrock(ev),
|
rsa_blinded_planchet: blindResp.blinded,
|
||||||
};
|
};
|
||||||
const tipPlanchet: DerivedTipPlanchet = {
|
const tipPlanchet: DerivedTipPlanchet = {
|
||||||
blindingKey: encodeCrock(fc.bks),
|
blindingKey: encodeCrock(fc.bks),
|
||||||
@ -798,32 +905,32 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
|
|||||||
const denomSel = newCoinDenoms[j];
|
const denomSel = newCoinDenoms[j];
|
||||||
for (let k = 0; k < denomSel.count; k++) {
|
for (let k = 0; k < denomSel.count; k++) {
|
||||||
const coinIndex = planchets.length;
|
const coinIndex = planchets.length;
|
||||||
const transferPriv = decodeCrock(transferPrivs[i]);
|
const transferSecretRes = await tci.keyExchangeEcdheEddsa(tci, {
|
||||||
const oldCoinPub = decodeCrock(meltCoinPub);
|
ecdhePriv: transferPrivs[i],
|
||||||
const transferSecret = keyExchangeEcdheEddsa(
|
eddsaPub: meltCoinPub,
|
||||||
transferPriv,
|
});
|
||||||
oldCoinPub,
|
|
||||||
);
|
|
||||||
let coinPub: Uint8Array;
|
let coinPub: Uint8Array;
|
||||||
let coinPriv: Uint8Array;
|
let coinPriv: Uint8Array;
|
||||||
let blindingFactor: Uint8Array;
|
let blindingFactor: Uint8Array;
|
||||||
// FIXME: make setupRefreshPlanchet a crypto api fn
|
let fresh: FreshCoinEncoded = await tci.setupRefreshPlanchet(tci, {
|
||||||
let fresh: FreshCoin = setupRefreshPlanchet(
|
coinNumber: coinIndex,
|
||||||
transferSecret,
|
transferSecret: transferSecretRes.h,
|
||||||
coinIndex,
|
});
|
||||||
);
|
coinPriv = decodeCrock(fresh.coinPriv);
|
||||||
coinPriv = fresh.coinPriv;
|
coinPub = decodeCrock(fresh.coinPub);
|
||||||
coinPub = fresh.coinPub;
|
blindingFactor = decodeCrock(fresh.bks);
|
||||||
blindingFactor = fresh.bks;
|
|
||||||
const coinPubHash = hash(coinPub);
|
const coinPubHash = hash(coinPub);
|
||||||
if (denomSel.denomPub.cipher !== DenomKeyType.Rsa) {
|
if (denomSel.denomPub.cipher !== DenomKeyType.Rsa) {
|
||||||
throw Error("unsupported cipher, can't create refresh session");
|
throw Error("unsupported cipher, can't create refresh session");
|
||||||
}
|
}
|
||||||
const rsaDenomPub = decodeCrock(denomSel.denomPub.rsa_public_key);
|
const blindResult = await tci.rsaBlind(tci, {
|
||||||
const ev = rsaBlind(coinPubHash, blindingFactor, rsaDenomPub);
|
bks: encodeCrock(blindingFactor),
|
||||||
|
hm: encodeCrock(coinPubHash),
|
||||||
|
pub: denomSel.denomPub.rsa_public_key,
|
||||||
|
});
|
||||||
const coinEv: CoinEnvelope = {
|
const coinEv: CoinEnvelope = {
|
||||||
cipher: DenomKeyType.Rsa,
|
cipher: DenomKeyType.Rsa,
|
||||||
rsa_blinded_planchet: encodeCrock(ev),
|
rsa_blinded_planchet: blindResult.blinded,
|
||||||
};
|
};
|
||||||
const coinEvHash = hashCoinEv(
|
const coinEvHash = hashCoinEv(
|
||||||
coinEv,
|
coinEv,
|
||||||
@ -921,6 +1028,19 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
|
|||||||
const uploadSig = eddsaSign(sigBlob, decodeCrock(req.accountPriv));
|
const uploadSig = eddsaSign(sigBlob, decodeCrock(req.accountPriv));
|
||||||
return { sig: encodeCrock(uploadSig) };
|
return { sig: encodeCrock(uploadSig) };
|
||||||
},
|
},
|
||||||
|
async keyExchangeEcdheEddsa(
|
||||||
|
tci: TalerCryptoInterfaceR,
|
||||||
|
req: KeyExchangeEcdheEddsaRequest,
|
||||||
|
): Promise<KeyExchangeResult> {
|
||||||
|
return {
|
||||||
|
h: encodeCrock(
|
||||||
|
keyExchangeEcdheEddsa(
|
||||||
|
decodeCrock(req.ecdhePriv),
|
||||||
|
decodeCrock(req.eddsaPub),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function amountToBuffer(amount: AmountJson): Uint8Array {
|
function amountToBuffer(amount: AmountJson): Uint8Array {
|
||||||
|
@ -122,7 +122,7 @@ export class CryptoDispatcher {
|
|||||||
worker.idleTimeoutHandle = null;
|
worker.idleTimeoutHandle = null;
|
||||||
}
|
}
|
||||||
if (worker.currentWorkItem) {
|
if (worker.currentWorkItem) {
|
||||||
worker.currentWorkItem.reject(Error("explicitly terminated"));
|
worker.currentWorkItem.reject(new CryptoApiStoppedError());
|
||||||
worker.currentWorkItem = null;
|
worker.currentWorkItem = null;
|
||||||
}
|
}
|
||||||
if (worker.w) {
|
if (worker.w) {
|
||||||
@ -143,7 +143,7 @@ export class CryptoDispatcher {
|
|||||||
*/
|
*/
|
||||||
wake(ws: WorkerState, work: WorkItem): void {
|
wake(ws: WorkerState, work: WorkItem): void {
|
||||||
if (this.stopped) {
|
if (this.stopped) {
|
||||||
throw new CryptoApiStoppedError();
|
return;
|
||||||
}
|
}
|
||||||
if (ws.currentWorkItem !== null) {
|
if (ws.currentWorkItem !== null) {
|
||||||
throw Error("assertion failed");
|
throw Error("assertion failed");
|
||||||
@ -331,8 +331,8 @@ export class CryptoDispatcher {
|
|||||||
}
|
}
|
||||||
timeout.clear();
|
timeout.clear();
|
||||||
resolve(x);
|
resolve(x);
|
||||||
});
|
}).catch((x) => {
|
||||||
p.catch((x) => {
|
logger.info(`crypto RPC call ${operation} threw`);
|
||||||
if (timedOut) {
|
if (timedOut) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -47,14 +47,11 @@ export class SynchronousCryptoWorker {
|
|||||||
|
|
||||||
this.cryptoImplR = { ...nativeCryptoR };
|
this.cryptoImplR = { ...nativeCryptoR };
|
||||||
|
|
||||||
if (
|
if (process.env["TALER_WALLET_PRIMITIVE_WORKER"]) {
|
||||||
process.env["TALER_WALLET_RPC_CRYPRO"] ||
|
logger.info("using RPC for some crypto operations");
|
||||||
// Old name
|
|
||||||
process.env["TALER_WALLET_PRIMITIVE_WORKER"]
|
|
||||||
) {
|
|
||||||
const rpc = (this.rpcClient = new CryptoRpcClient());
|
const rpc = (this.rpcClient = new CryptoRpcClient());
|
||||||
this.cryptoImplR.eddsaSign = async (_, req) => {
|
this.cryptoImplR.eddsaSign = async (_, req) => {
|
||||||
logger.trace("making RPC request");
|
logger.info("calling RPC impl of eddsaSign");
|
||||||
return await rpc.queueRequest({
|
return await rpc.queueRequest({
|
||||||
op: "eddsa_sign",
|
op: "eddsa_sign",
|
||||||
args: {
|
args: {
|
||||||
@ -63,6 +60,46 @@ export class SynchronousCryptoWorker {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
this.cryptoImplR.setupRefreshPlanchet = async (_, req) => {
|
||||||
|
const res = await rpc.queueRequest({
|
||||||
|
op: "setup_refresh_planchet",
|
||||||
|
args: {
|
||||||
|
coin_index: req.coinNumber,
|
||||||
|
transfer_secret: req.transferSecret,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
bks: res.blinding_key,
|
||||||
|
coinPriv: res.coin_priv,
|
||||||
|
coinPub: res.coin_pub,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
this.cryptoImplR.rsaBlind = async (_, req) => {
|
||||||
|
const res = await rpc.queueRequest({
|
||||||
|
op: "rsa_blind",
|
||||||
|
args: {
|
||||||
|
bks: req.bks,
|
||||||
|
hm: req.hm,
|
||||||
|
pub: req.pub,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
blinded: res.blinded,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
this.cryptoImplR.keyExchangeEcdheEddsa = async (_, req) => {
|
||||||
|
const res = await rpc.queueRequest({
|
||||||
|
op: "kx_ecdhe_eddsa",
|
||||||
|
args: {
|
||||||
|
ecdhe_priv: req.ecdhePriv,
|
||||||
|
eddsa_pub: req.eddsaPub,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
h: res.h,
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,8 +138,8 @@ export class SynchronousCryptoWorker {
|
|||||||
let result: any;
|
let result: any;
|
||||||
try {
|
try {
|
||||||
result = await (impl as any)[operation](impl, req);
|
result = await (impl as any)[operation](impl, req);
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
logger.error("error during operation", e);
|
logger.error(`error during operation '${operation}': ${e}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -797,11 +797,22 @@ async function processRefreshGroupImpl(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Process refresh sessions of the group in parallel.
|
// Process refresh sessions of the group in parallel.
|
||||||
|
logger.trace("processing refresh sessions for old coins");
|
||||||
const ps = refreshGroup.oldCoinPubs.map((x, i) =>
|
const ps = refreshGroup.oldCoinPubs.map((x, i) =>
|
||||||
processRefreshSession(ws, refreshGroupId, i),
|
processRefreshSession(ws, refreshGroupId, i).catch((x) => {
|
||||||
|
logger.warn("process refresh session got exception");
|
||||||
|
logger.warn(`exc ${x}`);
|
||||||
|
logger.warn(`exc stack ${x.stack}`);
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
await Promise.all(ps);
|
try {
|
||||||
logger.trace("refresh finished");
|
logger.trace("waiting for refreshes");
|
||||||
|
await Promise.all(ps);
|
||||||
|
logger.trace("refresh finished");
|
||||||
|
} catch (e) {
|
||||||
|
logger.warn("process refresh sessions got exception");
|
||||||
|
logger.warn(`exception: ${e}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processRefreshSession(
|
async function processRefreshSession(
|
||||||
|
@ -1077,6 +1077,7 @@ export async function handleCoreApiRequest(
|
|||||||
};
|
};
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
const err = getErrorDetailFromException(e);
|
const err = getErrorDetailFromException(e);
|
||||||
|
logger.info(`finished wallet core request with error: ${j2s(err)}`);
|
||||||
return {
|
return {
|
||||||
type: "error",
|
type: "error",
|
||||||
operation,
|
operation,
|
||||||
|
Loading…
Reference in New Issue
Block a user