summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2020-12-14 16:44:42 +0100
committerFlorian Dold <florian@dold.me>2020-12-14 16:44:42 +0100
commit12234083ecfe83de79eb2caf29808a0f17188e84 (patch)
tree2e369412845b51173ed0329bb08ee4dcaf48a3c6
parent80a0fab1261fc06f79db4c32fd7a1a6d0cb0db0f (diff)
downloadwallet-core-12234083ecfe83de79eb2caf29808a0f17188e84.tar.gz
wallet-core-12234083ecfe83de79eb2caf29808a0f17188e84.tar.bz2
wallet-core-12234083ecfe83de79eb2caf29808a0f17188e84.zip
derive refresh info from secret seed
-rw-r--r--packages/taler-wallet-core/src/crypto/talerCrypto.ts16
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts24
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts95
-rw-r--r--packages/taler-wallet-core/src/operations/refresh.ts236
-rw-r--r--packages/taler-wallet-core/src/types/cryptoTypes.ts111
-rw-r--r--packages/taler-wallet-core/src/types/dbTypes.ts76
6 files changed, 350 insertions, 208 deletions
diff --git a/packages/taler-wallet-core/src/crypto/talerCrypto.ts b/packages/taler-wallet-core/src/crypto/talerCrypto.ts
index 8713fc965..4faa523a0 100644
--- a/packages/taler-wallet-core/src/crypto/talerCrypto.ts
+++ b/packages/taler-wallet-core/src/crypto/talerCrypto.ts
@@ -389,3 +389,19 @@ export function setupRefreshPlanchet(
coinPub: eddsaGetPublic(coinPriv),
};
}
+
+export function setupRefreshTransferPub(
+ secretSeed: Uint8Array,
+ transferPubIndex: number,
+): EcdheKeyPair {
+ const info = stringToBytes("taler-transfer-pub-derivation");
+ const saltArrBuf = new ArrayBuffer(4);
+ const salt = new Uint8Array(saltArrBuf);
+ const saltDataView = new DataView(saltArrBuf);
+ saltDataView.setUint32(0, transferPubIndex);
+ const out = kdf(32, secretSeed, salt, info);
+ return {
+ ecdhePriv: out,
+ ecdhePub: ecdheGetPublic(out),
+ };
+}
diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts b/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts
index 29f3b02b2..6a4264d2c 100644
--- a/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts
@@ -47,6 +47,10 @@ import {
import * as timer from "../../util/timer";
import { Logger } from "../../util/logging";
+import {
+ DerivedRefreshSession,
+ DeriveRefreshSessionRequest,
+} from "../../types/cryptoTypes";
const logger = new Logger("cryptoApi.ts");
@@ -417,22 +421,10 @@ export class CryptoApi {
return this.doRpc<RecoupRequest>("createRecoupRequest", 1, coin);
}
- createRefreshSession(
- exchangeBaseUrl: string,
- kappa: number,
- meltCoin: CoinRecord,
- newCoinDenoms: DenominationSelectionInfo,
- meltFee: AmountJson,
- ): Promise<RefreshSessionRecord> {
- return this.doRpc<RefreshSessionRecord>(
- "createRefreshSession",
- 4,
- exchangeBaseUrl,
- kappa,
- meltCoin,
- newCoinDenoms,
- meltFee,
- );
+ deriveRefreshSession(
+ req: DeriveRefreshSessionRequest,
+ ): Promise<DerivedRefreshSession> {
+ return this.doRpc<DerivedRefreshSession>("deriveRefreshSession", 4, req);
}
signCoinLink(
diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts b/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts
index e55fa3d7b..d14f663e8 100644
--- a/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts
@@ -63,6 +63,8 @@ import {
keyExchangeEcdheEddsa,
setupRefreshPlanchet,
rsaVerify,
+ getRandomBytes,
+ setupRefreshTransferPub,
} from "../talerCrypto";
import { randomBytes } from "../primitives/nacl-fast";
import { kdf } from "../primitives/kdf";
@@ -73,6 +75,10 @@ import {
} from "../../util/time";
import { Logger } from "../../util/logging";
+import {
+ DerivedRefreshSession,
+ DeriveRefreshSessionRequest,
+} from "../../types/cryptoTypes";
const logger = new Logger("cryptoImplementation.ts");
@@ -375,21 +381,24 @@ export class CryptoImplementation {
return s;
}
- /**
- * Create a new refresh session.
- */
- createRefreshSession(
- exchangeBaseUrl: string,
- kappa: number,
- meltCoin: CoinRecord,
- newCoinDenoms: DenominationSelectionInfo,
- meltFee: AmountJson,
- ): RefreshSessionRecord {
- const currency = newCoinDenoms.selectedDenoms[0].denom.value.currency;
+ deriveRefreshSession(
+ req: DeriveRefreshSessionRequest,
+ ): DerivedRefreshSession {
+ const {
+ newCoinDenoms,
+ feeRefresh: meltFee,
+ kappa,
+ meltCoinDenomPubHash,
+ meltCoinPriv,
+ meltCoinPub,
+ sessionSecretSeed: refreshSessionSecretSeed,
+ } = req;
+
+ const currency = newCoinDenoms[0].value.currency;
let valueWithFee = Amounts.getZero(currency);
- for (const ncd of newCoinDenoms.selectedDenoms) {
- const t = Amounts.add(ncd.denom.value, ncd.denom.feeWithdraw).amount;
+ for (const ncd of newCoinDenoms) {
+ const t = Amounts.add(ncd.value, ncd.feeWithdraw).amount;
valueWithFee = Amounts.add(
valueWithFee,
Amounts.mult(t, ncd.count).amount,
@@ -409,7 +418,10 @@ export class CryptoImplementation {
logger.trace("starting RC computation");
for (let i = 0; i < kappa; i++) {
- const transferKeyPair = createEcdheKeyPair();
+ const transferKeyPair = setupRefreshTransferPub(
+ decodeCrock(refreshSessionSecretSeed),
+ i,
+ );
sessionHc.update(transferKeyPair.ecdhePub);
logger.trace(
`HASH transfer_pub ${encodeCrock(transferKeyPair.ecdhePub)}`,
@@ -418,16 +430,16 @@ export class CryptoImplementation {
transferPubs.push(encodeCrock(transferKeyPair.ecdhePub));
}
- for (const denomSel of newCoinDenoms.selectedDenoms) {
+ for (const denomSel of newCoinDenoms) {
for (let i = 0; i < denomSel.count; i++) {
- const r = decodeCrock(denomSel.denom.denomPub);
+ const r = decodeCrock(denomSel.denomPub);
sessionHc.update(r);
logger.trace(`HASH new_coins ${encodeCrock(r)}`);
}
}
- sessionHc.update(decodeCrock(meltCoin.coinPub));
- logger.trace(`HASH coin_pub ${meltCoin.coinPub}`);
+ sessionHc.update(decodeCrock(meltCoinPub));
+ logger.trace(`HASH coin_pub ${meltCoinPub}`);
sessionHc.update(amountToBuffer(valueWithFee));
logger.trace(
`HASH melt_amount ${encodeCrock(amountToBuffer(valueWithFee))}`,
@@ -435,12 +447,12 @@ export class CryptoImplementation {
for (let i = 0; i < kappa; i++) {
const planchets: RefreshPlanchet[] = [];
- for (let j = 0; j < newCoinDenoms.selectedDenoms.length; j++) {
- const denomSel = newCoinDenoms.selectedDenoms[j];
+ for (let j = 0; j < newCoinDenoms.length; j++) {
+ const denomSel = newCoinDenoms[j];
for (let k = 0; k < denomSel.count; k++) {
const coinNumber = planchets.length;
const transferPriv = decodeCrock(transferPrivs[i]);
- const oldCoinPub = decodeCrock(meltCoin.coinPub);
+ const oldCoinPub = decodeCrock(meltCoinPub);
const transferSecret = keyExchangeEcdheEddsa(
transferPriv,
oldCoinPub,
@@ -450,7 +462,7 @@ export class CryptoImplementation {
const coinPub = fresh.coinPub;
const blindingFactor = fresh.bks;
const pubHash = hash(coinPub);
- const denomPub = decodeCrock(denomSel.denom.denomPub);
+ const denomPub = decodeCrock(denomSel.denomPub);
const ev = rsaBlind(pubHash, blindingFactor, denomPub);
const planchet: RefreshPlanchet = {
blindingKey: encodeCrock(blindingFactor),
@@ -481,49 +493,22 @@ export class CryptoImplementation {
const confirmData = buildSigPS(SignaturePurpose.WALLET_COIN_MELT)
.put(sessionHash)
- .put(decodeCrock(meltCoin.denomPubHash))
+ .put(decodeCrock(meltCoinDenomPubHash))
.put(amountToBuffer(valueWithFee))
.put(amountToBuffer(meltFee))
- .put(decodeCrock(meltCoin.coinPub))
+ .put(decodeCrock(meltCoinPub))
.build();
- const confirmSig = eddsaSign(confirmData, decodeCrock(meltCoin.coinPriv));
-
- let valueOutput = Amounts.getZero(currency);
- for (const denomSel of newCoinDenoms.selectedDenoms) {
- const denom = denomSel.denom;
- for (let i = 0; i < denomSel.count; i++) {
- valueOutput = Amounts.add(valueOutput, denom.value).amount;
- }
- }
-
- const newDenoms: string[] = [];
- const newDenomHashes: string[] = [];
-
- for (const denomSel of newCoinDenoms.selectedDenoms) {
- const denom = denomSel.denom;
- for (let i = 0; i < denomSel.count; i++) {
- newDenoms.push(denom.denomPub);
- newDenomHashes.push(denom.denomPubHash);
- }
- }
+ const confirmSig = eddsaSign(confirmData, decodeCrock(meltCoinPriv));
- const refreshSession: RefreshSessionRecord = {
+ const refreshSession: DerivedRefreshSession = {
confirmSig: encodeCrock(confirmSig),
- exchangeBaseUrl,
hash: encodeCrock(sessionHash),
- meltCoinPub: meltCoin.coinPub,
- newDenomHashes,
- newDenoms,
- norevealIndex: undefined,
+ meltCoinPub: meltCoinPub,
planchetsForGammas: planchetsForGammas,
transferPrivs,
transferPubs,
- amountRefreshOutput: valueOutput,
- amountRefreshInput: valueWithFee,
- timestampCreated: getTimestampNow(),
- finishedTimestamp: undefined,
- lastError: undefined,
+ meltValueWithFee: valueWithFee,
};
return refreshSession;
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts
index 21c884d48..16b691ec8 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -60,6 +60,8 @@ import {
import { URL } from "../util/url";
import { checkDbInvariant } from "../util/invariants";
import { initRetryInfo, updateRetryInfoTimeout } from "../util/retries";
+import { WALLET_EXCHANGE_PROTOCOL_VERSION } from "./versions";
+import { RefreshNewDenomInfo } from "../types/cryptoTypes";
const logger = new Logger("refresh.ts");
@@ -182,13 +184,7 @@ async function refreshCreateSession(
return;
}
- const refreshSession: RefreshSessionRecord = await ws.cryptoApi.createRefreshSession(
- exchange.baseUrl,
- 3,
- coin,
- newCoinDenoms,
- oldDenom.feeRefresh,
- );
+ const sessionSecretSeed = encodeCrock(getRandomBytes(64));
// Store refresh session for this coin in the database.
await ws.db.runWithWriteTransaction(
@@ -201,7 +197,15 @@ async function refreshCreateSession(
if (rg.refreshSessionPerCoin[coinIndex]) {
return;
}
- rg.refreshSessionPerCoin[coinIndex] = refreshSession;
+ rg.refreshSessionPerCoin[coinIndex] = {
+ norevealIndex: undefined,
+ sessionSecretSeed: sessionSecretSeed,
+ newDenoms: newCoinDenoms.selectedDenoms.map((x) => ({
+ count: x.count,
+ denomPubHash: x.denom.denomPubHash,
+ })),
+ amountRefreshOutput: newCoinDenoms.totalCoinValue,
+ };
await tx.put(Stores.refreshGroups, rg);
},
);
@@ -232,24 +236,57 @@ async function refreshMelt(
return;
}
- const coin = await ws.db.get(Stores.coins, refreshSession.meltCoinPub);
+ const oldCoin = await ws.db.get(
+ Stores.coins,
+ refreshGroup.oldCoinPubs[coinIndex],
+ );
+ checkDbInvariant(!!oldCoin, "melt coin doesn't exist");
+ const oldDenom = await ws.db.get(Stores.denominations, [
+ oldCoin.exchangeBaseUrl,
+ oldCoin.denomPubHash,
+ ]);
+ checkDbInvariant(!!oldDenom, "denomination for melted coin doesn't exist");
- if (!coin) {
- console.error("can't melt coin, it does not exist");
- return;
+ const newCoinDenoms: RefreshNewDenomInfo[] = [];
+
+ for (const dh of refreshSession.newDenoms) {
+ const newDenom = await ws.db.get(Stores.denominations, [
+ oldCoin.exchangeBaseUrl,
+ dh.denomPubHash,
+ ]);
+ checkDbInvariant(
+ !!newDenom,
+ "new denomination for refresh not in database",
+ );
+ newCoinDenoms.push({
+ count: dh.count,
+ denomPub: newDenom.denomPub,
+ feeWithdraw: newDenom.feeWithdraw,
+ value: newDenom.value,
+ });
}
+ const derived = await ws.cryptoApi.deriveRefreshSession({
+ kappa: 3,
+ meltCoinDenomPubHash: oldCoin.denomPubHash,
+ meltCoinPriv: oldCoin.coinPriv,
+ meltCoinPub: oldCoin.coinPub,
+ feeRefresh: oldDenom.feeRefresh,
+ newCoinDenoms,
+ sessionSecretSeed: refreshSession.sessionSecretSeed,
+ });
+
const reqUrl = new URL(
- `coins/${coin.coinPub}/melt`,
- refreshSession.exchangeBaseUrl,
+ `coins/${oldCoin.coinPub}/melt`,
+ oldCoin.exchangeBaseUrl,
);
const meltReq = {
- coin_pub: coin.coinPub,
- confirm_sig: refreshSession.confirmSig,
- denom_pub_hash: coin.denomPubHash,
- denom_sig: coin.denomSig,
- rc: refreshSession.hash,
- value_with_fee: Amounts.stringify(refreshSession.amountRefreshInput),
+ coin_pub: oldCoin.coinPub,
+ confirm_sig: derived.confirmSig,
+ denom_pub_hash: oldCoin.denomPubHash,
+ denom_sig: oldCoin.denomSig,
+ rc: derived.hash,
+ value_with_fee: Amounts.stringify(derived.meltValueWithFee),
};
logger.trace(`melt request for coin:`, meltReq);
@@ -270,13 +307,13 @@ async function refreshMelt(
await ws.db.mutate(Stores.refreshGroups, refreshGroupId, (rg) => {
const rs = rg.refreshSessionPerCoin[coinIndex];
- if (!rs) {
+ if (rg.timestampFinished) {
return;
}
- if (rs.norevealIndex !== undefined) {
+ if (!rs) {
return;
}
- if (rs.finishedTimestamp) {
+ if (rs.norevealIndex !== undefined) {
return;
}
rs.norevealIndex = norevealIndex;
@@ -305,48 +342,95 @@ async function refreshReveal(
if (norevealIndex === undefined) {
throw Error("can't reveal without melting first");
}
- const privs = Array.from(refreshSession.transferPrivs);
+
+ const oldCoin = await ws.db.get(
+ Stores.coins,
+ refreshGroup.oldCoinPubs[coinIndex],
+ );
+ checkDbInvariant(!!oldCoin, "melt coin doesn't exist");
+ const oldDenom = await ws.db.get(Stores.denominations, [
+ oldCoin.exchangeBaseUrl,
+ oldCoin.denomPubHash,
+ ]);
+ checkDbInvariant(!!oldDenom, "denomination for melted coin doesn't exist");
+
+ const newCoinDenoms: RefreshNewDenomInfo[] = [];
+
+ for (const dh of refreshSession.newDenoms) {
+ const newDenom = await ws.db.get(Stores.denominations, [
+ oldCoin.exchangeBaseUrl,
+ dh.denomPubHash,
+ ]);
+ checkDbInvariant(
+ !!newDenom,
+ "new denomination for refresh not in database",
+ );
+ newCoinDenoms.push({
+ count: dh.count,
+ denomPub: newDenom.denomPub,
+ feeWithdraw: newDenom.feeWithdraw,
+ value: newDenom.value,
+ });
+ }
+
+ const derived = await ws.cryptoApi.deriveRefreshSession({
+ kappa: 3,
+ meltCoinDenomPubHash: oldCoin.denomPubHash,
+ meltCoinPriv: oldCoin.coinPriv,
+ meltCoinPub: oldCoin.coinPub,
+ feeRefresh: oldDenom.feeRefresh,
+ newCoinDenoms,
+ sessionSecretSeed: refreshSession.sessionSecretSeed,
+ });
+
+ const privs = Array.from(derived.transferPrivs);
privs.splice(norevealIndex, 1);
- const planchets = refreshSession.planchetsForGammas[norevealIndex];
+ const planchets = derived.planchetsForGammas[norevealIndex];
if (!planchets) {
throw Error("refresh index error");
}
const meltCoinRecord = await ws.db.get(
Stores.coins,
- refreshSession.meltCoinPub,
+ refreshGroup.oldCoinPubs[coinIndex],
);
if (!meltCoinRecord) {
throw Error("inconsistent database");
}
const evs = planchets.map((x: RefreshPlanchet) => x.coinEv);
-
+ const newDenomsFlat: string[] = [];
const linkSigs: string[] = [];
+
for (let i = 0; i < refreshSession.newDenoms.length; i++) {
- const linkSig = await ws.cryptoApi.signCoinLink(
- meltCoinRecord.coinPriv,
- refreshSession.newDenomHashes[i],
- refreshSession.meltCoinPub,
- refreshSession.transferPubs[norevealIndex],
- planchets[i].coinEv,
- );
- linkSigs.push(linkSig);
+ const dsel = refreshSession.newDenoms[i];
+ for (let j = 0; j < dsel.count; j++) {
+ const newCoinIndex = linkSigs.length;
+ const linkSig = await ws.cryptoApi.signCoinLink(
+ meltCoinRecord.coinPriv,
+ dsel.denomPubHash,
+ meltCoinRecord.coinPub,
+ derived.transferPubs[norevealIndex],
+ planchets[newCoinIndex].coinEv,
+ );
+ linkSigs.push(linkSig);
+ newDenomsFlat.push(dsel.denomPubHash);
+ }
}
const req = {
coin_evs: evs,
- new_denoms_h: refreshSession.newDenomHashes,
- rc: refreshSession.hash,
+ new_denoms_h: newDenomsFlat,
+ rc: derived.hash,
transfer_privs: privs,
- transfer_pub: refreshSession.transferPubs[norevealIndex],
+ transfer_pub: derived.transferPubs[norevealIndex],
link_sigs: linkSigs,
};
const reqUrl = new URL(
- `refreshes/${refreshSession.hash}/reveal`,
- refreshSession.exchangeBaseUrl,
+ `refreshes/${derived.hash}/reveal`,
+ oldCoin.exchangeBaseUrl,
);
const resp = await ws.runSequentialized([EXCHANGE_COINS_LOCK], async () => {
@@ -362,39 +446,42 @@ async function refreshReveal(
const coins: CoinRecord[] = [];
- for (let i = 0; i < reveal.ev_sigs.length; i++) {
- const denom = await ws.db.get(Stores.denominations, [
- refreshSession.exchangeBaseUrl,
- refreshSession.newDenomHashes[i],
- ]);
- if (!denom) {
- console.error("denom not found");
- continue;
+ for (let i = 0; i < refreshSession.newDenoms.length; i++) {
+ for (let j = 0; j < refreshSession.newDenoms[i].count; j++) {
+ const newCoinIndex = coins.length;
+ const denom = await ws.db.get(Stores.denominations, [
+ oldCoin.exchangeBaseUrl,
+ refreshSession.newDenoms[i].denomPubHash,
+ ]);
+ if (!denom) {
+ console.error("denom not found");
+ continue;
+ }
+ const pc = derived.planchetsForGammas[norevealIndex][newCoinIndex];
+ const denomSig = await ws.cryptoApi.rsaUnblind(
+ reveal.ev_sigs[newCoinIndex].ev_sig,
+ pc.blindingKey,
+ denom.denomPub,
+ );
+ const coin: CoinRecord = {
+ blindingKey: pc.blindingKey,
+ coinPriv: pc.privateKey,
+ coinPub: pc.publicKey,
+ currentAmount: denom.value,
+ denomPub: denom.denomPub,
+ denomPubHash: denom.denomPubHash,
+ denomSig,
+ exchangeBaseUrl: oldCoin.exchangeBaseUrl,
+ status: CoinStatus.Fresh,
+ coinSource: {
+ type: CoinSourceType.Refresh,
+ oldCoinPub: refreshGroup.oldCoinPubs[coinIndex],
+ },
+ suspended: false,
+ };
+
+ coins.push(coin);
}
- const pc = refreshSession.planchetsForGammas[norevealIndex][i];
- const denomSig = await ws.cryptoApi.rsaUnblind(
- reveal.ev_sigs[i].ev_sig,
- pc.blindingKey,
- denom.denomPub,
- );
- const coin: CoinRecord = {
- blindingKey: pc.blindingKey,
- coinPriv: pc.privateKey,
- coinPub: pc.publicKey,
- currentAmount: denom.value,
- denomPub: denom.denomPub,
- denomPubHash: denom.denomPubHash,
- denomSig,
- exchangeBaseUrl: refreshSession.exchangeBaseUrl,
- status: CoinStatus.Fresh,
- coinSource: {
- type: CoinSourceType.Refresh,
- oldCoinPub: refreshSession.meltCoinPub,
- },
- suspended: false,
- };
-
- coins.push(coin);
}
await ws.db.runWithWriteTransaction(
@@ -409,11 +496,6 @@ async function refreshReveal(
if (!rs) {
return;
}
- if (rs.finishedTimestamp) {
- logger.warn("refresh session already finished");
- return;
- }
- rs.finishedTimestamp = getTimestampNow();
rg.finishedPerCoin[coinIndex] = true;
let allDone = true;
for (const f of rg.finishedPerCoin) {
diff --git a/packages/taler-wallet-core/src/types/cryptoTypes.ts b/packages/taler-wallet-core/src/types/cryptoTypes.ts
new file mode 100644
index 000000000..a7f51ab52
--- /dev/null
+++ b/packages/taler-wallet-core/src/types/cryptoTypes.ts
@@ -0,0 +1,111 @@
+/*
+ This file is part of GNU Taler
+ (C) 2020 Taler Systems SA
+
+ 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.
+
+ 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
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Types used by the wallet crypto worker.
+ *
+ * These types are defined in a separate file make tree shaking easier, since
+ * some components use these types (via RPC) but do not depend on the wallet
+ * code directly.
+ *
+ * @author Florian Dold <dold@taler.net>
+ */
+
+/**
+ * Imports.
+ */
+import { AmountJson } from "../util/amounts";
+
+export interface RefreshNewDenomInfo {
+ count: number;
+ value: AmountJson;
+ feeWithdraw: AmountJson;
+ denomPub: string;
+}
+
+/**
+ * Request to derive a refresh session from the refresh session
+ * secret seed.
+ */
+export interface DeriveRefreshSessionRequest {
+ sessionSecretSeed: string;
+ kappa: number;
+ meltCoinPub: string;
+ meltCoinPriv: string;
+ meltCoinDenomPubHash: string;
+ newCoinDenoms: RefreshNewDenomInfo[];
+ feeRefresh: AmountJson;
+}
+
+/**
+ *
+ */
+export interface DerivedRefreshSession {
+ /**
+ * Public key that's being melted in this session.
+ */
+ meltCoinPub: string;
+
+ /**
+ * Signature to confirm the melting.
+ */
+ confirmSig: string;
+
+ /**
+ * Planchets for each cut-and-choose instance.
+ */
+ planchetsForGammas: {
+ /**
+ * Public key for the coin.
+ */
+ publicKey: string;
+
+ /**
+ * Private key for the coin.
+ */
+ privateKey: string;
+
+ /**
+ * Blinded public key.
+ */
+ coinEv: string;
+
+ /**
+ * Blinding key used.
+ */
+ blindingKey: string;
+ }[][];
+
+ /**
+ * The transfer keys, kappa of them.
+ */
+ transferPubs: string[];
+
+ /**
+ * Private keys for the transfer public keys.
+ */
+ transferPrivs: string[];
+
+ /**
+ * Hash of the session.
+ */
+ hash: string;
+
+ /**
+ * Exact value that is being melted.
+ */
+ meltValueWithFee: AmountJson;
+}
diff --git a/packages/taler-wallet-core/src/types/dbTypes.ts b/packages/taler-wallet-core/src/types/dbTypes.ts
index a4f14ff0c..18a1102b4 100644
--- a/packages/taler-wallet-core/src/types/dbTypes.ts
+++ b/packages/taler-wallet-core/src/types/dbTypes.ts
@@ -557,7 +557,7 @@ export interface ExchangeRecord {
/**
* Terms of service text or undefined if not downloaded yet.
- *
+ *
* This is just used as a cache of the last downloaded ToS.
*/
termsOfServiceText: string | undefined;
@@ -664,14 +664,17 @@ export interface RefreshPlanchet {
* Public key for the coin.
*/
publicKey: string;
+
/**
* Private key for the coin.
*/
privateKey: string;
+
/**
* Blinded public key.
*/
coinEv: string;
+
/**
* Blinding key used.
*/
@@ -991,18 +994,14 @@ export interface RefreshGroupRecord {
* Ongoing refresh
*/
export interface RefreshSessionRecord {
- lastError: TalerErrorDetails | undefined;
-
/**
- * Public key that's being melted in this session.
- */
- meltCoinPub: string;
-
- /**
- * How much of the coin's value is melted away
- * with this refresh session?
+ * 512-bit secret that can be used to derive
+ * the other cryptographic material for the refresh session.
+ *
+ * FIXME: We currently store the derived material, but
+ * should always derive it.
*/
- amountRefreshInput: AmountJson;
+ sessionSecretSeed: string;
/**
* Sum of the value of denominations we want
@@ -1011,59 +1010,17 @@ export interface RefreshSessionRecord {
amountRefreshOutput: AmountJson;
/**
- * Signature to confirm the melting.
+ * Hashed denominations of the newly requested coins.
*/
- confirmSig: string;
-
- /**
- * Hased denominations of the newly requested coins.
- */
- newDenomHashes: string[];
-
- /**
- * Denominations of the newly requested coins.
- */
- newDenoms: string[];
-
- /**
- * Planchets for each cut-and-choose instance.
- */
- planchetsForGammas: RefreshPlanchet[][];
-
- /**
- * The transfer keys, kappa of them.
- */
- transferPubs: string[];
-
- /**
- * Private keys for the transfer public keys.
- */
- transferPrivs: string[];
+ newDenoms: {
+ denomPubHash: string;
+ count: number;
+ }[];
/**
* The no-reveal-index after we've done the melting.
*/
norevealIndex?: number;
-
- /**
- * Hash of the session.
- */
- hash: string;
-
- /**
- * Timestamp when the refresh session finished.
- */
- finishedTimestamp: Timestamp | undefined;
-
- /**
- * When has this refresh session been created?
- */
- timestampCreated: Timestamp;
-
- /**
- * Base URL for the exchange we're doing the refresh with.
- */
- exchangeBaseUrl: string;
}
/**
@@ -1602,7 +1559,7 @@ class PurchasesStore extends Store<"purchases", PurchaseRecord> {
string,
PurchaseRecord
>(this, "fulfillmentUrlIndex", "contractData.fulfillmentUrl");
-
+
orderIdIndex = new Index<"purchases", "orderIdIndex", string, PurchaseRecord>(
this,
"orderIdIndex",
@@ -1712,7 +1669,6 @@ class BankWithdrawUrisStore extends Store<
}
}
-
/**
*/
class BackupProvidersStore extends Store<