aboutsummaryrefslogtreecommitdiff
path: root/src/crypto
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2019-06-26 15:30:32 +0200
committerFlorian Dold <florian.dold@gmail.com>2019-06-26 15:30:32 +0200
commitcfa1df734315efc8e24a1a846e4d694abe2249ea (patch)
treebe428e4179671a4b280fd7ba186befb44ce89354 /src/crypto
parent420a5ba23a83bb4e60a1b76e2605205e1c481551 (diff)
downloadwallet-core-cfa1df734315efc8e24a1a846e4d694abe2249ea.tar.xz
add link signature to /refresh/reveal
Diffstat (limited to 'src/crypto')
-rw-r--r--src/crypto/cryptoApi.ts147
-rw-r--r--src/crypto/cryptoWorker.ts299
-rw-r--r--src/crypto/emscInterface.ts32
3 files changed, 314 insertions, 164 deletions
diff --git a/src/crypto/cryptoApi.ts b/src/crypto/cryptoApi.ts
index 03c2a675b..43a3bc228 100644
--- a/src/crypto/cryptoApi.ts
+++ b/src/crypto/cryptoApi.ts
@@ -14,7 +14,6 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-
/**
* API to access the Taler crypto worker thread.
* @author Florian Dold
@@ -35,22 +34,14 @@ import {
WireFee,
} from "../dbTypes";
-import {
- ContractTerms,
- PaybackRequest,
-} from "../talerTypes";
+import { ContractTerms, PaybackRequest } from "../talerTypes";
-import {
- BenchmarkResult,
- CoinWithDenom,
- PayCoinInfo,
-} from "../walletTypes";
+import { BenchmarkResult, CoinWithDenom, PayCoinInfo } from "../walletTypes";
import * as timer from "../timer";
import { startWorker } from "./startWorker";
-
/**
* State of a crypto worker.
*/
@@ -58,17 +49,17 @@ interface WorkerState {
/**
* The actual worker thread.
*/
- w: Worker|null;
+ w: Worker | null;
/**
* Work we're currently executing or null if not busy.
*/
- currentWorkItem: WorkItem|null;
+ currentWorkItem: WorkItem | null;
/**
* Timer to terminate the worker if it's not busy enough.
*/
- terminationTimerHandle: timer.TimerHandle|null;
+ terminationTimerHandle: timer.TimerHandle | null;
}
interface WorkItem {
@@ -88,7 +79,6 @@ interface WorkItem {
startTime: number;
}
-
/**
* Number of different priorities. Each priority p
* must be 0 <= p < NUM_PRIO.
@@ -151,8 +141,10 @@ export class CryptoApi {
handleWorkerError(ws: WorkerState, e: ErrorEvent) {
if (ws.currentWorkItem) {
- console.error(`error in worker during ${ws.currentWorkItem!.operation}`,
- e);
+ console.error(
+ `error in worker during ${ws.currentWorkItem!.operation}`,
+ e,
+ );
} else {
console.error("error in worker", e);
}
@@ -201,7 +193,10 @@ export class CryptoApi {
console.error(`RPC with id ${id} has no registry entry`);
return;
}
- console.log(`rpc ${currentWorkItem.operation} took ${timer.performanceNow() - currentWorkItem.startTime}ms`);
+ console.log(
+ `rpc ${currentWorkItem.operation} took ${timer.performanceNow() -
+ currentWorkItem.startTime}ms`,
+ );
currentWorkItem.resolve(msg.data.result);
}
@@ -230,12 +225,21 @@ export class CryptoApi {
}
}
- private doRpc<T>(operation: string, priority: number,
- ...args: any[]): Promise<T> {
-
+ private doRpc<T>(
+ operation: string,
+ priority: number,
+ ...args: any[]
+ ): Promise<T> {
const p: Promise<T> = new Promise<T>((resolve, reject) => {
const rpcId = this.nextRpcId++;
- const workItem: WorkItem = {operation, args, resolve, reject, rpcId, startTime: 0};
+ const workItem: WorkItem = {
+ operation,
+ args,
+ resolve,
+ reject,
+ rpcId,
+ startTime: 0,
+ };
if (this.numBusy === this.workers.length) {
const q = this.workQueues[priority];
@@ -263,8 +267,10 @@ export class CryptoApi {
});
}
-
- createPreCoin(denom: DenominationRecord, reserve: ReserveRecord): Promise<PreCoinRecord> {
+ createPreCoin(
+ denom: DenominationRecord,
+ reserve: ReserveRecord,
+ ): Promise<PreCoinRecord> {
return this.doRpc<PreCoinRecord>("createPreCoin", 1, denom, reserve);
}
@@ -280,27 +286,48 @@ export class CryptoApi {
return this.doRpc<string>("hashDenomPub", 1, denomPub);
}
- isValidDenom(denom: DenominationRecord,
- masterPub: string): Promise<boolean> {
+ isValidDenom(denom: DenominationRecord, masterPub: string): Promise<boolean> {
return this.doRpc<boolean>("isValidDenom", 2, denom, masterPub);
}
- isValidWireFee(type: string, wf: WireFee, masterPub: string): Promise<boolean> {
+ isValidWireFee(
+ type: string,
+ wf: WireFee,
+ masterPub: string,
+ ): Promise<boolean> {
return this.doRpc<boolean>("isValidWireFee", 2, type, wf, masterPub);
}
- isValidPaymentSignature(sig: string, contractHash: string, merchantPub: string): Promise<boolean> {
- return this.doRpc<boolean>("isValidPaymentSignature", 1, sig, contractHash, merchantPub);
+ isValidPaymentSignature(
+ sig: string,
+ contractHash: string,
+ merchantPub: string,
+ ): Promise<boolean> {
+ return this.doRpc<boolean>(
+ "isValidPaymentSignature",
+ 1,
+ sig,
+ contractHash,
+ merchantPub,
+ );
}
- signDeposit(contractTerms: ContractTerms,
- cds: CoinWithDenom[],
- totalAmount: AmountJson): Promise<PayCoinInfo> {
- return this.doRpc<PayCoinInfo>("signDeposit", 3, contractTerms, cds, totalAmount);
+ signDeposit(
+ contractTerms: ContractTerms,
+ cds: CoinWithDenom[],
+ totalAmount: AmountJson,
+ ): Promise<PayCoinInfo> {
+ return this.doRpc<PayCoinInfo>(
+ "signDeposit",
+ 3,
+ contractTerms,
+ cds,
+ totalAmount,
+ );
}
- createEddsaKeypair(): Promise<{priv: string, pub: string}> {
- return this.doRpc<{priv: string, pub: string}>("createEddsaKeypair", 1);
+ createEddsaKeypair(): Promise<{ priv: string; pub: string }> {
+ return this.doRpc<{ priv: string; pub: string }>("createEddsaKeypair", 1);
}
rsaUnblind(sig: string, bk: string, pk: string): Promise<string> {
@@ -311,23 +338,43 @@ export class CryptoApi {
return this.doRpc<PaybackRequest>("createPaybackRequest", 1, coin);
}
- createRefreshSession(exchangeBaseUrl: string,
- kappa: number,
- meltCoin: CoinRecord,
- newCoinDenoms: DenominationRecord[],
- meltFee: AmountJson): Promise<RefreshSessionRecord> {
- return this.doRpc<RefreshSessionRecord>("createRefreshSession",
- 4,
- exchangeBaseUrl,
- kappa,
- meltCoin,
- newCoinDenoms,
- meltFee);
+ createRefreshSession(
+ exchangeBaseUrl: string,
+ kappa: number,
+ meltCoin: CoinRecord,
+ newCoinDenoms: DenominationRecord[],
+ meltFee: AmountJson,
+ ): Promise<RefreshSessionRecord> {
+ return this.doRpc<RefreshSessionRecord>(
+ "createRefreshSession",
+ 4,
+ exchangeBaseUrl,
+ kappa,
+ meltCoin,
+ newCoinDenoms,
+ meltFee,
+ );
+ }
+
+ signCoinLink(
+ oldCoinPriv: string,
+ newDenomHash: string,
+ oldCoinPub: string,
+ transferPub: string,
+ coinEv: string,
+ ): Promise<string> {
+ return this.doRpc<string>(
+ "signCoinLink",
+ 4,
+ oldCoinPriv,
+ newDenomHash,
+ oldCoinPub,
+ transferPub,
+ coinEv,
+ );
}
benchmark(repetitions: number): Promise<BenchmarkResult> {
- return this.doRpc<BenchmarkResult>("benchmark",
- 1,
- repetitions);
+ return this.doRpc<BenchmarkResult>("benchmark", 1, repetitions);
}
}
diff --git a/src/crypto/cryptoWorker.ts b/src/crypto/cryptoWorker.ts
index 5013e3acf..9c5263a6f 100644
--- a/src/crypto/cryptoWorker.ts
+++ b/src/crypto/cryptoWorker.ts
@@ -18,7 +18,6 @@
* Web worker for crypto operations.
*/
-
/**
* Imports.
*/
@@ -39,17 +38,9 @@ import {
WireFee,
} from "../dbTypes";
-import {
- CoinPaySig,
- ContractTerms,
- PaybackRequest,
-} from "../talerTypes";
+import { CoinPaySig, ContractTerms, PaybackRequest } from "../talerTypes";
-import {
- BenchmarkResult,
- CoinWithDenom,
- PayCoinInfo,
-} from "../walletTypes";
+import { BenchmarkResult, CoinWithDenom, PayCoinInfo } from "../walletTypes";
import { canonicalJson } from "../helpers";
@@ -64,15 +55,15 @@ import {
} from "./emscInterface";
import * as native from "./emscInterface";
-
namespace RpcFunctions {
-
/**
* Create a pre-coin of the given denomination to be withdrawn from then given
* reserve.
*/
- export function createPreCoin(denom: DenominationRecord,
- reserve: ReserveRecord): PreCoinRecord {
+ export function createPreCoin(
+ denom: DenominationRecord,
+ reserve: ReserveRecord,
+ ): PreCoinRecord {
const reservePriv = new native.EddsaPrivateKey();
reservePriv.loadCrock(reserve.reserve_priv);
const reservePub = new native.EddsaPublicKey();
@@ -125,7 +116,6 @@ namespace RpcFunctions {
return preCoin;
}
-
/**
* Create a planchet used for tipping, including the private keys.
*/
@@ -152,12 +142,14 @@ namespace RpcFunctions {
coinPub: coinPub.toCrock(),
coinValue: denom.value,
denomPub: denomPub.encode().toCrock(),
- denomPubHash: denomPub.encode().hash().toCrock(),
+ denomPubHash: denomPub
+ .encode()
+ .hash()
+ .toCrock(),
};
return tipPlanchet;
}
-
/**
* Create and sign a message to request payback for a coin.
*/
@@ -165,7 +157,9 @@ namespace RpcFunctions {
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(),
+ h_denom_pub: native.RsaPublicKey.fromCrock(coin.denomPub)
+ .encode()
+ .hash(),
});
const coinPriv = native.EddsaPrivateKey.fromCrock(coin.coinPriv);
const coinSig = native.eddsaSign(p.toPurpose(), coinPriv);
@@ -179,63 +173,83 @@ namespace RpcFunctions {
return paybackRequest;
}
-
/**
* Check if a payment signature is valid.
*/
- export function isValidPaymentSignature(sig: string, contractHash: string, merchantPub: string): boolean {
+ 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);
+ 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 {
+ export function isValidWireFee(
+ type: string,
+ wf: WireFee,
+ masterPub: string,
+ ): boolean {
const p = new native.MasterWireFeePS({
- closing_fee: (new native.Amount(wf.closingFee)).toNbo(),
+ 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(),
+ 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);
+ 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 {
+ 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(),
+ 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(),
+ value: new native.Amount(denom.value).toNbo(),
});
const nativeSig = new native.EddsaSignature();
@@ -243,42 +257,44 @@ namespace RpcFunctions {
const nativePub = native.EddsaPublicKey.fromCrock(masterPub);
- return native.eddsaVerify(native.SignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY,
- p.toPurpose(),
- nativeSig,
- nativePub);
-
+ 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} {
+ export function createEddsaKeypair(): { priv: string; pub: string } {
const priv = native.EddsaPrivateKey.create();
const pub = priv.getPublicKey();
- return {priv: priv.toCrock(), pub: pub.toCrock()};
+ 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));
+ 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 {
+ export function signDeposit(
+ contractTerms: ContractTerms,
+ cds: CoinWithDenom[],
+ totalAmount: AmountJson,
+ ): PayCoinInfo {
const ret: PayCoinInfo = {
originalCoins: [],
sigs: [],
@@ -287,17 +303,21 @@ namespace RpcFunctions {
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;
+ 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;
+ 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 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) };
+ const originalCoin = { ...cd.coin };
if (amountRemaining.value === 0 && amountRemaining.fraction === 0) {
break;
@@ -332,13 +352,20 @@ namespace RpcFunctions {
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),
+ 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 coinSig = native
+ .eddsaSign(
+ d.toPurpose(),
+ native.EddsaPrivateKey.fromCrock(cd.coin.coinPriv),
+ )
+ .toCrock();
const s: CoinPaySig = {
coin_pub: cd.coin.coinPub,
@@ -355,22 +382,21 @@ namespace RpcFunctions {
return ret;
}
-
/**
* Create a new refresh session.
*/
- export function createRefreshSession(exchangeBaseUrl: string,
- kappa: number,
- meltCoin: CoinRecord,
- newCoinDenoms: DenominationRecord[],
- meltFee: AmountJson): RefreshSessionRecord {
-
+ 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;
+ valueWithFee = Amounts.add(valueWithFee, ncd.value, ncd.feeWithdraw)
+ .amount;
}
// melt fee
@@ -397,12 +423,11 @@ namespace RpcFunctions {
}
sessionHc.read(native.EddsaPublicKey.fromCrock(meltCoin.coinPub));
- sessionHc.read((new native.Amount(valueWithFee)).toNbo());
+ 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);
@@ -413,10 +438,10 @@ namespace RpcFunctions {
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);
+ 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?)");
}
@@ -437,16 +462,18 @@ namespace RpcFunctions {
sessionHc.finish(sessionHash);
const confirmData = new RefreshMeltCoinAffirmationPS({
- amount_with_fee: (new Amount(valueWithFee)).toNbo(),
+ amount_with_fee: new Amount(valueWithFee).toNbo(),
coin_pub: EddsaPublicKey.fromCrock(meltCoin.coinPub),
- melt_fee: (new Amount(meltFee)).toNbo(),
+ melt_fee: new Amount(meltFee).toNbo(),
session_hash: sessionHash,
});
-
- const confirmSig: string = native.eddsaSign(confirmData.toPurpose(),
- native.EddsaPrivateKey.fromCrock(
- meltCoin.coinPriv)).toCrock();
+ 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) {
@@ -459,8 +486,8 @@ namespace RpcFunctions {
finished: false,
hash: sessionHash.toCrock(),
meltCoinPub: meltCoin.coinPub,
- newDenomHashes: newCoinDenoms.map((d) => d.denomPubHash),
- newDenoms: newCoinDenoms.map((d) => d.denomPub),
+ newDenomHashes: newCoinDenoms.map(d => d.denomPubHash),
+ newDenoms: newCoinDenoms.map(d => d.denomPub),
norevealIndex: undefined,
preCoinsForGammas,
transferPrivs,
@@ -484,7 +511,33 @@ namespace RpcFunctions {
* Hash a denomination public key.
*/
export function hashDenomPub(denomPub: string): string {
- return native.RsaPublicKey.fromCrock(denomPub).encode().hash().toCrock();
+ 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 {
@@ -500,7 +553,7 @@ namespace RpcFunctions {
for (let i = 0; i < repetitions; i++) {
ba.randomize(native.RandomQuality.WEAK);
const start = timer.performanceNow();
- ba.hash();
+ ba.hash();
time_hash_big += timer.performanceNow() - start;
}
@@ -508,7 +561,7 @@ namespace RpcFunctions {
for (let i = 0; i < repetitions; i++) {
const start = timer.performanceNow();
const priv: native.EddsaPrivateKey = native.EddsaPrivateKey.create();
- time_eddsa_create += timer.performanceNow() - start;
+ time_eddsa_create += timer.performanceNow() - start;
priv.destroy();
}
@@ -541,14 +594,15 @@ namespace RpcFunctions {
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);
+ native.eddsaVerify(
+ native.SignaturePurpose.MERCHANT_PAYMENT_OK,
+ p,
+ eddsaSig,
+ eddsaPub,
+ );
time_eddsa_verify += timer.performanceNow() - start;
}
@@ -564,11 +618,18 @@ namespace RpcFunctions {
time_rsa_2048_blind += timer.performanceNow() - start;
}
- const blindedMessage2048 = native.rsaBlind(h, blindingSecret2048, rsaPub2048);
+ const blindedMessage2048 = native.rsaBlind(
+ h,
+ blindingSecret2048,
+ rsaPub2048,
+ );
if (!blindedMessage2048) {
throw Error("should not happen");
}
- const rsaBlindSig2048 = native.rsaSignBlinded(rsaPriv2048, blindedMessage2048);
+ const rsaBlindSig2048 = native.rsaSignBlinded(
+ rsaPriv2048,
+ blindedMessage2048,
+ );
let time_rsa_2048_unblind = 0;
for (let i = 0; i < repetitions; i++) {
@@ -577,7 +638,11 @@ namespace RpcFunctions {
time_rsa_2048_unblind += timer.performanceNow() - start;
}
- const unblindedSig2048 = native.rsaUnblind(rsaBlindSig2048, blindingSecret2048, rsaPub2048);
+ const unblindedSig2048 = native.rsaUnblind(
+ rsaBlindSig2048,
+ blindingSecret2048,
+ rsaPub2048,
+ );
let time_rsa_2048_verify = 0;
for (let i = 0; i < repetitions; i++) {
@@ -586,7 +651,6 @@ namespace RpcFunctions {
time_rsa_2048_verify += timer.performanceNow() - start;
}
-
/* rsa 4096 */
let time_rsa_4096_blind = 0;
@@ -599,11 +663,18 @@ namespace RpcFunctions {
time_rsa_4096_blind += timer.performanceNow() - start;
}
- const blindedMessage4096 = native.rsaBlind(h, blindingSecret4096, rsaPub4096);
+ const blindedMessage4096 = native.rsaBlind(
+ h,
+ blindingSecret4096,
+ rsaPub4096,
+ );
if (!blindedMessage4096) {
throw Error("should not happen");
}
- const rsaBlindSig4096 = native.rsaSignBlinded(rsaPriv4096, blindedMessage4096);
+ const rsaBlindSig4096 = native.rsaSignBlinded(
+ rsaPriv4096,
+ blindedMessage4096,
+ );
let time_rsa_4096_unblind = 0;
for (let i = 0; i < repetitions; i++) {
@@ -612,7 +683,11 @@ namespace RpcFunctions {
time_rsa_4096_unblind += timer.performanceNow() - start;
}
- const unblindedSig4096 = native.rsaUnblind(rsaBlindSig4096, blindingSecret4096, rsaPub4096);
+ const unblindedSig4096 = native.rsaUnblind(
+ rsaBlindSig4096,
+ blindingSecret4096,
+ rsaPub4096,
+ );
let time_rsa_4096_verify = 0;
for (let i = 0; i < repetitions; i++) {
@@ -621,7 +696,6 @@ namespace RpcFunctions {
time_rsa_4096_verify += timer.performanceNow() - start;
}
-
return {
repetitions,
time: {
@@ -637,12 +711,11 @@ namespace RpcFunctions {
rsa_4096_blind: time_rsa_4096_blind,
rsa_4096_unblind: time_rsa_4096_unblind,
rsa_4096_verify: time_rsa_4096_verify,
- }
+ },
};
}
}
-
const worker: Worker = (self as any) as Worker;
worker.onmessage = (msg: MessageEvent) => {
@@ -665,7 +738,7 @@ worker.onmessage = (msg: MessageEvent) => {
console.log("onmessage with", msg.data.operation);
console.log("foo");
- emscLoader.getLib().then((p) => {
+ emscLoader.getLib().then(p => {
const lib = p.lib;
if (!native.isInitialized()) {
console.log("initializing emscripten for then first time with lib");
diff --git a/src/crypto/emscInterface.ts b/src/crypto/emscInterface.ts
index dcd16e633..2ddc15a37 100644
--- a/src/crypto/emscInterface.ts
+++ b/src/crypto/emscInterface.ts
@@ -223,6 +223,7 @@ export enum SignaturePurpose {
MERCHANT_PAYMENT_OK = 1104,
MASTER_WIRE_FEES = 1028,
WALLET_COIN_PAYBACK = 1203,
+ WALLET_COIN_LINK = 1204,
}
@@ -970,7 +971,7 @@ abstract class SignatureStruct {
throw Error(`Key ${name} not found`);
}
if (!(value instanceof typemap[name])) {
- throw Error("Wrong type for ${name}");
+ throw Error(`Wrong type for ${name}`);
}
this.members[name] = value;
}
@@ -1293,6 +1294,35 @@ export class DepositRequestPS extends SignatureStruct {
}
}
+
+interface CoinLinkSignaturePS_args {
+ h_denom_pub: HashCode;
+ old_coin_pub: EddsaPublicKey;
+ transfer_pub: EcdhePublicKey;
+ coin_envelope_hash: HashCode;
+}
+
+
+export class CoinLinkSignaturePS extends SignatureStruct {
+ constructor(w: CoinLinkSignaturePS_args) {
+ super(w);
+ }
+
+ purpose() {
+ return SignaturePurpose.WALLET_COIN_LINK;
+ }
+
+ fieldTypes() {
+ return [
+ ["h_denom_pub", HashCode],
+ ["old_coin_pub", EddsaPublicKey],
+ ["transfer_pub", EcdhePublicKey],
+ ["coin_envelope_hash", HashCode],
+ ];
+ }
+}
+
+
/**
* Arguments for constuctor of [[DenominationKeyValidityPS]].
*/