summaryrefslogtreecommitdiff
path: root/packages/taler-util
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2021-11-17 10:23:22 +0100
committerFlorian Dold <florian@dold.me>2021-11-17 10:23:30 +0100
commit9f0429cb2f8ad9cb2e98a787139602d913c1aefa (patch)
treecda55e2d07a291dd2ff6f243bb423121ecf220b3 /packages/taler-util
parenta994009d2f094c4d9c12da68dac3abb28bdef4b3 (diff)
downloadwallet-core-9f0429cb2f8ad9cb2e98a787139602d913c1aefa.tar.gz
wallet-core-9f0429cb2f8ad9cb2e98a787139602d913c1aefa.tar.bz2
wallet-core-9f0429cb2f8ad9cb2e98a787139602d913c1aefa.zip
wallet: implement exchange protocol v9
Diffstat (limited to 'packages/taler-util')
-rw-r--r--packages/taler-util/src/backupTypes.ts5
-rw-r--r--packages/taler-util/src/helpers.ts11
-rw-r--r--packages/taler-util/src/talerCrypto.ts15
-rw-r--r--packages/taler-util/src/talerTypes.ts77
-rw-r--r--packages/taler-util/src/walletTypes.ts8
5 files changed, 96 insertions, 20 deletions
diff --git a/packages/taler-util/src/backupTypes.ts b/packages/taler-util/src/backupTypes.ts
index 70e52e63b..ecdd6fdf8 100644
--- a/packages/taler-util/src/backupTypes.ts
+++ b/packages/taler-util/src/backupTypes.ts
@@ -53,6 +53,7 @@
/**
* Imports.
*/
+import { DenominationPubKey, UnblindedSignature } from "./talerTypes.js";
import { Duration, Timestamp } from "./time.js";
/**
@@ -440,7 +441,7 @@ export interface BackupCoin {
/**
* Unblinded signature by the exchange.
*/
- denom_sig: string;
+ denom_sig: UnblindedSignature;
/**
* Amount that's left on the coin.
@@ -831,7 +832,7 @@ export interface BackupDenomination {
/**
* The denomination public key.
*/
- denom_pub: string;
+ denom_pub: DenominationPubKey;
/**
* Fee for withdrawing.
diff --git a/packages/taler-util/src/helpers.ts b/packages/taler-util/src/helpers.ts
index 089602c9d..6c836c482 100644
--- a/packages/taler-util/src/helpers.ts
+++ b/packages/taler-util/src/helpers.ts
@@ -94,7 +94,7 @@ export function canonicalJson(obj: any): string {
/**
* Lexically compare two strings.
*/
-export function strcmp(s1: string, s2: string): number {
+export function strcmp(s1: string, s2: string): -1 | 0 | 1 {
if (s1 < s2) {
return -1;
}
@@ -113,15 +113,14 @@ export function j2s(x: any): string {
/**
* Use this to filter null or undefined from an array in a type-safe fashion
- *
+ *
* example:
* const array: Array<T | undefined> = [undefined, null]
* const filtered: Array<T> = array.filter(notEmpty)
- *
- * @param value
- * @returns
+ *
+ * @param value
+ * @returns
*/
export function notEmpty<T>(value: T | null | undefined): value is T {
return value !== null && value !== undefined;
}
-
diff --git a/packages/taler-util/src/talerCrypto.ts b/packages/taler-util/src/talerCrypto.ts
index d8ac75dc0..b107786cd 100644
--- a/packages/taler-util/src/talerCrypto.ts
+++ b/packages/taler-util/src/talerCrypto.ts
@@ -24,6 +24,7 @@
import * as nacl from "./nacl-fast.js";
import { kdf } from "./kdf.js";
import bigint from "big-integer";
+import { DenominationPubKey } from "./talerTypes.js";
export function getRandomBytes(n: number): Uint8Array {
return nacl.randomBytes(n);
@@ -348,6 +349,20 @@ export function hash(d: Uint8Array): Uint8Array {
return nacl.hash(d);
}
+export function hashDenomPub(pub: DenominationPubKey): Uint8Array {
+ if (pub.cipher !== 1) {
+ throw Error("unsupported cipher");
+ }
+ const pubBuf = decodeCrock(pub.rsa_public_key);
+ const hashInputBuf = new ArrayBuffer(pubBuf.length + 4 + 4);
+ const uint8ArrayBuf = new Uint8Array(hashInputBuf);
+ const dv = new DataView(hashInputBuf);
+ dv.setUint32(0, pub.age_mask ?? 0);
+ dv.setUint32(4, pub.cipher);
+ uint8ArrayBuf.set(pubBuf, 8);
+ return nacl.hash(uint8ArrayBuf);
+}
+
export function eddsaSign(msg: Uint8Array, eddsaPriv: Uint8Array): Uint8Array {
const pair = nacl.crypto_sign_keyPair_fromSeed(eddsaPriv);
return nacl.sign_detached(msg, pair.secretKey);
diff --git a/packages/taler-util/src/talerTypes.ts b/packages/taler-util/src/talerTypes.ts
index 56110ec1e..04d700483 100644
--- a/packages/taler-util/src/talerTypes.ts
+++ b/packages/taler-util/src/talerTypes.ts
@@ -59,7 +59,7 @@ export class Denomination {
/**
* Public signing key of the denomination.
*/
- denom_pub: string;
+ denom_pub: DenominationPubKey;
/**
* Fee for withdrawing.
@@ -158,7 +158,7 @@ export interface RecoupRequest {
/**
* Signature over the coin public key by the denomination.
*/
- denom_sig: string;
+ denom_sig: UnblindedSignature;
/**
* Coin public key of the coin we want to refund.
@@ -198,6 +198,11 @@ export interface RecoupConfirmation {
old_coin_pub?: string;
}
+export interface UnblindedSignature {
+ cipher: DenomKeyType.Rsa;
+ rsa_signature: string;
+}
+
/**
* Deposit permission for a single coin.
*/
@@ -213,7 +218,7 @@ export interface CoinDepositPermission {
/**
* Signature made by the denomination public key.
*/
- ub_sig: string;
+ ub_sig: UnblindedSignature;
/**
* The denomination public key associated with this coin.
*/
@@ -779,8 +784,38 @@ export class TipPickupGetResponse {
expiration: Timestamp;
}
+export enum DenomKeyType {
+ Rsa = 1,
+ ClauseSchnorr = 2,
+}
+
+export interface RsaBlindedDenominationSignature {
+ cipher: DenomKeyType.Rsa;
+ blinded_rsa_signature: string;
+}
+
+export interface CSBlindedDenominationSignature {
+ cipher: DenomKeyType.ClauseSchnorr;
+}
+
+export type BlindedDenominationSignature =
+ | RsaBlindedDenominationSignature
+ | CSBlindedDenominationSignature;
+
+export const codecForBlindedDenominationSignature = () =>
+ buildCodecForUnion<BlindedDenominationSignature>()
+ .discriminateOn("cipher")
+ .alternative(1, codecForRsaBlindedDenominationSignature())
+ .build("BlindedDenominationSignature");
+
+export const codecForRsaBlindedDenominationSignature = () =>
+ buildCodecForObject<RsaBlindedDenominationSignature>()
+ .property("cipher", codecForConstNumber(1))
+ .property("blinded_rsa_signature", codecForString())
+ .build("RsaBlindedDenominationSignature");
+
export class WithdrawResponse {
- ev_sig: string;
+ ev_sig: BlindedDenominationSignature;
}
/**
@@ -792,7 +827,7 @@ export interface CoinDumpJson {
/**
* The coin's denomination's public key.
*/
- denom_pub: string;
+ denom_pub: DenominationPubKey;
/**
* Hash of denom_pub.
*/
@@ -875,7 +910,7 @@ export interface ExchangeMeltResponse {
}
export interface ExchangeRevealItem {
- ev_sig: string;
+ ev_sig: BlindedDenominationSignature;
}
export interface ExchangeRevealResponse {
@@ -994,6 +1029,30 @@ export interface BankWithdrawalOperationPostResponse {
transfer_done: boolean;
}
+export type DenominationPubKey = RsaDenominationPubKey | CsDenominationPubKey;
+
+export interface RsaDenominationPubKey {
+ cipher: 1;
+ rsa_public_key: string;
+ age_mask?: number;
+}
+
+export interface CsDenominationPubKey {
+ cipher: 2;
+}
+
+export const codecForDenominationPubKey = () =>
+ buildCodecForUnion<DenominationPubKey>()
+ .discriminateOn("cipher")
+ .alternative(1, codecForRsaDenominationPubKey())
+ .build("DenominationPubKey");
+
+export const codecForRsaDenominationPubKey = () =>
+ buildCodecForObject<RsaDenominationPubKey>()
+ .property("cipher", codecForConstNumber(1))
+ .property("rsa_public_key", codecForString())
+ .build("DenominationPubKey");
+
export const codecForBankWithdrawalOperationPostResponse = (): Codec<BankWithdrawalOperationPostResponse> =>
buildCodecForObject<BankWithdrawalOperationPostResponse>()
.property("transfer_done", codecForBoolean())
@@ -1008,7 +1067,7 @@ export type CoinPublicKeyString = string;
export const codecForDenomination = (): Codec<Denomination> =>
buildCodecForObject<Denomination>()
.property("value", codecForString())
- .property("denom_pub", codecForString())
+ .property("denom_pub", codecForDenominationPubKey())
.property("fee_withdraw", codecForString())
.property("fee_deposit", codecForString())
.property("fee_refresh", codecForString())
@@ -1242,7 +1301,7 @@ export const codecForRecoupConfirmation = (): Codec<RecoupConfirmation> =>
export const codecForWithdrawResponse = (): Codec<WithdrawResponse> =>
buildCodecForObject<WithdrawResponse>()
- .property("ev_sig", codecForString())
+ .property("ev_sig", codecForBlindedDenominationSignature())
.build("WithdrawResponse");
export const codecForMerchantPayResponse = (): Codec<MerchantPayResponse> =>
@@ -1260,7 +1319,7 @@ export const codecForExchangeMeltResponse = (): Codec<ExchangeMeltResponse> =>
export const codecForExchangeRevealItem = (): Codec<ExchangeRevealItem> =>
buildCodecForObject<ExchangeRevealItem>()
- .property("ev_sig", codecForString())
+ .property("ev_sig", codecForBlindedDenominationSignature())
.build("ExchangeRevealItem");
export const codecForExchangeRevealResponse = (): Codec<ExchangeRevealResponse> =>
diff --git a/packages/taler-util/src/walletTypes.ts b/packages/taler-util/src/walletTypes.ts
index 6e68ee080..879640e82 100644
--- a/packages/taler-util/src/walletTypes.ts
+++ b/packages/taler-util/src/walletTypes.ts
@@ -48,6 +48,8 @@ import {
AmountString,
codecForContractTerms,
ContractTerms,
+ DenominationPubKey,
+ UnblindedSignature,
} from "./talerTypes.js";
import { OrderShortInfo, codecForOrderShortInfo } from "./transactionsTypes.js";
import { BackupRecovery } from "./backupTypes.js";
@@ -454,7 +456,7 @@ export interface PlanchetCreationResult {
coinPriv: string;
reservePub: string;
denomPubHash: string;
- denomPub: string;
+ denomPub: DenominationPubKey;
blindingKey: string;
withdrawSig: string;
coinEv: string;
@@ -467,7 +469,7 @@ export interface PlanchetCreationRequest {
coinIndex: number;
value: AmountJson;
feeWithdraw: AmountJson;
- denomPub: string;
+ denomPub: DenominationPubKey;
reservePub: string;
reservePriv: string;
}
@@ -514,7 +516,7 @@ export interface DepositInfo {
feeDeposit: AmountJson;
wireInfoHash: string;
denomPubHash: string;
- denomSig: string;
+ denomSig: UnblindedSignature;
}
export interface ExchangesListRespose {