[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.