wallet-core: towards exchange protocol v12

This commit is contained in:
Florian Dold 2022-01-05 20:29:55 +01:00
parent 188ff0b453
commit a7b89247e4
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
6 changed files with 86 additions and 21 deletions

View File

@ -1620,3 +1620,9 @@ export const codecForMerchantConfigResponse = (): Codec<MerchantConfigResponse>
.property("name", codecForString()) .property("name", codecForString())
.property("version", codecForString()) .property("version", codecForString())
.build("MerchantConfigResponse"); .build("MerchantConfigResponse");
export enum ExchangeProtocolVersion {
V9 = 9,
V12 = 12,
}

View File

@ -4,7 +4,8 @@ import nodeResolve from "@rollup/plugin-node-resolve";
import json from "@rollup/plugin-json"; import json from "@rollup/plugin-json";
import builtins from "builtin-modules"; import builtins from "builtin-modules";
import pkg from "./package.json"; import pkg from "./package.json";
import sourcemaps from 'rollup-plugin-sourcemaps'; import sourcemaps from "rollup-plugin-sourcemaps";
import path from "path";
export default { export default {
input: "lib/index.js", input: "lib/index.js",
@ -12,6 +13,15 @@ export default {
file: pkg.main, file: pkg.main,
format: "cjs", format: "cjs",
sourcemap: true, sourcemap: true,
sourcemapPathTransform: (relativeSourcePath, sourcemapPath) => {
// Transform to source map paths to virtual path. Otherwise,
// error messages would contain paths that look like they should exist (relative to
// the bundle) but don't.
const res = path.normalize(
path.join("/_walletsrc/packages/taler-wallet-cli/src/", relativeSourcePath),
);
return res;
},
}, },
external: builtins, external: builtins,
plugins: [ plugins: [
@ -29,5 +39,4 @@ export default {
json(), json(),
], ],
} };

View File

@ -27,7 +27,7 @@
/** /**
* Imports. * Imports.
*/ */
import { AmountJson, DenominationPubKey } from "@gnu-taler/taler-util"; import { AmountJson, DenominationPubKey, ExchangeProtocolVersion } from "@gnu-taler/taler-util";
export interface RefreshNewDenomInfo { export interface RefreshNewDenomInfo {
count: number; count: number;
@ -41,6 +41,7 @@ export interface RefreshNewDenomInfo {
* secret seed. * secret seed.
*/ */
export interface DeriveRefreshSessionRequest { export interface DeriveRefreshSessionRequest {
exchangeProtocolVersion: ExchangeProtocolVersion;
sessionSecretSeed: string; sessionSecretSeed: string;
kappa: number; kappa: number;
meltCoinPub: string; meltCoinPub: string;

View File

@ -36,6 +36,7 @@ import {
buildSigPS, buildSigPS,
CoinDepositPermission, CoinDepositPermission,
DenomKeyType, DenomKeyType,
ExchangeProtocolVersion,
FreshCoin, FreshCoin,
hashDenomPub, hashDenomPub,
RecoupRequest, RecoupRequest,
@ -162,7 +163,7 @@ async function myEddsaSign(
export class CryptoImplementation { export class CryptoImplementation {
static enableTracing = false; static enableTracing = false;
constructor(private primitiveWorker?: PrimitiveWorker) { } constructor(private primitiveWorker?: PrimitiveWorker) {}
/** /**
* Create a pre-coin of the given denomination to be withdrawn from then given * Create a pre-coin of the given denomination to be withdrawn from then given
@ -364,18 +365,18 @@ export class CryptoImplementation {
} }
isValidWireAccount( isValidWireAccount(
versionCurrent: number, versionCurrent: ExchangeProtocolVersion,
paytoUri: string, paytoUri: string,
sig: string, sig: string,
masterPub: string, masterPub: string,
): boolean { ): boolean {
if (versionCurrent === 10 || versionCurrent === 11) { if (versionCurrent === ExchangeProtocolVersion.V12) {
const paytoHash = hash(stringToBytes(paytoUri + "\0")); const paytoHash = hash(stringToBytes(paytoUri + "\0"));
const p = buildSigPS(TalerSignaturePurpose.MASTER_WIRE_DETAILS) const p = buildSigPS(TalerSignaturePurpose.MASTER_WIRE_DETAILS)
.put(paytoHash) .put(paytoHash)
.build(); .build();
return eddsaVerify(p, decodeCrock(sig), decodeCrock(masterPub)); return eddsaVerify(p, decodeCrock(sig), decodeCrock(masterPub));
} else if (versionCurrent === 9) { } else if (versionCurrent === ExchangeProtocolVersion.V9) {
const h = kdf( const h = kdf(
64, 64,
stringToBytes("exchange-wire-signature"), stringToBytes("exchange-wire-signature"),
@ -623,13 +624,27 @@ export class CryptoImplementation {
} }
const sessionHash = sessionHc.finish(); const sessionHash = sessionHc.finish();
const confirmData = buildSigPS(TalerSignaturePurpose.WALLET_COIN_MELT) let confirmData: Uint8Array;
.put(sessionHash) if (req.exchangeProtocolVersion === ExchangeProtocolVersion.V9) {
.put(decodeCrock(meltCoinDenomPubHash)) confirmData = buildSigPS(TalerSignaturePurpose.WALLET_COIN_MELT)
.put(amountToBuffer(valueWithFee)) .put(sessionHash)
.put(amountToBuffer(meltFee)) .put(decodeCrock(meltCoinDenomPubHash))
.put(decodeCrock(meltCoinPub)) .put(amountToBuffer(valueWithFee))
.build(); .put(amountToBuffer(meltFee))
.put(decodeCrock(meltCoinPub))
.build();
} else if (req.exchangeProtocolVersion === ExchangeProtocolVersion.V12) {
confirmData = buildSigPS(TalerSignaturePurpose.WALLET_COIN_MELT)
.put(sessionHash)
.put(decodeCrock(meltCoinDenomPubHash))
.put(amountToBuffer(valueWithFee))
.put(amountToBuffer(meltFee))
.build();
} else {
throw Error(
`Exchange protocol version (${req.exchangeProtocolVersion}) not supported`,
);
}
const confirmSigResp = await myEddsaSign(this.primitiveWorker, { const confirmSigResp = await myEddsaSign(this.primitiveWorker, {
msg: encodeCrock(confirmData), msg: encodeCrock(confirmData),

View File

@ -17,6 +17,7 @@
import { import {
DenomKeyType, DenomKeyType,
encodeCrock, encodeCrock,
ExchangeProtocolVersion,
getRandomBytes, getRandomBytes,
HttpStatusCode, HttpStatusCode,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
@ -91,8 +92,10 @@ export function getTotalRefreshCost(
refreshedDenom: DenominationRecord, refreshedDenom: DenominationRecord,
amountLeft: AmountJson, amountLeft: AmountJson,
): AmountJson { ): AmountJson {
const withdrawAmount = Amounts.sub(amountLeft, refreshedDenom.feeRefresh) const withdrawAmount = Amounts.sub(
.amount; amountLeft,
refreshedDenom.feeRefresh,
).amount;
const withdrawDenoms = selectWithdrawalDenominations(withdrawAmount, denoms); const withdrawDenoms = selectWithdrawalDenominations(withdrawAmount, denoms);
const resultingAmount = Amounts.add( const resultingAmount = Amounts.add(
Amounts.getZero(withdrawAmount.currency), Amounts.getZero(withdrawAmount.currency),
@ -198,9 +201,10 @@ async function refreshCreateSession(
} }
// FIXME: use an index here, based on the withdrawal expiration time. // FIXME: use an index here, based on the withdrawal expiration time.
const availableDenoms: DenominationRecord[] = await tx.denominations.indexes.byExchangeBaseUrl const availableDenoms: DenominationRecord[] =
.iter(exchange.baseUrl) await tx.denominations.indexes.byExchangeBaseUrl
.toArray(); .iter(exchange.baseUrl)
.toArray();
const availableAmount = Amounts.sub( const availableAmount = Amounts.sub(
refreshGroup.inputPerCoin[coinIndex], refreshGroup.inputPerCoin[coinIndex],
@ -351,7 +355,22 @@ async function refreshMelt(
const { newCoinDenoms, oldCoin, oldDenom, refreshGroup, refreshSession } = d; const { newCoinDenoms, oldCoin, oldDenom, refreshGroup, refreshSession } = d;
let exchangeProtocolVersion: ExchangeProtocolVersion;
switch (d.oldDenom.denomPub.cipher) {
case DenomKeyType.LegacyRsa: {
exchangeProtocolVersion = ExchangeProtocolVersion.V9;
break;
}
case DenomKeyType.Rsa: {
exchangeProtocolVersion = ExchangeProtocolVersion.V12;
break;
}
default:
throw Error("unsupported key type");
}
const derived = await ws.cryptoApi.deriveRefreshSession({ const derived = await ws.cryptoApi.deriveRefreshSession({
exchangeProtocolVersion,
kappa: 3, kappa: 3,
meltCoinDenomPubHash: oldCoin.denomPubHash, meltCoinDenomPubHash: oldCoin.denomPubHash,
meltCoinPriv: oldCoin.coinPriv, meltCoinPriv: oldCoin.coinPriv,
@ -531,7 +550,22 @@ async function refreshReveal(
norevealIndex, norevealIndex,
} = d; } = d;
let exchangeProtocolVersion: ExchangeProtocolVersion;
switch (d.oldDenom.denomPub.cipher) {
case DenomKeyType.LegacyRsa: {
exchangeProtocolVersion = ExchangeProtocolVersion.V9;
break;
}
case DenomKeyType.Rsa: {
exchangeProtocolVersion = ExchangeProtocolVersion.V12;
break;
}
default:
throw Error("unsupported key type");
}
const derived = await ws.cryptoApi.deriveRefreshSession({ const derived = await ws.cryptoApi.deriveRefreshSession({
exchangeProtocolVersion,
kappa: 3, kappa: 3,
meltCoinDenomPubHash: oldCoin.denomPubHash, meltCoinDenomPubHash: oldCoin.denomPubHash,
meltCoinPriv: oldCoin.coinPriv, meltCoinPriv: oldCoin.coinPriv,

View File

@ -19,7 +19,7 @@
* *
* Uses libtool's current:revision:age versioning. * Uses libtool's current:revision:age versioning.
*/ */
export const WALLET_EXCHANGE_PROTOCOL_VERSION = "10:0:1"; export const WALLET_EXCHANGE_PROTOCOL_VERSION = "12:0:0";
/** /**
* Protocol version spoken with the merchant. * Protocol version spoken with the merchant.