gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-wallet-webex] 04/04: worker refactoring / sync worke


From: gnunet
Subject: [GNUnet-SVN] [taler-wallet-webex] 04/04: worker refactoring / sync worker
Date: Thu, 15 Aug 2019 23:34:20 +0200

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

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

commit ea2fb677d0268eed8153a614603cca04b1b2172d
Author: Florian Dold <address@hidden>
AuthorDate: Thu Aug 15 23:34:08 2019 +0200

    worker refactoring / sync worker
---
 package.json                                       |   4 +-
 src/crypto/cryptoApi.ts                            |  40 +-
 .../{cryptoWorker.ts => cryptoImplementation.ts}   | 342 +++++-----
 src/crypto/cryptoWorker.ts                         | 741 +--------------------
 src/crypto/emscInterface-test.ts                   |  83 ++-
 src/crypto/emscInterface.ts                        | 402 ++++++-----
 src/crypto/{nodeWorker.ts => nodeProcessWorker.ts} |   0
 src/crypto/synchronousWorker.ts                    | 162 +++++
 src/headless/taler-wallet-cli.ts                   |   5 +-
 src/wallet.ts                                      |  22 +-
 tsconfig.json                                      |   5 +-
 yarn.lock                                          |   8 +-
 12 files changed, 643 insertions(+), 1171 deletions(-)

diff --git a/package.json b/package.json
index afa6f4e7..d72316e7 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "taler-wallet",
-  "version": "0.0.1",
+  "version": "0.0.2",
   "description": "",
   "main": "dist/node/index.js",
   "repository": {
@@ -48,7 +48,7 @@
   "dependencies": {
     "axios": "^0.19.0",
     "commander": "^2.20.0",
-    "idb-bridge": "^0.0.1",
+    "idb-bridge": "0.0.2",
     "source-map-support": "^0.5.12",
     "urijs": "^1.18.10"
   }
diff --git a/src/crypto/cryptoApi.ts b/src/crypto/cryptoApi.ts
index accebd65..c68b1070 100644
--- a/src/crypto/cryptoApi.ts
+++ b/src/crypto/cryptoApi.ts
@@ -39,7 +39,6 @@ import { ContractTerms, PaybackRequest } from "../talerTypes";
 import { BenchmarkResult, CoinWithDenom, PayCoinInfo } from "../walletTypes";
 
 import * as timer from "../timer";
-import { string } from "prop-types";
 
 /**
  * State of a crypto worker.
@@ -103,33 +102,31 @@ export interface CryptoWorkerFactory {
    * Query the number of workers that should be
    * run at the same time.
    */
-  getConcurrency(): number
+  getConcurrency(): number;
 }
 
-
 export class NodeCryptoWorkerFactory implements CryptoWorkerFactory {
   startWorker(): CryptoWorker {
     if (typeof require === "undefined") {
       throw Error("cannot make worker, require(...) not defined");
     }
-    const workerCtor = require("./nodeWorker").Worker;
+    const workerCtor = require("./nodeProcessWorker").Worker;
     const workerPath = __dirname + "/cryptoWorker.js";
     return new workerCtor(workerPath);
   }
-  
+
   getConcurrency(): number {
     return 2;
   }
 }
 
-
 export class BrowserCryptoWorkerFactory implements CryptoWorkerFactory {
   startWorker(): CryptoWorker {
     const workerCtor = Worker;
     const workerPath = "/dist/cryptoWorker-bundle.js";
     return new workerCtor(workerPath) as CryptoWorker;
   }
-  
+
   getConcurrency(): number {
     let concurrency = 2;
     try {
@@ -144,6 +141,23 @@ export class BrowserCryptoWorkerFactory implements 
CryptoWorkerFactory {
   }
 }
 
+/**
+ * The synchronous crypto worker produced by this factory doesn't run in the
+ * background, but actually blocks the caller until the operation is done.
+ */
+export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory {
+  startWorker(): CryptoWorker {
+    if (typeof require === "undefined") {
+      throw Error("cannot make worker, require(...) not defined");
+    }
+    const workerCtor = require("./synchronousWorker").SynchronousCryptoWorker;
+    return new workerCtor();
+  }
+
+  getConcurrency(): number {
+    return 1;
+  }
+}
 
 /**
  * Crypto API that interfaces manages a background crypto thread
@@ -166,8 +180,7 @@ export class CryptoApi {
    */
   private stopped: boolean = false;
 
-  public enableTracing = false;
-
+  public enableTracing = true;
 
   /**
    * Terminate all worker threads.
@@ -295,10 +308,11 @@ export class CryptoApi {
       return;
     }
 
-    this.enableTracing && console.log(
-      `rpc ${currentWorkItem.operation} took ${timer.performanceNow() -
-        currentWorkItem.startTime}ms`,
-    );
+    this.enableTracing &&
+      console.log(
+        `rpc ${currentWorkItem.operation} took ${timer.performanceNow() -
+          currentWorkItem.startTime}ms`,
+      );
     currentWorkItem.resolve(msg.data.result);
   }
 
diff --git a/src/crypto/cryptoWorker.ts b/src/crypto/cryptoImplementation.ts
similarity index 67%
copy from src/crypto/cryptoWorker.ts
copy to src/crypto/cryptoImplementation.ts
index 5acda905..d50d4002 100644
--- a/src/crypto/cryptoWorker.ts
+++ b/src/crypto/cryptoImplementation.ts
@@ -1,6 +1,6 @@
 /*
- This file is part of TALER
- (C) 2016 GNUnet e.V.
+ This file is part of GNU Taler
+ (C) 2019 GNUnet e.V.
 
  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
@@ -14,17 +14,16 @@
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+
 /**
- * Web worker for crypto operations.
+ * Synchronous implementation of crypto-related functions for the wallet.
+ * 
+ * The functionality is parameterized over an Emscripten environment.
  */
 
 /**
  * Imports.
  */
-import * as Amounts from "../amounts";
-import { AmountJson } from "../amounts";
-
-import * as timer from "../timer";
 
 import {
   CoinRecord,
@@ -39,42 +38,35 @@ import {
 } from "../dbTypes";
 
 import { CoinPaySig, ContractTerms, PaybackRequest } from "../talerTypes";
-
 import { BenchmarkResult, CoinWithDenom, PayCoinInfo } from "../walletTypes";
-
 import { canonicalJson } from "../helpers";
-
-import * as emscLoader from "./emscLoader";
-
-import {
-  Amount,
-  EddsaPublicKey,
-  HashCode,
-  HashContext,
-  RefreshMeltCoinAffirmationPS,
-} from "./emscInterface";
+import { EmscEnvironment } from "./emscInterface";
 import * as native from "./emscInterface";
+import { AmountJson } from "../amounts";
+import * as Amounts from "../amounts";
+import * as timer from "../timer";
 
-namespace RpcFunctions {
+export class CryptoImplementation {
+  static enableTracing: boolean = false;
 
-  export let enableTracing: boolean = false;
+  constructor(private emsc: EmscEnvironment) {}
 
   /**
    * Create a pre-coin of the given denomination to be withdrawn from then 
given
    * reserve.
    */
-  export function createPreCoin(
+  createPreCoin(
     denom: DenominationRecord,
     reserve: ReserveRecord,
   ): PreCoinRecord {
-    const reservePriv = new native.EddsaPrivateKey();
+    const reservePriv = new native.EddsaPrivateKey(this.emsc);
     reservePriv.loadCrock(reserve.reserve_priv);
-    const reservePub = new native.EddsaPublicKey();
+    const reservePub = new native.EddsaPublicKey(this.emsc);
     reservePub.loadCrock(reserve.reserve_pub);
-    const denomPub = native.RsaPublicKey.fromCrock(denom.denomPub);
-    const coinPriv = native.EddsaPrivateKey.create();
+    const denomPub = native.RsaPublicKey.fromCrock(this.emsc, denom.denomPub);
+    const coinPriv = native.EddsaPrivateKey.create(this.emsc);
     const coinPub = coinPriv.getPublicKey();
-    const blindingFactor = native.RsaBlindingKeySecret.create();
+    const blindingFactor = native.RsaBlindingKeySecret.create(this.emsc);
     const pubHash: native.HashCode = coinPub.hash();
     const ev = native.rsaBlind(pubHash, blindingFactor, denomPub);
 
@@ -86,14 +78,14 @@ namespace RpcFunctions {
       throw Error("Field fee_withdraw missing");
     }
 
-    const amountWithFee = new native.Amount(denom.value);
-    amountWithFee.add(new native.Amount(denom.feeWithdraw));
-    const withdrawFee = new native.Amount(denom.feeWithdraw);
+    const amountWithFee = new native.Amount(this.emsc, denom.value);
+    amountWithFee.add(new native.Amount(this.emsc, denom.feeWithdraw));
+    const withdrawFee = new native.Amount(this.emsc, denom.feeWithdraw);
 
     const denomPubHash = denomPub.encode().hash();
 
     // Signature
-    const withdrawRequest = new native.WithdrawRequestPS({
+    const withdrawRequest = new native.WithdrawRequestPS(this.emsc, {
       amount_with_fee: amountWithFee.toNbo(),
       h_coin_envelope: ev.hash(),
       h_denomination_pub: denomPubHash,
@@ -122,11 +114,11 @@ namespace RpcFunctions {
   /**
    * Create a planchet used for tipping, including the private keys.
    */
-  export function createTipPlanchet(denom: DenominationRecord): TipPlanchet {
-    const denomPub = native.RsaPublicKey.fromCrock(denom.denomPub);
-    const coinPriv = native.EddsaPrivateKey.create();
+  createTipPlanchet(denom: DenominationRecord): TipPlanchet {
+    const denomPub = native.RsaPublicKey.fromCrock(this.emsc, denom.denomPub);
+    const coinPriv = native.EddsaPrivateKey.create(this.emsc);
     const coinPub = coinPriv.getPublicKey();
-    const blindingFactor = native.RsaBlindingKeySecret.create();
+    const blindingFactor = native.RsaBlindingKeySecret.create(this.emsc);
     const pubHash: native.HashCode = coinPub.hash();
     const ev = native.rsaBlind(pubHash, blindingFactor, denomPub);
 
@@ -156,15 +148,18 @@ namespace RpcFunctions {
   /**
    * Create and sign a message to request payback for a coin.
    */
-  export function createPaybackRequest(coin: CoinRecord): PaybackRequest {
-    const p = new native.PaybackRequestPS({
-      coin_blind: native.RsaBlindingKeySecret.fromCrock(coin.blindingKey),
-      coin_pub: native.EddsaPublicKey.fromCrock(coin.coinPub),
-      h_denom_pub: native.RsaPublicKey.fromCrock(coin.denomPub)
+  createPaybackRequest(coin: CoinRecord): PaybackRequest {
+    const p = new native.PaybackRequestPS(this.emsc, {
+      coin_blind: native.RsaBlindingKeySecret.fromCrock(
+        this.emsc,
+        coin.blindingKey,
+      ),
+      coin_pub: native.EddsaPublicKey.fromCrock(this.emsc, coin.coinPub),
+      h_denom_pub: native.RsaPublicKey.fromCrock(this.emsc, coin.denomPub)
         .encode()
         .hash(),
     });
-    const coinPriv = native.EddsaPrivateKey.fromCrock(coin.coinPriv);
+    const coinPriv = native.EddsaPrivateKey.fromCrock(this.emsc, 
coin.coinPriv);
     const coinSig = native.eddsaSign(p.toPurpose(), coinPriv);
     const paybackRequest: PaybackRequest = {
       coin_blind_key_secret: coin.blindingKey,
@@ -179,17 +174,17 @@ namespace RpcFunctions {
   /**
    * Check if a payment signature is valid.
    */
-  export function isValidPaymentSignature(
+  isValidPaymentSignature(
     sig: string,
     contractHash: string,
     merchantPub: string,
   ): boolean {
-    const p = new native.PaymentSignaturePS({
-      contract_hash: native.HashCode.fromCrock(contractHash),
+    const p = new native.PaymentSignaturePS(this.emsc, {
+      contract_hash: native.HashCode.fromCrock(this.emsc, contractHash),
     });
-    const nativeSig = new native.EddsaSignature();
+    const nativeSig = new native.EddsaSignature(this.emsc);
     nativeSig.loadCrock(sig);
-    const nativePub = native.EddsaPublicKey.fromCrock(merchantPub);
+    const nativePub = native.EddsaPublicKey.fromCrock(this.emsc, merchantPub);
     return native.eddsaVerify(
       native.SignaturePurpose.MERCHANT_PAYMENT_OK,
       p.toPurpose(),
@@ -201,22 +196,24 @@ namespace RpcFunctions {
   /**
    * Check if a wire fee is correctly signed.
    */
-  export function isValidWireFee(
-    type: string,
-    wf: WireFee,
-    masterPub: string,
-  ): boolean {
-    const p = new native.MasterWireFeePS({
-      closing_fee: new native.Amount(wf.closingFee).toNbo(),
-      end_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.endStamp),
-      h_wire_method: native.ByteArray.fromStringWithNull(type).hash(),
-      start_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.startStamp),
-      wire_fee: new native.Amount(wf.wireFee).toNbo(),
+  isValidWireFee(type: string, wf: WireFee, masterPub: string): boolean {
+    const p = new native.MasterWireFeePS(this.emsc, {
+      closing_fee: new native.Amount(this.emsc, wf.closingFee).toNbo(),
+      end_date: native.AbsoluteTimeNbo.fromStampSeconds(this.emsc, 
wf.endStamp),
+      h_wire_method: native.ByteArray.fromStringWithNull(
+        this.emsc,
+        type,
+      ).hash(),
+      start_date: native.AbsoluteTimeNbo.fromStampSeconds(
+        this.emsc,
+        wf.startStamp,
+      ),
+      wire_fee: new native.Amount(this.emsc, wf.wireFee).toNbo(),
     });
 
-    const nativeSig = new native.EddsaSignature();
+    const nativeSig = new native.EddsaSignature(this.emsc);
     nativeSig.loadCrock(wf.sig);
-    const nativePub = native.EddsaPublicKey.fromCrock(masterPub);
+    const nativePub = native.EddsaPublicKey.fromCrock(this.emsc, masterPub);
 
     return native.eddsaVerify(
       native.SignaturePurpose.MASTER_WIRE_FEES,
@@ -229,36 +226,39 @@ namespace RpcFunctions {
   /**
    * Check if the signature of a denomination is valid.
    */
-  export function isValidDenom(
-    denom: DenominationRecord,
-    masterPub: string,
-  ): boolean {
-    const p = new native.DenominationKeyValidityPS({
-      denom_hash: native.RsaPublicKey.fromCrock(denom.denomPub)
+  isValidDenom(denom: DenominationRecord, masterPub: string): boolean {
+    const p = new native.DenominationKeyValidityPS(this.emsc, {
+      denom_hash: native.RsaPublicKey.fromCrock(this.emsc, denom.denomPub)
         .encode()
         .hash(),
       expire_legal: native.AbsoluteTimeNbo.fromTalerString(
+        this.emsc,
         denom.stampExpireLegal,
       ),
       expire_spend: native.AbsoluteTimeNbo.fromTalerString(
+        this.emsc,
         denom.stampExpireDeposit,
       ),
       expire_withdraw: native.AbsoluteTimeNbo.fromTalerString(
+        this.emsc,
         denom.stampExpireWithdraw,
       ),
-      fee_deposit: new native.Amount(denom.feeDeposit).toNbo(),
-      fee_refresh: new native.Amount(denom.feeRefresh).toNbo(),
-      fee_refund: new native.Amount(denom.feeRefund).toNbo(),
-      fee_withdraw: new native.Amount(denom.feeWithdraw).toNbo(),
-      master: native.EddsaPublicKey.fromCrock(masterPub),
-      start: native.AbsoluteTimeNbo.fromTalerString(denom.stampStart),
-      value: new native.Amount(denom.value).toNbo(),
+      fee_deposit: new native.Amount(this.emsc, denom.feeDeposit).toNbo(),
+      fee_refresh: new native.Amount(this.emsc, denom.feeRefresh).toNbo(),
+      fee_refund: new native.Amount(this.emsc, denom.feeRefund).toNbo(),
+      fee_withdraw: new native.Amount(this.emsc, denom.feeWithdraw).toNbo(),
+      master: native.EddsaPublicKey.fromCrock(this.emsc, masterPub),
+      start: native.AbsoluteTimeNbo.fromTalerString(
+        this.emsc,
+        denom.stampStart,
+      ),
+      value: new native.Amount(this.emsc, denom.value).toNbo(),
     });
 
-    const nativeSig = new native.EddsaSignature();
+    const nativeSig = new native.EddsaSignature(this.emsc);
     nativeSig.loadCrock(denom.masterSig);
 
-    const nativePub = native.EddsaPublicKey.fromCrock(masterPub);
+    const nativePub = native.EddsaPublicKey.fromCrock(this.emsc, masterPub);
 
     return native.eddsaVerify(
       native.SignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY,
@@ -271,8 +271,8 @@ namespace RpcFunctions {
   /**
    * Create a new EdDSA key pair.
    */
-  export function createEddsaKeypair(): { priv: string; pub: string } {
-    const priv = native.EddsaPrivateKey.create();
+  createEddsaKeypair(): { priv: string; pub: string } {
+    const priv = native.EddsaPrivateKey.create(this.emsc);
     const pub = priv.getPublicKey();
     return { priv: priv.toCrock(), pub: pub.toCrock() };
   }
@@ -280,11 +280,11 @@ namespace RpcFunctions {
   /**
    * Unblind a blindly signed value.
    */
-  export function rsaUnblind(sig: string, bk: string, pk: string): string {
+  rsaUnblind(sig: string, bk: string, pk: string): string {
     const denomSig = native.rsaUnblind(
-      native.RsaSignature.fromCrock(sig),
-      native.RsaBlindingKeySecret.fromCrock(bk),
-      native.RsaPublicKey.fromCrock(pk),
+      native.RsaSignature.fromCrock(this.emsc, sig),
+      native.RsaBlindingKeySecret.fromCrock(this.emsc, bk),
+      native.RsaPublicKey.fromCrock(this.emsc, pk),
     );
     return denomSig.encode().toCrock();
   }
@@ -293,7 +293,7 @@ namespace RpcFunctions {
    * Generate updated coins (to store in the database)
    * and deposit permissions for each given coin.
    */
-  export function signDeposit(
+  signDeposit(
     contractTerms: ContractTerms,
     cds: CoinWithDenom[],
     totalAmount: AmountJson,
@@ -304,7 +304,7 @@ namespace RpcFunctions {
       updatedCoins: [],
     };
 
-    const contractTermsHash = hashString(canonicalJson(contractTerms));
+    const contractTermsHash = this.hashString(canonicalJson(contractTerms));
 
     const feeList: AmountJson[] = cds.map(x => x.denom.feeDeposit);
     let fees = Amounts.add(Amounts.getZero(feeList[0].currency), ...feeList)
@@ -315,27 +315,35 @@ namespace RpcFunctions {
     const total = Amounts.add(fees, totalAmount).amount;
 
     const amountSpent = native.Amount.getZero(
+      this.emsc,
       cds[0].coin.currentAmount.currency,
     );
-    const amountRemaining = new native.Amount(total);
+    const amountRemaining = new native.Amount(this.emsc, total);
     for (const cd of cds) {
-      let coinSpend: Amount;
+      let coinSpend: native.Amount;
       const originalCoin = { ...cd.coin };
 
       if (amountRemaining.value === 0 && amountRemaining.fraction === 0) {
         break;
       }
 
-      if (amountRemaining.cmp(new native.Amount(cd.coin.currentAmount)) < 0) {
-        coinSpend = new native.Amount(amountRemaining.toJson());
+      if (
+        amountRemaining.cmp(
+          new native.Amount(this.emsc, cd.coin.currentAmount),
+        ) < 0
+      ) {
+        coinSpend = new native.Amount(this.emsc, amountRemaining.toJson());
       } else {
-        coinSpend = new native.Amount(cd.coin.currentAmount);
+        coinSpend = new native.Amount(this.emsc, cd.coin.currentAmount);
       }
 
       amountSpent.add(coinSpend);
       amountRemaining.sub(coinSpend);
 
-      const feeDeposit: Amount = new native.Amount(cd.denom.feeDeposit);
+      const feeDeposit: native.Amount = new native.Amount(
+        this.emsc,
+        cd.denom.feeDeposit,
+      );
 
       // Give the merchant at least the deposit fee, otherwise it'll reject
       // the coin.
@@ -343,22 +351,27 @@ namespace RpcFunctions {
         coinSpend = feeDeposit;
       }
 
-      const newAmount = new native.Amount(cd.coin.currentAmount);
+      const newAmount = new native.Amount(this.emsc, cd.coin.currentAmount);
       newAmount.sub(coinSpend);
       cd.coin.currentAmount = newAmount.toJson();
       cd.coin.status = CoinStatus.PurchasePending;
 
-      const d = new native.DepositRequestPS({
+      const d = new native.DepositRequestPS(this.emsc, {
         amount_with_fee: coinSpend.toNbo(),
-        coin_pub: native.EddsaPublicKey.fromCrock(cd.coin.coinPub),
-        deposit_fee: new native.Amount(cd.denom.feeDeposit).toNbo(),
-        h_contract: native.HashCode.fromCrock(contractTermsHash),
-        h_wire: native.HashCode.fromCrock(contractTerms.H_wire),
-        merchant: native.EddsaPublicKey.fromCrock(contractTerms.merchant_pub),
+        coin_pub: native.EddsaPublicKey.fromCrock(this.emsc, cd.coin.coinPub),
+        deposit_fee: new native.Amount(this.emsc, cd.denom.feeDeposit).toNbo(),
+        h_contract: native.HashCode.fromCrock(this.emsc, contractTermsHash),
+        h_wire: native.HashCode.fromCrock(this.emsc, contractTerms.H_wire),
+        merchant: native.EddsaPublicKey.fromCrock(
+          this.emsc,
+          contractTerms.merchant_pub,
+        ),
         refund_deadline: native.AbsoluteTimeNbo.fromTalerString(
+          this.emsc,
           contractTerms.refund_deadline,
         ),
         timestamp: native.AbsoluteTimeNbo.fromTalerString(
+          this.emsc,
           contractTerms.timestamp,
         ),
       });
@@ -366,7 +379,7 @@ namespace RpcFunctions {
       const coinSig = native
         .eddsaSign(
           d.toPurpose(),
-          native.EddsaPrivateKey.fromCrock(cd.coin.coinPriv),
+          native.EddsaPrivateKey.fromCrock(this.emsc, cd.coin.coinPriv),
         )
         .toCrock();
 
@@ -388,7 +401,7 @@ namespace RpcFunctions {
   /**
    * Create a new refresh session.
    */
-  export function createRefreshSession(
+  createRefreshSession(
     exchangeBaseUrl: string,
     kappa: number,
     meltCoin: CoinRecord,
@@ -405,7 +418,7 @@ namespace RpcFunctions {
     // melt fee
     valueWithFee = Amounts.add(valueWithFee, meltFee).amount;
 
-    const sessionHc = new HashContext();
+    const sessionHc = new native.HashContext(this.emsc);
 
     const transferPubs: string[] = [];
     const transferPrivs: string[] = [];
@@ -413,7 +426,7 @@ namespace RpcFunctions {
     const preCoinsForGammas: RefreshPreCoinRecord[][] = [];
 
     for (let i = 0; i < kappa; i++) {
-      const t = native.EcdhePrivateKey.create();
+      const t = native.EcdhePrivateKey.create(this.emsc);
       const pub = t.getPublicKey();
       sessionHc.read(pub);
       transferPrivs.push(t.toCrock());
@@ -421,18 +434,26 @@ namespace RpcFunctions {
     }
 
     for (const denom of newCoinDenoms) {
-      const r = native.RsaPublicKey.fromCrock(denom.denomPub);
+      const r = native.RsaPublicKey.fromCrock(this.emsc, denom.denomPub);
       sessionHc.read(r.encode());
     }
 
-    sessionHc.read(native.EddsaPublicKey.fromCrock(meltCoin.coinPub));
-    sessionHc.read(new native.Amount(valueWithFee).toNbo());
+    sessionHc.read(
+      native.EddsaPublicKey.fromCrock(this.emsc, meltCoin.coinPub),
+    );
+    sessionHc.read(new native.Amount(this.emsc, valueWithFee).toNbo());
 
     for (let i = 0; i < kappa; i++) {
       const preCoins: RefreshPreCoinRecord[] = [];
       for (let j = 0; j < newCoinDenoms.length; j++) {
-        const transferPriv = 
native.EcdhePrivateKey.fromCrock(transferPrivs[i]);
-        const oldCoinPub = native.EddsaPublicKey.fromCrock(meltCoin.coinPub);
+        const transferPriv = native.EcdhePrivateKey.fromCrock(
+          this.emsc,
+          transferPrivs[i],
+        );
+        const oldCoinPub = native.EddsaPublicKey.fromCrock(
+          this.emsc,
+          meltCoin.coinPub,
+        );
         const transferSecret = native.ecdhEddsa(transferPriv, oldCoinPub);
 
         const fresh = native.setupFreshCoin(transferSecret, j);
@@ -442,6 +463,7 @@ namespace RpcFunctions {
         const blindingFactor = fresh.blindingKey;
         const pubHash: native.HashCode = coinPub.hash();
         const denomPub = native.RsaPublicKey.fromCrock(
+          this.emsc,
           newCoinDenoms[j].denomPub,
         );
         const ev = native.rsaBlind(pubHash, blindingFactor, denomPub);
@@ -460,21 +482,21 @@ namespace RpcFunctions {
       preCoinsForGammas.push(preCoins);
     }
 
-    const sessionHash = new HashCode();
+    const sessionHash = new native.HashCode(this.emsc);
     sessionHash.alloc();
     sessionHc.finish(sessionHash);
 
-    const confirmData = new RefreshMeltCoinAffirmationPS({
-      amount_with_fee: new Amount(valueWithFee).toNbo(),
-      coin_pub: EddsaPublicKey.fromCrock(meltCoin.coinPub),
-      melt_fee: new Amount(meltFee).toNbo(),
+    const confirmData = new native.RefreshMeltCoinAffirmationPS(this.emsc, {
+      amount_with_fee: new native.Amount(this.emsc, valueWithFee).toNbo(),
+      coin_pub: native.EddsaPublicKey.fromCrock(this.emsc, meltCoin.coinPub),
+      melt_fee: new native.Amount(this.emsc, meltFee).toNbo(),
       session_hash: sessionHash,
     });
 
     const confirmSig: string = native
       .eddsaSign(
         confirmData.toPurpose(),
-        native.EddsaPrivateKey.fromCrock(meltCoin.coinPriv),
+        native.EddsaPrivateKey.fromCrock(this.emsc, meltCoin.coinPriv),
       )
       .toCrock();
 
@@ -505,54 +527,54 @@ namespace RpcFunctions {
   /**
    * Hash a string including the zero terminator.
    */
-  export function hashString(str: string): string {
-    const b = native.ByteArray.fromStringWithNull(str);
+  hashString(str: string): string {
+    const b = native.ByteArray.fromStringWithNull(this.emsc, str);
     return b.hash().toCrock();
   }
 
   /**
    * Hash a denomination public key.
    */
-  export function hashDenomPub(denomPub: string): string {
-    return native.RsaPublicKey.fromCrock(denomPub)
+  hashDenomPub(denomPub: string): string {
+    return native.RsaPublicKey.fromCrock(this.emsc, denomPub)
       .encode()
       .hash()
       .toCrock();
   }
 
-  export function signCoinLink(
+  signCoinLink(
     oldCoinPriv: string,
     newDenomHash: string,
     oldCoinPub: string,
     transferPub: string,
     coinEv: string,
   ): string {
-    const coinEvHash = native.ByteArray.fromCrock(coinEv).hash();
+    const coinEvHash = native.ByteArray.fromCrock(this.emsc, coinEv).hash();
 
-    const coinLink = new native.CoinLinkSignaturePS({
+    const coinLink = new native.CoinLinkSignaturePS(this.emsc, {
       coin_envelope_hash: coinEvHash,
-      h_denom_pub: native.HashCode.fromCrock(newDenomHash),
-      old_coin_pub: native.EddsaPublicKey.fromCrock(oldCoinPub),
-      transfer_pub: native.EcdhePublicKey.fromCrock(transferPub),
+      h_denom_pub: native.HashCode.fromCrock(this.emsc, newDenomHash),
+      old_coin_pub: native.EddsaPublicKey.fromCrock(this.emsc, oldCoinPub),
+      transfer_pub: native.EcdhePublicKey.fromCrock(this.emsc, transferPub),
     });
 
-    const coinPriv = native.EddsaPrivateKey.fromCrock(oldCoinPriv);
+    const coinPriv = native.EddsaPrivateKey.fromCrock(this.emsc, oldCoinPriv);
 
     const sig = native.eddsaSign(coinLink.toPurpose(), coinPriv);
 
     return sig.toCrock();
   }
 
-  export function benchmark(repetitions: number): BenchmarkResult {
+  benchmark(repetitions: number): BenchmarkResult {
     let time_hash = 0;
     for (let i = 0; i < repetitions; i++) {
       const start = timer.performanceNow();
-      hashString("hello world");
+      this.hashString("hello world");
       time_hash += timer.performanceNow() - start;
     }
 
     let time_hash_big = 0;
-    const ba = new native.ByteArray(4096);
+    const ba = new native.ByteArray(this.emsc, 4096);
     for (let i = 0; i < repetitions; i++) {
       ba.randomize(native.RandomQuality.WEAK);
       const start = timer.performanceNow();
@@ -563,19 +585,23 @@ namespace RpcFunctions {
     let time_eddsa_create = 0;
     for (let i = 0; i < repetitions; i++) {
       const start = timer.performanceNow();
-      const priv: native.EddsaPrivateKey = native.EddsaPrivateKey.create();
+      const priv: native.EddsaPrivateKey = native.EddsaPrivateKey.create(
+        this.emsc,
+      );
       time_eddsa_create += timer.performanceNow() - start;
       priv.destroy();
     }
 
     let time_eddsa_sign = 0;
-    const eddsaPriv: native.EddsaPrivateKey = native.EddsaPrivateKey.create();
+    const eddsaPriv: native.EddsaPrivateKey = native.EddsaPrivateKey.create(
+      this.emsc,
+    );
     const eddsaPub: native.EddsaPublicKey = eddsaPriv.getPublicKey();
-    const h: native.HashCode = new native.HashCode();
+    const h: native.HashCode = new native.HashCode(this.emsc);
     h.alloc();
     h.random(native.RandomQuality.WEAK);
 
-    const ps = new native.PaymentSignaturePS({
+    const ps = new native.PaymentSignaturePS(this.emsc, {
       contract_hash: h,
     });
 
@@ -592,7 +618,9 @@ namespace RpcFunctions {
     let time_ecdsa_create = 0;
     for (let i = 0; i < repetitions; i++) {
       const start = timer.performanceNow();
-      const priv: native.EcdsaPrivateKey = native.EcdsaPrivateKey.create();
+      const priv: native.EcdsaPrivateKey = native.EcdsaPrivateKey.create(
+        this.emsc,
+      );
       time_ecdsa_create += timer.performanceNow() - start;
       priv.destroy();
     }
@@ -612,9 +640,12 @@ namespace RpcFunctions {
     /* rsa 2048 */
 
     let time_rsa_2048_blind = 0;
-    const rsaPriv2048: native.RsaPrivateKey = 
native.RsaPrivateKey.create(2048);
+    const rsaPriv2048: native.RsaPrivateKey = native.RsaPrivateKey.create(
+      this.emsc,
+      2048,
+    );
     const rsaPub2048 = rsaPriv2048.getPublicKey();
-    const blindingSecret2048 = native.RsaBlindingKeySecret.create();
+    const blindingSecret2048 = native.RsaBlindingKeySecret.create(this.emsc);
     for (let i = 0; i < repetitions; i++) {
       const start = timer.performanceNow();
       native.rsaBlind(h, blindingSecret2048, rsaPub2048);
@@ -657,9 +688,12 @@ namespace RpcFunctions {
     /* rsa 4096 */
 
     let time_rsa_4096_blind = 0;
-    const rsaPriv4096: native.RsaPrivateKey = 
native.RsaPrivateKey.create(4096);
+    const rsaPriv4096: native.RsaPrivateKey = native.RsaPrivateKey.create(
+      this.emsc,
+      4096,
+    );
     const rsaPub4096 = rsaPriv4096.getPublicKey();
-    const blindingSecret4096 = native.RsaBlindingKeySecret.create();
+    const blindingSecret4096 = native.RsaBlindingKeySecret.create(this.emsc);
     for (let i = 0; i < repetitions; i++) {
       const start = timer.performanceNow();
       native.rsaBlind(h, blindingSecret4096, rsaPub4096);
@@ -718,45 +752,3 @@ namespace RpcFunctions {
     };
   }
 }
-
-const worker: Worker = (self as any) as Worker;
-
-worker.onmessage = (msg: MessageEvent) => {
-  if (!Array.isArray(msg.data.args)) {
-    console.error("args must be array");
-    return;
-  }
-  if (typeof msg.data.id !== "number") {
-    console.error("RPC id must be number");
-  }
-  if (typeof msg.data.operation !== "string") {
-    console.error("RPC operation must be string");
-  }
-  const f = (RpcFunctions as any)[msg.data.operation];
-  if (!f) {
-    console.error(`unknown operation: '${msg.data.operation}'`);
-    return;
-  }
-
-  if (RpcFunctions.enableTracing) {
-    console.log("onmessage with", msg.data.operation);
-  }
-
-  emscLoader.getLib().then(p => {
-    const lib = p.lib;
-    if (!native.isInitialized()) {
-      if (RpcFunctions.enableTracing) {
-        console.log("initializing emscripten for then first time with lib");
-      }
-      native.initialize(lib);
-    }
-    if (RpcFunctions.enableTracing) {
-      console.log("about to execute", msg.data.operation);
-    }
-    const res = f(...msg.data.args);
-    if (RpcFunctions.enableTracing) {
-      console.log("finished executing", msg.data.operation);
-    }
-    worker.postMessage({ result: res, id: msg.data.id });
-  });
-};
diff --git a/src/crypto/cryptoWorker.ts b/src/crypto/cryptoWorker.ts
index 5acda905..11e3d964 100644
--- a/src/crypto/cryptoWorker.ts
+++ b/src/crypto/cryptoWorker.ts
@@ -21,742 +21,57 @@
 /**
  * Imports.
  */
-import * as Amounts from "../amounts";
-import { AmountJson } from "../amounts";
-
-import * as timer from "../timer";
-
-import {
-  CoinRecord,
-  CoinStatus,
-  DenominationRecord,
-  PreCoinRecord,
-  RefreshPreCoinRecord,
-  RefreshSessionRecord,
-  ReserveRecord,
-  TipPlanchet,
-  WireFee,
-} from "../dbTypes";
-
-import { CoinPaySig, ContractTerms, PaybackRequest } from "../talerTypes";
-
-import { BenchmarkResult, CoinWithDenom, PayCoinInfo } from "../walletTypes";
-
-import { canonicalJson } from "../helpers";
 
 import * as emscLoader from "./emscLoader";
 
-import {
-  Amount,
-  EddsaPublicKey,
-  HashCode,
-  HashContext,
-  RefreshMeltCoinAffirmationPS,
-} from "./emscInterface";
-import * as native from "./emscInterface";
-
-namespace RpcFunctions {
-
-  export let enableTracing: boolean = false;
-
-  /**
-   * Create a pre-coin of the given denomination to be withdrawn from then 
given
-   * reserve.
-   */
-  export function createPreCoin(
-    denom: DenominationRecord,
-    reserve: ReserveRecord,
-  ): PreCoinRecord {
-    const reservePriv = new native.EddsaPrivateKey();
-    reservePriv.loadCrock(reserve.reserve_priv);
-    const reservePub = new native.EddsaPublicKey();
-    reservePub.loadCrock(reserve.reserve_pub);
-    const denomPub = native.RsaPublicKey.fromCrock(denom.denomPub);
-    const coinPriv = native.EddsaPrivateKey.create();
-    const coinPub = coinPriv.getPublicKey();
-    const blindingFactor = native.RsaBlindingKeySecret.create();
-    const pubHash: native.HashCode = coinPub.hash();
-    const ev = native.rsaBlind(pubHash, blindingFactor, denomPub);
-
-    if (!ev) {
-      throw Error("couldn't blind (malicious exchange key?)");
-    }
-
-    if (!denom.feeWithdraw) {
-      throw Error("Field fee_withdraw missing");
-    }
-
-    const amountWithFee = new native.Amount(denom.value);
-    amountWithFee.add(new native.Amount(denom.feeWithdraw));
-    const withdrawFee = new native.Amount(denom.feeWithdraw);
-
-    const denomPubHash = denomPub.encode().hash();
-
-    // Signature
-    const withdrawRequest = new native.WithdrawRequestPS({
-      amount_with_fee: amountWithFee.toNbo(),
-      h_coin_envelope: ev.hash(),
-      h_denomination_pub: denomPubHash,
-      reserve_pub: reservePub,
-      withdraw_fee: withdrawFee.toNbo(),
-    });
-
-    const sig = native.eddsaSign(withdrawRequest.toPurpose(), reservePriv);
-
-    const preCoin: PreCoinRecord = {
-      blindingKey: blindingFactor.toCrock(),
-      coinEv: ev.toCrock(),
-      coinPriv: coinPriv.toCrock(),
-      coinPub: coinPub.toCrock(),
-      coinValue: denom.value,
-      denomPub: denomPub.toCrock(),
-      denomPubHash: denomPubHash.toCrock(),
-      exchangeBaseUrl: reserve.exchange_base_url,
-      isFromTip: false,
-      reservePub: reservePub.toCrock(),
-      withdrawSig: sig.toCrock(),
-    };
-    return preCoin;
-  }
-
-  /**
-   * Create a planchet used for tipping, including the private keys.
-   */
-  export function createTipPlanchet(denom: DenominationRecord): TipPlanchet {
-    const denomPub = native.RsaPublicKey.fromCrock(denom.denomPub);
-    const coinPriv = native.EddsaPrivateKey.create();
-    const coinPub = coinPriv.getPublicKey();
-    const blindingFactor = native.RsaBlindingKeySecret.create();
-    const pubHash: native.HashCode = coinPub.hash();
-    const ev = native.rsaBlind(pubHash, blindingFactor, denomPub);
-
-    if (!ev) {
-      throw Error("couldn't blind (malicious exchange key?)");
-    }
-
-    if (!denom.feeWithdraw) {
-      throw Error("Field fee_withdraw missing");
-    }
-
-    const tipPlanchet: TipPlanchet = {
-      blindingKey: blindingFactor.toCrock(),
-      coinEv: ev.toCrock(),
-      coinPriv: coinPriv.toCrock(),
-      coinPub: coinPub.toCrock(),
-      coinValue: denom.value,
-      denomPub: denomPub.encode().toCrock(),
-      denomPubHash: denomPub
-        .encode()
-        .hash()
-        .toCrock(),
-    };
-    return tipPlanchet;
-  }
-
-  /**
-   * Create and sign a message to request payback for a coin.
-   */
-  export function createPaybackRequest(coin: CoinRecord): PaybackRequest {
-    const p = new native.PaybackRequestPS({
-      coin_blind: native.RsaBlindingKeySecret.fromCrock(coin.blindingKey),
-      coin_pub: native.EddsaPublicKey.fromCrock(coin.coinPub),
-      h_denom_pub: native.RsaPublicKey.fromCrock(coin.denomPub)
-        .encode()
-        .hash(),
-    });
-    const coinPriv = native.EddsaPrivateKey.fromCrock(coin.coinPriv);
-    const coinSig = native.eddsaSign(p.toPurpose(), coinPriv);
-    const paybackRequest: PaybackRequest = {
-      coin_blind_key_secret: coin.blindingKey,
-      coin_pub: coin.coinPub,
-      coin_sig: coinSig.toCrock(),
-      denom_pub: coin.denomPub,
-      denom_sig: coin.denomSig,
-    };
-    return paybackRequest;
-  }
-
-  /**
-   * Check if a payment signature is valid.
-   */
-  export function isValidPaymentSignature(
-    sig: string,
-    contractHash: string,
-    merchantPub: string,
-  ): boolean {
-    const p = new native.PaymentSignaturePS({
-      contract_hash: native.HashCode.fromCrock(contractHash),
-    });
-    const nativeSig = new native.EddsaSignature();
-    nativeSig.loadCrock(sig);
-    const nativePub = native.EddsaPublicKey.fromCrock(merchantPub);
-    return native.eddsaVerify(
-      native.SignaturePurpose.MERCHANT_PAYMENT_OK,
-      p.toPurpose(),
-      nativeSig,
-      nativePub,
-    );
-  }
-
-  /**
-   * Check if a wire fee is correctly signed.
-   */
-  export function isValidWireFee(
-    type: string,
-    wf: WireFee,
-    masterPub: string,
-  ): boolean {
-    const p = new native.MasterWireFeePS({
-      closing_fee: new native.Amount(wf.closingFee).toNbo(),
-      end_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.endStamp),
-      h_wire_method: native.ByteArray.fromStringWithNull(type).hash(),
-      start_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.startStamp),
-      wire_fee: new native.Amount(wf.wireFee).toNbo(),
-    });
-
-    const nativeSig = new native.EddsaSignature();
-    nativeSig.loadCrock(wf.sig);
-    const nativePub = native.EddsaPublicKey.fromCrock(masterPub);
-
-    return native.eddsaVerify(
-      native.SignaturePurpose.MASTER_WIRE_FEES,
-      p.toPurpose(),
-      nativeSig,
-      nativePub,
-    );
-  }
-
-  /**
-   * Check if the signature of a denomination is valid.
-   */
-  export function isValidDenom(
-    denom: DenominationRecord,
-    masterPub: string,
-  ): boolean {
-    const p = new native.DenominationKeyValidityPS({
-      denom_hash: native.RsaPublicKey.fromCrock(denom.denomPub)
-        .encode()
-        .hash(),
-      expire_legal: native.AbsoluteTimeNbo.fromTalerString(
-        denom.stampExpireLegal,
-      ),
-      expire_spend: native.AbsoluteTimeNbo.fromTalerString(
-        denom.stampExpireDeposit,
-      ),
-      expire_withdraw: native.AbsoluteTimeNbo.fromTalerString(
-        denom.stampExpireWithdraw,
-      ),
-      fee_deposit: new native.Amount(denom.feeDeposit).toNbo(),
-      fee_refresh: new native.Amount(denom.feeRefresh).toNbo(),
-      fee_refund: new native.Amount(denom.feeRefund).toNbo(),
-      fee_withdraw: new native.Amount(denom.feeWithdraw).toNbo(),
-      master: native.EddsaPublicKey.fromCrock(masterPub),
-      start: native.AbsoluteTimeNbo.fromTalerString(denom.stampStart),
-      value: new native.Amount(denom.value).toNbo(),
-    });
-
-    const nativeSig = new native.EddsaSignature();
-    nativeSig.loadCrock(denom.masterSig);
-
-    const nativePub = native.EddsaPublicKey.fromCrock(masterPub);
-
-    return native.eddsaVerify(
-      native.SignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY,
-      p.toPurpose(),
-      nativeSig,
-      nativePub,
-    );
-  }
-
-  /**
-   * Create a new EdDSA key pair.
-   */
-  export function createEddsaKeypair(): { priv: string; pub: string } {
-    const priv = native.EddsaPrivateKey.create();
-    const pub = priv.getPublicKey();
-    return { priv: priv.toCrock(), pub: pub.toCrock() };
-  }
-
-  /**
-   * Unblind a blindly signed value.
-   */
-  export function rsaUnblind(sig: string, bk: string, pk: string): string {
-    const denomSig = native.rsaUnblind(
-      native.RsaSignature.fromCrock(sig),
-      native.RsaBlindingKeySecret.fromCrock(bk),
-      native.RsaPublicKey.fromCrock(pk),
-    );
-    return denomSig.encode().toCrock();
-  }
-
-  /**
-   * Generate updated coins (to store in the database)
-   * and deposit permissions for each given coin.
-   */
-  export function signDeposit(
-    contractTerms: ContractTerms,
-    cds: CoinWithDenom[],
-    totalAmount: AmountJson,
-  ): PayCoinInfo {
-    const ret: PayCoinInfo = {
-      originalCoins: [],
-      sigs: [],
-      updatedCoins: [],
-    };
-
-    const contractTermsHash = hashString(canonicalJson(contractTerms));
-
-    const feeList: AmountJson[] = cds.map(x => x.denom.feeDeposit);
-    let fees = Amounts.add(Amounts.getZero(feeList[0].currency), ...feeList)
-      .amount;
-    // okay if saturates
-    fees = Amounts.sub(fees, Amounts.parseOrThrow(contractTerms.max_fee))
-      .amount;
-    const total = Amounts.add(fees, totalAmount).amount;
-
-    const amountSpent = native.Amount.getZero(
-      cds[0].coin.currentAmount.currency,
-    );
-    const amountRemaining = new native.Amount(total);
-    for (const cd of cds) {
-      let coinSpend: Amount;
-      const originalCoin = { ...cd.coin };
-
-      if (amountRemaining.value === 0 && amountRemaining.fraction === 0) {
-        break;
-      }
-
-      if (amountRemaining.cmp(new native.Amount(cd.coin.currentAmount)) < 0) {
-        coinSpend = new native.Amount(amountRemaining.toJson());
-      } else {
-        coinSpend = new native.Amount(cd.coin.currentAmount);
-      }
-
-      amountSpent.add(coinSpend);
-      amountRemaining.sub(coinSpend);
-
-      const feeDeposit: Amount = new native.Amount(cd.denom.feeDeposit);
-
-      // Give the merchant at least the deposit fee, otherwise it'll reject
-      // the coin.
-      if (coinSpend.cmp(feeDeposit) < 0) {
-        coinSpend = feeDeposit;
-      }
-
-      const newAmount = new native.Amount(cd.coin.currentAmount);
-      newAmount.sub(coinSpend);
-      cd.coin.currentAmount = newAmount.toJson();
-      cd.coin.status = CoinStatus.PurchasePending;
-
-      const d = new native.DepositRequestPS({
-        amount_with_fee: coinSpend.toNbo(),
-        coin_pub: native.EddsaPublicKey.fromCrock(cd.coin.coinPub),
-        deposit_fee: new native.Amount(cd.denom.feeDeposit).toNbo(),
-        h_contract: native.HashCode.fromCrock(contractTermsHash),
-        h_wire: native.HashCode.fromCrock(contractTerms.H_wire),
-        merchant: native.EddsaPublicKey.fromCrock(contractTerms.merchant_pub),
-        refund_deadline: native.AbsoluteTimeNbo.fromTalerString(
-          contractTerms.refund_deadline,
-        ),
-        timestamp: native.AbsoluteTimeNbo.fromTalerString(
-          contractTerms.timestamp,
-        ),
-      });
-
-      const coinSig = native
-        .eddsaSign(
-          d.toPurpose(),
-          native.EddsaPrivateKey.fromCrock(cd.coin.coinPriv),
-        )
-        .toCrock();
-
-      const s: CoinPaySig = {
-        coin_pub: cd.coin.coinPub,
-        coin_sig: coinSig,
-        contribution: Amounts.toString(coinSpend.toJson()),
-        denom_pub: cd.coin.denomPub,
-        exchange_url: cd.denom.exchangeBaseUrl,
-        ub_sig: cd.coin.denomSig,
-      };
-      ret.sigs.push(s);
-      ret.updatedCoins.push(cd.coin);
-      ret.originalCoins.push(originalCoin);
-    }
-    return ret;
-  }
-
-  /**
-   * Create a new refresh session.
-   */
-  export function createRefreshSession(
-    exchangeBaseUrl: string,
-    kappa: number,
-    meltCoin: CoinRecord,
-    newCoinDenoms: DenominationRecord[],
-    meltFee: AmountJson,
-  ): RefreshSessionRecord {
-    let valueWithFee = Amounts.getZero(newCoinDenoms[0].value.currency);
-
-    for (const ncd of newCoinDenoms) {
-      valueWithFee = Amounts.add(valueWithFee, ncd.value, ncd.feeWithdraw)
-        .amount;
-    }
-
-    // melt fee
-    valueWithFee = Amounts.add(valueWithFee, meltFee).amount;
-
-    const sessionHc = new HashContext();
-
-    const transferPubs: string[] = [];
-    const transferPrivs: string[] = [];
-
-    const preCoinsForGammas: RefreshPreCoinRecord[][] = [];
-
-    for (let i = 0; i < kappa; i++) {
-      const t = native.EcdhePrivateKey.create();
-      const pub = t.getPublicKey();
-      sessionHc.read(pub);
-      transferPrivs.push(t.toCrock());
-      transferPubs.push(pub.toCrock());
-    }
-
-    for (const denom of newCoinDenoms) {
-      const r = native.RsaPublicKey.fromCrock(denom.denomPub);
-      sessionHc.read(r.encode());
-    }
+import { CryptoImplementation } from "./cryptoImplementation";
+import { EmscEnvironment } from "./emscInterface";
 
-    sessionHc.read(native.EddsaPublicKey.fromCrock(meltCoin.coinPub));
-    sessionHc.read(new native.Amount(valueWithFee).toNbo());
-
-    for (let i = 0; i < kappa; i++) {
-      const preCoins: RefreshPreCoinRecord[] = [];
-      for (let j = 0; j < newCoinDenoms.length; j++) {
-        const transferPriv = 
native.EcdhePrivateKey.fromCrock(transferPrivs[i]);
-        const oldCoinPub = native.EddsaPublicKey.fromCrock(meltCoin.coinPub);
-        const transferSecret = native.ecdhEddsa(transferPriv, oldCoinPub);
-
-        const fresh = native.setupFreshCoin(transferSecret, j);
-
-        const coinPriv = fresh.priv;
-        const coinPub = coinPriv.getPublicKey();
-        const blindingFactor = fresh.blindingKey;
-        const pubHash: native.HashCode = coinPub.hash();
-        const denomPub = native.RsaPublicKey.fromCrock(
-          newCoinDenoms[j].denomPub,
-        );
-        const ev = native.rsaBlind(pubHash, blindingFactor, denomPub);
-        if (!ev) {
-          throw Error("couldn't blind (malicious exchange key?)");
-        }
-        const preCoin: RefreshPreCoinRecord = {
-          blindingKey: blindingFactor.toCrock(),
-          coinEv: ev.toCrock(),
-          privateKey: coinPriv.toCrock(),
-          publicKey: coinPub.toCrock(),
-        };
-        preCoins.push(preCoin);
-        sessionHc.read(ev);
-      }
-      preCoinsForGammas.push(preCoins);
-    }
-
-    const sessionHash = new HashCode();
-    sessionHash.alloc();
-    sessionHc.finish(sessionHash);
-
-    const confirmData = new RefreshMeltCoinAffirmationPS({
-      amount_with_fee: new Amount(valueWithFee).toNbo(),
-      coin_pub: EddsaPublicKey.fromCrock(meltCoin.coinPub),
-      melt_fee: new Amount(meltFee).toNbo(),
-      session_hash: sessionHash,
-    });
-
-    const confirmSig: string = native
-      .eddsaSign(
-        confirmData.toPurpose(),
-        native.EddsaPrivateKey.fromCrock(meltCoin.coinPriv),
-      )
-      .toCrock();
-
-    let valueOutput = Amounts.getZero(newCoinDenoms[0].value.currency);
-    for (const denom of newCoinDenoms) {
-      valueOutput = Amounts.add(valueOutput, denom.value).amount;
-    }
-
-    const refreshSession: RefreshSessionRecord = {
-      confirmSig,
-      exchangeBaseUrl,
-      finished: false,
-      hash: sessionHash.toCrock(),
-      meltCoinPub: meltCoin.coinPub,
-      newDenomHashes: newCoinDenoms.map(d => d.denomPubHash),
-      newDenoms: newCoinDenoms.map(d => d.denomPub),
-      norevealIndex: undefined,
-      preCoinsForGammas,
-      transferPrivs,
-      transferPubs,
-      valueOutput,
-      valueWithFee,
-    };
-
-    return refreshSession;
-  }
-
-  /**
-   * Hash a string including the zero terminator.
-   */
-  export function hashString(str: string): string {
-    const b = native.ByteArray.fromStringWithNull(str);
-    return b.hash().toCrock();
-  }
-
-  /**
-   * Hash a denomination public key.
-   */
-  export function hashDenomPub(denomPub: string): string {
-    return native.RsaPublicKey.fromCrock(denomPub)
-      .encode()
-      .hash()
-      .toCrock();
-  }
-
-  export function signCoinLink(
-    oldCoinPriv: string,
-    newDenomHash: string,
-    oldCoinPub: string,
-    transferPub: string,
-    coinEv: string,
-  ): string {
-    const coinEvHash = native.ByteArray.fromCrock(coinEv).hash();
-
-    const coinLink = new native.CoinLinkSignaturePS({
-      coin_envelope_hash: coinEvHash,
-      h_denom_pub: native.HashCode.fromCrock(newDenomHash),
-      old_coin_pub: native.EddsaPublicKey.fromCrock(oldCoinPub),
-      transfer_pub: native.EcdhePublicKey.fromCrock(transferPub),
-    });
-
-    const coinPriv = native.EddsaPrivateKey.fromCrock(oldCoinPriv);
-
-    const sig = native.eddsaSign(coinLink.toPurpose(), coinPriv);
-
-    return sig.toCrock();
-  }
-
-  export function benchmark(repetitions: number): BenchmarkResult {
-    let time_hash = 0;
-    for (let i = 0; i < repetitions; i++) {
-      const start = timer.performanceNow();
-      hashString("hello world");
-      time_hash += timer.performanceNow() - start;
-    }
-
-    let time_hash_big = 0;
-    const ba = new native.ByteArray(4096);
-    for (let i = 0; i < repetitions; i++) {
-      ba.randomize(native.RandomQuality.WEAK);
-      const start = timer.performanceNow();
-      ba.hash();
-      time_hash_big += timer.performanceNow() - start;
-    }
-
-    let time_eddsa_create = 0;
-    for (let i = 0; i < repetitions; i++) {
-      const start = timer.performanceNow();
-      const priv: native.EddsaPrivateKey = native.EddsaPrivateKey.create();
-      time_eddsa_create += timer.performanceNow() - start;
-      priv.destroy();
-    }
-
-    let time_eddsa_sign = 0;
-    const eddsaPriv: native.EddsaPrivateKey = native.EddsaPrivateKey.create();
-    const eddsaPub: native.EddsaPublicKey = eddsaPriv.getPublicKey();
-    const h: native.HashCode = new native.HashCode();
-    h.alloc();
-    h.random(native.RandomQuality.WEAK);
-
-    const ps = new native.PaymentSignaturePS({
-      contract_hash: h,
-    });
-
-    const p = ps.toPurpose();
-
-    for (let i = 0; i < repetitions; i++) {
-      const start = timer.performanceNow();
-      native.eddsaSign(p, eddsaPriv);
-      time_eddsa_sign += timer.performanceNow() - start;
-    }
-
-    const eddsaSig = native.eddsaSign(p, eddsaPriv);
-
-    let time_ecdsa_create = 0;
-    for (let i = 0; i < repetitions; i++) {
-      const start = timer.performanceNow();
-      const priv: native.EcdsaPrivateKey = native.EcdsaPrivateKey.create();
-      time_ecdsa_create += timer.performanceNow() - start;
-      priv.destroy();
-    }
-
-    let time_eddsa_verify = 0;
-    for (let i = 0; i < repetitions; i++) {
-      const start = timer.performanceNow();
-      native.eddsaVerify(
-        native.SignaturePurpose.MERCHANT_PAYMENT_OK,
-        p,
-        eddsaSig,
-        eddsaPub,
-      );
-      time_eddsa_verify += timer.performanceNow() - start;
-    }
-
-    /* rsa 2048 */
-
-    let time_rsa_2048_blind = 0;
-    const rsaPriv2048: native.RsaPrivateKey = 
native.RsaPrivateKey.create(2048);
-    const rsaPub2048 = rsaPriv2048.getPublicKey();
-    const blindingSecret2048 = native.RsaBlindingKeySecret.create();
-    for (let i = 0; i < repetitions; i++) {
-      const start = timer.performanceNow();
-      native.rsaBlind(h, blindingSecret2048, rsaPub2048);
-      time_rsa_2048_blind += timer.performanceNow() - start;
-    }
-
-    const blindedMessage2048 = native.rsaBlind(
-      h,
-      blindingSecret2048,
-      rsaPub2048,
-    );
-    if (!blindedMessage2048) {
-      throw Error("should not happen");
-    }
-    const rsaBlindSig2048 = native.rsaSignBlinded(
-      rsaPriv2048,
-      blindedMessage2048,
-    );
-
-    let time_rsa_2048_unblind = 0;
-    for (let i = 0; i < repetitions; i++) {
-      const start = timer.performanceNow();
-      native.rsaUnblind(rsaBlindSig2048, blindingSecret2048, rsaPub2048);
-      time_rsa_2048_unblind += timer.performanceNow() - start;
-    }
-
-    const unblindedSig2048 = native.rsaUnblind(
-      rsaBlindSig2048,
-      blindingSecret2048,
-      rsaPub2048,
-    );
-
-    let time_rsa_2048_verify = 0;
-    for (let i = 0; i < repetitions; i++) {
-      const start = timer.performanceNow();
-      native.rsaVerify(h, unblindedSig2048, rsaPub2048);
-      time_rsa_2048_verify += timer.performanceNow() - start;
-    }
-
-    /* rsa 4096 */
-
-    let time_rsa_4096_blind = 0;
-    const rsaPriv4096: native.RsaPrivateKey = 
native.RsaPrivateKey.create(4096);
-    const rsaPub4096 = rsaPriv4096.getPublicKey();
-    const blindingSecret4096 = native.RsaBlindingKeySecret.create();
-    for (let i = 0; i < repetitions; i++) {
-      const start = timer.performanceNow();
-      native.rsaBlind(h, blindingSecret4096, rsaPub4096);
-      time_rsa_4096_blind += timer.performanceNow() - start;
-    }
-
-    const blindedMessage4096 = native.rsaBlind(
-      h,
-      blindingSecret4096,
-      rsaPub4096,
-    );
-    if (!blindedMessage4096) {
-      throw Error("should not happen");
-    }
-    const rsaBlindSig4096 = native.rsaSignBlinded(
-      rsaPriv4096,
-      blindedMessage4096,
-    );
-
-    let time_rsa_4096_unblind = 0;
-    for (let i = 0; i < repetitions; i++) {
-      const start = timer.performanceNow();
-      native.rsaUnblind(rsaBlindSig4096, blindingSecret4096, rsaPub4096);
-      time_rsa_4096_unblind += timer.performanceNow() - start;
-    }
-
-    const unblindedSig4096 = native.rsaUnblind(
-      rsaBlindSig4096,
-      blindingSecret4096,
-      rsaPub4096,
-    );
-
-    let time_rsa_4096_verify = 0;
-    for (let i = 0; i < repetitions; i++) {
-      const start = timer.performanceNow();
-      native.rsaVerify(h, unblindedSig4096, rsaPub4096);
-      time_rsa_4096_verify += timer.performanceNow() - start;
-    }
+const worker: Worker = (self as any) as Worker;
 
-    return {
-      repetitions,
-      time: {
-        hash_small: time_hash,
-        hash_big: time_hash_big,
-        eddsa_create: time_eddsa_create,
-        eddsa_sign: time_eddsa_sign,
-        eddsa_verify: time_eddsa_verify,
-        ecdsa_create: time_ecdsa_create,
-        rsa_2048_blind: time_rsa_2048_blind,
-        rsa_2048_unblind: time_rsa_2048_unblind,
-        rsa_2048_verify: time_rsa_2048_verify,
-        rsa_4096_blind: time_rsa_4096_blind,
-        rsa_4096_unblind: time_rsa_4096_unblind,
-        rsa_4096_verify: time_rsa_4096_verify,
-      },
-    };
-  }
-}
+let impl: CryptoImplementation | undefined;
 
-const worker: Worker = (self as any) as Worker;
 
 worker.onmessage = (msg: MessageEvent) => {
-  if (!Array.isArray(msg.data.args)) {
+  const args = msg.data.args;
+  if (!Array.isArray(args)) {
     console.error("args must be array");
     return;
   }
-  if (typeof msg.data.id !== "number") {
+  const id = msg.data.id;
+  if (typeof id !== "number") {
     console.error("RPC id must be number");
+    return;
   }
-  if (typeof msg.data.operation !== "string") {
+  const operation = msg.data.operation;
+  if (typeof operation !== "string") {
     console.error("RPC operation must be string");
-  }
-  const f = (RpcFunctions as any)[msg.data.operation];
-  if (!f) {
-    console.error(`unknown operation: '${msg.data.operation}'`);
     return;
   }
 
-  if (RpcFunctions.enableTracing) {
-    console.log("onmessage with", msg.data.operation);
+  if (CryptoImplementation.enableTracing) {
+    console.log("onmessage with", operation);
   }
 
   emscLoader.getLib().then(p => {
     const lib = p.lib;
-    if (!native.isInitialized()) {
-      if (RpcFunctions.enableTracing) {
-        console.log("initializing emscripten for then first time with lib");
-      }
-      native.initialize(lib);
+    const emsc = new EmscEnvironment(lib);
+    const impl = new CryptoImplementation(emsc);
+
+    if (!(operation in impl)) {
+      console.error(`unknown operation: '${operation}'`);
+      return;
     }
-    if (RpcFunctions.enableTracing) {
-      console.log("about to execute", msg.data.operation);
+
+    if (CryptoImplementation.enableTracing) {
+      console.log("about to execute", operation);
     }
-    const res = f(...msg.data.args);
-    if (RpcFunctions.enableTracing) {
-      console.log("finished executing", msg.data.operation);
+
+    const result = (impl as any)[operation](...args);
+
+    if (CryptoImplementation.enableTracing) {
+      console.log("finished executing", operation);
     }
-    worker.postMessage({ result: res, id: msg.data.id });
+    worker.postMessage({ result, id });
   });
 };
diff --git a/src/crypto/emscInterface-test.ts b/src/crypto/emscInterface-test.ts
index 305e50ff..51f2d58b 100644
--- a/src/crypto/emscInterface-test.ts
+++ b/src/crypto/emscInterface-test.ts
@@ -20,13 +20,12 @@ import test from "ava";
 import * as emscLoader from "./emscLoader";
 import * as native from "./emscInterface";
 
-test.before(async () => {
+
+test("string hashing", async (t) => {
   const { lib } = await emscLoader.getLib();
-  native.initialize(lib);
-});
+  const emsc = new native.EmscEnvironment(lib);
 
-test("string hashing", (t) => {
-  const x = native.ByteArray.fromStringWithNull("hello taler");
+  const x = native.ByteArray.fromStringWithNull(emsc, "hello taler");
   const h = 
"8RDMADB3YNF3QZBS3V467YZVJAMC2QAQX0TZGVZ6Q5PFRRAJFT70HHN0QF661QR9QWKYMMC7YEMPD679D2RADXCYK8Y669A2A5MKQFR";
   const hc = x.hash().toCrock();
   console.log(`# hc ${hc}`);
@@ -35,28 +34,34 @@ test("string hashing", (t) => {
 });
 
 
-test("signing", (t) => {
-  const x = native.ByteArray.fromStringWithNull("hello taler");
-  const priv = native.EddsaPrivateKey.create();
+test("signing", async (t) => {
+  const { lib } = await emscLoader.getLib();
+  const emsc = new native.EmscEnvironment(lib);
+
+  const x = native.ByteArray.fromStringWithNull(emsc, "hello taler");
+  const priv = native.EddsaPrivateKey.create(emsc, );
   const pub = priv.getPublicKey();
-  const purpose = new native.EccSignaturePurpose(native.SignaturePurpose.TEST, 
x);
+  const purpose = new native.EccSignaturePurpose(emsc, 
native.SignaturePurpose.TEST, x);
   const sig = native.eddsaSign(purpose, priv);
   t.true(native.eddsaVerify(native.SignaturePurpose.TEST, purpose, sig, pub));
   t.pass();
 });
 
 
-test("signing-fixed-data", (t) => {
-  const x = native.ByteArray.fromStringWithNull("hello taler");
-  const purpose = new native.EccSignaturePurpose(native.SignaturePurpose.TEST, 
x);
+test("signing-fixed-data", async (t) => {
+  const { lib } = await emscLoader.getLib();
+  const emsc = new native.EmscEnvironment(lib);
+
+  const x = native.ByteArray.fromStringWithNull(emsc, "hello taler");
+  const purpose = new native.EccSignaturePurpose(emsc, 
native.SignaturePurpose.TEST, x);
   const privStr = "G9R8KRRCAFKPD0KW7PW48CC2T03VQ8K2AN9J6J6K2YW27J5MHN90";
   const pubStr = "YHCZB442FQFJ0ET20MWA8YJ53M61EZGJ6QKV1KTJZMRNXDY45WT0";
   const sigStr = 
"7V6XY4QGC1406GPMT305MZQ1HDCR7R0S5BP02GTGDQFPSXB6YD2YDN5ZS7NJQCNP61Y39MRHXNXQ1Z15JY4CJY4CPDA6CKQ3313WG38";
-  const priv = native.EddsaPrivateKey.fromCrock(privStr);
+  const priv = native.EddsaPrivateKey.fromCrock(emsc, privStr);
   t.true(privStr === priv.toCrock());
   const pub = priv.getPublicKey();
   t.true(pubStr === pub.toCrock());
-  const sig = native.EddsaSignature.fromCrock(sigStr);
+  const sig = native.EddsaSignature.fromCrock(emsc, sigStr);
   t.true(sigStr === sig.toCrock());
   const sig2 = native.eddsaSign(purpose, priv);
   t.true(sig.toCrock() === sig2.toCrock());
@@ -68,27 +73,33 @@ test("signing-fixed-data", (t) => {
 const denomPubStr1 = 
"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30G9R64VK6HHS6MW42DSN8MVKJGHK6WR3CGT18MWMCDSM75138E1K8S0MADSQ68W34DHH6MW4CHA270W4CG9J6GW48DHG8MVK4E9S7523GEA56H0K4E1Q891KCCSG752KGC1M88VMCDSQ6D23CHHG8H33AGHG6MSK8GT26CRKAC1M64V3JCJ56CVKCC228MWMCHA26MS30H1J8MVKEDHJ70TMADHK892KJC1H60TKJDHM710KGGT584T38H9K851KCDHG60W30HJ28CT4CC1G8CR3JGJ28H236DJ28H330H9S890M2D9S8S14AGA369344GA36S248CHS70RKEDSS6MWKGDJ26D136GT465348CSS8S232CHM6GS34C9N8CS3GD9H60W36H1R8MSK2GSQ8MSM6C9R70SKCHHN6MW3AC
 [...]
 
 
-test("rsa-encode", (t) => {
+test("rsa-encode", async (t) => {
+  const { lib } = await emscLoader.getLib();
+  const emsc = new native.EmscEnvironment(lib);
+
   const pubHashStr = 
"JM63YM5X7X547164QJ3MGJZ4WDD47GEQR5DW5SH35G4JFZXEJBHE5JBNZM5K8XN5C4BRW25BE6GSVAYBF790G2BZZ13VW91D41S4DS0";
-  const denomPub = native.RsaPublicKey.fromCrock(denomPubStr1);
+  const denomPub = native.RsaPublicKey.fromCrock(emsc, denomPubStr1);
   const pubHash = denomPub.encode().hash();
   t.true(pubHashStr === pubHash.toCrock());
   t.pass();
 });
 
 
-test("withdraw-request", (t) => {
+test("withdraw-request", async (t) => {
+  const { lib } = await emscLoader.getLib();
+  const emsc = new native.EmscEnvironment(lib);
+
   const reservePrivStr = 
"G9R8KRRCAFKPD0KW7PW48CC2T03VQ8K2AN9J6J6K2YW27J5MHN90";
-  const reservePriv = native.EddsaPrivateKey.fromCrock(reservePrivStr);
+  const reservePriv = native.EddsaPrivateKey.fromCrock(emsc, reservePrivStr);
   const reservePub = reservePriv.getPublicKey();
-  const amountWithFee = new native.Amount({currency: "KUDOS", value: 1, 
fraction: 10000});
-  amountWithFee.add(new native.Amount({currency: "KUDOS", value: 0, fraction: 
20000}));
-  const withdrawFee = new native.Amount({currency: "KUDOS", value: 0, 
fraction: 20000});
-  const denomPub = native.RsaPublicKey.fromCrock(denomPubStr1);
-  const ev = native.ByteArray.fromStringWithNull("hello, world");
+  const amountWithFee = new native.Amount(emsc, {currency: "KUDOS", value: 1, 
fraction: 10000});
+  amountWithFee.add(new native.Amount(emsc, {currency: "KUDOS", value: 0, 
fraction: 20000}));
+  const withdrawFee = new native.Amount(emsc, {currency: "KUDOS", value: 0, 
fraction: 20000});
+  const denomPub = native.RsaPublicKey.fromCrock(emsc, denomPubStr1);
+  const ev = native.ByteArray.fromStringWithNull(emsc, "hello, world");
 
   // Signature
-  const withdrawRequest = new native.WithdrawRequestPS({
+  const withdrawRequest = new native.WithdrawRequestPS(emsc, {
     amount_with_fee: amountWithFee.toNbo(),
     h_coin_envelope: ev.hash(),
     h_denomination_pub: denomPub.encode().hash(),
@@ -105,9 +116,13 @@ test("withdraw-request", (t) => {
 });
 
 
-test("currency-conversion", (t) => {
-  const a1 = new native.Amount({currency: "KUDOS", value: 1, fraction: 
50000000});
-  const a2 = new native.Amount({currency: "KUDOS", value: 1, fraction: 
50000000});
+test("currency-conversion", async (t) => {
+
+  const { lib } = await emscLoader.getLib();
+  const emsc = new native.EmscEnvironment(lib);
+
+  const a1 = new native.Amount(emsc, {currency: "KUDOS", value: 1, fraction: 
50000000});
+  const a2 = new native.Amount(emsc, {currency: "KUDOS", value: 1, fraction: 
50000000});
   a1.add(a2);
   const x = a1.toJson();
   t.true(x.currency === "KUDOS");
@@ -117,8 +132,11 @@ test("currency-conversion", (t) => {
 });
 
 
-test("ecdsa", (t) => {
-  const priv = native.EcdsaPrivateKey.create();
+test("ecdsa", async (t) => {
+  const { lib } = await emscLoader.getLib();
+  const emsc = new native.EmscEnvironment(lib);
+
+  const priv = native.EcdsaPrivateKey.create(emsc);
   const pub1 = priv.getPublicKey();
   t.truthy(priv);
   t.truthy(pub1);
@@ -126,8 +144,11 @@ test("ecdsa", (t) => {
 });
 
 
-test("ecdhe", (t) => {
-  const priv = native.EcdhePrivateKey.create();
+test("ecdhe", async (t) => {
+  const { lib } = await emscLoader.getLib();
+  const emsc = new native.EmscEnvironment(lib);
+
+  const priv = native.EcdhePrivateKey.create(emsc);
   const pub = priv.getPublicKey();
   t.truthy(priv);
   t.truthy(pub);
diff --git a/src/crypto/emscInterface.ts b/src/crypto/emscInterface.ts
index 70a85cda..96e94e3f 100644
--- a/src/crypto/emscInterface.ts
+++ b/src/crypto/emscInterface.ts
@@ -30,37 +30,6 @@ import { AmountJson } from "../amounts";
 
 import { EmscFunGen, EmscLib } from "./emscLoader";
 
-
-// Will be set only after initialization.
-let maybeEmscEnv: EmscEnvironment | undefined = undefined;
-
-export function isInitialized() {
-  return !!maybeEmscEnv;
-}
-
-
-export function initialize(lib: EmscLib) {
-  if (!lib) {
-    throw Error("library must be object");
-  }
-  if (!lib.ccall) {
-    throw Error("sanity check failed: EmscLib does not have 'ccall'");
-  }
-  if (maybeEmscEnv) {
-    throw Error("emsc lib already initialized");
-  }
-  maybeEmscEnv = new EmscEnvironment(lib);
-}
-
-
-function emsc() {
-  if (maybeEmscEnv) {
-    return maybeEmscEnv;
-  }
-  throw Error("cannot use taler emscripten before initialization");
-}
-
-
 /**
  * Size of a native pointer.  Must match the size
  * use when compiling via emscripten.
@@ -132,7 +101,7 @@ interface EmscAllocFunctions {
   rsa_unblind(a1: number, a2: number, a3: number): number;
 }
 
-class EmscEnvironment {
+export class EmscEnvironment {
 
   /**
    * Emscripten functions that don't do any memory allocations.
@@ -254,8 +223,8 @@ interface ArenaObject {
 export class HashContext implements ArenaObject {
   private hashContextPtr: number | undefined;
 
-  constructor() {
-    this.hashContextPtr = emsc().allocFuncs.hash_context_start();
+  constructor(private emsc: EmscEnvironment) {
+    this.hashContextPtr = emsc.allocFuncs.hash_context_start();
   }
 
   /**
@@ -265,7 +234,7 @@ export class HashContext implements ArenaObject {
     if (!this.hashContextPtr) {
       throw Error("assertion failed");
     }
-    emsc().funcs.hash_context_read(this.hashContextPtr, obj.nativePtr, 
obj.size());
+    this.emsc.funcs.hash_context_read(this.hashContextPtr, obj.nativePtr, 
obj.size());
   }
 
   /**
@@ -276,7 +245,7 @@ export class HashContext implements ArenaObject {
       throw Error("assertion failed");
     }
     h.alloc();
-    emsc().funcs.hash_context_finish(this.hashContextPtr, h.nativePtr);
+    this.emsc.funcs.hash_context_finish(this.hashContextPtr, h.nativePtr);
   }
 
   /**
@@ -284,7 +253,7 @@ export class HashContext implements ArenaObject {
    */
   destroy(): void {
     if (this.hashContextPtr) {
-      emsc().funcs.hash_context_abort(this.hashContextPtr);
+      this.emsc.funcs.hash_context_abort(this.hashContextPtr);
     }
     this.hashContextPtr = undefined;
   }
@@ -304,12 +273,12 @@ abstract class MallocArenaObject implements ArenaObject {
 
   destroy(): void {
     if (this._nativePtr && !this.isWeak) {
-      emsc().funcs.free(this.nativePtr);
+      this.emsc.funcs.free(this.nativePtr);
       this._nativePtr = undefined;
     }
   }
 
-  constructor(arena?: Arena) {
+  constructor(public emsc: EmscEnvironment, arena?: Arena) {
     if (!arena) {
       if (arenaStack.length === 0) {
         throw Error("No arena available");
@@ -323,7 +292,7 @@ abstract class MallocArenaObject implements ArenaObject {
     if (this._nativePtr !== undefined) {
       throw Error("Double allocation");
     }
-    this.nativePtr = emsc().allocFuncs.malloc(size);
+    this.nativePtr = this.emsc.allocFuncs.malloc(size);
   }
 
   set nativePtr(v: number) {
@@ -414,21 +383,21 @@ arenaStack.push(new SyncArena());
  * Representation of monetary value in a given currency.
  */
 export class Amount extends MallocArenaObject {
-  constructor(args?: AmountJson, arena?: Arena) {
-    super(arena);
+  constructor(emsc: EmscEnvironment, args?: AmountJson, arena?: Arena) {
+    super(emsc, arena);
     if (args) {
-      this.nativePtr = emsc().allocFuncs.get_amount(args.value,
+      this.nativePtr = emsc.allocFuncs.get_amount(args.value,
                                             0,
                                             args.fraction,
                                             args.currency);
     } else {
-      this.nativePtr = emsc().allocFuncs.get_amount(0, 0, 0, "");
+      this.nativePtr = emsc.allocFuncs.get_amount(0, 0, 0, "");
     }
   }
 
-  static getZero(currency: string, a?: Arena): Amount {
-    const am = new Amount(undefined, a);
-    const r = emsc().funcs.amount_get_zero(currency, am.nativePtr);
+  static getZero(emsc: EmscEnvironment, currency: string, a?: Arena): Amount {
+    const am = new Amount(emsc, undefined, a);
+    const r = emsc.funcs.amount_get_zero(currency, am.nativePtr);
     if (r !== GNUNET_OK) {
       throw Error("invalid currency");
     }
@@ -437,33 +406,33 @@ export class Amount extends MallocArenaObject {
 
 
   toNbo(a?: Arena): AmountNbo {
-    const x = new AmountNbo(a);
+    const x = new AmountNbo(this.emsc, a);
     x.alloc();
-    emsc().funcs.amount_hton(x.nativePtr, this.nativePtr);
+    this.emsc.funcs.amount_hton(x.nativePtr, this.nativePtr);
     return x;
   }
 
   fromNbo(nbo: AmountNbo): void {
-    emsc().funcs.amount_ntoh(this.nativePtr, nbo.nativePtr);
+    this.emsc.funcs.amount_ntoh(this.nativePtr, nbo.nativePtr);
   }
 
   get value() {
-    return emsc().funcs.get_value(this.nativePtr);
+    return this.emsc.funcs.get_value(this.nativePtr);
   }
 
   get fraction() {
-    return emsc().funcs.get_fraction(this.nativePtr);
+    return this.emsc.funcs.get_fraction(this.nativePtr);
   }
 
   get currency(): string {
-    return emsc().funcs.get_currency(this.nativePtr);
+    return this.emsc.funcs.get_currency(this.nativePtr);
   }
 
   toJson(): AmountJson {
     return {
-      currency: emsc().funcs.get_currency(this.nativePtr),
-      fraction: emsc().funcs.get_fraction(this.nativePtr),
-      value: emsc().funcs.get_value(this.nativePtr),
+      currency: this.emsc.funcs.get_currency(this.nativePtr),
+      fraction: this.emsc.funcs.get_fraction(this.nativePtr),
+      value: this.emsc.funcs.get_value(this.nativePtr),
     };
   }
 
@@ -471,7 +440,7 @@ export class Amount extends MallocArenaObject {
    * Add an amount to this amount.
    */
   add(a: Amount) {
-    const res = emsc().funcs.amount_add(this.nativePtr, a.nativePtr, 
this.nativePtr);
+    const res = this.emsc.funcs.amount_add(this.nativePtr, a.nativePtr, 
this.nativePtr);
     if (res < 1) {
       // Overflow
       return false;
@@ -484,7 +453,7 @@ export class Amount extends MallocArenaObject {
    */
   sub(a: Amount) {
     // this = this - a
-    const res = emsc().funcs.amount_subtract(this.nativePtr, this.nativePtr, 
a.nativePtr);
+    const res = this.emsc.funcs.amount_subtract(this.nativePtr, 
this.nativePtr, a.nativePtr);
     if (res === 0) {
       // Underflow
       return false;
@@ -500,11 +469,11 @@ export class Amount extends MallocArenaObject {
     if (this.currency !== a.currency) {
       throw Error(`incomparable currencies (${this.currency} and 
${a.currency})`);
     }
-    return emsc().funcs.amount_cmp(this.nativePtr, a.nativePtr);
+    return this.emsc.funcs.amount_cmp(this.nativePtr, a.nativePtr);
   }
 
   normalize() {
-    emsc().funcs.amount_normalize(this.nativePtr);
+    this.emsc.funcs.amount_normalize(this.nativePtr);
   }
 }
 
@@ -541,18 +510,18 @@ function countUtf8Bytes(str: string): number {
 abstract class PackedArenaObject extends MallocArenaObject {
   abstract size(): number;
 
-  constructor(a?: Arena) {
-    super(a);
+  constructor(emsc: EmscEnvironment, a?: Arena) {
+    super(emsc, a);
   }
 
   randomize(qual: RandomQuality = RandomQuality.STRONG): void {
-    emsc().funcs.random_block(qual, this.nativePtr, this.size());
+    this.emsc.funcs.random_block(qual, this.nativePtr, this.size());
   }
 
   toCrock(): string {
-    const d = emsc().allocFuncs.data_to_string_alloc(this.nativePtr, 
this.size());
-    const s = emsc().lib.Pointer_stringify(d);
-    emsc().funcs.free(d);
+    const d = this.emsc.allocFuncs.data_to_string_alloc(this.nativePtr, 
this.size());
+    const s = this.emsc.lib.Pointer_stringify(d);
+    this.emsc.funcs.free(d);
     return s;
   }
 
@@ -567,8 +536,8 @@ abstract class PackedArenaObject extends MallocArenaObject {
     this.alloc();
     // We need to get the javascript string
     // to the emscripten heap first.
-    const buf = ByteArray.fromStringWithNull(s);
-    const res = emsc().funcs.string_to_data(buf.nativePtr,
+    const buf = ByteArray.fromStringWithNull(this.emsc, s);
+    const res = this.emsc.funcs.string_to_data(buf.nativePtr,
                                   s.length,
                                   this.nativePtr,
                                   this.size());
@@ -581,21 +550,21 @@ abstract class PackedArenaObject extends 
MallocArenaObject {
   alloc() {
     // FIXME: should the client be allowed to call alloc multiple times?
     if (!this._nativePtr) {
-      this.nativePtr = emsc().allocFuncs.malloc(this.size());
+      this.nativePtr = this.emsc.allocFuncs.malloc(this.size());
     }
   }
 
   hash(): HashCode {
-    const x = new HashCode();
+    const x = new HashCode(this.emsc);
     x.alloc();
-    emsc().funcs.hash(this.nativePtr, this.size(), x.nativePtr);
+    this.emsc.funcs.hash(this.nativePtr, this.size(), x.nativePtr);
     return x;
   }
 
   hexdump() {
     const bytes: string[] = [];
     for (let i = 0; i < this.size(); i++) {
-      let b = emsc().lib.getValue(this.nativePtr + i, "i8");
+      let b = this.emsc.lib.getValue(this.nativePtr + i, "i8");
       b = (b + 256) % 256;
       bytes.push("0".concat(b.toString(16)).slice(-2));
     }
@@ -618,7 +587,7 @@ export class AmountNbo extends PackedArenaObject {
 
   toJson(): any {
     const a = new SimpleArena();
-    const am = new Amount(undefined, a);
+    const am = new Amount(this.emsc, undefined, a);
     am.fromNbo(this);
     const json = am.toJson();
     a.destroy();
@@ -630,8 +599,8 @@ export class AmountNbo extends PackedArenaObject {
 /**
  * Create a packed arena object from the base32 crockford encoding.
  */
-function fromCrock<T extends PackedArenaObject>(s: string, ctor: Ctor<T>): T {
-  const x: T = new ctor();
+function fromCrock<T extends PackedArenaObject>(emsc: EmscEnvironment, s: 
string, ctor: Ctor<T>): T {
+  const x: T = new ctor(emsc);
   x.alloc();
   x.loadCrock(s);
   return x;
@@ -642,11 +611,11 @@ function fromCrock<T extends PackedArenaObject>(s: 
string, ctor: Ctor<T>): T {
  * Create a packed arena object from the base32 crockford encoding for objects
  * that have a special decoding function.
  */
-function fromCrockDecoded<T extends MallocArenaObject>(s: string,
+function fromCrockDecoded<T extends MallocArenaObject>(emsc: EmscEnvironment, 
s: string,
                                                        ctor: Ctor<T>,
                                                        decodeFn: (p: number, 
s: number) => number): T {
-  const obj = new ctor();
-  const buf = ByteArray.fromCrock(s);
+  const obj = new ctor(emsc);
+  const buf = ByteArray.fromCrock(emsc, s);
   obj.nativePtr = decodeFn(buf.nativePtr, buf.size());
   buf.destroy();
   return obj;
@@ -657,11 +626,11 @@ function fromCrockDecoded<T extends MallocArenaObject>(s: 
string,
  * Encode an object using a special encoding function.
  */
 function encode<T extends MallocArenaObject>(obj: T, encodeFn: any, arena?: 
Arena): ByteArray {
-  const ptr = emsc().allocFuncs.malloc(PTR_SIZE);
+  const ptr = obj.emsc.allocFuncs.malloc(PTR_SIZE);
   const len = encodeFn(obj.nativePtr, ptr);
-  const res = new ByteArray(len, undefined, arena);
-  res.nativePtr = emsc().lib.getValue(ptr, "*");
-  emsc().funcs.free(ptr);
+  const res = new ByteArray(obj.emsc, len, undefined, arena);
+  res.nativePtr = obj.emsc.lib.getValue(ptr, "*");
+  obj.emsc.funcs.free(ptr);
   return res;
 }
 
@@ -670,9 +639,9 @@ function encode<T extends MallocArenaObject>(obj: T, 
encodeFn: any, arena?: Aren
  * Private EdDSA key.
  */
 export class EddsaPrivateKey extends PackedArenaObject {
-  static create(a?: Arena): EddsaPrivateKey {
-    const obj = new EddsaPrivateKey(a);
-    obj.nativePtr = emsc().allocFuncs.eddsa_key_create();
+  static create(emsc: EmscEnvironment, a?: Arena): EddsaPrivateKey {
+    const obj = new EddsaPrivateKey(emsc, a);
+    obj.nativePtr = emsc.allocFuncs.eddsa_key_create();
     return obj;
   }
 
@@ -681,13 +650,13 @@ export class EddsaPrivateKey extends PackedArenaObject {
   }
 
   getPublicKey(a?: Arena): EddsaPublicKey {
-    const obj = new EddsaPublicKey(a);
-    obj.nativePtr = 
emsc().allocFuncs.eddsa_public_key_from_private(this.nativePtr);
+    const obj = new EddsaPublicKey(this.emsc, a);
+    obj.nativePtr = 
this.emsc.allocFuncs.eddsa_public_key_from_private(this.nativePtr);
     return obj;
   }
 
-  static fromCrock(s: string): EddsaPrivateKey {
-    return fromCrock(s, this);
+  static fromCrock(emsc: EmscEnvironment, s: string): EddsaPrivateKey {
+    return fromCrock(emsc, s, this);
   }
 }
 
@@ -696,9 +665,9 @@ export class EddsaPrivateKey extends PackedArenaObject {
  * Low-level handle to an EdDSA private key.
  */
 export class EcdsaPrivateKey extends PackedArenaObject {
-  static create(a?: Arena): EcdsaPrivateKey {
-    const obj = new EcdsaPrivateKey(a);
-    obj.nativePtr = emsc().allocFuncs.ecdsa_key_create();
+  static create(emsc: EmscEnvironment, a?: Arena): EcdsaPrivateKey {
+    const obj = new EcdsaPrivateKey(emsc, a);
+    obj.nativePtr = emsc.allocFuncs.ecdsa_key_create();
     return obj;
   }
 
@@ -707,13 +676,13 @@ export class EcdsaPrivateKey extends PackedArenaObject {
   }
 
   getPublicKey(a?: Arena): EcdsaPublicKey {
-    const obj = new EcdsaPublicKey(a);
-    obj.nativePtr = 
emsc().allocFuncs.ecdsa_public_key_from_private(this.nativePtr);
+    const obj = new EcdsaPublicKey(this.emsc, a);
+    obj.nativePtr = 
this.emsc.allocFuncs.ecdsa_public_key_from_private(this.nativePtr);
     return obj;
   }
 
-  static fromCrock(s: string): EcdsaPrivateKey {
-    return fromCrock(s, this);
+  static fromCrock(emsc: EmscEnvironment, s: string): EcdsaPrivateKey {
+    return fromCrock(emsc, s, this);
   }
 }
 
@@ -722,9 +691,9 @@ export class EcdsaPrivateKey extends PackedArenaObject {
  * Low-level handle to an ECDHE private key.
  */
 export class EcdhePrivateKey extends PackedArenaObject {
-  static create(a?: Arena): EcdhePrivateKey {
-    const obj = new EcdhePrivateKey(a);
-    obj.nativePtr = emsc().allocFuncs.ecdhe_key_create();
+  static create(emsc: EmscEnvironment, a?: Arena): EcdhePrivateKey {
+    const obj = new EcdhePrivateKey(emsc, a);
+    obj.nativePtr = emsc.allocFuncs.ecdhe_key_create();
     return obj;
   }
 
@@ -733,13 +702,13 @@ export class EcdhePrivateKey extends PackedArenaObject {
   }
 
   getPublicKey(a?: Arena): EcdhePublicKey {
-    const obj = new EcdhePublicKey(a);
-    obj.nativePtr = 
emsc().allocFuncs.ecdhe_public_key_from_private(this.nativePtr);
+    const obj = new EcdhePublicKey(this.emsc, a);
+    obj.nativePtr = 
this.emsc.allocFuncs.ecdhe_public_key_from_private(this.nativePtr);
     return obj;
   }
 
-  static fromCrock(s: string): EcdhePrivateKey {
-    return fromCrock(s, this);
+  static fromCrock(emsc: EmscEnvironment, s: string): EcdhePrivateKey {
+    return fromCrock(emsc, s, this);
   }
 }
 
@@ -748,7 +717,7 @@ export class EcdhePrivateKey extends PackedArenaObject {
  * Constructor for a given type.
  */
 interface Ctor<T> {
-  new(): T;
+  new(emsc: EmscEnvironment): T;
 }
 
 
@@ -760,8 +729,8 @@ export class EddsaPublicKey extends PackedArenaObject {
     return 32;
   }
 
-  static fromCrock(s: string): EddsaPublicKey {
-    return fromCrock(s, this);
+  static fromCrock(emsc: EmscEnvironment, s: string): EddsaPublicKey {
+    return fromCrock(emsc, s, this);
   }
 }
 
@@ -773,8 +742,8 @@ export class EcdsaPublicKey extends PackedArenaObject {
     return 32;
   }
 
-  static fromCrock(s: string): EcdsaPublicKey {
-    return fromCrock(s, this);
+  static fromCrock(emsc: EmscEnvironment, s: string): EcdsaPublicKey {
+    return fromCrock(emsc, s, this);
   }
 }
 
@@ -787,8 +756,8 @@ export class EcdhePublicKey extends PackedArenaObject {
     return 32;
   }
 
-  static fromCrock(s: string): EcdhePublicKey {
-    return fromCrock(s, this);
+  static fromCrock(emsc: EmscEnvironment, s: string): EcdhePublicKey {
+    return fromCrock(emsc, s, this);
   }
 }
 
@@ -804,15 +773,15 @@ export class RsaBlindingKeySecret extends 
PackedArenaObject {
   /**
    * Create a random blinding key secret.
    */
-  static create(a?: Arena): RsaBlindingKeySecret {
-    const o = new RsaBlindingKeySecret(a);
+  static create(emsc: EmscEnvironment, a?: Arena): RsaBlindingKeySecret {
+    const o = new RsaBlindingKeySecret(emsc, a);
     o.alloc();
     o.randomize();
     return o;
   }
 
-  static fromCrock(s: string): RsaBlindingKeySecret {
-    return fromCrock(s, this);
+  static fromCrock(emsc: EmscEnvironment, s: string): RsaBlindingKeySecret {
+    return fromCrock(emsc, s, this);
   }
 }
 
@@ -825,13 +794,13 @@ export class HashCode extends PackedArenaObject {
     return 64;
   }
 
-  static fromCrock(s: string): HashCode {
-    return fromCrock(s, this);
+  static fromCrock(emsc: EmscEnvironment, s: string): HashCode {
+    return fromCrock(emsc, s, this);
   }
 
   random(qual: RandomQuality = RandomQuality.STRONG) {
     this.alloc();
-    emsc().funcs.hash_create_random(qual, this.nativePtr);
+    this.emsc.funcs.hash_create_random(qual, this.nativePtr);
   }
 }
 
@@ -846,42 +815,42 @@ export class ByteArray extends PackedArenaObject {
     return this.allocatedSize;
   }
 
-  constructor(desiredSize: number, init?: number, a?: Arena) {
-    super(a);
+  constructor(public emsc: EmscEnvironment, desiredSize: number, init?: 
number, a?: Arena) {
+    super(emsc, a);
     if (init === undefined) {
-      this.nativePtr = emsc().allocFuncs.malloc(desiredSize);
+      this.nativePtr = this.emsc.allocFuncs.malloc(desiredSize);
     } else {
       this.nativePtr = init;
     }
     this.allocatedSize = desiredSize;
   }
 
-  static fromStringWithoutNull(s: string, a?: Arena): ByteArray {
+  static fromStringWithoutNull(emsc: EmscEnvironment, s: string, a?: Arena): 
ByteArray {
     // UTF-8 bytes, including 0-terminator
     const terminatedByteLength = countUtf8Bytes(s) + 1;
-    const hstr = emsc().allocFuncs.malloc(terminatedByteLength);
-    emsc().lib.stringToUTF8(s, hstr, terminatedByteLength);
-    return new ByteArray(terminatedByteLength - 1, hstr, a);
+    const hstr = emsc.allocFuncs.malloc(terminatedByteLength);
+    emsc.lib.stringToUTF8(s, hstr, terminatedByteLength);
+    return new ByteArray(emsc, terminatedByteLength - 1, hstr, a);
   }
 
-  static fromStringWithNull(s: string, a?: Arena): ByteArray {
+  static fromStringWithNull(emsc: EmscEnvironment, s: string, a?: Arena): 
ByteArray {
     // UTF-8 bytes, including 0-terminator
     const terminatedByteLength = countUtf8Bytes(s) + 1;
-    const hstr = emsc().allocFuncs.malloc(terminatedByteLength);
-    emsc().lib.stringToUTF8(s, hstr, terminatedByteLength);
-    return new ByteArray(terminatedByteLength, hstr, a);
+    const hstr = emsc.allocFuncs.malloc(terminatedByteLength);
+    emsc.lib.stringToUTF8(s, hstr, terminatedByteLength);
+    return new ByteArray(emsc, terminatedByteLength, hstr, a);
   }
 
-  static fromCrock(s: string, a?: Arena): ByteArray {
+  static fromCrock(emsc: EmscEnvironment, s: string, a?: Arena): ByteArray {
     // this one is a bit more complicated than the other fromCrock functions,
     // since we don't have a fixed size
     const byteLength = countUtf8Bytes(s);
-    const hstr = emsc().allocFuncs.malloc(byteLength + 1);
-    emsc().lib.stringToUTF8(s, hstr, byteLength + 1);
+    const hstr = emsc.allocFuncs.malloc(byteLength + 1);
+    emsc.lib.stringToUTF8(s, hstr, byteLength + 1);
     const decodedLen = Math.floor((byteLength * 5) / 8);
-    const ba = new ByteArray(decodedLen, undefined, a);
-    const res = emsc().funcs.string_to_data(hstr, byteLength, ba.nativePtr, 
decodedLen);
-    emsc().funcs.free(hstr);
+    const ba = new ByteArray(emsc, decodedLen, undefined, a);
+    const res = emsc.funcs.string_to_data(hstr, byteLength, ba.nativePtr, 
decodedLen);
+    emsc.funcs.free(hstr);
     if (res !== GNUNET_OK) {
       throw Error("decoding failed");
     }
@@ -901,11 +870,12 @@ export class EccSignaturePurpose extends 
PackedArenaObject {
 
   private payloadSize: number;
 
-  constructor(purpose: SignaturePurpose,
+  constructor(emsc: EmscEnvironment,
+              purpose: SignaturePurpose,
               payload: PackedArenaObject,
               a?: Arena) {
-    super(a);
-    this.nativePtr = emsc().allocFuncs.purpose_create(purpose,
+    super(emsc, a);
+    this.nativePtr = emsc.allocFuncs.purpose_create(purpose,
                                                       payload.nativePtr,
                                                       payload.size());
     this.payloadSize = payload.size();
@@ -920,7 +890,7 @@ abstract class SignatureStruct {
 
   private members: any = {};
 
-  constructor(x: { [name: string]: any }) {
+  constructor(public emsc: EmscEnvironment, x: { [name: string]: any }) {
     for (const k in x) {
       this.set(k, x[k]);
     }
@@ -937,17 +907,17 @@ abstract class SignatureStruct {
       totalSize += member.size();
     }
 
-    const buf = emsc().allocFuncs.malloc(totalSize);
+    const buf = this.emsc.allocFuncs.malloc(totalSize);
     let ptr = buf;
     for (const f of this.fieldTypes()) {
       const name = f[0];
       const member = this.members[name];
       const size = member.size();
-      emsc().funcs.memmove(ptr, member.nativePtr, size);
+      this.emsc.funcs.memmove(ptr, member.nativePtr, size);
       ptr += size;
     }
-    const ba = new ByteArray(totalSize, buf, a);
-    return new EccSignaturePurpose(this.purpose(), ba);
+    const ba = new ByteArray(this.emsc, totalSize, buf, a);
+    return new EccSignaturePurpose(this.emsc, this.purpose(), ba);
   }
 
 
@@ -1012,8 +982,8 @@ export interface WithdrawRequestPS_Args {
  * Low-level handle to a WithdrawRequest signature structure.
  */
 export class WithdrawRequestPS extends SignatureStruct {
-  constructor(w: WithdrawRequestPS_Args) {
-    super(w);
+  constructor(emsc: EmscEnvironment, w: WithdrawRequestPS_Args) {
+    super(emsc, w);
   }
 
   purpose() {
@@ -1046,8 +1016,8 @@ export interface PaybackRequestPS_args {
  * Low-level handle to a PaybackRequest signature structure.
  */
 export class PaybackRequestPS extends SignatureStruct {
-  constructor(w: PaybackRequestPS_args) {
-    super(w);
+  constructor(emsc: EmscEnvironment, w: PaybackRequestPS_args) {
+    super(emsc, w);
   }
 
   purpose() {
@@ -1078,8 +1048,8 @@ interface RefreshMeltCoinAffirmationPS_Args {
  * Low-level handle to a RefreshMeltCoinAffirmationPS signature structure.
  */
 export class RefreshMeltCoinAffirmationPS extends SignatureStruct {
-  constructor(w: RefreshMeltCoinAffirmationPS_Args) {
-    super(w);
+  constructor(emsc: EmscEnvironment, w: RefreshMeltCoinAffirmationPS_Args) {
+    super(emsc, w);
   }
 
   purpose() {
@@ -1128,8 +1098,8 @@ interface MasterWireFeePS_Args {
  * Low-level handle to a structure being signed over.
  */
 export class MasterWireFeePS extends SignatureStruct {
-  constructor(w: MasterWireFeePS_Args) {
-    super(w);
+  constructor(emsc: EmscEnvironment, w: MasterWireFeePS_Args) {
+    super(emsc, w);
   }
 
   purpose() {
@@ -1152,8 +1122,8 @@ export class MasterWireFeePS extends SignatureStruct {
  * Low-level handle to an absolute time in network byte order (NBO).
  */
 export class AbsoluteTimeNbo extends PackedArenaObject {
-  static fromTalerString(s: string): AbsoluteTimeNbo {
-    const x = new AbsoluteTimeNbo();
+  static fromTalerString(emsc: EmscEnvironment, s: string): AbsoluteTimeNbo {
+    const x = new AbsoluteTimeNbo(emsc);
     x.alloc();
     const r = /Date\(([0-9]+)\)/;
     const m = r.exec(s);
@@ -1162,15 +1132,15 @@ export class AbsoluteTimeNbo extends PackedArenaObject {
     }
     const n = parseInt(m[1], 10) * 1000000;
     // XXX: This only works up to 54 bit numbers.
-    set64(x.nativePtr, n);
+    set64(emsc, x.nativePtr, n);
     return x;
   }
 
-  static fromStampSeconds(stamp: number): AbsoluteTimeNbo {
-    const x = new AbsoluteTimeNbo();
+  static fromStampSeconds(emsc: EmscEnvironment, stamp: number): 
AbsoluteTimeNbo {
+    const x = new AbsoluteTimeNbo(emsc);
     x.alloc();
     // XXX: This only works up to 54 bit numbers.
-    set64(x.nativePtr, stamp * 1000000);
+    set64(emsc, x.nativePtr, stamp * 1000000);
     return x;
   }
 
@@ -1182,17 +1152,17 @@ export class AbsoluteTimeNbo extends PackedArenaObject {
 
 
 // XXX: This only works up to 54 bit numbers.
-function set64(p: number, n: number) {
+function set64(emsc: EmscEnvironment, p: number, n: number) {
   for (let i = 0; i < 8; ++i) {
-    emsc().lib.setValue(p + (7 - i), n & 0xFF, "i8");
+    emsc.lib.setValue(p + (7 - i), n & 0xFF, "i8");
     n = Math.floor(n / 256);
   }
 }
 
 // XXX: This only works up to 54 bit numbers.
-function set32(p: number, n: number) {
+function set32(emsc: EmscEnvironment, p: number, n: number) {
   for (let i = 0; i < 4; ++i) {
-    emsc().lib.setValue(p + (3 - i), n & 0xFF, "i8");
+    emsc.lib.setValue(p + (3 - i), n & 0xFF, "i8");
     n = Math.floor(n / 256);
   }
 }
@@ -1202,10 +1172,10 @@ function set32(p: number, n: number) {
  * Low-level handle to an unsigned 64-bit value.
  */
 export class UInt64 extends PackedArenaObject {
-  static fromNumber(n: number): UInt64 {
-    const x = new UInt64();
+  static fromNumber(emsc: EmscEnvironment, n: number): UInt64 {
+    const x = new UInt64(emsc);
     x.alloc();
-    set64(x.nativePtr, n);
+    set64(emsc, x.nativePtr, n);
     return x;
   }
 
@@ -1219,10 +1189,10 @@ export class UInt64 extends PackedArenaObject {
  * Low-level handle to an unsigned 32-bit value.
  */
 export class UInt32 extends PackedArenaObject {
-  static fromNumber(n: number): UInt32 {
-    const x = new UInt32();
+  static fromNumber(emsc: EmscEnvironment, n: number): UInt32 {
+    const x = new UInt32(emsc);
     x.alloc();
-    set32(x.nativePtr, n);
+    set32(emsc, x.nativePtr, n);
     return x;
   }
 
@@ -1275,8 +1245,8 @@ export interface DepositRequestPS_Args {
  * Low-level handle to a struct being signed over.
  */
 export class DepositRequestPS extends SignatureStruct {
-  constructor(w: DepositRequestPS_Args) {
-    super(w);
+  constructor(emsc: EmscEnvironment, w: DepositRequestPS_Args) {
+    super(emsc, w);
   }
 
   purpose() {
@@ -1307,8 +1277,8 @@ interface CoinLinkSignaturePS_args {
 
 
 export class CoinLinkSignaturePS extends SignatureStruct {
-  constructor(w: CoinLinkSignaturePS_args) {
-    super(w);
+  constructor(emsc: EmscEnvironment, w: CoinLinkSignaturePS_args) {
+    super(emsc, w);
   }
 
   purpose() {
@@ -1348,8 +1318,8 @@ export interface DenominationKeyValidityPS_args {
  * Low-level handle to a structure being signed over.
  */
 export class DenominationKeyValidityPS extends SignatureStruct {
-  constructor(w: DenominationKeyValidityPS_args) {
-    super(w);
+  constructor(emsc: EmscEnvironment, w: DenominationKeyValidityPS_args) {
+    super(emsc, w);
   }
 
   purpose() {
@@ -1388,8 +1358,8 @@ export interface PaymentSignaturePS_args {
  * Low-level handle to a structure being signed over.
  */
 export class PaymentSignaturePS extends SignatureStruct {
-  constructor(w: PaymentSignaturePS_args) {
-    super(w);
+  constructor(emsc: EmscEnvironment, w: PaymentSignaturePS_args) {
+    super(emsc, w);
   }
 
   purpose() {
@@ -1408,13 +1378,13 @@ export class PaymentSignaturePS extends SignatureStruct 
{
  * Low-level handle to an RsaPrivateKey.
  */
 export class RsaPrivateKey extends MallocArenaObject {
-  static fromCrock(s: string): RsaPrivateKey {
-    return fromCrockDecoded(s, this, emsc().allocFuncs.rsa_private_key_decode);
+  static fromCrock(emsc: EmscEnvironment, s: string): RsaPrivateKey {
+    return fromCrockDecoded(emsc, s, this, 
emsc.allocFuncs.rsa_private_key_decode);
   }
 
-  static create(bitLen: number, a?: Arena): RsaPrivateKey {
-    const obj = new RsaPrivateKey(a);
-    obj.nativePtr = emsc().allocFuncs.rsa_private_key_create(bitLen);
+  static create(emsc: EmscEnvironment, bitLen: number, a?: Arena): 
RsaPrivateKey {
+    const obj = new RsaPrivateKey(emsc, a);
+    obj.nativePtr = emsc.allocFuncs.rsa_private_key_create(bitLen);
     return obj;
   }
 
@@ -1424,18 +1394,18 @@ export class RsaPrivateKey extends MallocArenaObject {
 
 
   getPublicKey(a?: Arena): RsaPublicKey {
-    const obj = new RsaPublicKey(a);
-    obj.nativePtr = 
emsc().allocFuncs.rsa_private_key_get_public(this.nativePtr);
+    const obj = new RsaPublicKey(this.emsc, a);
+    obj.nativePtr = 
this.emsc.allocFuncs.rsa_private_key_get_public(this.nativePtr);
     return obj;
   }
 
   destroy() {
-    emsc().funcs.rsa_public_key_free(this.nativePtr);
+    this.emsc.funcs.rsa_public_key_free(this.nativePtr);
     this.nativePtr = 0;
   }
 
   encode(arena?: Arena): ByteArray {
-    return encode(this, emsc().allocFuncs.rsa_private_key_encode);
+    return encode(this, this.emsc.allocFuncs.rsa_private_key_encode);
   }
 }
 
@@ -1444,8 +1414,8 @@ export class RsaPrivateKey extends MallocArenaObject {
  * Low-level handle to an RsaPublicKey.
  */
 export class RsaPublicKey extends MallocArenaObject {
-  static fromCrock(s: string): RsaPublicKey {
-    return fromCrockDecoded(s, this, emsc().allocFuncs.rsa_public_key_decode);
+  static fromCrock(emsc: EmscEnvironment, s: string): RsaPublicKey {
+    return fromCrockDecoded(emsc, s, this, 
emsc.allocFuncs.rsa_public_key_decode);
   }
 
   toCrock() {
@@ -1453,12 +1423,12 @@ export class RsaPublicKey extends MallocArenaObject {
   }
 
   destroy() {
-    emsc().funcs.rsa_public_key_free(this.nativePtr);
+    this.emsc.funcs.rsa_public_key_free(this.nativePtr);
     this.nativePtr = 0;
   }
 
   encode(arena?: Arena): ByteArray {
-    return encode(this, emsc().allocFuncs.rsa_public_key_encode);
+    return encode(this, this.emsc.allocFuncs.rsa_public_key_encode);
   }
 }
 
@@ -1470,8 +1440,8 @@ export class EddsaSignature extends PackedArenaObject {
   size() {
     return 64;
   }
-  static fromCrock(s: string): EddsaSignature {
-    return fromCrock(s, this);
+  static fromCrock(emsc: EmscEnvironment, s: string): EddsaSignature {
+    return fromCrock(emsc, s, this);
   }
 }
 
@@ -1480,16 +1450,16 @@ export class EddsaSignature extends PackedArenaObject {
  * Low-level handle to an RsaSignature.
  */
 export class RsaSignature extends MallocArenaObject {
-  static fromCrock(s: string, a?: Arena) {
-    return fromCrockDecoded(s, this, emsc().allocFuncs.rsa_signature_decode);
+  static fromCrock(emsc: EmscEnvironment, s: string, a?: Arena) {
+    return fromCrockDecoded(emsc, s, this, 
emsc.allocFuncs.rsa_signature_decode);
   }
 
   encode(arena?: Arena): ByteArray {
-    return encode(this, emsc().allocFuncs.rsa_signature_encode);
+    return encode(this, this.emsc.allocFuncs.rsa_signature_encode);
   }
 
   destroy() {
-    emsc().funcs.rsa_signature_free(this.nativePtr);
+    this.emsc.funcs.rsa_signature_free(this.nativePtr);
     this.nativePtr = 0;
   }
 }
@@ -1502,22 +1472,23 @@ export function rsaBlind(hashCode: HashCode,
                          blindingKey: RsaBlindingKeySecret,
                          pkey: RsaPublicKey,
                          arena?: Arena): ByteArray|null {
-  const buf_ptr_out = emsc().allocFuncs.malloc(PTR_SIZE);
-  const buf_size_out = emsc().allocFuncs.malloc(PTR_SIZE);
-  const res = emsc().allocFuncs.rsa_blind(hashCode.nativePtr,
+  const emsc: EmscEnvironment = hashCode.emsc;
+  const buf_ptr_out = emsc.allocFuncs.malloc(PTR_SIZE);
+  const buf_size_out = emsc.allocFuncs.malloc(PTR_SIZE);
+  const res = emsc.allocFuncs.rsa_blind(hashCode.nativePtr,
                                           blindingKey.nativePtr,
                                           pkey.nativePtr,
                                           buf_ptr_out,
                                           buf_size_out);
-  const buf_ptr = emsc().lib.getValue(buf_ptr_out, "*");
-  const buf_size = emsc().lib.getValue(buf_size_out, "*");
-  emsc().funcs.free(buf_ptr_out);
-  emsc().funcs.free(buf_size_out);
+  const buf_ptr = emsc.lib.getValue(buf_ptr_out, "*");
+  const buf_size = emsc.lib.getValue(buf_size_out, "*");
+  emsc.funcs.free(buf_ptr_out);
+  emsc.funcs.free(buf_size_out);
   if (res !== GNUNET_OK) {
     // malicious key
     return null;
   }
-  return new ByteArray(buf_size, buf_ptr, arena);
+  return new ByteArray(emsc, buf_size, buf_ptr, arena);
 }
 
 
@@ -1527,9 +1498,9 @@ export function rsaBlind(hashCode: HashCode,
 export function eddsaSign(purpose: EccSignaturePurpose,
                           priv: EddsaPrivateKey,
                           a?: Arena): EddsaSignature {
-  const sig = new EddsaSignature(a);
+  const sig = new EddsaSignature(purpose.emsc, a);
   sig.alloc();
-  const res = emsc().funcs.eddsa_sign(priv.nativePtr, purpose.nativePtr, 
sig.nativePtr);
+  const res = purpose.emsc.funcs.eddsa_sign(priv.nativePtr, purpose.nativePtr, 
sig.nativePtr);
   if (res < 1) {
     throw Error("EdDSA signing failed");
   }
@@ -1545,7 +1516,7 @@ export function eddsaVerify(purposeNum: number,
                             sig: EddsaSignature,
                             pub: EddsaPublicKey,
                             a?: Arena): boolean {
-  const r = emsc().funcs.eddsa_verify(purposeNum,
+  const r = verify.emsc.funcs.eddsa_verify(purposeNum,
                                       verify.nativePtr,
                                       sig.nativePtr,
                                       pub.nativePtr);
@@ -1556,7 +1527,7 @@ export function eddsaVerify(purposeNum: number,
 export function rsaVerify(h: HashCode,
                           sig: RsaSignature,
                           pub: RsaPublicKey) {
-  const r = emsc().funcs.rsa_verify(h.nativePtr,
+  const r = h.emsc.funcs.rsa_verify(h.nativePtr,
                                     sig.nativePtr,
                                     pub.nativePtr);
   return r === GNUNET_OK;
@@ -1570,8 +1541,8 @@ export function rsaUnblind(sig: RsaSignature,
                            bk: RsaBlindingKeySecret,
                            pk: RsaPublicKey,
                            a?: Arena): RsaSignature {
-  const x = new RsaSignature(a);
-  x.nativePtr = emsc().allocFuncs.rsa_unblind(sig.nativePtr,
+  const x = new RsaSignature(sig.emsc, a);
+  x.nativePtr = sig.emsc.allocFuncs.rsa_unblind(sig.nativePtr,
                                               bk.nativePtr,
                                               pk.nativePtr);
   return x;
@@ -1600,9 +1571,9 @@ export interface FreshCoin {
  */
 export function ecdhEddsa(priv: EcdhePrivateKey,
                           pub: EddsaPublicKey): HashCode {
-  const h = new HashCode();
+  const h = new HashCode(priv.emsc);
   h.alloc();
-  const res = emsc().funcs.ecdh_eddsa(priv.nativePtr, pub.nativePtr, 
h.nativePtr);
+  const res = priv.emsc.funcs.ecdh_eddsa(priv.nativePtr, pub.nativePtr, 
h.nativePtr);
   if (res !== GNUNET_OK) {
     throw Error("ecdh_eddsa failed");
   }
@@ -1611,8 +1582,8 @@ export function ecdhEddsa(priv: EcdhePrivateKey,
 
 export function rsaSignBlinded(priv: RsaPrivateKey,
                                msg: ByteArray): RsaSignature {
-  const sig = new RsaSignature();
-  sig.nativePtr = emsc().allocFuncs.rsa_sign_blinded (priv.nativePtr,
+  const sig = new RsaSignature(priv.emsc);
+  sig.nativePtr = priv.emsc.allocFuncs.rsa_sign_blinded (priv.nativePtr,
                                                       msg.nativePtr,
                                                       msg.size());
   return sig;
@@ -1625,13 +1596,14 @@ export function rsaSignBlinded(priv: RsaPrivateKey,
  */
 export function setupFreshCoin(secretSeed: TransferSecretP,
                                coinIndex: number): FreshCoin {
-  const priv = new EddsaPrivateKey();
+  const emsc: EmscEnvironment = secretSeed.emsc; 
+  const priv = new EddsaPrivateKey(emsc);
   priv.isWeak = true;
-  const blindingKey = new RsaBlindingKeySecret();
+  const blindingKey = new RsaBlindingKeySecret(emsc);
   blindingKey.isWeak = true;
-  const buf = new ByteArray(priv.size() + blindingKey.size());
+  const buf = new ByteArray(emsc, priv.size() + blindingKey.size());
 
-  emsc().funcs.setup_fresh_coin(secretSeed.nativePtr, coinIndex, 
buf.nativePtr);
+  emsc.funcs.setup_fresh_coin(secretSeed.nativePtr, coinIndex, buf.nativePtr);
 
   priv.nativePtr = buf.nativePtr;
   blindingKey.nativePtr = buf.nativePtr + priv.size();
diff --git a/src/crypto/nodeWorker.ts b/src/crypto/nodeProcessWorker.ts
similarity index 100%
rename from src/crypto/nodeWorker.ts
rename to src/crypto/nodeProcessWorker.ts
diff --git a/src/crypto/synchronousWorker.ts b/src/crypto/synchronousWorker.ts
new file mode 100644
index 00000000..d8a3d83c
--- /dev/null
+++ b/src/crypto/synchronousWorker.ts
@@ -0,0 +1,162 @@
+/*
+ This file is part of GNU Taler
+ (C) 2019 GNUnet e.V.
+
+ 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/>
+ */
+
+import { EmscEnvironment } from "./emscInterface";
+import { CryptoImplementation } from "./cryptoImplementation";
+
+/**
+ * Worker implementation that uses node subprocesses.
+ */
+export class SynchronousCryptoWorker {
+  private cachedEmscEnvironment: EmscEnvironment | undefined = undefined;
+  private cachedEmscEnvironmentPromise: Promise<EmscEnvironment> | undefined = 
undefined;
+
+  /**
+   * Function to be called when we receive a message from the worker thread.
+   */
+  onmessage: undefined | ((m: any) => void);
+
+  /**
+   * Function to be called when we receive an error from the worker thread.
+   */
+  onerror: undefined | ((m: any) => void);
+
+  constructor() {
+    this.onerror = undefined;
+    this.onmessage = undefined;
+  }
+
+  /**
+   * Add an event listener for either an "error" or "message" event.
+   */
+  addEventListener(event: "message" | "error", fn: (x: any) => void): void {
+    switch (event) {
+      case "message":
+        this.onmessage = fn;
+        break;
+      case "error":
+        this.onerror = fn;
+        break;
+    }
+  }
+
+  private getEmscriptenEnvironment(): Promise<EmscEnvironment> {
+    if (this.cachedEmscEnvironment) {
+      return Promise.resolve(this.cachedEmscEnvironment);
+    }
+
+    if (this.cachedEmscEnvironmentPromise) {
+      return this.cachedEmscEnvironmentPromise;
+    }
+
+    // Make sure that TypeScript doesn't try
+    // to check the taler-emscripten-lib.
+    const indirectRequire = require;
+
+    const g = global;
+
+    // unavoidable hack, so that emscripten detects
+    // the environment as node even though importScripts
+    // is present.
+
+    // @ts-ignore
+    const savedImportScripts = g.importScripts;
+    // @ts-ignore
+    delete g.importScripts;
+
+    // Assume that the code is run from the build/ directory.
+    const libFn = indirectRequire(
+      "../../../emscripten/taler-emscripten-lib.js",
+    );
+    const lib = libFn();
+    // @ts-ignore
+    g.importScripts = savedImportScripts;
+
+    if (!lib) {
+      throw Error("could not load taler-emscripten-lib.js");
+    }
+
+    if (!lib.ccall) {
+      throw Error(
+        "sanity check failed: taler-emscripten lib does not have 'ccall'",
+      );
+    }
+
+    this.cachedEmscEnvironmentPromise = new Promise((resolve, reject) => {
+      lib.onRuntimeInitialized = () => {
+        this.cachedEmscEnvironmentPromise = undefined;
+        this.cachedEmscEnvironment = new EmscEnvironment(lib);
+        resolve(this.cachedEmscEnvironment);
+      };
+    });
+    return this.cachedEmscEnvironmentPromise;
+  }
+
+  private dispatchMessage(msg: any) {
+    if (this.onmessage) {
+      this.onmessage({ data: msg });
+    }
+  }
+
+  private async handleRequest(operation: string, id: number, args: string[]) {
+    let emsc = await this.getEmscriptenEnvironment();
+
+    const impl = new CryptoImplementation(emsc);
+
+    if (!(operation in impl)) {
+      console.error(`crypto operation '${operation}' not found`);
+      return;
+    }
+
+    try {
+      const result = (impl as any)[operation](...args);
+      this.dispatchMessage({ result, id });
+    } catch (e) {
+      console.log("error during operation", e);
+      return;
+    }
+  }
+
+  /**
+   * Send a message to the worker thread.
+   */
+  postMessage(msg: any) {
+    const args = msg.args;
+    if (!Array.isArray(args)) {
+      console.error("args must be array");
+      return;
+    }
+    const id = msg.id;
+    if (typeof id !== "number") {
+      console.error("RPC id must be number");
+      return;
+    }
+    const operation = msg.operation;
+    if (typeof operation !== "string") {
+      console.error("RPC operation must be string");
+      return;
+    }
+
+    this.handleRequest(operation, id, args);
+  }
+
+  /**
+   * Forcibly terminate the worker thread.
+   */
+  terminate() {
+    console.log("terminating synchronous worker (no-op)");
+  }
+}
diff --git a/src/headless/taler-wallet-cli.ts b/src/headless/taler-wallet-cli.ts
index 95ee40e7..1e501cdc 100644
--- a/src/headless/taler-wallet-cli.ts
+++ b/src/headless/taler-wallet-cli.ts
@@ -26,7 +26,7 @@ import URI = require("urijs");
 
 import querystring = require("querystring");
 import { CheckPaymentResponse } from "../talerTypes";
-import { NodeCryptoWorkerFactory } from "../crypto/cryptoApi";
+import { NodeCryptoWorkerFactory, SynchronousCryptoWorkerFactory } from 
"../crypto/cryptoApi";
 
 const enableTracing = false;
 
@@ -269,7 +269,8 @@ export async function main() {
     myUnsupportedUpgrade,
   );
 
-  const myWallet = new Wallet(myDb, myHttpLib, myBadge, myNotifier, new 
NodeCryptoWorkerFactory());
+  const myWallet = new Wallet(myDb, myHttpLib, myBadge, myNotifier, new 
SynchronousCryptoWorkerFactory());
+  //const myWallet = new Wallet(myDb, myHttpLib, myBadge, myNotifier, new 
NodeCryptoWorkerFactory());
 
   const reserveResponse = await myWallet.createReserve({
     amount: amounts.parseOrThrow("TESTKUDOS:10.0"),
diff --git a/src/wallet.ts b/src/wallet.ts
index e3b60935..ffdb60fa 100644
--- a/src/wallet.ts
+++ b/src/wallet.ts
@@ -242,7 +242,7 @@ export function selectPayCoins(
       ) >= 0;
     const isBelowFee = Amounts.cmp(accDepositFee, depositFeeLimit) <= 0;
 
-    console.log("coin selection", {
+    console.log("candidate coin selection", {
       coversAmount,
       isBelowFee,
       accDepositFee,
@@ -536,8 +536,8 @@ export class Wallet {
   }
 
   /**
-   * Get exchanges and associated coins that are still spendable,
-   * but only if the sum the coins' remaining value exceeds the payment amount.
+   * Get exchanges and associated coins that are still spendable, but only
+   * if the sum the coins' remaining value covers the payment amount and fees.
    */
   private async getCoinsForPayment(
     args: CoinsForPaymentArgs,
@@ -592,6 +592,7 @@ export class Wallet {
       const coins: CoinRecord[] = await this.q()
         .iterIndex(Stores.coins.exchangeBaseUrlIndex, exchange.baseUrl)
         .toArray();
+
       const denoms = await this.q()
         .iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchange.baseUrl)
         .toArray();
@@ -644,12 +645,6 @@ export class Wallet {
         continue;
       }
 
-      console.log("payment coins: wireFeeLimit", wireFeeLimit);
-      console.log("payment coins: wireFeeAmortization", wireFeeAmortization);
-      console.log("payment coins: fees", fees);
-      console.log("payment coins: wireMethod", wireMethod);
-      console.log("payment coins: wireFeeTime", wireFeeTime);
-
       let totalFees = Amounts.getZero(currency);
       let wireFee: AmountJson | undefined;
       for (const fee of fees.feesForType[wireMethod] || []) {
@@ -659,8 +654,6 @@ export class Wallet {
         }
       }
 
-      console.log("payment coins: current wire fees", wireFee);
-
       if (wireFee) {
         const amortizedWireFee = Amounts.divide(wireFee, wireFeeAmortization);
         if (Amounts.cmp(wireFeeLimit, amortizedWireFee) < 0) {
@@ -671,6 +664,7 @@ export class Wallet {
       }
 
       const res = selectPayCoins(denoms, cds, remainingAmount, 
depositFeeLimit);
+
       if (res) {
         totalFees = Amounts.add(totalFees, res.totalFees).amount;
         return {
@@ -748,7 +742,6 @@ export class Wallet {
       console.log("contract download failed", e);
       throw e;
     }
-    console.log("got response", resp);
 
     const proposal = Proposal.checked(resp.data);
 
@@ -919,7 +912,6 @@ export class Wallet {
       wireMethod: proposal.contractTerms.wire_method,
     });
 
-    console.log("max_fee", proposal.contractTerms.max_fee);
     console.log("coin selection result", res);
 
     if (!res) {
@@ -1033,6 +1025,8 @@ export class Wallet {
       return { status: "insufficient-balance" };
     }
 
+    console.log("checkPay: payment possible!");
+
     // Only create speculative signature if we don't already have one for this 
proposal
     if (
       !this.speculativePayData ||
@@ -1051,6 +1045,7 @@ export class Wallet {
         proposal,
         proposalId,
       };
+      console.log("created speculative pay data for payment");
     }
 
     return { status: "payment-possible", coinSelection: res };
@@ -1156,7 +1151,6 @@ export class Wallet {
         return op.promise;
       }
 
-      //console.log("executing processPreCoin", preCoin);
       this.processPreCoinConcurrent++;
 
       try {
diff --git a/tsconfig.json b/tsconfig.json
index 3f29f420..8104054a 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -29,14 +29,15 @@
     "src/checkable.ts",
     "src/crypto/cryptoApi-test.ts",
     "src/crypto/cryptoApi.ts",
+    "src/crypto/cryptoImplementation.ts",
     "src/crypto/cryptoWorker.ts",
     "src/crypto/emscInterface-test.ts",
     "src/crypto/emscInterface.ts",
     "src/crypto/emscLoader.d.ts",
     "src/crypto/emscLoader.js",
-    "src/crypto/nodeWorker.ts",
+    "src/crypto/nodeProcessWorker.ts",
     "src/crypto/nodeWorkerEntry.ts",
-    "src/crypto/startWorker.js",
+    "src/crypto/synchronousWorker.ts",
     "src/db.ts",
     "src/dbTypes.ts",
     "src/headless/taler-wallet-cli.ts",
diff --git a/yarn.lock b/yarn.lock
index f779b403..c61d6fd2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3216,10 +3216,10 @@ iconv-lite@^0.4.4, iconv-lite@~0.4.13:
   dependencies:
     safer-buffer ">= 2.1.2 < 3"
 
-idb-bridge@^0.0.1:
-  version "0.0.1"
-  resolved 
"https://registry.yarnpkg.com/idb-bridge/-/idb-bridge-0.0.1.tgz#4498704b79f354dcd3a628825656967939003614";
-  integrity 
sha512-GTFqRkjFk4C98zvPA65cKpB1JnBt+bFftn+Kkwucoy+hLmxVfdmbwZ6hj2ZieBHOppMtRs0il3zbzSzLofWrDg==
+idb-bridge@0.0.2:
+  version "0.0.2"
+  resolved 
"https://registry.yarnpkg.com/idb-bridge/-/idb-bridge-0.0.2.tgz#daa46d75060bd6a116b26155c314446bea355570";
+  integrity 
sha512-PEfZmdbIQUV4vxJRSSXhan7niclJDJGPGUSJ2WlHCYCgdFK6n25UD8z/lsLoqWKfcp+xPuL+9MI+h9Ql8XFzkw==
 
 ieee754@^1.1.4:
   version "1.1.13"

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

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