taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

commit e1b71d87fc789796f3864c13395bb4260a314909
parent 66be441df4e6ad63924d4aba08bd81d66098f53c
Author: Özgür Kesim <oec-taler@kesim.org>
Date:   Sun, 30 Nov 2025 19:47:48 +0100

[exchange][refresh] spec for /refresh according to Dold'19++

The current design for refresh requires _unique_ coin signatures,
which we do not have.  We therefore revert to the Dold'19 refresh,
_but_ keep the improvements regarding batch-handling and idempotency.

Diffstat:
Mcore/api-common.rst | 17++++++++---------
Mcore/api-exchange.rst | 107++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
2 files changed, 89 insertions(+), 35 deletions(-)

diff --git a/core/api-common.rst b/core/api-common.rst @@ -1197,8 +1197,6 @@ uses 512-bit hash codes (64 bytes). struct TALER_TransferSecretP { uint8_t key[sizeof (struct GNUNET_HashCode)]; }; - uint8_t key[sizeof (struct GNUNET_HashCode)]; - }; struct TALER_EncryptedLinkSecretP { uint8_t enc[sizeof (struct TALER_LinkSecretP)]; @@ -1449,20 +1447,21 @@ within the /** * @since vDOLDPLUS * Hash over: - * 1. kappa*n tranfer public keys: T[1,1],⋯,T[1,n],T[2,1],⋯,T[κ,n] - * 2. hash over all pairs of R-values (for CS) if present, skipped otherwise - * 3. n denomination hashes, in order - * 4. amount with fee - * 5. kappa*n planchets, depths first: [0..n),[0..n),[0..n) + * 1. master_refresh_seed + * 2. kappa * n tranfer public keys, depths first: [0..n),...,[0..n) + * 3. hash over all pairs of R-values (for CS) if present, skipped otherwise + * 4. n denomination hashes, in order + * 5. amount with fee + * 6. kappa*n planchets, depths first: [0..n),...,[0..n) * * @since v27 * @deprecated vDOLDPLUS * Hash over: - * 1. refresh_seed (v27) + * 1. refresh_seed * 2. hash over all pairs of R-values if present, skipped otherwise * 3. n denomination hashes, in order * 4. amount with fee - * 5. kappa * n planchets, depths first: [0..n),[0..n),[0..n) + * 5. kappa * n planchets, depths first: [0..n),...,[0..n) */ struct GNUNET_HashCode session_hash; }; diff --git a/core/api-exchange.rst b/core/api-exchange.rst @@ -2026,7 +2026,7 @@ These endpoints are called by the client The request body is a `RevealMeltRequest`. - This endpoint was introduced in this form in protocol **v27**. + This endpoint was introduced in this form in protocol **vDOLDPLUS**. :http:statuscode:`200 OK`: The coin's' secret material matched the commitment and the original request was well-formed. @@ -2062,12 +2062,17 @@ These endpoints are called by the client // over Hash1a("Refresh", Cp, r, i), where Cp is the melted coin's public key, // r is the public refresh nonce from the metling step and i runs over the // _disclosed_ kappa-1 indices. - signatures?: CoinSignature[kappa-1]; + signatures: CoinSignature[kappa-1]; - // TODO[oec]: Add the transfer secrets - transfer_secrets: string[kappa-1]; + // @since vDOLDPLUS + // The seeds for the transfer secrets to reveal. + // For the kappa many batches of n coin candidates, + // each of the seeds in this list are expanded via HKDF: + // ``ts[k][] = HKDF(sizeof(HashCode)*n, ts_seeds[k], "ts")`` + // An individual coin's transfer secret at kappa-index k and + // coin index i in the batch is then ``ts[k][i]``. + transfer_secret_seeds: HashCode[kappa-1]; - // TODO[oec]: Is this the right place? // IFF the denomination of the old coin had support for age restriction, // the client MUST provide the original age commitment, i. e. the // vector of public keys, or omitted otherwise. @@ -2110,7 +2115,7 @@ These endpoints are called by the client The request body is a `RevealWithdrawRequest`. - This endpoint was introduced in this form in protocol **v27**. + This endpoint was introduced in this form in protocol **vDOLDPLUS**. :http:statuscode:`200 OK`: The coin's' secret material matched the commitment and the original request was well-formed. @@ -2668,30 +2673,57 @@ Coin History // Melt fee. melt_fee: Amount; - // Commitment from the melt operation. - rc: TALER_RefreshCommitmentP; + // Commitment from the melt operation, see `TALER_RefreshCommitmentP` + rc: HashCode; - // Hash of the public denomination key used to sign the coin. + // Hash of the public denomination key used to sign the old coin. // Needed because 'coin_sig' signs over this, and // that is important to fix the coin's denomination. - h_denom_pub: HashCode; + old_denom_pub_h: HashCode; - // Seed from which the nonces for the n*κ coin candidates are derived - // from. - refresh_seed: HashCode; + // Hash over the age commitment of the coin. Optional. + old_age_commitment_h?: AgeCommitmentHash; + + // @since vDOLDPLUS + // This value is opaque to the exchange. It was provided by the client + // as part of the original refresh request, and was therefore verified + // with the confirm_sig below. + // If the reveal step was not performed yet by the old coin owner, + // they can use this value and the old coin's private key to derive + // all indivual seeds for the n*κ coin candidates for the original + // refresh request and replay it + master_refresh_seed: HashCode; + + // @since vDOLDPLUS + // The kappa*n list of transfer public keys that were provided by the + // old coin owner during the melt request. + transfer_pubs: EddsaPublicKey[kappa][]; + + // @since vDOLDPLUS + // The n denomination public keys for the fresh coins + // that the coin owner had requested. + denoms_h: HashCode[]; + + // @since vDOLDPLUS + // The `noreveal_index` value that was returned by the exchange as response + // to the melt request. + noreveal_index: Integer; + + // @since vDOLDPLUS + // If the reveal step was successfully peformed by the coin owner, + // this field contains the blind coin signatures that were returned + // by the exchange for the chosen batch of coins. + ev_sigs?: BlindedDenominationSignature[]; // Master seed for the Clause-Schnorr R-value // Present if one of the fresh coin's // denominations is of type Clause-Schnorr. blinding_seed?: BlindingMasterSeed; - // Hash over the age commitment of the coin. Optional. - h_age_commitment?: HashCode; - // Signature by the coin over a // `TALER_RefreshMeltCoinAffirmationPS` of // purpose ``TALER_SIGNATURE_WALLET_COIN_MELT``. - coin_sig: EddsaSignature; + confirm_sig: EddsaSignature; } @@ -3419,9 +3451,27 @@ by anyone except the wallet itself. // @since v27 // @deprecated vDOLDPLUS - // // Seed from which the nonces for the n*κ coin candidates are derived from. - refresh_seed?: HashCode; + refresh_seed: HashCode; + + // @since vDOLDPLUS + // This value is opaque to the exchange. It was provided by the client + // as part of the original refresh request, and was therefore + // verified with the coin_sig below. + // + // Note: The honest owner of the old coin SHOULD use this value + // and the old coin's private key to derive kappa many + // transfer secret seeds like this: + // ``ts_seeds[k] = SHA512(master_refresh_seed, old_coin_priv, "s", k)`` + // Each of the kappa seeds is then expanded via HKDF: + // ``ts[k][] = HKDF(sizeof(HashCode)*n, ts_seeds[k], "ts")`` + // An individual coin's transfer secret at kappa-index k and + // coin index i in the batch is then ``ts[k][i]`` + // This ensures that the honest owner of the old coin can replay + // a MeltRequest from the coin history provided by the exchange + // (which includes this value), in case a wallet was restored + // from a backup into a state prior to the refresh operation. + master_refresh_seed: HashCode; // Master seed for the Clause-Schnorr R-value // creation. Must match the /blinding-prepare request. @@ -3439,8 +3489,10 @@ by anyone except the wallet itself. coin_evs: CoinEnvelope[kappa][]; // @since vDOLDPLUS - // ``kappa`` arrays of ``n`` entries of transwer public keys each. - // These are ephemeral ECDHE keys. + // ``kappa`` arrays of ``n`` entries of transfer public keys each. + // These are ephemeral ECDHE keys that allow the owner of a coin + // to (re-)obtain the derived coins from a refresh operation, f.e. should + // the wallet state be restored from a backup, prior to the refresh operation. transfer_pubs: EddsaPublicKey[kappa][]; // Signature by the `coin <coin-priv>` over `TALER_RefreshMeltCoinAffirmationPS`. @@ -3520,7 +3572,7 @@ became minted, and proof ownership of the coin itself. Note that the original withdrawal fees will **not** be recouped. - .. note:: This endpoint will become active with version **vRECOUP**, sometime after v27. + .. note:: This endpoint still Work-in-Progress. It will be implemented in **vRECOUP**, sometime after **vDOLDPLUS**. **Request:** @@ -3653,20 +3705,20 @@ became minted, and proof ownership of the coin itself. } -.. http:post:: /coins/$COIN_PUB/recoup-refresh +.. http:post:: /recoup-refresh Demand that a coin be refunded via wire transfer to the original owner. - The base URL for ``/coins/``-requests may differ from the main base URL of the + The base URL for coin related requests may differ from the main base URL of the exchange. The exchange MUST return a 307 or 308 redirection to the correct base URL if this is the case. The remaining amount on the coin will be credited to - the old coin that ``$COIN_PUB`` was refreshed from. + the old coin that this coin was refreshed from. Note that the original refresh fees will **not** be recouped. - .. note:: This endpoint is not implemented and the API going to change after **v27**. + .. note:: This endpoint still Work-in-Progress. It will be implemented in **vRECOUP**, sometime after **vDOLDPLUS**. **Request:** @@ -3707,6 +3759,9 @@ became minted, and proof ownership of the coin itself. .. ts:def:: RecoupRefreshRequest interface RecoupRefreshRequest { + // The coin's public key + coin_pub: CoinPublicKey; + // Hash of denomination public key, specifying the type of coin the client // would like the exchange to pay back. denom_pub_hash: HashCode;