aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/taler-util/src/taler-crypto.ts25
-rw-r--r--packages/taler-util/src/taler-types.ts83
-rw-r--r--packages/taler-wallet-core/src/db.ts14
-rw-r--r--packages/taler-wallet-core/src/operations/withdraw.ts5
4 files changed, 103 insertions, 24 deletions
diff --git a/packages/taler-util/src/taler-crypto.ts b/packages/taler-util/src/taler-crypto.ts
index 3ad388794..de5be71a1 100644
--- a/packages/taler-util/src/taler-crypto.ts
+++ b/packages/taler-util/src/taler-crypto.ts
@@ -1253,30 +1253,9 @@ export namespace AgeRestriction {
age: number,
): Promise<AgeCommitmentProof> {
invariant((ageMask & 1) === 1);
- const numPubs = countAgeGroups(ageMask) - 1;
- const numPrivs = getAgeGroupIndex(ageMask, age);
-
- const pubs: Edx25519PublicKey[] = [];
- const privs: Edx25519PrivateKey[] = [];
-
- for (let i = 0; i < numPubs; i++) {
- const priv = await Edx25519.keyCreate();
- const pub = await Edx25519.getPublic(priv);
- pubs.push(pub);
- if (i < numPrivs) {
- privs.push(priv);
- }
- }
+ const seed = getRandomBytes(32);
- return {
- commitment: {
- mask: ageMask,
- publicKeys: pubs.map((x) => encodeCrock(x)),
- },
- proof: {
- privateKeys: privs.map((x) => encodeCrock(x)),
- },
- };
+ return restrictionCommitSeeded(ageMask, age, seed);
}
const PublishedAgeRestrictionBaseKey: Edx25519PublicKey = decodeCrock(
diff --git a/packages/taler-util/src/taler-types.ts b/packages/taler-util/src/taler-types.ts
index eaba1ae3d..8a0608008 100644
--- a/packages/taler-util/src/taler-types.ts
+++ b/packages/taler-util/src/taler-types.ts
@@ -1889,6 +1889,89 @@ export interface ExchangeRefreshRevealRequest {
old_age_commitment?: Edx25519PublicKeyEnc[];
}
+export interface ExchangeAgeWithdrawRequest {
+ // Array of n hash codes of denomination public keys to order.
+ // These denominations MUST support age restriction as defined in the
+ // output to /keys.
+ // The sum of all denomination's values and fees MUST be at most the
+ // balance of the reserve. The balance of the reserve will be
+ // immediatley reduced by that amount.
+ denoms_h: HashCodeString[];
+
+ // n arrays of kappa entries with blinded coin envelopes. Each
+ // (toplevel) entry represents kappa canditates for a particular
+ // coin. The exchange will respond with an index gamma, which is
+ // the index that shall remain undisclosed during the reveal phase.
+ // The SHA512 hash $ACH over the blinded coin envelopes is the commitment
+ // that is later used as the key to the reveal-URL.
+ blinded_coins_evs: CoinEnvelope[][];
+
+ // The maximum age to commit to. MUST be the same as the maximum
+ // age value assigned to the reserve, based on its birthday date.
+ max_age: number;
+
+ // Signature of TALER_AgeWithdrawRequestPS created with
+ // the reserves's private key
+ // using purpose TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW.
+ reserve_sig: EddsaSignatureString;
+}
+
+export interface ExchangeAgeWithdrawResponse {
+ // index of the commitments that the client doesn't
+ // have to disclose
+ noreveal_index: number;
+
+ // Signature of TALER_AgeWithdrawConfirmationPS whereby
+ // the exchange confirms the noreveal_index.
+ exchange_sig: EddsaSignatureString;
+
+ // Public EdDSA key of the exchange that was used to
+ // generate the signature. Should match one of the exchange's signing
+ // keys from /keys. Again given explicitly as the client might
+ // otherwise be confused by clock skew as to which signing key was used.
+ exchange_pub: EddsaPublicKeyString;
+}
+
+export interface ExchangeAgeWithdrawRevealRequest {
+ // Array of n of (kappa - 1) disclosed coin master secrets, from
+ // which the coins' private key, blinding, nonce (for Clause-Schnorr) and
+ // age-restriction is calculated.
+ //
+ // Given each coin's private key and age commitment, the exchange will
+ // calculate each coin's blinded hash value und use all those (disclosed)
+ // blinded hashes together with the non-disclosed envelopes coin_evs
+ // during the verification of the original age-withdraw-commitment.
+ disclosed_coin_secrets: AgeRestrictedCoinSecret[][];
+}
+
+// The Master key material from which the coins' private key coin_priv,
+// blinding beta and nonce nonce (for Clause-Schnorr) itself are
+// derived as usually in wallet-core. Given a coin's master key material,
+// the age commitment for the coin MUST be derived from this private key as
+// follows:
+//
+// Let m ∈ {1,...,M} be the maximum age group as defined in the reserve
+// that the wallet can commit to.
+//
+// For age group $AG ∈ {1,...m}, set
+// seed = HDKF(coin_secret, "age-commitment", $AG)
+// p[$AG] = Edx25519_generate_private(seed)
+// and calculate the corresponding Edx25519PublicKey as
+// q[$AG] = Edx25519_public_from_private(p[$AG])
+//
+// For age groups $AG ∈ {m,...,M}, set
+// f[$AG] = HDKF(coin_secret, "age-factor", $AG)
+// and calculate the corresponding Edx25519PublicKey as
+// q[$AG] = Edx25519_derive_public(PublishedAgeRestrictionBaseKey, f[$AG])
+//
+// FIXME: shall we add some flavor to this string?
+export type AgeRestrictedCoinSecret = string;
+
+export interface ExchangeAgeWithdrawRevealResponse {
+ // List of the exchange's blinded RSA or CS signatures on the new coins.
+ ev_sigs : BlindedDenominationSignature[];
+}
+
interface DepositConfirmationSignature {
// The EdDSA signature of `TALER_DepositConfirmationPS` using a current
// `signing key of the exchange <sign-key-priv>` affirming the successful
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 9bf9a29cc..239a6d4a4 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -648,6 +648,7 @@ export interface PlanchetRecord {
*/
coinIdx: number;
+
planchetStatus: PlanchetStatus;
lastError: TalerErrorDetail | undefined;
@@ -662,6 +663,12 @@ export interface PlanchetRecord {
coinEvHash: string;
+ /**
+ * Index into the kappa-many planchet commitments per coin
+ * for the age-withdraw operation.
+ */
+ ageWithdrawIdx?: number;
+
ageCommitmentProof?: AgeCommitmentProof;
}
@@ -1353,7 +1360,7 @@ export interface KycPendingInfo {
}
/**
* Group of withdrawal operations that need to be executed.
- * (Either for a normal withdrawal or from a reward.)
+ * (Either for a normal {single-|batch-|age-} withdrawal or from a reward.)
*
* The withdrawal group record is only created after we know
* the coin selection we want to withdraw.
@@ -2382,6 +2389,11 @@ export const WalletStoresV1 = {
"planchets",
describeContents<PlanchetRecord>({ keyPath: "coinPub" }),
{
+ byGroupAgeCoin: describeIndex("byGroupAgeCoin", [
+ "withdrawalGroupId",
+ "ageWithdrawIdx",
+ "coinIdx",
+ ]),
byGroupAndIndex: describeIndex("byGroupAndIndex", [
"withdrawalGroupId",
"coinIdx",
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts
index 32e63f4f6..bae348dc1 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -62,6 +62,10 @@ import {
ExchangeWithdrawResponse,
WithdrawUriInfoResponse,
ExchangeBatchWithdrawRequest,
+ ExchangeAgeWithdrawRequest,
+ ExchangeAgeWithdrawRevealRequest,
+ ExchangeAgeWithdrawResponse,
+ ExchangeAgeWithdrawRevealResponse,
TransactionState,
TransactionMajorState,
TransactionMinorState,
@@ -864,6 +868,7 @@ async function processPlanchetExchangeBatchRequest(
coinIdx < wgContext.numPlanchets;
coinIdx++
) {
+ // FIXME[oec]: Add lookup of planchet for age-withdraw here
let planchet = await tx.planchets.indexes.byGroupAndIndex.get([
withdrawalGroup.withdrawalGroupId,
coinIdx,