aboutsummaryrefslogtreecommitdiff
path: root/extension
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2016-02-22 21:52:53 +0100
committerFlorian Dold <florian.dold@gmail.com>2016-02-22 21:53:05 +0100
commit2760591d4deb00b594010493a0bbd07b347204ab (patch)
treeacce52e557f004b20391aee0771147f2b62f034d /extension
parent81428771b8fc526a692dd26cf3f1421b65e32d6d (diff)
put all crypto into backend
Diffstat (limited to 'extension')
-rw-r--r--extension/lib/wallet/cryptoApi.ts19
-rw-r--r--extension/lib/wallet/cryptoLib.ts91
-rw-r--r--extension/lib/wallet/types.ts24
-rw-r--r--extension/lib/wallet/wallet.ts197
4 files changed, 192 insertions, 139 deletions
diff --git a/extension/lib/wallet/cryptoApi.ts b/extension/lib/wallet/cryptoApi.ts
index c29e9a45e..300b928db 100644
--- a/extension/lib/wallet/cryptoApi.ts
+++ b/extension/lib/wallet/cryptoApi.ts
@@ -18,6 +18,9 @@
import {PreCoin} from "./types";
import {Reserve} from "./types";
import {Denomination} from "./types";
+import {Offer} from "./wallet";
+import {CoinWithDenom} from "./wallet";
+import {PayCoinInfo} from "./types";
export class CryptoApi {
private nextRpcId: number = 1;
private rpcRegistry = {};
@@ -66,9 +69,25 @@ export class CryptoApi {
return this.doRpc("createPreCoin", denom, reserve);
}
+ hashRsaPub(rsaPub: string): Promise<string> {
+ return this.doRpc("hashRsaPub", rsaPub);
+ }
isValidDenom(denom: Denomination,
masterPub: string): Promise<boolean> {
return this.doRpc("isValidDenom", denom, masterPub);
}
+
+ signDeposit(offer: Offer,
+ cds: CoinWithDenom[]): Promise<PayCoinInfo> {
+ return this.doRpc("signDeposit", offer, cds);
+ }
+
+ createEddsaKeypair(): Promise<{priv: string, pub: string}> {
+ return this.doRpc("createEddsaKeypair");
+ }
+
+ rsaUnblind(sig: string, bk: string, pk: string): Promise<string> {
+ return this.doRpc("rsaUnblind", sig, bk, pk);
+ }
} \ No newline at end of file
diff --git a/extension/lib/wallet/cryptoLib.ts b/extension/lib/wallet/cryptoLib.ts
index 2c32b3a63..869ddbaff 100644
--- a/extension/lib/wallet/cryptoLib.ts
+++ b/extension/lib/wallet/cryptoLib.ts
@@ -23,8 +23,11 @@ import {Denomination} from "./types";
"use strict";
import * as native from "./emscriptif";
-import {PreCoin, Reserve} from "./types";
+import {PreCoin, Reserve, PayCoinInfo} from "./types";
import create = chrome.alarms.create;
+import {Offer} from "./wallet";
+import {CoinWithDenom} from "./wallet";
+import {CoinPaySig} from "./types";
export function main(worker: Worker) {
@@ -58,7 +61,8 @@ namespace RpcFunctions {
* Create a pre-coin of the given denomination to be withdrawn from then given
* reserve.
*/
- export function createPreCoin(denom: Denomination, reserve: Reserve): PreCoin {
+ export function createPreCoin(denom: Denomination,
+ reserve: Reserve): PreCoin {
let reservePriv = new native.EddsaPrivateKey();
reservePriv.loadCrock(reserve.reserve_priv);
let reservePub = new native.EddsaPublicKey();
@@ -107,7 +111,7 @@ namespace RpcFunctions {
export function isValidDenom(denom: Denomination,
- masterPub: string): boolean {
+ masterPub: string): boolean {
let p = new native.DenominationKeyValidityPS({
master: native.EddsaPublicKey.fromCrock(masterPub),
denom_hash: native.RsaPublicKey.fromCrock(denom.denom_pub)
@@ -134,4 +138,85 @@ namespace RpcFunctions {
nativePub);
}
+
+
+ export function hashRsaPub(rsaPub: string): string {
+ return native.RsaPublicKey.fromCrock(rsaPub)
+ .encode()
+ .hash()
+ .toCrock();
+ }
+
+
+ export function createEddsaKeypair(): {priv: string, pub: string} {
+ const priv = native.EddsaPrivateKey.create();
+ const pub = priv.getPublicKey();
+ return {priv: priv.toCrock(), pub: pub.toCrock()};
+ }
+
+
+ export function rsaUnblind(sig, bk, pk): string {
+ let denomSig = native.rsaUnblind(native.RsaSignature.fromCrock(sig),
+ native.RsaBlindingKey.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(offer: Offer,
+ cds: CoinWithDenom[]): PayCoinInfo {
+ let ret = [];
+ let amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency);
+ let amountRemaining = new native.Amount(offer.contract.amount);
+ for (let cd of cds) {
+ let coinSpend;
+
+ 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);
+
+ let newAmount = new native.Amount(cd.coin.currentAmount);
+ newAmount.sub(coinSpend);
+ cd.coin.currentAmount = newAmount.toJson();
+
+ let d = new native.DepositRequestPS({
+ h_contract: native.HashCode.fromCrock(offer.H_contract),
+ h_wire: native.HashCode.fromCrock(offer.contract.H_wire),
+ amount_with_fee: coinSpend.toNbo(),
+ coin_pub: native.EddsaPublicKey.fromCrock(cd.coin.coinPub),
+ deposit_fee: new native.Amount(cd.denom.fee_deposit).toNbo(),
+ merchant: native.EddsaPublicKey.fromCrock(offer.contract.merchant_pub),
+ refund_deadline: native.AbsoluteTimeNbo.fromTalerString(offer.contract.refund_deadline),
+ timestamp: native.AbsoluteTimeNbo.fromTalerString(offer.contract.timestamp),
+ transaction_id: native.UInt64.fromNumber(offer.contract.transaction_id),
+ });
+
+ let coinSig = native.eddsaSign(d.toPurpose(),
+ native.EddsaPrivateKey.fromCrock(cd.coin.coinPriv))
+ .toCrock();
+
+ let s: CoinPaySig = {
+ coin_sig: coinSig,
+ coin_pub: cd.coin.coinPub,
+ ub_sig: cd.coin.denomSig,
+ denom_pub: cd.coin.denomPub,
+ f: coinSpend.toJson(),
+ };
+ ret.push({sig: s, updatedCoin: cd.coin});
+ }
+ return ret;
+ }
}
diff --git a/extension/lib/wallet/types.ts b/extension/lib/wallet/types.ts
index cfd30bbc3..77603e083 100644
--- a/extension/lib/wallet/types.ts
+++ b/extension/lib/wallet/types.ts
@@ -120,12 +120,36 @@ export interface PreCoin {
coinValue: AmountJson;
}
+
export interface Reserve {
mint_base_url: string
reserve_priv: string;
reserve_pub: string;
}
+
+export interface CoinPaySig {
+ coin_sig: string;
+ coin_pub: string;
+ ub_sig: string;
+ denom_pub: string;
+ f: AmountJson;
+}
+
+
+export interface Coin {
+ coinPub: string;
+ coinPriv: string;
+ denomPub: string;
+ denomSig: string;
+ currentAmount: AmountJson;
+ mintBaseUrl: string;
+}
+
+
+export type PayCoinInfo = Array<{ updatedCoin: Coin, sig: CoinPaySig }>;
+
+
export namespace Amounts {
export interface Result {
amount: AmountJson;
diff --git a/extension/lib/wallet/wallet.ts b/extension/lib/wallet/wallet.ts
index 2bd2beee5..8446d7194 100644
--- a/extension/lib/wallet/wallet.ts
+++ b/extension/lib/wallet/wallet.ts
@@ -27,10 +27,12 @@ import {HttpResponse, RequestException} from "./http";
import {Query} from "./query";
import {Checkable} from "./checkable";
import {canonicalizeBaseUrl} from "./helpers";
-import {ReserveCreationInfo} from "./types";
+import {ReserveCreationInfo, Amounts} from "./types";
import {PreCoin} from "./types";
import {Reserve} from "./types";
import {CryptoApi} from "./cryptoApi";
+import {Coin} from "./types";
+import {PayCoinInfo} from "./types";
"use strict";
@@ -68,16 +70,6 @@ export class KeysJson {
}
-export interface Coin {
- coinPub: string;
- coinPriv: string;
- denomPub: string;
- denomSig: string;
- currentAmount: AmountJson;
- mintBaseUrl: string;
-}
-
-
class MintInfo implements IMintInfo {
baseUrl: string;
masterPublicKey: string;
@@ -147,14 +139,10 @@ class MintInfo implements IMintInfo {
if (!valid) {
throw Error("signature on denomination invalid");
}
-
- let d: Denomination = Object.assign({}, newDenom);
- d.pub_hash = native.RsaPublicKey.fromCrock(d.denom_pub)
- .encode()
- .hash()
- .toCrock();
- this.denoms.push(d);
-
+ return cryptoApi.hashRsaPub(newDenom.denom_pub);
+ })
+ .then((h) => {
+ this.denoms.push(Object.assign({}, newDenom, {pub_hash: h}));
});
});
@@ -302,8 +290,6 @@ export interface Badge {
setColor(c: string): void;
}
-type PayCoinInfo = Array<{ updatedCoin: Coin, sig: CoinPaySig }>;
-
function deepEquals(x, y) {
if (x === y) {
@@ -362,11 +348,8 @@ function copy(o) {
* Rank two denomination by how desireable it is to withdraw them,
* based on their fees and value.
*/
-function rankDenom(denom1: any, denom2: any) {
- // Slow ... we should find a better way than to convert it evert time.
- let v1 = new native.Amount(denom1.value);
- let v2 = new native.Amount(denom2.value);
- return (-1) * v1.cmp(v2);
+function rankDenom(denom1: Denomination, denom2: Denomination) {
+ return (-1) * Amounts.cmp(denom1.value, denom2.value);
}
@@ -428,65 +411,6 @@ export class Wallet {
/**
- * Generate updated coins (to store in the database)
- * and deposit permissions for each given coin.
- */
- private static signDeposit(offer: Offer,
- cds: CoinWithDenom[]): PayCoinInfo {
- let ret = [];
- let amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency);
- let amountRemaining = new native.Amount(offer.contract.amount);
- cds = copy(cds);
- for (let cd of cds) {
- let coinSpend;
-
- 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);
-
- let newAmount = new native.Amount(cd.coin.currentAmount);
- newAmount.sub(coinSpend);
- cd.coin.currentAmount = newAmount.toJson();
-
- let d = new native.DepositRequestPS({
- h_contract: native.HashCode.fromCrock(offer.H_contract),
- h_wire: native.HashCode.fromCrock(offer.contract.H_wire),
- amount_with_fee: coinSpend.toNbo(),
- coin_pub: native.EddsaPublicKey.fromCrock(cd.coin.coinPub),
- deposit_fee: new native.Amount(cd.denom.fee_deposit).toNbo(),
- merchant: native.EddsaPublicKey.fromCrock(offer.contract.merchant_pub),
- refund_deadline: native.AbsoluteTimeNbo.fromTalerString(offer.contract.refund_deadline),
- timestamp: native.AbsoluteTimeNbo.fromTalerString(offer.contract.timestamp),
- transaction_id: native.UInt64.fromNumber(offer.contract.transaction_id),
- });
-
- let coinSig = native.eddsaSign(d.toPurpose(),
- native.EddsaPrivateKey.fromCrock(cd.coin.coinPriv))
- .toCrock();
-
- let s: CoinPaySig = {
- coin_sig: coinSig,
- coin_pub: cd.coin.coinPub,
- ub_sig: cd.coin.denomSig,
- denom_pub: cd.coin.denomPub,
- f: coinSpend.toJson(),
- };
- ret.push({sig: s, updatedCoin: cd.coin});
- }
- return ret;
- }
-
-
- /**
* Get mints and associated coins that are still spendable,
* but only if the sum the coins' remaining value exceeds the payment amount.
*/
@@ -647,9 +571,10 @@ export class Wallet {
}
console.log("about to record ...");
let mintUrl = Object.keys(mcs)[0];
- let ds = Wallet.signDeposit(offer, mcs[mintUrl]);
- return this.recordConfirmPay(offer, ds, mintUrl)
- .then((() => ({})));
+
+ return this.cryptoApi.signDeposit(offer, mcs[mintUrl])
+ .then((ds) => this.recordConfirmPay(offer, ds, mintUrl))
+ .then(() => ({}));
});
}
@@ -711,44 +636,43 @@ export class Wallet {
* Create a reserve, but do not flag it as confirmed yet.
*/
createReserve(req: CreateReserveRequest): Promise<CreateReserveResponse> {
- const reservePriv = native.EddsaPrivateKey.create();
- const reservePub = reservePriv.getPublicKey();
-
- const now = (new Date).getTime();
- const canonMint = canonicalizeBaseUrl(req.mint);
-
- const reserveRecord = {
- reserve_pub: reservePub.toCrock(),
- reserve_priv: reservePriv.toCrock(),
- mint_base_url: canonMint,
- created: now,
- last_query: null,
- current_amount: null,
- requested_amount: req.amount,
- confirmed: false,
- };
+ return this.cryptoApi.createEddsaKeypair().then((keypair) => {
+ const now = (new Date).getTime();
+ const canonMint = canonicalizeBaseUrl(req.mint);
+
+ const reserveRecord = {
+ reserve_pub: keypair.pub,
+ reserve_priv: keypair.priv,
+ mint_base_url: canonMint,
+ created: now,
+ last_query: null,
+ current_amount: null,
+ requested_amount: req.amount,
+ confirmed: false,
+ };
- const historyEntry = {
- type: "create-reserve",
- timestamp: now,
- detail: {
- requestedAmount: req.amount,
- reservePub: reserveRecord.reserve_pub,
- }
- };
+ const historyEntry = {
+ type: "create-reserve",
+ timestamp: now,
+ detail: {
+ requestedAmount: req.amount,
+ reservePub: reserveRecord.reserve_pub,
+ }
+ };
- return Query(this.db)
- .put("reserves", reserveRecord)
- .put("history", historyEntry)
- .finish()
- .then(() => {
- let r: CreateReserveResponse = {
- mint: canonMint,
- reservePub: reservePub.toCrock(),
- };
- return r;
- });
+ return Query(this.db)
+ .put("reserves", reserveRecord)
+ .put("history", historyEntry)
+ .finish()
+ .then(() => {
+ let r: CreateReserveResponse = {
+ mint: canonMint,
+ reservePub: keypair.pub,
+ };
+ return r;
+ });
+ });
}
@@ -806,18 +730,19 @@ export class Wallet {
});
}
let r = JSON.parse(resp.responseText);
- let denomSig = native.rsaUnblind(native.RsaSignature.fromCrock(r.ev_sig),
- native.RsaBlindingKey.fromCrock(pc.blindingKey),
- native.RsaPublicKey.fromCrock(pc.denomPub));
- let coin: Coin = {
- coinPub: pc.coinPub,
- coinPriv: pc.coinPriv,
- denomPub: pc.denomPub,
- denomSig: denomSig.encode().toCrock(),
- currentAmount: pc.coinValue,
- mintBaseUrl: pc.mintBaseUrl,
- };
- return coin;
+ return this.cryptoApi.rsaUnblind(r.ev_sig, pc.blindingKey, pc.denomPub)
+ .then((denomSig) => {
+ let coin: Coin = {
+ coinPub: pc.coinPub,
+ coinPriv: pc.coinPriv,
+ denomPub: pc.denomPub,
+ denomSig: denomSig,
+ currentAmount: pc.coinValue,
+ mintBaseUrl: pc.mintBaseUrl,
+ };
+ return coin;
+
+ });
});
}
@@ -965,7 +890,7 @@ export class Wallet {
console.log("using old mint");
}
- return mintInfo.mergeKeys(mintKeysJson, this)
+ return mintInfo.mergeKeys(mintKeysJson, this.cryptoApi)
.then(() => {
return Query(this.db)
.put("mints", mintInfo)