From 12234083ecfe83de79eb2caf29808a0f17188e84 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Mon, 14 Dec 2020 16:44:42 +0100 Subject: [PATCH] derive refresh info from secret seed --- .../src/crypto/talerCrypto.ts | 16 ++ .../src/crypto/workers/cryptoApi.ts | 24 +- .../crypto/workers/cryptoImplementation.ts | 95 +++---- .../src/operations/refresh.ts | 236 ++++++++++++------ .../src/types/cryptoTypes.ts | 111 ++++++++ .../taler-wallet-core/src/types/dbTypes.ts | 76 ++---- 6 files changed, 350 insertions(+), 208 deletions(-) create mode 100644 packages/taler-wallet-core/src/types/cryptoTypes.ts 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("createRecoupRequest", 1, coin); } - createRefreshSession( - exchangeBaseUrl: string, - kappa: number, - meltCoin: CoinRecord, - newCoinDenoms: DenominationSelectionInfo, - meltFee: AmountJson, - ): Promise { - return this.doRpc( - "createRefreshSession", - 4, - exchangeBaseUrl, - kappa, - meltCoin, - newCoinDenoms, - meltFee, - ); + deriveRefreshSession( + req: DeriveRefreshSessionRequest, + ): Promise { + return this.doRpc("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)); + const confirmSig = eddsaSign(confirmData, decodeCrock(meltCoinPriv)); - 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 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,15 +307,15 @@ async function refreshMelt( await ws.db.mutate(Stores.refreshGroups, refreshGroupId, (rg) => { const rs = rg.refreshSessionPerCoin[coinIndex]; + if (rg.timestampFinished) { + return; + } if (!rs) { return; } if (rs.norevealIndex !== undefined) { return; } - if (rs.finishedTimestamp) { - return; - } rs.norevealIndex = norevealIndex; return rg; }); @@ -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; - } - 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, - }; + 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); + 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 + */ + +/** + * 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 + */ + +/** + * 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. + * 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. */ - meltCoinPub: string; - - /** - * How much of the coin's value is melted away - * with this refresh session? - */ - 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<