[age-withdraw] simplify lib-API

This commit is contained in:
Özgür Kesim 2023-07-18 13:34:27 +02:00
parent 2ca7ce1b89
commit 2eb3ff1f64
Signed by: oec
GPG Key ID: 3D76A56D79EDD9D7
4 changed files with 337 additions and 188 deletions

View File

@ -2670,7 +2670,7 @@ struct TALER_EXCHANGE_AgeWithdrawCoinInput
* The master secret from which we derive all other relevant values for * The master secret from which we derive all other relevant values for
* the coin: private key, nonces (if applicable) and age restriction * the coin: private key, nonces (if applicable) and age restriction
*/ */
const struct TALER_PlanchetMasterSecretP secrets[TALER_CNC_KAPPA]; struct TALER_PlanchetMasterSecretP secrets[TALER_CNC_KAPPA];
/** /**
* The denomination of the coin. Must support age restriction, i.e * The denomination of the coin. Must support age restriction, i.e
@ -2679,6 +2679,42 @@ struct TALER_EXCHANGE_AgeWithdrawCoinInput
const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
}; };
/**
* All the details about a coin that are generated during age-withdrawal and
* that may be needed for future operations on the coin.
*/
struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails
{
/**
* Private key of the coin.
*/
struct TALER_CoinSpendPrivateKeyP coin_priv;
/**
* Value used to blind the key for the signature.
* Needed for recoup operations.
*/
union TALER_DenominationBlindingKeyP blinding_key;
/**
* The age commitment, proof for the coin, derived from the
* Master secret and maximum age in the originating request
*/
struct TALER_AgeCommitmentProof age_commitment_proof;
/**
* The hash of the age commitment
*/
struct TALER_AgeCommitmentHash h_age_commitment;
/**
* Values contributed from the exchange during the
* withdraw protocol.
*/
struct TALER_ExchangeWithdrawValues alg_values;
};
/** /**
* @brief A handle to a /reserves/$RESERVE_PUB/age-withdraw request * @brief A handle to a /reserves/$RESERVE_PUB/age-withdraw request
*/ */
@ -2705,39 +2741,38 @@ struct TALER_EXCHANGE_AgeWithdrawResponse
struct struct
{ {
/** /**
* Index that should not be revealed during the age-withdraw reveal phase. * Index that should not be revealed during the age-withdraw reveal
* The struct TALER_PlanchetMasterSecretP * from the request * phase.
* with this index are the ones to keep.
*/ */
uint8_t noreveal_index; uint8_t noreveal_index;
/** /**
* The commitment of the call to /age-withdraw * The commitment of the age-withdraw request, needed for the
* subsequent call to /age-withdraw/$ACH/reveal
*/ */
struct TALER_AgeWithdrawCommitmentHashP h_commitment; struct TALER_AgeWithdrawCommitmentHashP h_commitment;
/** /**
* The algorithm specific values (for CS) need for the coins that were * The number of elements in @e coins, each referring to
* retrieved from /csr-withdraw. * TALER_CNC_KAPPA elements
*/ */
struct TALER_ExchangeWithdrawValues *alg_values; size_t num_coins;
/** /**
* Number of elements in @e alg_values, same as number coin candidates.from * The computed details of the non-revealed @e num_coins coins to keep.
* the request.
*/ */
size_t num_alg_values; const struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails *coins;
/** /**
* Signature of the exchange over the origina TALER_AgeWithdrawRequestPS * The array of blinded hashes of the non-revealed
* (kappa - 1)*@e num_coins coins, needed for the reveal step;
*/ */
struct TALER_ExchangeSignatureP exchange_sig; const struct TALER_BlindedCoinHashP *blinded_coin_hs;
/** /**
* Key used by the exchange for @e exchange_sig * Key used by the exchange to sign the response.
*/ */
struct TALER_ExchangePublicKeyP exchange_pub; struct TALER_ExchangePublicKeyP exchange_pub;
} ok; } ok;
} details; } details;
}; };
@ -2809,7 +2844,6 @@ struct TALER_EXCHANGE_AgeWithdrawBlindedInput
* Blinded Planchets * Blinded Planchets
*/ */
struct TALER_PlanchetDetail planchet_details[TALER_CNC_KAPPA]; struct TALER_PlanchetDetail planchet_details[TALER_CNC_KAPPA];
}; };
/** /**
@ -2840,19 +2874,16 @@ struct TALER_EXCHANGE_AgeWithdrawBlindedResponse
uint8_t noreveal_index; uint8_t noreveal_index;
/** /**
* The commitment of the call to /age-withdraw * The commitment of the call to age-withdraw, needed for the subsequent
* call to /age-withdraw/$ACH/reveal.
*/ */
struct TALER_AgeWithdrawCommitmentHashP h_commitment; struct TALER_AgeWithdrawCommitmentHashP h_commitment;
/** /**
* Signature of the exchange over the origina TALER_AgeWithdrawRequestPS * Key used by the exchange to sign the response.
*/
struct TALER_ExchangeSignatureP exchange_sig;
/**
* Key used by the exchange for @e exchange_sig
*/ */
struct TALER_ExchangePublicKeyP exchange_pub; struct TALER_ExchangePublicKeyP exchange_pub;
} ok; } ok;
} details; } details;
@ -2964,12 +2995,12 @@ struct TALER_EXCHANGE_AgeWithdrawRevealResponse
unsigned int num_coins; unsigned int num_coins;
/** /**
* Array of @e num_coins values about the coins obtained via the reveal * Array of @e num_coins blinded denomination signatures, giving each
* operation. The array give these coins in the same order (and should * coin its value and validity. The array give these coins in the same
* have the same length) in which the original age-withdraw request * order (and should have the same length) in which the original
* specified the respective denomination keys. * age-withdraw request specified the respective denomination keys.
*/ */
const struct TALER_EXCHANGE_RevealedCoinInfo *revealed_coins; const struct TALER_BlindedDenominationSignature *denom_sigs;
} ok; } ok;
} details; } details;
@ -2994,10 +3025,8 @@ typedef void
* @param exchange_url The base url of the exchange * @param exchange_url The base url of the exchange
* @param num_coins The number of elements in @e coin_inputs and @e alg_values * @param num_coins The number of elements in @e coin_inputs and @e alg_values
* @param coin_inputs The input for the coins to withdraw, same as in the previous call to /age-withdraw * @param coin_inputs The input for the coins to withdraw, same as in the previous call to /age-withdraw
* @param alg_values The algorithm specific parameters per coin, from the result to the previous call to /age-withdraw
* @param noreveal_index The index into each of the kappa coin candidates, that should not be revealed to the exchange * @param noreveal_index The index into each of the kappa coin candidates, that should not be revealed to the exchange
* @param h_commitment The commmitment from the previous call to /age-withdraw * @param h_commitment The commmitment from the previous call to /age-withdraw
* @param max_age maximum age, as used in the to /age-withdraw
* @param res_cb A callback for the result, maybe NULL * @param res_cb A callback for the result, maybe NULL
* @param res_cb_cls A closure for @e res_cb, maybe NULL * @param res_cb_cls A closure for @e res_cb, maybe NULL
* @return a handle for this request; NULL if the argument was invalid. * @return a handle for this request; NULL if the argument was invalid.
@ -3010,10 +3039,8 @@ TALER_EXCHANGE_age_withdraw_reveal (
size_t num_coins, size_t num_coins,
const struct TALER_EXCHANGE_AgeWithdrawCoinInput coin_inputs[static const struct TALER_EXCHANGE_AgeWithdrawCoinInput coin_inputs[static
num_coins], num_coins],
const struct TALER_ExchangeWithdrawValues alg_values[static num_coins],
uint8_t noreveal_index, uint8_t noreveal_index,
const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, const struct TALER_AgeWithdrawCommitmentHashP *h_commitment,
uint8_t max_age,
TALER_EXCHANGE_AgeWithdrawRevealCallback res_cb, TALER_EXCHANGE_AgeWithdrawRevealCallback res_cb,
void *res_cb_cls); void *res_cb_cls);
@ -3034,7 +3061,8 @@ TALER_EXCHANGE_age_withdraw_reveal_cancel (
/** /**
* Information needed to melt (partially spent) coins to obtain fresh coins * Information needed to melt (partially spent) coins to obtain fresh coins
* that are unlinkable to the original coin(s). Note that melting more than * that are unlinkable to the original coin(s). Note that melting more than
* one coin in a single request will make those coins linkable, so we only melt one coin at a time. * one coin in a single request will make those coins linkable, so we only melt
* one coin at a time.
*/ */
struct TALER_EXCHANGE_RefreshData struct TALER_EXCHANGE_RefreshData
{ {

View File

@ -47,30 +47,9 @@ struct CoinCandidate
struct TALER_PlanchetMasterSecretP secret; struct TALER_PlanchetMasterSecretP secret;
/** /**
* Age commitment for the coin candidates, calculated from the @e ps and a * The details derived form the master secrets
* given maximum age
*/ */
struct TALER_AgeCommitmentProof age_commitment_proof; struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails details;
/**
* Age commitment for the coin.
*/
struct TALER_AgeCommitmentHash h_age_commitment;
/**
* blinding secret
*/
union TALER_DenominationBlindingKeyP blinding_key;
/**
* Private key of the coin we are withdrawing.
*/
struct TALER_CoinSpendPrivateKeyP coin_priv;
/**
* Values of the @cipher selected
*/
struct TALER_ExchangeWithdrawValues alg_values;
/** /**
* Hash of the public key of the coin we are signing. * Hash of the public key of the coin we are signing.
@ -340,11 +319,12 @@ reserve_age_withdraw_ok (
.hr.http_status = MHD_HTTP_OK, .hr.http_status = MHD_HTTP_OK,
.details.ok.h_commitment = awbh->h_commitment .details.ok.h_commitment = awbh->h_commitment
}; };
struct TALER_ExchangeSignatureP exchange_sig;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint8 ("noreaveal_index", GNUNET_JSON_spec_uint8 ("noreaveal_index",
&response.details.ok.noreveal_index), &response.details.ok.noreveal_index),
GNUNET_JSON_spec_fixed_auto ("exchange_sig", GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&response.details.ok.exchange_sig), &exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub", GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&response.details.ok.exchange_pub) &response.details.ok.exchange_pub)
}; };
@ -363,7 +343,7 @@ reserve_age_withdraw_ok (
&awbh->h_commitment, &awbh->h_commitment,
response.details.ok.noreveal_index, response.details.ok.noreveal_index,
&response.details.ok.exchange_pub, &response.details.ok.exchange_pub,
&response.details.ok.exchange_sig)) &exchange_sig))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -785,21 +765,25 @@ copy_results (
{ {
struct TALER_EXCHANGE_AgeWithdrawHandle *awh = cls; struct TALER_EXCHANGE_AgeWithdrawHandle *awh = cls;
uint8_t idx = awbr->details.ok.noreveal_index; uint8_t idx = awbr->details.ok.noreveal_index;
struct TALER_ExchangeWithdrawValues alg_values[awh->num_coins]; struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails coins[awh->num_coins];
struct TALER_BlindedCoinHashP blinded_coin_hs[awh->num_coins];
struct TALER_EXCHANGE_AgeWithdrawResponse resp = { struct TALER_EXCHANGE_AgeWithdrawResponse resp = {
.hr = awbr->hr, .hr = awbr->hr,
.details = { .details = {
.ok = { .noreveal_index = awbr->details.ok.noreveal_index, .ok = { .noreveal_index = awbr->details.ok.noreveal_index,
.h_commitment = awbr->details.ok.h_commitment, .h_commitment = awbr->details.ok.h_commitment,
.exchange_pub = awbr->details.ok.exchange_pub, .exchange_pub = awbr->details.ok.exchange_pub,
.exchange_sig = awbr->details.ok.exchange_sig, .num_coins = awh->num_coins,
.num_alg_values = awh->num_coins, .coins = coins,
.alg_values = alg_values}, .blinded_coin_hs = blinded_coin_hs},
}, },
}; };
for (size_t n = 0; n< awh->num_coins; n++) for (size_t n = 0; n< awh->num_coins; n++)
alg_values[n] = awh->coin_data[n].coin_candidates[idx].alg_values; {
coins[n] = awh->coin_data[n].coin_candidates[idx].details;
blinded_coin_hs[n] = awh->coin_data[n].coin_candidates[idx].blinded_coin_h;
}
awh->callback (awh->callback_cls, awh->callback (awh->callback_cls,
&resp); &resp);
@ -915,22 +899,22 @@ csr_withdraw_done (
{ {
bool success = false; bool success = false;
/* Complete the initialization of the coin with CS denomination */ /* Complete the initialization of the coin with CS denomination */
can->alg_values = csrr->details.ok.alg_values; can->details.alg_values = csrr->details.ok.alg_values;
TALER_planchet_setup_coin_priv (&can->secret, TALER_planchet_setup_coin_priv (&can->secret,
&can->alg_values, &can->details.alg_values,
&can->coin_priv); &can->details.coin_priv);
TALER_planchet_blinding_secret_create (&can->secret, TALER_planchet_blinding_secret_create (&can->secret,
&can->alg_values, &can->details.alg_values,
&can->blinding_key); &can->details.blinding_key);
/* This initializes the 2nd half of the /* This initializes the 2nd half of the
can->planchet_detail.blinded_planchet! */ can->planchet_detail.blinded_planchet! */
do { do {
if (GNUNET_OK != if (GNUNET_OK !=
TALER_planchet_prepare (&csr->denom_pub->key, TALER_planchet_prepare (&csr->denom_pub->key,
&can->alg_values, &can->details.alg_values,
&can->blinding_key, &can->details.blinding_key,
&can->coin_priv, &can->details.coin_priv,
&can->h_age_commitment, &can->details.h_age_commitment,
&can->h_coin_pub, &can->h_coin_pub,
planchet)) planchet))
{ {
@ -1029,28 +1013,28 @@ prepare_coins (
&can->secret, &can->secret,
&input->denom_pub->key.age_mask, &input->denom_pub->key.age_mask,
awh->max_age, awh->max_age,
&can->age_commitment_proof)); &can->details.age_commitment_proof));
TALER_age_commitment_hash (&can->age_commitment_proof.commitment, TALER_age_commitment_hash (&can->details.age_commitment_proof.commitment,
&can->h_age_commitment); &can->details.h_age_commitment);
switch (input->denom_pub->key.cipher) switch (input->denom_pub->key.cipher)
{ {
case TALER_DENOMINATION_RSA: case TALER_DENOMINATION_RSA:
{ {
can->alg_values.cipher = TALER_DENOMINATION_RSA; can->details.alg_values.cipher = TALER_DENOMINATION_RSA;
TALER_planchet_setup_coin_priv (&can->secret, TALER_planchet_setup_coin_priv (&can->secret,
&can->alg_values, &can->details.alg_values,
&can->coin_priv); &can->details.coin_priv);
TALER_planchet_blinding_secret_create (&can->secret, TALER_planchet_blinding_secret_create (&can->secret,
&can->alg_values, &can->details.alg_values,
&can->blinding_key); &can->details.blinding_key);
FAIL_IF (GNUNET_OK != FAIL_IF (GNUNET_OK !=
TALER_planchet_prepare (&cd->denom_pub.key, TALER_planchet_prepare (&cd->denom_pub.key,
&can->alg_values, &can->details.alg_values,
&can->blinding_key, &can->details.blinding_key,
&can->coin_priv, &can->details.coin_priv,
&can->h_age_commitment, &can->details.h_age_commitment,
&can->h_coin_pub, &can->h_coin_pub,
planchet)); planchet));
FAIL_IF (GNUNET_OK != FAIL_IF (GNUNET_OK !=

View File

@ -47,19 +47,12 @@ struct TALER_EXCHANGE_AgeWithdrawRevealHandle
/* The age-withdraw commitment */ /* The age-withdraw commitment */
struct TALER_AgeWithdrawCommitmentHashP h_commitment; struct TALER_AgeWithdrawCommitmentHashP h_commitment;
/* The maximum age */
uint8_t max_age;
/* Number of coins */ /* Number of coins */
size_t num_coins; size_t num_coins;
/* The @e num_coins * kappa coin secrets from the age-withdraw commitment */ /* The @e num_coins * kappa coin secrets from the age-withdraw commitment */
const struct TALER_EXCHANGE_AgeWithdrawCoinInput *coins_input; const struct TALER_EXCHANGE_AgeWithdrawCoinInput *coins_input;
/* The @e num_coins algorithm- and coin-specific parameters from the
* previous call to /age-withdraw. */
const struct TALER_ExchangeWithdrawValues *alg_values;
/* The url for the reveal request */ /* The url for the reveal request */
const char *request_url; const char *request_url;
@ -81,82 +74,6 @@ struct TALER_EXCHANGE_AgeWithdrawRevealHandle
}; };
static enum GNUNET_GenericReturnValue
reveal_coin (
const struct TALER_PlanchetMasterSecretP *secret,
const struct TALER_DenominationPublicKey *denom_pub,
const struct TALER_ExchangeWithdrawValues *alg_values,
const struct TALER_BlindedDenominationSignature *blind_sig,
uint8_t max_age,
struct TALER_EXCHANGE_RevealedCoinInfo *revealed_coin)
{
enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR;
#define BREAK_ON_FAILURE(call) \
do { \
if (GNUNET_OK != (call)) { GNUNET_break (0); break; } \
} while(0)
do {
struct TALER_CoinPubHashP h_coin_pub;
struct TALER_PlanchetDetail planchet_detail;
const struct TALER_AgeCommitmentHash *hac = NULL;
struct TALER_FreshCoin fresh_coin;
TALER_planchet_setup_coin_priv (secret,
alg_values,
&revealed_coin->coin_priv);
TALER_planchet_blinding_secret_create (secret,
alg_values,
&revealed_coin->bks);
revealed_coin->age_commitment_proof = NULL;
if (0 < max_age)
{
BREAK_ON_FAILURE (
TALER_age_restriction_from_secret (
secret,
&denom_pub->age_mask,
max_age,
revealed_coin->age_commitment_proof));
TALER_age_commitment_hash (
&revealed_coin->age_commitment_proof->commitment,
&revealed_coin->h_age_commitment);
hac = &revealed_coin->h_age_commitment;
}
BREAK_ON_FAILURE (
TALER_planchet_prepare (denom_pub,
alg_values,
&revealed_coin->bks,
&revealed_coin->coin_priv,
hac,
&h_coin_pub,
&planchet_detail));
BREAK_ON_FAILURE (
TALER_planchet_to_coin (denom_pub,
blind_sig,
&revealed_coin->bks,
&revealed_coin->coin_priv,
&revealed_coin->h_age_commitment,
&h_coin_pub,
alg_values,
&fresh_coin));
/* success */
revealed_coin->sig = fresh_coin.sig;
ret = GNUNET_OK;
} while(0);
return ret;
#undef BREAK_ON_FAILURE
}
/** /**
* We got a 200 OK response for the /age-withdraw/$ACH/reveal operation. * We got a 200 OK response for the /age-withdraw/$ACH/reveal operation.
* Extract the signed blindedcoins and return it to the caller. * Extract the signed blindedcoins and return it to the caller.
@ -197,16 +114,14 @@ age_withdraw_reveal_ok (
} }
{ {
struct TALER_EXCHANGE_RevealedCoinInfo revealed_coins[awrh->num_coins]; struct TALER_BlindedDenominationSignature denom_sigs[awrh->num_coins];
/* Reconstruct the coins and unblind the signatures */ /* Reconstruct the coins and unblind the signatures */
for (size_t n = 0; n < awrh->num_coins; n++) for (size_t n = 0; n < awrh->num_coins; n++)
{ {
enum GNUNET_GenericReturnValue ret;
struct TALER_BlindedDenominationSignature blinded_sig;
json_t *j_sig = json_array_get (j_sigs, n); json_t *j_sig = json_array_get (j_sigs, n);
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("", &blinded_sig), GNUNET_JSON_spec_fixed_auto ("", &denom_sigs[n]),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
@ -218,19 +133,10 @@ age_withdraw_reveal_ok (
GNUNET_break_op (0); GNUNET_break_op (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
ret = reveal_coin (&awrh->coins_input[n].secrets[awrh->noreveal_index],
&awrh->coins_input[n].denom_pub->key,
&awrh->alg_values[n],
&blinded_sig,
awrh->max_age,
&revealed_coins[n]);
if (GNUNET_OK != ret)
return ret;
} }
response.details.ok.num_coins = awrh->num_coins; response.details.ok.num_coins = awrh->num_coins;
response.details.ok.revealed_coins = revealed_coins; response.details.ok.denom_sigs = denom_sigs;
awrh->callback (awrh->callback_cls, awrh->callback (awrh->callback_cls,
&response); &response);
/* Make sure the callback isn't called again */ /* Make sure the callback isn't called again */
@ -510,24 +416,19 @@ TALER_EXCHANGE_age_withdraw_reveal (
size_t num_coins, size_t num_coins,
const struct TALER_EXCHANGE_AgeWithdrawCoinInput coins_input[static const struct TALER_EXCHANGE_AgeWithdrawCoinInput coins_input[static
num_coins], num_coins],
const struct TALER_ExchangeWithdrawValues alg_values[static num_coins],
uint8_t noreveal_index, uint8_t noreveal_index,
const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, const struct TALER_AgeWithdrawCommitmentHashP *h_commitment,
uint8_t max_age,
TALER_EXCHANGE_AgeWithdrawRevealCallback reveal_cb, TALER_EXCHANGE_AgeWithdrawRevealCallback reveal_cb,
void *reveal_cb_cls) void *reveal_cb_cls)
{ {
struct TALER_EXCHANGE_AgeWithdrawRevealHandle *awrh = struct TALER_EXCHANGE_AgeWithdrawRevealHandle *awrh =
GNUNET_new (struct TALER_EXCHANGE_AgeWithdrawRevealHandle); GNUNET_new (struct TALER_EXCHANGE_AgeWithdrawRevealHandle);
awrh->noreveal_index = noreveal_index; awrh->noreveal_index = noreveal_index;
awrh->callback = reveal_cb;
awrh->callback_cls = reveal_cb_cls;
awrh->h_commitment = *h_commitment; awrh->h_commitment = *h_commitment;
awrh->num_coins = num_coins; awrh->num_coins = num_coins;
awrh->coins_input = coins_input; awrh->coins_input = coins_input;
awrh->alg_values = alg_values; awrh->callback = reveal_cb;
awrh->max_age = max_age; awrh->callback_cls = reveal_cb_cls;
if (GNUNET_OK != if (GNUNET_OK !=
prepare_url (exchange_url, prepare_url (exchange_url,

236
src/lib/notizen.md Normal file
View File

@ -0,0 +1,236 @@
# Notes re: planchets and blinding
## `TALER_denom_blind()`
```
Blind coin for blind signing with @a dk using blinding secret @a coin_bks.
```
- `@param[out] c_hash resulting hashed coin`
- `@param[out] blinded_planchet planchet data to initialize`
## `TALER_planchet_prepare()`
Prepare a planchet for withdrawal. Creates and blinds a coin.
- calls `TALER_denom_blind()!`
- `@param[out] c_hash set to the hash of the public key of the coin (needed later)`
- `@param[out] pd set to the planchet detail for TALER_MERCHANT_tip_pickup() and other withdraw operations, pd->blinded_planchet.cipher will be set to cipher from @a dk`
## `TALER_coin_ev_hash`
Compute the hash of a blinded coin.
- `@param blinded_planchet blinded planchet`
- `@param denom_hash hash of the denomination publick key`
- `@param[out] bch where to write the hash, type struct TALER_BlindedCoinHashP`
**Where is this called!?**
```
taler-exchange-httpd_refreshes_reveal.c
605: TALER_coin_ev_hash (&rrc->blinded_planchet,
taler-exchange-httpd_recoup.c
290: TALER_coin_ev_hash (&blinded_planchet,
taler-exchange-httpd_withdraw.c
581: TALER_coin_ev_hash (&wc.blinded_planchet,
taler-exchange-httpd_age-withdraw_reveal.c
350: ret = TALER_coin_ev_hash (&detail.blinded_planchet,
taler-exchange-httpd_recoup-refresh.c
284: TALER_coin_ev_hash (&blinded_planchet,
taler-exchange-httpd_age-withdraw.c
279: ret = TALER_coin_ev_hash (&awc->coin_evs[c],
884: TALER_coin_ev_hash (&awc->coin_evs[i],
taler-exchange-httpd_batch-withdraw.c
832: TALER_coin_ev_hash (&pc->blinded_planchet,
```
## `TALER_coin_pub_hash`
Compute the hash of a coin.
- `@param coin_pub public key of the coin`
- `@param age_commitment_hash hash of the age commitment vector. NULL, if no age commitment was set`
- `@param[out] coin_h where to write the hash`
**Where is this called!?**
### In `lib/crypto.c`, function `TALER_test_coin_valid`.
```
Check if a coin is valid; that is, whether the denomination key
exists, is not expired, and the signature is correct.
@param coin_public_info the coin public info to check for validity
@param denom_pub denomination key, must match @a coin_public_info's `denom_pub_hash`
@return #GNUNET_YES if the coin is valid,
#GNUNET_NO if it is invalid
#GNUNET_SYSERR if an internal error occurred
```
It then calls `TALER_denom_pub_verify` on the result of `TALER_coin_pub_hash` and the signature
### In `util/denom.c`, function `TALER_denom_blind`
## `TALER_EXCHANGE_batch_withdraw` vs `TALER_EXCHANGE_batch_withdraw2`
### `TALER_EXCHANGE_batch_withdraw`
```
/**
* Withdraw multiple coins from the exchange using a /reserves/$RESERVE_PUB/batch-withdraw
* request. This API is typically used by a wallet to withdraw many coins from a
* reserve.
*
* Note that to ensure that no money is lost in case of hardware
* failures, the caller must have committed (most of) the arguments to
* disk before calling, and be ready to repeat the request with the
* same arguments in case of failures.
*
* @param curl_ctx The curl context to use
* @param exchange_url The base-URL of the exchange
* @param keys The /keys material from the exchange
* @param reserve_priv private key of the reserve to withdraw from
* @param wci_length number of entries in @a wcis
* @param wcis inputs that determine the planchets
* @param res_cb the callback to call when the final result for this request is available
* @param res_cb_cls closure for @a res_cb
* @return NULL
* if the inputs are invalid (i.e. denomination key not with this exchange).
* In this case, the callback is not called.
*/
struct TALER_EXCHANGE_BatchWithdrawHandle *
TALER_EXCHANGE_batch_withdraw (
struct GNUNET_CURL_Context *curl_ctx,
const char *exchange_url,
const struct TALER_EXCHANGE_Keys *keys,
const struct TALER_ReservePrivateKeyP *reserve_priv,
unsigned int wci_length,
const struct TALER_EXCHANGE_WithdrawCoinInput wcis[static wci_length],
TALER_EXCHANGE_BatchWithdrawCallback res_cb,
void *res_cb_cls);
```
### `TALER_EXCHANGE_batch_withdraw2`
```
/**
* Withdraw a coin from the exchange using a /reserves/$RESERVE_PUB/batch-withdraw
* request. This API is typically used by a merchant to withdraw a tip
* where the blinding factor is unknown to the merchant.
*
* Note that to ensure that no money is lost in case of hardware
* failures, the caller must have committed (most of) the arguments to
* disk before calling, and be ready to repeat the request with the
* same arguments in case of failures.
*
* @param curl_ctx The curl context to use
* @param exchange_url The base-URL of the exchange
* @param keys The /keys material from the exchange
* @param pds array of planchet details of the planchet to withdraw
* @param pds_length number of entries in the @a pds array
* @param reserve_priv private key of the reserve to withdraw from
* @param res_cb the callback to call when the final result for this request is available
* @param res_cb_cls closure for @a res_cb
* @return NULL
* if the inputs are invalid (i.e. denomination key not with this exchange).
* In this case, the callback is not called.
*/
struct TALER_EXCHANGE_BatchWithdraw2Handle *
TALER_EXCHANGE_batch_withdraw2 (
struct GNUNET_CURL_Context *curl_ctx,
const char *exchange_url,
const struct TALER_EXCHANGE_Keys *keys,
const struct TALER_ReservePrivateKeyP *reserve_priv,
unsigned int pds_length,
const struct TALER_PlanchetDetail pds[static pds_length],
TALER_EXCHANGE_BatchWithdraw2Callback res_cb,
void *res_cb_cls);
```
### Differences
| batch_withdraw | batch_withdraw2 |
|------------------------------------|------------------------|
| `TALER_EXCHANGE_WithdrawCoinInput` | `TALER_PlanchetDetail` |
```
struct TALER_EXCHANGE_WithdrawCoinInput
{
/**
* Denomination of the coin.
*/
const struct TALER_EXCHANGE_DenomPublicKey *pk;
/**
* Master key material for the coin.
*/
const struct TALER_PlanchetMasterSecretP *ps;
/**
* Age commitment for the coin.
*/
const struct TALER_AgeCommitmentHash *ach;
};
```
```
struct TALER_PlanchetDetail
{
/**
* Hash of the denomination public key.
*/
struct TALER_DenominationHashP denom_pub_hash;
/**
* The blinded planchet
*/
struct TALER_BlindedPlanchet {
/**
* Type of the sign blinded message
*/
enum TALER_DenominationCipher cipher;
/**
* Details, depending on @e cipher.
*/
union
{
/**
* If we use #TALER_DENOMINATION_CS in @a cipher.
*/
struct TALER_BlindedCsPlanchet cs_blinded_planchet;
/**
* If we use #TALER_DENOMINATION_RSA in @a cipher.
*/
struct TALER_BlindedRsaPlanchet rsa_blinded_planchet;
} details;
} blinded_planchet;
};
```
## TODOs
### Update documentation
- [x] batch-withdraw needs error code for AgeRestrictionRequired
- [x] withdraw needs error code for AgeRestrictionRequired