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: experiment with C-bas


From: gnunet
Subject: [taler-wallet-core] branch master updated: wallet: experiment with C-based crypto worker for some primitives
Date: Tue, 16 Nov 2021 17:20:47 +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 c33ed919 wallet: experiment with C-based crypto worker for some 
primitives
c33ed919 is described below

commit c33ed919719845f518d6491ef37df6ae16820dd0
Author: Florian Dold <florian@dold.me>
AuthorDate: Tue Nov 16 17:20:36 2021 +0100

    wallet: experiment with C-based crypto worker for some primitives
---
 packages/anastasis-core/src/crypto.ts              |   2 -
 packages/taler-util/src/talerCrypto.ts             |   4 -
 packages/taler-wallet-cli/src/bench1.ts            |   1 +
 .../src/crypto/workers/cryptoApi.ts                |   2 +-
 .../src/crypto/workers/cryptoImplementation.ts     |  74 ++++++++++---
 .../{cryptoWorker.ts => cryptoWorkerInterface.ts}  |   0
 .../src/crypto/workers/nodeThreadWorker.ts         |   4 +-
 .../src/crypto/workers/synchronousWorker.ts        | 114 +++++++++++++++++++--
 packages/taler-wallet-core/src/headless/helpers.ts |  26 +++--
 packages/taler-wallet-core/src/index.ts            |   2 +-
 .../src/browserWorkerEntry.ts                      |   2 +-
 11 files changed, 190 insertions(+), 41 deletions(-)

diff --git a/packages/anastasis-core/src/crypto.ts 
b/packages/anastasis-core/src/crypto.ts
index 206d9eca..75bd4b32 100644
--- a/packages/anastasis-core/src/crypto.ts
+++ b/packages/anastasis-core/src/crypto.ts
@@ -11,8 +11,6 @@ import {
   stringToBytes,
   secretbox_open,
   hash,
-  Logger,
-  j2s,
 } from "@gnu-taler/taler-util";
 import { argon2id } from "hash-wasm";
 
diff --git a/packages/taler-util/src/talerCrypto.ts 
b/packages/taler-util/src/talerCrypto.ts
index 536c4dc4..d8ac75dc 100644
--- a/packages/taler-util/src/talerCrypto.ts
+++ b/packages/taler-util/src/talerCrypto.ts
@@ -161,10 +161,6 @@ interface RsaPub {
   e: bigint.BigInteger;
 }
 
-interface RsaBlindingKey {
-  r: bigint.BigInteger;
-}
-
 /**
  * KDF modulo a big integer.
  */
diff --git a/packages/taler-wallet-cli/src/bench1.ts 
b/packages/taler-wallet-cli/src/bench1.ts
index ec0430d8..ad95eebc 100644
--- a/packages/taler-wallet-cli/src/bench1.ts
+++ b/packages/taler-wallet-cli/src/bench1.ts
@@ -40,6 +40,7 @@ export async function runBench1(configJson: any): 
Promise<void> {
   const b1conf = codecForBench1Config().decode(configJson);
 
   const myHttpLib = new NodeHttpLib();
+  myHttpLib.setThrottling(false);
 
   const numIter = b1conf.iterations ?? 1;
 
diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts 
b/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts
index 6bace01a..e6c0290f 100644
--- a/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts
@@ -24,7 +24,7 @@
  */
 import { CoinRecord, DenominationRecord, WireFee } from "../../db.js";
 
-import { CryptoWorker } from "./cryptoWorker.js";
+import { CryptoWorker } from "./cryptoWorkerInterface.js";
 
 import { RecoupRequest, CoinDepositPermission } from "@gnu-taler/taler-util";
 
diff --git 
a/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts 
b/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts
index c42ece77..169d1d9b 100644
--- a/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts
@@ -15,9 +15,7 @@
  */
 
 /**
- * Synchronous implementation of crypto-related functions for the wallet.
- *
- * The functionality is parameterized over an Emscripten environment.
+ * Implementation of crypto-related high-level functions for the Taler wallet.
  *
  * @author Florian Dold <dold@taler.net>
  */
@@ -37,9 +35,9 @@ import {
 import {
   buildSigPS,
   CoinDepositPermission,
+  FreshCoin,
   RecoupRequest,
   RefreshPlanchetInfo,
-  SignaturePurposeBuilder,
   TalerSignaturePurpose,
 } from "@gnu-taler/taler-util";
 // FIXME: These types should be internal to the wallet!
@@ -128,9 +126,27 @@ function timestampRoundedToBuffer(ts: Timestamp): 
Uint8Array {
   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 }>;
+}
+
 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.
@@ -246,7 +262,11 @@ export class CryptoImplementation {
   /**
    * Check if a wire fee is correctly signed.
    */
-  isValidWireFee(type: string, wf: WireFee, masterPub: string): boolean {
+  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))
@@ -256,13 +276,25 @@ export class CryptoImplementation {
       .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.
    */
-  isValidDenom(denom: DenominationRecord, masterPub: string): boolean {
+  async isValidDenom(
+    denom: DenominationRecord,
+    masterPub: string,
+  ): Promise<boolean> {
     const p = 
buildSigPS(TalerSignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY)
       .put(decodeCrock(masterPub))
       .put(timestampRoundedToBuffer(denom.stampStart))
@@ -377,9 +409,9 @@ export class CryptoImplementation {
     return s;
   }
 
-  deriveRefreshSession(
+  async deriveRefreshSession(
     req: DeriveRefreshSessionRequest,
-  ): DerivedRefreshSession {
+  ): Promise<DerivedRefreshSession> {
     const {
       newCoinDenoms,
       feeRefresh: meltFee,
@@ -435,17 +467,33 @@ export class CryptoImplementation {
       for (let j = 0; j < newCoinDenoms.length; j++) {
         const denomSel = newCoinDenoms[j];
         for (let k = 0; k < denomSel.count; k++) {
-          const coinNumber = planchets.length;
+          const coinIndex = planchets.length;
           const transferPriv = decodeCrock(transferPrivs[i]);
           const oldCoinPub = decodeCrock(meltCoinPub);
           const transferSecret = keyExchangeEcdheEddsa(
             transferPriv,
             oldCoinPub,
           );
-          const fresh = setupRefreshPlanchet(transferSecret, coinNumber);
-          const coinPriv = fresh.coinPriv;
-          const coinPub = fresh.coinPub;
-          const blindingFactor = fresh.bks;
+          let coinPub: Uint8Array;
+          let coinPriv: Uint8Array;
+          let blindingFactor: Uint8Array;
+          if (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 pubHash = hash(coinPub);
           const denomPub = decodeCrock(denomSel.denomPub);
           const ev = rsaBlind(pubHash, blindingFactor, denomPub);
diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoWorker.ts 
b/packages/taler-wallet-core/src/crypto/workers/cryptoWorkerInterface.ts
similarity index 100%
rename from packages/taler-wallet-core/src/crypto/workers/cryptoWorker.ts
rename to packages/taler-wallet-core/src/crypto/workers/cryptoWorkerInterface.ts
diff --git a/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts 
b/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts
index 3f7f9e17..df57635d 100644
--- a/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts
@@ -18,7 +18,7 @@
  * Imports
  */
 import { CryptoWorkerFactory } from "./cryptoApi.js";
-import { CryptoWorker } from "./cryptoWorker.js";
+import { CryptoWorker } from "./cryptoWorkerInterface.js";
 import os from "os";
 import { CryptoImplementation } from "./cryptoImplementation.js";
 import { Logger } from "@gnu-taler/taler-util";
@@ -94,7 +94,7 @@ export function handleWorkerMessage(msg: any): void {
     }
 
     try {
-      const result = (impl as any)[operation](...args);
+      const result = await (impl as any)[operation](...args);
       // eslint-disable-next-line @typescript-eslint/no-var-requires
       const _r = "require";
       const worker_threads: typeof import("worker_threads") = module[_r](
diff --git a/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts 
b/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts
index f6b8ac5d..8293bb36 100644
--- a/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts
@@ -14,10 +14,107 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { CryptoImplementation } from "./cryptoImplementation.js";
+import {
+  CryptoImplementation,
+  PrimitiveWorker,
+} from "./cryptoImplementation.js";
 
 import { CryptoWorkerFactory } from "./cryptoApi.js";
-import { CryptoWorker } from "./cryptoWorker.js";
+import { CryptoWorker } from "./cryptoWorkerInterface.js";
+
+import child_process from "child_process";
+import type internal from "stream";
+import { OpenedPromise, openPromise } from "../../index.js";
+import { FreshCoin, Logger } from "@gnu-taler/taler-util";
+
+const logger = new Logger("synchronousWorker.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", function (code) {
+      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 (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,
+    });
+  }
+}
 
 /**
  * The synchronous crypto worker produced by this factory doesn't run in the
@@ -50,9 +147,14 @@ export class SynchronousCryptoWorker {
    */
   onerror: undefined | ((m: any) => void);
 
+  primitiveWorker: PrimitiveWorker;
+
   constructor() {
     this.onerror = undefined;
     this.onmessage = undefined;
+    if (process.env["TALER_WALLET_PRIMITIVE_WORKER"]) {
+      this.primitiveWorker = new MyPrimitiveWorker();
+    }
   }
 
   /**
@@ -80,7 +182,7 @@ export class SynchronousCryptoWorker {
     id: number,
     args: string[],
   ): Promise<void> {
-    const impl = new CryptoImplementation();
+    const impl = new CryptoImplementation(this.primitiveWorker);
 
     if (!(operation in impl)) {
       console.error(`crypto operation '${operation}' not found`);
@@ -89,16 +191,16 @@ export class SynchronousCryptoWorker {
 
     let result: any;
     try {
-      result = (impl as any)[operation](...args);
+      result = await (impl as any)[operation](...args);
     } catch (e) {
-      console.log("error during operation", e);
+      logger.error("error during operation", e);
       return;
     }
 
     try {
       setTimeout(() => this.dispatchMessage({ result, id }), 0);
     } catch (e) {
-      console.log("got error during dispatch", e);
+      logger.error("got error during dispatch", e);
     }
   }
 
diff --git a/packages/taler-wallet-core/src/headless/helpers.ts 
b/packages/taler-wallet-core/src/headless/helpers.ts
index f2285e14..191c4844 100644
--- a/packages/taler-wallet-core/src/headless/helpers.ts
+++ b/packages/taler-wallet-core/src/headless/helpers.ts
@@ -142,19 +142,23 @@ export async function getDefaultNodeWallet(
   const myDb = await openTalerDatabase(myIdbFactory, myVersionChange);
 
   let workerFactory;
-  try {
-    // Try if we have worker threads available, fails in older node versions.
-    const _r = "require";
-    const worker_threads = module[_r]("worker_threads");
-    // require("worker_threads");
-    workerFactory = new NodeThreadCryptoWorkerFactory();
-  } catch (e) {
-    logger.warn(
-      "worker threads not available, falling back to synchronous workers",
-    );
+  if (process.env["TALER_WALLET_SYNC_CRYPTO"]) {
+    logger.info("using synchronous crypto worker");
     workerFactory = new SynchronousCryptoWorkerFactory();
+  } else {
+    try {
+      // Try if we have worker threads available, fails in older node versions.
+      const _r = "require";
+      const worker_threads = module[_r]("worker_threads");
+      // require("worker_threads");
+      workerFactory = new NodeThreadCryptoWorkerFactory();
+    } catch (e) {
+      logger.warn(
+        "worker threads not available, falling back to synchronous workers",
+      );
+      workerFactory = new SynchronousCryptoWorkerFactory();
+    }
   }
-
   const w = await Wallet.create(myDb, myHttpLib, workerFactory);
 
   if (args.notifyHandler) {
diff --git a/packages/taler-wallet-core/src/index.ts 
b/packages/taler-wallet-core/src/index.ts
index 0b360a24..5489bd5a 100644
--- a/packages/taler-wallet-core/src/index.ts
+++ b/packages/taler-wallet-core/src/index.ts
@@ -34,7 +34,7 @@ export * from "./db-utils.js";
 // Crypto and crypto workers
 // export * from "./crypto/workers/nodeThreadWorker.js";
 export { CryptoImplementation } from 
"./crypto/workers/cryptoImplementation.js";
-export type { CryptoWorker } from "./crypto/workers/cryptoWorker.js";
+export type { CryptoWorker } from "./crypto/workers/cryptoWorkerInterface.js";
 export { CryptoWorkerFactory, CryptoApi } from "./crypto/workers/cryptoApi.js";
 
 export * from "./pending-types.js";
diff --git a/packages/taler-wallet-webextension/src/browserWorkerEntry.ts 
b/packages/taler-wallet-webextension/src/browserWorkerEntry.ts
index b5c26a7b..7829e6d6 100644
--- a/packages/taler-wallet-webextension/src/browserWorkerEntry.ts
+++ b/packages/taler-wallet-webextension/src/browserWorkerEntry.ts
@@ -42,7 +42,7 @@ async function handleRequest(
   }
 
   try {
-    const result = (impl as any)[operation](...args);
+    const result = await (impl as any)[operation](...args);
     worker.postMessage({ result, id });
   } catch (e) {
     logger.error("error during operation", e);

-- 
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]