gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: wallet: crypto worker fixes,


From: gnunet
Subject: [taler-wallet-core] branch master updated: wallet: crypto worker fixes, better taler-crypto-worker integration
Date: Thu, 24 Mar 2022 01:10:53 +0100

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new 9d38cb56 wallet: crypto worker fixes, better taler-crypto-worker 
integration
9d38cb56 is described below

commit 9d38cb56a6fa4c9a975df339cb0aa08f040368c1
Author: Florian Dold <florian@dold.me>
AuthorDate: Thu Mar 24 01:10:34 2022 +0100

    wallet: crypto worker fixes, better taler-crypto-worker integration
---
 packages/taler-util/src/talerCrypto.ts             |  39 +----
 packages/taler-wallet-cli/src/index.ts             |  29 +++-
 .../src/crypto/cryptoImplementation.ts             | 168 ++++++++++++++++++---
 .../src/crypto/workers/cryptoDispatcher.ts         |   8 +-
 .../src/crypto/workers/synchronousWorker.ts        |  53 ++++++-
 .../taler-wallet-core/src/operations/refresh.ts    |  17 ++-
 packages/taler-wallet-core/src/wallet.ts           |   1 +
 7 files changed, 234 insertions(+), 81 deletions(-)

diff --git a/packages/taler-util/src/talerCrypto.ts 
b/packages/taler-util/src/talerCrypto.ts
index 4d6e7367..0385658c 100644
--- a/packages/taler-util/src/talerCrypto.ts
+++ b/packages/taler-util/src/talerCrypto.ts
@@ -692,7 +692,7 @@ export interface FreshCoin {
   bks: Uint8Array;
 }
 
-function bufferForUint32(n: number): Uint8Array {
+export function bufferForUint32(n: number): Uint8Array {
   const arrBuf = new ArrayBuffer(4);
   const buf = new Uint8Array(arrBuf);
   const dv = new DataView(arrBuf);
@@ -700,37 +700,6 @@ function bufferForUint32(n: number): Uint8Array {
   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(
   secretSeed: Uint8Array,
   coinNumber: number,
@@ -786,10 +755,10 @@ export function setupRefreshTransferPub(
 }
 
 /**
- * 
+ *
  * @param paytoUri
- * @param salt 16-byte salt 
- * @returns 
+ * @param salt 16-byte salt
+ * @returns
  */
 export function hashWire(paytoUri: string, salt: string): string {
   const r = kdf(
diff --git a/packages/taler-wallet-cli/src/index.ts 
b/packages/taler-wallet-cli/src/index.ts
index 3b79f78b..254dadf9 100644
--- a/packages/taler-wallet-cli/src/index.ts
+++ b/packages/taler-wallet-cli/src/index.ts
@@ -64,7 +64,10 @@ import { runBench1 } from "./bench1.js";
 import { runEnv1 } from "./env1.js";
 import { GlobalTestState, runTestWithState } from "./harness/harness.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
 // thread worker, and thus must expose these two handlers.
@@ -75,6 +78,12 @@ export {
 
 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";
 
 function assertUnreachable(x: never): never {
@@ -218,6 +227,7 @@ async function withWallet<T>(
   } finally {
     logger.info("operation with wallet finished, stopping");
     wallet.stop();
+    logger.info("stopped wallet");
   }
 }
 
@@ -250,13 +260,18 @@ walletCli
         console.error("Invalid JSON");
         process.exit(1);
       }
-      const resp = await wallet.ws.handleCoreApiRequest(
-        args.api.operation,
-        "reqid-1",
-        requestJson,
-      );
-      console.log(JSON.stringify(resp, undefined, 2));
+      try {
+        const resp = await wallet.ws.handleCoreApiRequest(
+          args.api.operation,
+          "reqid-1",
+          requestJson,
+        );
+        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
diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts 
b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
index 63b2687b..a6093e36 100644
--- a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
+++ b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
@@ -42,7 +42,6 @@ import {
   eddsaVerify,
   encodeCrock,
   ExchangeProtocolVersion,
-  FreshCoin,
   hash,
   hashCoinEv,
   hashCoinEvInner,
@@ -53,14 +52,12 @@ import {
   MakeSyncSignatureRequest,
   PlanchetCreationRequest,
   WithdrawalPlanchet,
-  randomBytes,
   RecoupRefreshRequest,
   RecoupRequest,
   RefreshPlanchetInfo,
   rsaBlind,
   rsaUnblind,
   rsaVerify,
-  setupRefreshPlanchet,
   setupRefreshTransferPub,
   setupTipPlanchet,
   setupWithdrawPlanchet,
@@ -70,6 +67,8 @@ import {
   UnblindedSignature,
   PlanchetUnblindInfo,
   TalerProtocolTimestamp,
+  kdfKw,
+  bufferForUint32,
 } from "@gnu-taler/taler-util";
 import bigint from "big-integer";
 import { DenominationRecord, WireFee } from "../db.js";
@@ -141,6 +140,8 @@ export interface TalerCryptoInterface {
 
   rsaVerify(req: RsaVerificationRequest): Promise<ValidationResult>;
 
+  rsaBlind(req: RsaBlindRequest): Promise<RsaBlindResponse>;
+
   signDepositPermission(
     depositInfo: DepositInfo,
   ): Promise<CoinDepositPermission>;
@@ -154,6 +155,14 @@ export interface TalerCryptoInterface {
   signCoinLink(req: SignCoinLinkRequest): 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> {
     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
@@ -275,12 +297,23 @@ export interface SignCoinLinkRequest {
   coinEv: CoinEnvelope;
 }
 
+export interface SetupRefreshPlanchetRequest {
+  transferSecret: string;
+  coinNumber: number;
+}
+
 export interface RsaVerificationRequest {
   hm: string;
   sig: string;
   pk: string;
 }
 
+export interface RsaBlindRequest {
+  hm: string;
+  bks: string;
+  pub: string;
+}
+
 export interface EddsaSigningResult {
   sig: string;
 }
@@ -341,16 +374,35 @@ export interface UnblindDenominationSignatureRequest {
   evSig: BlindedDenominationSignature;
 }
 
+export interface FreshCoinEncoded {
+  coinPub: string;
+  coinPriv: string;
+  bks: string;
+}
+
 export interface RsaUnblindRequest {
   blindedSig: string;
   bk: string;
   pk: string;
 }
 
+export interface RsaBlindResponse {
+  blinded: string;
+}
+
 export interface RsaUnblindResponse {
   sig: string;
 }
 
+export interface KeyExchangeEcdheEddsaRequest {
+  ecdhePriv: string;
+  eddsaPub: string;
+}
+
+export interface KeyExchangeResult {
+  h: string;
+}
+
 export const nativeCryptoR: TalerCryptoInterfaceR = {
   async eddsaSign(
     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(
     tci: TalerCryptoInterfaceR,
     req: PlanchetCreationRequest,
@@ -374,10 +473,14 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
         req.coinIndex,
       );
       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 = {
         cipher: DenomKeyType.Rsa,
-        rsa_blinded_planchet: encodeCrock(ev),
+        rsa_blinded_planchet: blindResp.blinded,
       };
       const amountWithFee = Amounts.add(req.value, req.feeWithdraw).amount;
       const denomPubHash = hashDenomPub(req.denomPub);
@@ -423,10 +526,14 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
     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 blindResp = await tci.rsaBlind(tci, {
+      bks: encodeCrock(fc.bks),
+      hm: encodeCrock(coinPubHash),
+      pub: encodeCrock(denomPub),
+    });
     const coinEv = {
       cipher: DenomKeyType.Rsa,
-      rsa_blinded_planchet: encodeCrock(ev),
+      rsa_blinded_planchet: blindResp.blinded,
     };
     const tipPlanchet: DerivedTipPlanchet = {
       blindingKey: encodeCrock(fc.bks),
@@ -798,32 +905,32 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
         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,
-          );
+          const transferSecretRes = await tci.keyExchangeEcdheEddsa(tci, {
+            ecdhePriv: transferPrivs[i],
+            eddsaPub: meltCoinPub,
+          });
           let coinPub: Uint8Array;
           let coinPriv: Uint8Array;
           let blindingFactor: Uint8Array;
-          // FIXME: make setupRefreshPlanchet a crypto api fn
-          let fresh: FreshCoin = setupRefreshPlanchet(
-            transferSecret,
-            coinIndex,
-          );
-          coinPriv = fresh.coinPriv;
-          coinPub = fresh.coinPub;
-          blindingFactor = fresh.bks;
+          let fresh: FreshCoinEncoded = await tci.setupRefreshPlanchet(tci, {
+            coinNumber: coinIndex,
+            transferSecret: transferSecretRes.h,
+          });
+          coinPriv = decodeCrock(fresh.coinPriv);
+          coinPub = decodeCrock(fresh.coinPub);
+          blindingFactor = decodeCrock(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 blindResult = await tci.rsaBlind(tci, {
+            bks: encodeCrock(blindingFactor),
+            hm: encodeCrock(coinPubHash),
+            pub: denomSel.denomPub.rsa_public_key,
+          });
           const coinEv: CoinEnvelope = {
             cipher: DenomKeyType.Rsa,
-            rsa_blinded_planchet: encodeCrock(ev),
+            rsa_blinded_planchet: blindResult.blinded,
           };
           const coinEvHash = hashCoinEv(
             coinEv,
@@ -921,6 +1028,19 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
     const uploadSig = eddsaSign(sigBlob, decodeCrock(req.accountPriv));
     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 {
diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoDispatcher.ts 
b/packages/taler-wallet-core/src/crypto/workers/cryptoDispatcher.ts
index 810273cc..f5782ab0 100644
--- a/packages/taler-wallet-core/src/crypto/workers/cryptoDispatcher.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/cryptoDispatcher.ts
@@ -122,7 +122,7 @@ export class CryptoDispatcher {
         worker.idleTimeoutHandle = null;
       }
       if (worker.currentWorkItem) {
-        worker.currentWorkItem.reject(Error("explicitly terminated"));
+        worker.currentWorkItem.reject(new CryptoApiStoppedError());
         worker.currentWorkItem = null;
       }
       if (worker.w) {
@@ -143,7 +143,7 @@ export class CryptoDispatcher {
    */
   wake(ws: WorkerState, work: WorkItem): void {
     if (this.stopped) {
-      throw new CryptoApiStoppedError();
+      return;
     }
     if (ws.currentWorkItem !== null) {
       throw Error("assertion failed");
@@ -331,8 +331,8 @@ export class CryptoDispatcher {
         }
         timeout.clear();
         resolve(x);
-      });
-      p.catch((x) => {
+      }).catch((x) => {
+        logger.info(`crypto RPC call ${operation} threw`);
         if (timedOut) {
           return;
         }
diff --git a/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts 
b/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts
index 1d7539ed..a5f154e9 100644
--- a/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts
@@ -47,14 +47,11 @@ export class SynchronousCryptoWorker {
 
     this.cryptoImplR = { ...nativeCryptoR };
 
-    if (
-      process.env["TALER_WALLET_RPC_CRYPRO"] ||
-      // Old name
-      process.env["TALER_WALLET_PRIMITIVE_WORKER"]
-    ) {
+    if (process.env["TALER_WALLET_PRIMITIVE_WORKER"]) {
+      logger.info("using RPC for some crypto operations");
       const rpc = (this.rpcClient = new CryptoRpcClient());
       this.cryptoImplR.eddsaSign = async (_, req) => {
-        logger.trace("making RPC request");
+        logger.info("calling RPC impl of eddsaSign");
         return await rpc.queueRequest({
           op: "eddsa_sign",
           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;
     try {
       result = await (impl as any)[operation](impl, req);
-    } catch (e) {
-      logger.error("error during operation", e);
+    } catch (e: any) {
+      logger.error(`error during operation '${operation}': ${e}`);
       return;
     }
 
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts 
b/packages/taler-wallet-core/src/operations/refresh.ts
index a7773826..2ab06aba 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -797,11 +797,22 @@ async function processRefreshGroupImpl(
     return;
   }
   // Process refresh sessions of the group in parallel.
+  logger.trace("processing refresh sessions for old coins");
   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);
-  logger.trace("refresh finished");
+  try {
+    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(
diff --git a/packages/taler-wallet-core/src/wallet.ts 
b/packages/taler-wallet-core/src/wallet.ts
index d1e9aa64..bb560774 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -1077,6 +1077,7 @@ export async function handleCoreApiRequest(
     };
   } catch (e: any) {
     const err = getErrorDetailFromException(e);
+    logger.info(`finished wallet core request with error: ${j2s(err)}`);
     return {
       type: "error",
       operation,

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]