Merge branch 'master' of ssh://git.taler.net/exchange

This commit is contained in:
Gian Demarmels 2022-02-05 00:33:16 +01:00
commit f46dc9ea5e
No known key found for this signature in database
GPG Key ID: 030CEDDCCC92D778
5 changed files with 376 additions and 463 deletions

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2021 Taler Systems SA Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software terms of the GNU Affero General Public License as published by the Free Software
@ -1063,9 +1063,15 @@ struct TALER_EXCHANGE_CsRResponse
struct struct
{ {
/** /**
* Signature over the coin. * Length of the @e alg_values array.
*/ */
struct TALER_DenominationCsPublicR r_pubs; unsigned int arg_values_len;
/**
* Values contributed by the exchange for the
* respective coin's withdraw operation.
*/
const struct TALER_ExchangeWithdrawValues *alg_values;
} success; } success;
/** /**
@ -1092,12 +1098,29 @@ typedef void
const struct TALER_EXCHANGE_CsRResponse *csrr); const struct TALER_EXCHANGE_CsRResponse *csrr);
/**
* Information we pass per coin to a /csr request.
*/
struct TALER_EXCHANGE_NonceKey
{
/**
* Which denomination key is the /csr request for?
*/
const struct TALER_EXCHANGE_DenomPublicKey *pk;
/**
* What is the client nonce for the request?
*/
struct TALER_CsNonce nonce;
};
/** /**
* Get a CS R using a /csr request. * Get a CS R using a /csr request.
* *
* @param exchange the exchange handle; the exchange must be ready to operate * @param exchange the exchange handle; the exchange must be ready to operate
* @param pk denomination of coin the R's will be used for * @param nks_len length of the @a nks array
* @param nonce public nonce for CS R request * @param nks array of denominations and nonces
* @param res_cb the callback to call when the final result for this request is available * @param res_cb the callback to call when the final result for this request is available
* @param res_cb_cls closure for the above callback * @param res_cb_cls closure for the above callback
* @return handle for the operation on success, NULL on error, i.e. * @return handle for the operation on success, NULL on error, i.e.
@ -1106,8 +1129,8 @@ typedef void
*/ */
struct TALER_EXCHANGE_CsRHandle * struct TALER_EXCHANGE_CsRHandle *
TALER_EXCHANGE_csr (struct TALER_EXCHANGE_Handle *exchange, TALER_EXCHANGE_csr (struct TALER_EXCHANGE_Handle *exchange,
const struct TALER_EXCHANGE_DenomPublicKey *pk, unsigned int nks_len,
const struct TALER_CsNonce *nonce, struct TALER_EXCHANGE_NonceKey *nks,
TALER_EXCHANGE_CsRCallback res_cb, TALER_EXCHANGE_CsRCallback res_cb,
void *res_cb_cls); void *res_cb_cls);
@ -1383,10 +1406,21 @@ struct TALER_EXCHANGE_WithdrawResponse
*/ */
struct struct
{ {
/**
* Private key of the coin.
*/
struct TALER_CoinSpendPrivateKeyP coin_priv;
/** /**
* Signature over the coin. * Signature over the coin.
*/ */
struct TALER_DenominationSignature sig; struct TALER_DenominationSignature sig;
/**
* Values contributed from the exchange during the
* withdraw protocol.
*/
struct TALER_ExchangeWithdrawValues exchange_vals;
} success; } success;
/** /**
@ -1541,50 +1575,45 @@ TALER_EXCHANGE_withdraw2_cancel (struct TALER_EXCHANGE_Withdraw2Handle *wh);
/** /**
* Melt (partially spent) coins to obtain fresh coins that are * Information needed to melt (partially spent) coins to obtain fresh coins
* unlinkable to the original coin(s). Note that melting more * that are unlinkable to the original coin(s). Note that melting more than
* than one coin in a single request will make those coins linkable, * one coin in a single request will make those coins linkable, so we only melt one coin at a time.
* so the safest operation only melts one coin at a time.
*
* This API is typically used by a wallet. Note that to ensure that
* no money is lost in case of hardware failures, is operation does
* not actually initiate the request. Instead, it generates a buffer
* which the caller must store before proceeding with the actual call
* to #TALER_EXCHANGE_melt() that will generate the request.
*
* This function does verify that the given request data is internally
* consistent. However, the @a melts_sigs are NOT verified.
*
* Aside from some non-trivial cryptographic operations that might
* take a bit of CPU time to complete, this function returns
* its result immediately and does not start any asynchronous
* processing. This function is also thread-safe.
*
* @param melt_priv private keys of the coin to melt
* @param melt_amount amount specifying how much
* the coin will contribute to the melt (including fee)
* @param melt_sig signatures affirming the
* validity of the public keys corresponding to the
* @a melt_priv private key
* @param melt_pk denomination key information
* record corresponding to the @a melt_sig
* validity of the keys
* @param fresh_pks_len length of the @a pks array
* @param fresh_pks array of @a pks_len denominations of fresh coins to create
* @return NULL
* if the inputs are invalid (i.e. denomination key not with this exchange).
* Otherwise, JSON data structure to store persistently
* before proceeding to #TALER_EXCHANGE_melt().
* Non-null results should be freed using GNUNET_free().
*/ */
json_t * struct TALER_EXCHANGE_RefreshData
TALER_EXCHANGE_refresh_prepare ( {
const struct TALER_CoinSpendPrivateKeyP *melt_priv, /**
const struct TALER_Amount *melt_amount, * private key of the coin to melt
const struct TALER_DenominationSignature *melt_sig, */
const struct TALER_EXCHANGE_DenomPublicKey *melt_pk, struct TALER_CoinSpendPrivateKeyP melt_priv;
unsigned int fresh_pks_len,
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pks); /**
* amount specifying how much the coin will contribute to the melt
* (including fee)
*/
struct TALER_Amount melt_amount;
/**
* signatures affirming the validity of the public keys corresponding to the
* @e melt_priv private key
*/
struct TALER_DenominationSignature melt_sig;
/**
* denomination key information record corresponding to the @e melt_sig
* validity of the keys
*/
struct TALER_EXCHANGE_DenomPublicKey melt_pk;
/**
* array of @e pks_len denominations of fresh coins to create
*/
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pks;
/**
* length of the @e pks array
*/
unsigned int fresh_pks_len;
};
/* ********************* /coins/$COIN_PUB/melt ***************************** */ /* ********************* /coins/$COIN_PUB/melt ***************************** */
@ -1603,6 +1632,8 @@ struct TALER_EXCHANGE_MeltHandle;
* *
* @param cls closure * @param cls closure
* @param hr HTTP response data * @param hr HTTP response data
* @param num_coins number of fresh coins to be created, length of the @a exchange_vals array, 0 if the operation failed
* @param alg_values array @a num_coins of exchange values contributed to the refresh operation
* @param noreveal_index choice by the exchange in the cut-and-choose protocol, * @param noreveal_index choice by the exchange in the cut-and-choose protocol,
* UINT32_MAX on error * UINT32_MAX on error
* @param sign_key exchange key used to sign @a full_response, or NULL * @param sign_key exchange key used to sign @a full_response, or NULL
@ -1611,6 +1642,8 @@ typedef void
(*TALER_EXCHANGE_MeltCallback) ( (*TALER_EXCHANGE_MeltCallback) (
void *cls, void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr, const struct TALER_EXCHANGE_HttpResponse *hr,
unsigned int num_coins,
const struct TALER_ExchangeWithdrawValues *alg_values,
uint32_t noreveal_index, uint32_t noreveal_index,
const struct TALER_ExchangePublicKeyP *sign_key); const struct TALER_ExchangePublicKeyP *sign_key);
@ -1626,8 +1659,8 @@ typedef void
* prior to calling this function. * prior to calling this function.
* *
* @param exchange the exchange handle; the exchange must be ready to operate * @param exchange the exchange handle; the exchange must be ready to operate
* @param refresh_data the refresh data as returned from * @param ps the fresh secret that defines the refresh operation
#TALER_EXCHANGE_refresh_prepare()) * @param rd the refresh data specifying the characteristics of the operation
* @param melt_cb the callback to call with the result * @param melt_cb the callback to call with the result
* @param melt_cb_cls closure for @a melt_cb * @param melt_cb_cls closure for @a melt_cb
* @return a handle for this request; NULL if the argument was invalid. * @return a handle for this request; NULL if the argument was invalid.
@ -1635,7 +1668,8 @@ typedef void
*/ */
struct TALER_EXCHANGE_MeltHandle * struct TALER_EXCHANGE_MeltHandle *
TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange, TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
const json_t *refresh_data, const struct TALER_PlanchetSecretsP *ps,
const struct TALER_EXCHANGE_RefreshData *rd,
TALER_EXCHANGE_MeltCallback melt_cb, TALER_EXCHANGE_MeltCallback melt_cb,
void *melt_cb_cls); void *melt_cb_cls);
@ -1664,6 +1698,7 @@ TALER_EXCHANGE_melt_cancel (struct TALER_EXCHANGE_MeltHandle *mh);
* @param cls closure * @param cls closure
* @param hr HTTP response data * @param hr HTTP response data
* @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
* @param exchange_vals array of contributions from the exchange on the refreshes
* @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
* @param sigs array of signature over @a num_coins coins, NULL on error * @param sigs array of signature over @a num_coins coins, NULL on error
*/ */
@ -1672,7 +1707,7 @@ typedef void
void *cls, void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr, const struct TALER_EXCHANGE_HttpResponse *hr,
unsigned int num_coins, unsigned int num_coins,
const struct TALER_PlanchetSecretsP *coin_privs, const struct TALER_CoinSpendPrivateKeyP *coin_privs,
const struct TALER_DenominationSignature *sigs); const struct TALER_DenominationSignature *sigs);
@ -1692,8 +1727,10 @@ struct TALER_EXCHANGE_RefreshesRevealHandle;
* prior to calling this function. * prior to calling this function.
* *
* @param exchange the exchange handle; the exchange must be ready to operate * @param exchange the exchange handle; the exchange must be ready to operate
* @param refresh_data the refresh data as returned from * @param ps the fresh secret that defines the refresh operation
#TALER_EXCHANGE_refresh_prepare()) * @param rd the refresh data that characterizes the refresh operation
* @param num_coins number of fresh coins to be created, length of the @a exchange_vals array, must match value in @a rd
* @param alg_values array @a num_coins of exchange values contributed to the refresh operation
* @param noreveal_index response from the exchange to the * @param noreveal_index response from the exchange to the
* #TALER_EXCHANGE_melt() invocation * #TALER_EXCHANGE_melt() invocation
* @param reveal_cb the callback to call with the final result of the * @param reveal_cb the callback to call with the final result of the
@ -1705,7 +1742,10 @@ struct TALER_EXCHANGE_RefreshesRevealHandle;
struct TALER_EXCHANGE_RefreshesRevealHandle * struct TALER_EXCHANGE_RefreshesRevealHandle *
TALER_EXCHANGE_refreshes_reveal ( TALER_EXCHANGE_refreshes_reveal (
struct TALER_EXCHANGE_Handle *exchange, struct TALER_EXCHANGE_Handle *exchange,
const json_t *refresh_data, const struct TALER_PlanchetSecretsP *ps,
const struct TALER_EXCHANGE_RefreshData *rd,
unsigned int num_coins,
const struct TALER_ExchangeWithdrawValues *alg_values,
uint32_t noreveal_index, uint32_t noreveal_index,
TALER_EXCHANGE_RefreshesRevealCallback reveal_cb, TALER_EXCHANGE_RefreshesRevealCallback reveal_cb,
void *reveal_cb_cls); void *reveal_cb_cls);
@ -2124,6 +2164,7 @@ typedef void
* @param exchange the exchange handle; the exchange must be ready to operate * @param exchange the exchange handle; the exchange must be ready to operate
* @param pk kind of coin to pay back * @param pk kind of coin to pay back
* @param denom_sig signature over the coin by the exchange using @a pk * @param denom_sig signature over the coin by the exchange using @a pk
* @param exchange_vals contribution from the exchange on the withdraw
* @param ps secret internals of the original planchet * @param ps secret internals of the original planchet
* @param recoup_cb the callback to call when the final result for this request is available * @param recoup_cb the callback to call when the final result for this request is available
* @param recoup_cb_cls closure for @a recoup_cb * @param recoup_cb_cls closure for @a recoup_cb
@ -2135,6 +2176,7 @@ struct TALER_EXCHANGE_RecoupHandle *
TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange, TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
const struct TALER_EXCHANGE_DenomPublicKey *pk, const struct TALER_EXCHANGE_DenomPublicKey *pk,
const struct TALER_DenominationSignature *denom_sig, const struct TALER_DenominationSignature *denom_sig,
const struct TALER_ExchangeWithdrawValues *exchange_vals,
const struct TALER_PlanchetSecretsP *ps, const struct TALER_PlanchetSecretsP *ps,
TALER_EXCHANGE_RecoupResultCallback recoup_cb, TALER_EXCHANGE_RecoupResultCallback recoup_cb,
void *recoup_cb_cls); void *recoup_cb_cls);
@ -2184,7 +2226,8 @@ typedef void
* @param exchange the exchange handle; the exchange must be ready to operate * @param exchange the exchange handle; the exchange must be ready to operate
* @param pk kind of coin to pay back * @param pk kind of coin to pay back
* @param denom_sig signature over the coin by the exchange using @a pk * @param denom_sig signature over the coin by the exchange using @a pk
* @param ps secret internals of the original planchet * @param exchange_vals contribution from the exchange on the withdraw
* @param ps secret internals of the original refresh-reveal operation
* @param recoup_cb the callback to call when the final result for this request is available * @param recoup_cb the callback to call when the final result for this request is available
* @param recoup_cb_cls closure for @a recoup_cb * @param recoup_cb_cls closure for @a recoup_cb
* @return NULL * @return NULL
@ -2196,6 +2239,7 @@ TALER_EXCHANGE_recoup_refresh (
struct TALER_EXCHANGE_Handle *exchange, struct TALER_EXCHANGE_Handle *exchange,
const struct TALER_EXCHANGE_DenomPublicKey *pk, const struct TALER_EXCHANGE_DenomPublicKey *pk,
const struct TALER_DenominationSignature *denom_sig, const struct TALER_DenominationSignature *denom_sig,
const struct TALER_ExchangeWithdrawValues *exchange_vals,
const struct TALER_PlanchetSecretsP *ps, const struct TALER_PlanchetSecretsP *ps,
TALER_EXCHANGE_RecoupRefreshResultCallback recoup_cb, TALER_EXCHANGE_RecoupRefreshResultCallback recoup_cb,
void *recoup_cb_cls); void *recoup_cb_cls);

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2015-2021 Taler Systems SA Copyright (C) 2015-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software terms of the GNU General Public License as published by the Free Software
@ -73,7 +73,23 @@ struct TALER_EXCHANGE_MeltHandle
/** /**
* Actual information about the melt operation. * Actual information about the melt operation.
*/ */
struct MeltData *md; struct MeltData md;
/**
* The secret the entire melt operation is seeded from.
*/
const struct TALER_PlanchetSecretsP *ps;
/**
* Details about the characteristics of the requested melt operation.
*/
const struct TALER_EXCHANGE_RefreshData *rd;
/**
* Array of `num_fresh_coins` contributory values of
* the exchange to the melt operation.
*/
struct TALER_ExchangeWithdrawValues *alg_values;
/** /**
* Public key of the coin being melted. * Public key of the coin being melted.
@ -106,9 +122,12 @@ verify_melt_signature_ok (struct TALER_EXCHANGE_MeltHandle *mh,
struct TALER_ExchangeSignatureP exchange_sig; struct TALER_ExchangeSignatureP exchange_sig;
const struct TALER_EXCHANGE_Keys *key_state; const struct TALER_EXCHANGE_Keys *key_state;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig), GNUNET_JSON_spec_fixed_auto ("exchange_sig",
GNUNET_JSON_spec_fixed_auto ("exchange_pub", exchange_pub), &exchange_sig),
GNUNET_JSON_spec_uint32 ("noreveal_index", noreveal_index), GNUNET_JSON_spec_fixed_auto ("exchange_pub",
exchange_pub),
GNUNET_JSON_spec_uint32 ("noreveal_index",
noreveal_index),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
struct TALER_RefreshMeltConfirmationPS confirm; struct TALER_RefreshMeltConfirmationPS confirm;
@ -338,6 +357,12 @@ handle_melt_finished (void *cls,
{ {
mh->melt_cb (mh->melt_cb_cls, mh->melt_cb (mh->melt_cb_cls,
&hr, &hr,
(0 == hr.http_status)
? 0
: mh->rd->fresh_pks_len,
(0 == hr.http_status)
? NULL
: mh->alg_values,
noreveal_index, noreveal_index,
(0 == hr.http_status) (0 == hr.http_status)
? NULL ? NULL
@ -419,40 +444,37 @@ handle_melt_finished (void *cls,
if (NULL != mh->melt_cb) if (NULL != mh->melt_cb)
mh->melt_cb (mh->melt_cb_cls, mh->melt_cb (mh->melt_cb_cls,
&hr, &hr,
0,
NULL,
UINT32_MAX, UINT32_MAX,
NULL); NULL);
TALER_EXCHANGE_melt_cancel (mh); TALER_EXCHANGE_melt_cancel (mh);
} }
struct TALER_EXCHANGE_MeltHandle * static enum GNUNET_GenericReturnValue
TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange, start_melt (struct TALER_EXCHANGE_MeltHandle *mh)
const json_t *refresh_data,
TALER_EXCHANGE_MeltCallback melt_cb,
void *melt_cb_cls)
{ {
const struct TALER_EXCHANGE_Keys *key_state; const struct TALER_EXCHANGE_Keys *key_state;
const struct TALER_EXCHANGE_DenomPublicKey *dki; const struct TALER_EXCHANGE_DenomPublicKey *dki;
json_t *melt_obj; json_t *melt_obj;
struct TALER_EXCHANGE_MeltHandle *mh;
CURL *eh; CURL *eh;
struct GNUNET_CURL_Context *ctx; struct GNUNET_CURL_Context *ctx;
struct MeltData *md;
struct TALER_CoinSpendSignatureP confirm_sig; struct TALER_CoinSpendSignatureP confirm_sig;
char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32]; char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32];
struct TALER_DenominationHash h_denom_pub; struct TALER_DenominationHash h_denom_pub;
struct TALER_CoinSpendPublicKeyP coin_pub; struct TALER_CoinSpendPublicKeyP coin_pub;
GNUNET_assert (GNUNET_YES == if (GNUNET_OK !=
TEAH_handle_is_ready (exchange)); TALER_EXCHANGE_get_melt_data_ (mh->ps,
md = TALER_EXCHANGE_deserialize_melt_data_ (refresh_data, mh->rd,
exchange->key_data.currency); mh->alg_values,
if (NULL == md) &mh->md))
{ {
GNUNET_break (0); GNUNET_break (0);
return NULL; return GNUNET_SYSERR;
} }
TALER_denom_pub_hash (&md->melted_coin.pub_key, TALER_denom_pub_hash (&mh->md.melted_coin.pub_key,
&h_denom_pub); &h_denom_pub);
TALER_wallet_melt_sign (&md->melted_coin.melt_amount_with_fee, TALER_wallet_melt_sign (&md->melted_coin.melt_amount_with_fee,
&md->melted_coin.fee_melt, &md->melted_coin.fee_melt,
@ -489,29 +511,19 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
pub_str); pub_str);
} }
key_state = TALER_EXCHANGE_get_keys (exchange); ctx = TEAH_handle_to_context (mh->exchange);
key_state = TALER_EXCHANGE_get_keys (mh->exchange);
dki = TALER_EXCHANGE_get_denomination_key (key_state, dki = TALER_EXCHANGE_get_denomination_key (key_state,
&md->melted_coin.pub_key); &mh->md.melted_coin.pub_key);
/* and now we can at last begin the actual request handling */ /* and now we can at last begin the actual request handling */
mh = GNUNET_new (struct TALER_EXCHANGE_MeltHandle);
mh->exchange = exchange; mh->url = TEAH_path_to_url (mh->exchange,
mh->coin_pub = coin_pub;
mh->dki = *dki;
memset (&mh->dki.key,
0,
sizeof (mh->dki.key)); /* lifetime not warranted, so better
not copy the pointers */
mh->melt_cb = melt_cb;
mh->melt_cb_cls = melt_cb_cls;
mh->md = md;
mh->url = TEAH_path_to_url (exchange,
arg_str); arg_str);
if (NULL == mh->url) if (NULL == mh->url)
{ {
json_decref (melt_obj); json_decref (melt_obj);
GNUNET_free (mh); return GNUNET_SYSERR;
return NULL;
} }
eh = TALER_EXCHANGE_curl_easy_get_ (mh->url); eh = TALER_EXCHANGE_curl_easy_get_ (mh->url);
if ( (NULL == eh) || if ( (NULL == eh) ||
@ -524,17 +536,154 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
if (NULL != eh) if (NULL != eh)
curl_easy_cleanup (eh); curl_easy_cleanup (eh);
json_decref (melt_obj); json_decref (melt_obj);
GNUNET_free (mh->url); return GNUNET_SYSERR;
GNUNET_free (mh);
return NULL;
} }
json_decref (melt_obj); json_decref (melt_obj);
ctx = TEAH_handle_to_context (exchange);
mh->job = GNUNET_CURL_job_add2 (ctx, mh->job = GNUNET_CURL_job_add2 (ctx,
eh, eh,
mh->ctx.headers, mh->ctx.headers,
&handle_melt_finished, &handle_melt_finished,
mh); mh);
return GNUNET_OK;
}
static void
fail_mh (struct TALER_EXCHANGE_MeltHandle *mh)
{
// FIXME: do return more than NULLs if
// the /csr failed!
mh->melt_cb (mh->melt_cb_cls,
NULL,
0,
NULL,
UINT32_MAX,
NULL);
TALER_EXCHANGE_melt_cancel (mh);
}
/**
* Callbacks of this type are used to serve the result of submitting a
* CS R request to a exchange.
*
* @param cls closure with our `struct TALER_EXCHANGE_MeltHandle *`
* @param csrr response details
*/
static void
csr_cb (void *cls,
const struct TALER_EXCHANGE_CsRResponse *csrr)
{
struct TALER_EXCHANGE_MeltHandle *mh = cls;
unsigned int nks_off = 0;
for (unsigned int i = 0; i<rd->fresh_pks_len; i++)
{
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk = &rd->fresh_pks[i];
struct TALER_ExchangeWithdrawValues *wv = &mh->alg_values[i];
switch (fresh_pk->cipher)
{
case TALER_DENOMINATION_INVALID:
GNUNET_break (0);
fail_mh (mh).
return;
case TALER_DENOMINATION_RSA:
GNUNET_assert (TALER_DENOMINATION_RSA == wv->cipher);
break;
case TALER_DENOMINATION_CS:
GNUNET_assert (TALER_DENOMINATION_CS == wv->cipher);
*wv = csrr->details.success.alg_values[nks_off];
nks_off++;
break;
}
}
if (GNUNET_OK !=
start_melt (mh))
{
GNUNET_break (0);
fail_mh (mh);
return;
}
}
struct TALER_EXCHANGE_MeltHandle *
TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
const struct TALER_PlanchetSecretsP *ps,
const struct TALER_EXCHANGE_RefreshData *rd,
TALER_EXCHANGE_MeltCallback melt_cb,
void *melt_cb_cls)
s
{
const struct TALER_EXCHANGE_NonceKey *nks[GNUNET_NZL (rd->refresh_pks_len)];
unsigned int nks_off = 0;
if (0 == rd->refresh_pks_len)
{
GNUNET_break (0);
return NULL;
}
GNUNET_assert (GNUNET_YES ==
TEAH_handle_is_ready (exchange));
mh = GNUNET_new (struct TALER_EXCHANGE_MeltHandle);
mh->exchange = exchange;
mh->rd = rd;
mh->ps = ps;
mh->melt_cb = melt_cb;
mh->melt_cb_cls = melt_cb_cls;
mh->alg_values = GNUNET_new_array (struct TALER_ExchangeWithdrawValues,
rd->fresh_pks_len);
for (unsigned int i = 0; i<rd->fresh_pks_len; i++)
{
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk = &rd->fresh_pks[i];
struct TALER_ExchangeWithdrawValues *wv = &mh->alg_values[i];
switch (fresh_pk->cipher)
{
case TALER_DENOMINATION_INVALID:
GNUNET_break (0);
GNUNET_free (mh->alg_values);
GNUNET_free (mh);
return NULL;
case TALER_DENOMINATION_RSA:
wv->cipher = TALER_DENOMINATION_RSA;
break;
case TALER_DENOMINATION_CS:
wv->cipher = TALER_DENOMINATION_CS;
nks[nks_off].pk = fresh_pk;
// derive nonce for refresh by index and ps;
// FIXME: include fresh_pk or not?
TALER_CRYPTO_XXX (ps,
fresh_pk,
i,
&nks[nks_off].nonce);
nks_off++;
break;
}
}
if (0 != nks_off)
{
mh->csr = TALER_EXCHANGE_csr (exchange,
nks_off,
nks,
&csr_cb,
mh);
if (NULL == mh->csr)
{
GNUNET_break (0);
TALER_EXCHANGE_melt_cancel (mh->csr);
return NULL;
}
return mh;
}
if (GNUNET_OK !=
start_melt (mh))
{
GNUNET_break (0);
TALER_EXCHANGE_melt_cancel (mh->csr);
return NULL;
}
return mh; return mh;
} }
@ -547,8 +696,7 @@ TALER_EXCHANGE_melt_cancel (struct TALER_EXCHANGE_MeltHandle *mh)
GNUNET_CURL_job_cancel (mh->job); GNUNET_CURL_job_cancel (mh->job);
mh->job = NULL; mh->job = NULL;
} }
TALER_EXCHANGE_free_melt_data_ (mh->md); /* does not free 'md' itself */ TALER_EXCHANGE_free_melt_data_ (&mh->md); /* does not free 'md' itself */
GNUNET_free (mh->md);
GNUNET_free (mh->url); GNUNET_free (mh->url);
TALER_curl_easy_post_finished (&mh->ctx); TALER_curl_easy_post_finished (&mh->ctx);
GNUNET_free (mh); GNUNET_free (mh);

View File

@ -23,24 +23,11 @@
#include "exchange_api_refresh_common.h" #include "exchange_api_refresh_common.h"
/**
* Free all information associated with a melted coin session.
*
* @param mc melted coin to release, the pointer itself is NOT
* freed (as it is typically not allocated by itself)
*/
static void
free_melted_coin (struct MeltedCoin *mc)
{
TALER_denom_pub_free (&mc->pub_key);
TALER_denom_sig_free (&mc->sig);
}
void void
TALER_EXCHANGE_free_melt_data_ (struct MeltData *md) TALER_EXCHANGE_free_melt_data_ (struct MeltData *md)
{ {
free_melted_coin (&md->melted_coin); TALER_denom_pub_free (&md->melted_coin.pub_key);
TALER_denom_sig_free (&md->melted_coin.sig);
if (NULL != md->fresh_pks) if (NULL != md->fresh_pks)
{ {
for (unsigned int i = 0; i<md->num_fresh_coins; i++) for (unsigned int i = 0; i<md->num_fresh_coins; i++)
@ -55,296 +42,12 @@ TALER_EXCHANGE_free_melt_data_ (struct MeltData *md)
} }
/** enum GNUNET_GenericReturnValue
* Serialize information about a coin we are melting. TALER_EXCHANGE_get_melt_data_ (
* const struct TALER_PlanchetSecretsP *ps,
* @param mc information to serialize const struct struct TALER_EXCHANGE_RefreshData *rd,
* @return NULL on error const struct TALER_ExchangeWithdrawValues *alg_values,
*/ struct MeltData *md)
static json_t *
serialize_melted_coin (const struct MeltedCoin *mc)
{
json_t *tprivs;
tprivs = json_array ();
GNUNET_assert (NULL != tprivs);
for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++)
GNUNET_assert (0 ==
json_array_append_new (
tprivs,
GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto (
"transfer_priv",
&mc->transfer_priv[i]))));
return GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("coin_priv",
&mc->coin_priv),
TALER_JSON_pack_denom_sig ("denom_sig",
&mc->sig),
TALER_JSON_pack_denom_pub ("denom_pub",
&mc->pub_key),
TALER_JSON_pack_amount ("melt_amount_with_fee",
&mc->melt_amount_with_fee),
TALER_JSON_pack_amount ("original_value",
&mc->original_value),
TALER_JSON_pack_amount ("melt_fee",
&mc->fee_melt),
GNUNET_JSON_pack_timestamp ("expire_deposit",
mc->expire_deposit),
GNUNET_JSON_pack_array_steal ("transfer_privs",
tprivs));
}
/**
* Deserialize information about a coin we are melting.
*
* @param[out] mc information to deserialize
* @param currency expected currency
* @param in JSON object to read data from
* @return #GNUNET_NO to report errors
*/
static enum GNUNET_GenericReturnValue
deserialize_melted_coin (struct MeltedCoin *mc,
const char *currency,
const json_t *in)
{
json_t *trans_privs;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("coin_priv",
&mc->coin_priv),
TALER_JSON_spec_denom_sig ("denom_sig",
&mc->sig),
TALER_JSON_spec_denom_pub ("denom_pub",
&mc->pub_key),
TALER_JSON_spec_amount ("melt_amount_with_fee",
currency,
&mc->melt_amount_with_fee),
TALER_JSON_spec_amount ("original_value",
currency,
&mc->original_value),
TALER_JSON_spec_amount ("melt_fee",
currency,
&mc->fee_melt),
GNUNET_JSON_spec_timestamp ("expire_deposit",
&mc->expire_deposit),
GNUNET_JSON_spec_json ("transfer_privs",
&trans_privs),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (in,
spec,
NULL, NULL))
{
GNUNET_break_op (0);
return GNUNET_NO;
}
if (TALER_CNC_KAPPA != json_array_size (trans_privs))
{
GNUNET_JSON_parse_free (spec);
GNUNET_break_op (0);
return GNUNET_NO;
}
for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++)
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("transfer_priv",
&mc->transfer_priv[i]),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (json_array_get (trans_privs,
i),
spec,
NULL, NULL))
{
GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_NO;
}
}
json_decref (trans_privs);
return GNUNET_OK;
}
/**
* Serialize melt data.
*
* @param md data to serialize
* @return serialized melt data
*/
static json_t *
serialize_melt_data (const struct MeltData *md)
{
json_t *fresh_coins;
fresh_coins = json_array ();
GNUNET_assert (NULL != fresh_coins);
for (int i = 0; i<md->num_fresh_coins; i++)
{
json_t *planchet_secrets;
planchet_secrets = json_array ();
GNUNET_assert (NULL != planchet_secrets);
for (unsigned int j = 0; j<TALER_CNC_KAPPA; j++)
{
json_t *ps;
ps = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("ps",
&md->fresh_coins[j][i]));
GNUNET_assert (0 ==
json_array_append_new (planchet_secrets,
ps));
}
GNUNET_assert (0 ==
json_array_append_new (
fresh_coins,
GNUNET_JSON_PACK (
TALER_JSON_pack_denom_pub ("denom_pub",
&md->fresh_pks[i]),
GNUNET_JSON_pack_array_steal ("planchet_secrets",
planchet_secrets)))
);
}
return GNUNET_JSON_PACK (
GNUNET_JSON_pack_array_steal ("fresh_coins",
fresh_coins),
GNUNET_JSON_pack_object_steal ("melted_coin",
serialize_melted_coin (&md->melted_coin)),
GNUNET_JSON_pack_data_auto ("rc",
&md->rc));
}
struct MeltData *
TALER_EXCHANGE_deserialize_melt_data_ (const json_t *melt_data,
const char *currency)
{
struct MeltData *md = GNUNET_new (struct MeltData);
json_t *fresh_coins;
json_t *melted_coin;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("rc",
&md->rc),
GNUNET_JSON_spec_json ("melted_coin",
&melted_coin),
GNUNET_JSON_spec_json ("fresh_coins",
&fresh_coins),
GNUNET_JSON_spec_end ()
};
bool ok;
if (GNUNET_OK !=
GNUNET_JSON_parse (melt_data,
spec,
NULL, NULL))
{
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
GNUNET_free (md);
return NULL;
}
if (! (json_is_array (fresh_coins) &&
json_is_object (melted_coin)) )
{
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
return NULL;
}
if (GNUNET_OK !=
deserialize_melted_coin (&md->melted_coin,
currency,
melted_coin))
{
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
return NULL;
}
md->num_fresh_coins = json_array_size (fresh_coins);
md->fresh_pks = GNUNET_new_array (md->num_fresh_coins,
struct TALER_DenominationPublicKey);
for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++)
md->fresh_coins[i] = GNUNET_new_array (md->num_fresh_coins,
struct TALER_PlanchetSecretsP);
ok = true;
for (unsigned int i = 0; i<md->num_fresh_coins; i++)
{
const json_t *ji = json_array_get (fresh_coins,
i);
json_t *planchet_secrets;
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_json ("planchet_secrets",
&planchet_secrets),
TALER_JSON_spec_denom_pub ("denom_pub",
&md->fresh_pks[i]),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (ji,
ispec,
NULL, NULL))
{
GNUNET_break (0);
ok = false;
break;
}
if ( (! json_is_array (planchet_secrets)) ||
(TALER_CNC_KAPPA != json_array_size (planchet_secrets)) )
{
GNUNET_break (0);
ok = false;
GNUNET_JSON_parse_free (ispec);
break;
}
for (unsigned int j = 0; j<TALER_CNC_KAPPA; j++)
{
struct GNUNET_JSON_Specification jspec[] = {
GNUNET_JSON_spec_fixed_auto ("ps",
&md->fresh_coins[j][i]),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (json_array_get (planchet_secrets,
j),
jspec,
NULL, NULL))
{
GNUNET_break (0);
ok = false;
break;
}
}
json_decref (planchet_secrets);
if (! ok)
break;
}
GNUNET_JSON_parse_free (spec);
if (! ok)
{
TALER_EXCHANGE_free_melt_data_ (md);
GNUNET_free (md);
return NULL;
}
return md;
}
json_t *
TALER_EXCHANGE_refresh_prepare (
const struct TALER_CoinSpendPrivateKeyP *melt_priv,
const struct TALER_Amount *melt_amount,
const struct TALER_DenominationSignature *melt_sig,
const struct TALER_EXCHANGE_DenomPublicKey *melt_pk,
unsigned int fresh_pks_len,
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pks)
{ {
struct MeltData md; struct MeltData md;
json_t *ret; json_t *ret;
@ -359,68 +62,68 @@ TALER_EXCHANGE_refresh_prepare (
memset (&md, memset (&md,
0, 0,
sizeof (md)); sizeof (md));
md.num_fresh_coins = fresh_pks_len; md.num_fresh_coins = rd->fresh_pks_len;
md.melted_coin.coin_priv = *melt_priv; md.melted_coin.coin_priv = rd->melt_priv;
md.melted_coin.melt_amount_with_fee = *melt_amount; md.melted_coin.melt_amount_with_fee = rd->melt_amount;
md.melted_coin.fee_melt = melt_pk->fee_refresh; md.melted_coin.fee_melt = rd->melt_pk->fee_refresh;
md.melted_coin.original_value = melt_pk->value; md.melted_coin.original_value = rd->melt_pk->value;
md.melted_coin.expire_deposit md.melted_coin.expire_deposit = rd->melt_pk->expire_deposit;
= melt_pk->expire_deposit;
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (melt_amount->currency, TALER_amount_set_zero (melt_amount->currency,
&total)); &total));
TALER_denom_pub_deep_copy (&md.melted_coin.pub_key, TALER_denom_pub_deep_copy (&md.melted_coin.pub_key,
&melt_pk->key); &rd->melt_pk->key);
TALER_denom_sig_deep_copy (&md.melted_coin.sig, TALER_denom_sig_deep_copy (&md.melted_coin.sig,
melt_sig); rd->melt_sig);
md.fresh_pks = GNUNET_new_array (fresh_pks_len, md.fresh_pks = GNUNET_new_array (rd->fresh_pks_len,
struct TALER_DenominationPublicKey); struct TALER_DenominationPublicKey);
for (unsigned int i = 0; i<fresh_pks_len; i++) for (unsigned int i = 0; i<rd->fresh_pks_len; i++)
{ {
TALER_denom_pub_deep_copy (&md.fresh_pks[i], TALER_denom_pub_deep_copy (&md.fresh_pks[i],
&fresh_pks[i].key); &fresh_pks[i].key);
if ( (0 > if ( (0 >
TALER_amount_add (&total, TALER_amount_add (&total,
&total, &total,
&fresh_pks[i].value)) || &rd->fresh_pks[i].value)) ||
(0 > (0 >
TALER_amount_add (&total, TALER_amount_add (&total,
&total, &total,
&fresh_pks[i].fee_withdraw)) ) &rd->fresh_pks[i].fee_withdraw)) )
{ {
GNUNET_break (0); GNUNET_break (0);
TALER_EXCHANGE_free_melt_data_ (&md); TALER_EXCHANGE_free_melt_data_ (&md);
return NULL; return GNUNET_SYSERR;
} }
} }
/* verify that melt_amount is above total cost */ /* verify that melt_amount is above total cost */
if (1 == if (1 ==
TALER_amount_cmp (&total, TALER_amount_cmp (&total,
melt_amount) ) rd->melt_amount) )
{ {
/* Eh, this operation is more expensive than the /* Eh, this operation is more expensive than the
@a melt_amount. This is not OK. */ @a melt_amount. This is not OK. */
GNUNET_break (0); GNUNET_break (0);
TALER_EXCHANGE_free_melt_data_ (&md); TALER_EXCHANGE_free_melt_data_ (&md);
return NULL; return GNUNET_SYSERR;
} }
/* build up coins */ /* build up coins */
for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++) for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++)
{ {
// FIXME: derive!
GNUNET_CRYPTO_ecdhe_key_create ( GNUNET_CRYPTO_ecdhe_key_create (
&md.melted_coin.transfer_priv[i].ecdhe_priv); &md.melted_coin.transfer_priv[i].ecdhe_priv);
GNUNET_CRYPTO_ecdhe_key_get_public ( GNUNET_CRYPTO_ecdhe_key_get_public (
&md.melted_coin.transfer_priv[i].ecdhe_priv, &md.melted_coin.transfer_priv[i].ecdhe_priv,
&rce[i].transfer_pub.ecdhe_pub); &rce[i].transfer_pub.ecdhe_pub);
TALER_link_derive_transfer_secret (melt_priv, TALER_link_derive_transfer_secret (&rd->melt_priv,
&md.melted_coin.transfer_priv[i], &md.melted_coin.transfer_priv[i],
&trans_sec[i]); &trans_sec[i]);
md.fresh_coins[i] = GNUNET_new_array (fresh_pks_len, md.fresh_coins[i] = GNUNET_new_array (rd->fresh_pks_len,
struct TALER_PlanchetSecretsP); struct TALER_PlanchetSecretsP);
rce[i].new_coins = GNUNET_new_array (fresh_pks_len, rce[i].new_coins = GNUNET_new_array (rd->fresh_pks_len,
struct TALER_RefreshCoinData); struct TALER_RefreshCoinData);
for (unsigned int j = 0; j<fresh_pks_len; j++) for (unsigned int j = 0; j<rd->fresh_pks_len; j++)
{ {
struct TALER_PlanchetSecretsP *fc = &md.fresh_coins[i][j]; struct TALER_PlanchetSecretsP *fc = &md.fresh_coins[i][j];
struct TALER_RefreshCoinData *rcd = &rce[i].new_coins[j]; struct TALER_RefreshCoinData *rcd = &rce[i].new_coins[j];
@ -458,15 +161,12 @@ TALER_EXCHANGE_refresh_prepare (
fresh_pks_len, fresh_pks_len,
rce, rce,
&coin_pub, &coin_pub,
melt_amount); &rd->melt_amount);
/* finally, serialize everything */
ret = serialize_melt_data (&md);
for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++) for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)
{ {
for (unsigned int j = 0; j < fresh_pks_len; j++) for (unsigned int j = 0; j < fresh_pks_len; j++)
GNUNET_free (rce[i].new_coins[j].coin_ev); GNUNET_free (rce[i].new_coins[j].coin_ev);
GNUNET_free (rce[i].new_coins); GNUNET_free (rce[i].new_coins);
} }
TALER_EXCHANGE_free_melt_data_ (&md); return GNUNET_OK;
return ret;
} }

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2015-2020 Taler Systems SA Copyright (C) 2015-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software terms of the GNU General Public License as published by the Free Software
@ -102,6 +102,12 @@ struct MeltData
*/ */
struct TALER_DenominationPublicKey *fresh_pks; struct TALER_DenominationPublicKey *fresh_pks;
/**
* Array of @e num_fresh_coins with exchange contributions
* made during the refresh.
*/
struct TALER_ExchangeWithdrawValues *exchange_vals;
/** /**
* Arrays of @e num_fresh_coins with information about the fresh * Arrays of @e num_fresh_coins with information about the fresh
* coins to be created, for each cut-and-choose dimension. * coins to be created, for each cut-and-choose dimension.
@ -111,15 +117,19 @@ struct MeltData
/** /**
* Deserialize melt data. * Compute the melt data from the refresh data and secret.
* *
* @param data json data to deserialize * @param ps secret internals of the refresh-reveal operation
* @param currency expected currency for the coins * @param rd refresh data with the characteristics of the operation
* @return deserialized melt data, NULL on error * @param alg_values contributions from the exchange into the melt
* @param[out] rd where to write the derived melt data
*/ */
struct MeltData * enum GNUNET_GenericReturnValue
TALER_EXCHANGE_deserialize_melt_data_ (const json_t *data, TALER_EXCHANGE_get_melt_data_ (
const char *currency); const struct TALER_PlanchetSecretsP *ps,
const struct struct TALER_EXCHANGE_RefreshData *rd,
const struct TALER_ExchangeWithdrawValues *alg_values,
struct MeltData *md);
/** /**

View File

@ -73,7 +73,7 @@ struct TALER_EXCHANGE_RefreshesRevealHandle
/** /**
* Actual information about the melt operation. * Actual information about the melt operation.
*/ */
struct MeltData *md; struct MeltData md;
/** /**
* The index selected by the exchange in cut-and-choose to not be revealed. * The index selected by the exchange in cut-and-choose to not be revealed.
@ -95,12 +95,14 @@ struct TALER_EXCHANGE_RefreshesRevealHandle
* *
* @param rrh operation handle * @param rrh operation handle
* @param json reply from the exchange * @param json reply from the exchange
* @param[out] sigs array of length `num_fresh_coins`, initialized to contain RSA signatures * @param[out] sigs array of length `num_fresh_coins`, initialized to contain the coin private keys
* @param[out] sigs array of length `num_fresh_coins`, initialized to contain signatures
* @return #GNUNET_OK on success, #GNUNET_SYSERR on errors * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
*/ */
static enum GNUNET_GenericReturnValue static enum GNUNET_GenericReturnValue
refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh, refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh,
const json_t *json, const json_t *json,
struct TALER_CoinSpendPrivateKeyP *coin_privs,
struct TALER_DenominationSignature *sigs) struct TALER_DenominationSignature *sigs)
{ {
json_t *jsona; json_t *jsona;
@ -165,6 +167,7 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh,
/* needed to verify the signature, and we didn't store it earlier, /* needed to verify the signature, and we didn't store it earlier,
hence recomputing it here... */ hence recomputing it here... */
coin_privs[i] = fc->coin_priv;
GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv, GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
&coin_pub.eddsa_pub); &coin_pub.eddsa_pub);
/* FIXME-Oec: Age commitment hash. */ /* FIXME-Oec: Age commitment hash. */
@ -223,13 +226,15 @@ handle_refresh_reveal_finished (void *cls,
case MHD_HTTP_OK: case MHD_HTTP_OK:
{ {
struct TALER_DenominationSignature sigs[rrh->md->num_fresh_coins]; struct TALER_DenominationSignature sigs[rrh->md->num_fresh_coins];
int ret; struct TALER_CoinSpendPrivateKeyP coin_privs[rrh->md->num_fresh_coins];
enum GNUNET_GenericReturnValue ret;
memset (sigs, memset (sigs,
0, 0,
sizeof (sigs)); sizeof (sigs));
ret = refresh_reveal_ok (rrh, ret = refresh_reveal_ok (rrh,
j, j,
coin_privs,
sigs); sigs);
if (GNUNET_OK != ret) if (GNUNET_OK != ret)
{ {
@ -241,7 +246,7 @@ handle_refresh_reveal_finished (void *cls,
rrh->reveal_cb (rrh->reveal_cb_cls, rrh->reveal_cb (rrh->reveal_cb_cls,
&hr, &hr,
rrh->md->num_fresh_coins, rrh->md->num_fresh_coins,
rrh->md->fresh_coins[rrh->noreveal_index], coin_privs,
sigs); sigs);
rrh->reveal_cb = NULL; rrh->reveal_cb = NULL;
} }
@ -298,7 +303,10 @@ handle_refresh_reveal_finished (void *cls,
struct TALER_EXCHANGE_RefreshesRevealHandle * struct TALER_EXCHANGE_RefreshesRevealHandle *
TALER_EXCHANGE_refreshes_reveal ( TALER_EXCHANGE_refreshes_reveal (
struct TALER_EXCHANGE_Handle *exchange, struct TALER_EXCHANGE_Handle *exchange,
const json_t *refresh_data, const struct TALER_PlanchetSecretsP *ps,
const struct TALER_EXCHANGE_RefreshData *rd,
unsigned int num_coins,
const struct TALER_ExchangeWithdrawValues *alg_values,
uint32_t noreveal_index, uint32_t noreveal_index,
TALER_EXCHANGE_RefreshesRevealCallback reveal_cb, TALER_EXCHANGE_RefreshesRevealCallback reveal_cb,
void *reveal_cb_cls) void *reveal_cb_cls)
@ -311,10 +319,11 @@ TALER_EXCHANGE_refreshes_reveal (
json_t *link_sigs; json_t *link_sigs;
CURL *eh; CURL *eh;
struct GNUNET_CURL_Context *ctx; struct GNUNET_CURL_Context *ctx;
struct MeltData *md; struct MeltData md;
struct TALER_TransferPublicKeyP transfer_pub; struct TALER_TransferPublicKeyP transfer_pub;
char arg_str[sizeof (struct TALER_RefreshCommitmentP) * 2 + 32]; char arg_str[sizeof (struct TALER_RefreshCommitmentP) * 2 + 32];
GNUNET_assert (num_coins == rd->fresh_pks_len);
if (noreveal_index >= TALER_CNC_KAPPA) if (noreveal_index >= TALER_CNC_KAPPA)
{ {
/* We check this here, as it would be really bad to below just /* We check this here, as it would be really bad to below just
@ -330,9 +339,11 @@ TALER_EXCHANGE_refreshes_reveal (
GNUNET_break (0); GNUNET_break (0);
return NULL; return NULL;
} }
md = TALER_EXCHANGE_deserialize_melt_data_ (refresh_data, if (GNUNET_OK !=
exchange->key_data.currency); TALER_EXCHANGE_get_melt_data_ (ps,
if (NULL == md) rd,
alg_values,
&md))
{ {
GNUNET_break (0); GNUNET_break (0);
return NULL; return NULL;
@ -340,33 +351,31 @@ TALER_EXCHANGE_refreshes_reveal (
/* now transfer_pub */ /* now transfer_pub */
GNUNET_CRYPTO_ecdhe_key_get_public ( GNUNET_CRYPTO_ecdhe_key_get_public (
&md->melted_coin.transfer_priv[noreveal_index].ecdhe_priv, &md.melted_coin.transfer_priv[noreveal_index].ecdhe_priv,
&transfer_pub.ecdhe_pub); &transfer_pub.ecdhe_pub);
/* now new_denoms */ /* now new_denoms */
GNUNET_assert (NULL != (new_denoms_h = json_array ())); GNUNET_assert (NULL != (new_denoms_h = json_array ()));
GNUNET_assert (NULL != (coin_evs = json_array ())); GNUNET_assert (NULL != (coin_evs = json_array ()));
GNUNET_assert (NULL != (link_sigs = json_array ())); GNUNET_assert (NULL != (link_sigs = json_array ()));
for (unsigned int i = 0; i<md->num_fresh_coins; i++) for (unsigned int i = 0; i<md.num_fresh_coins; i++)
{ {
struct TALER_DenominationHash denom_hash; struct TALER_DenominationHash denom_hash;
struct TALER_ExchangeWithdrawValues alg_values; struct TALER_ExchangeWithdrawValues alg_values;
struct TALER_PlanchetDetail pd; struct TALER_PlanchetDetail pd;
struct TALER_CoinPubHash c_hash; struct TALER_CoinPubHash c_hash;
TALER_denom_pub_hash (&md->fresh_pks[i], TALER_denom_pub_hash (&md.fresh_pks[i],
&denom_hash); &denom_hash);
GNUNET_assert (0 == GNUNET_assert (0 ==
json_array_append_new (new_denoms_h, json_array_append_new (new_denoms_h,
GNUNET_JSON_from_data_auto ( GNUNET_JSON_from_data_auto (
&denom_hash))); &denom_hash)));
// TODO: implement cipher handling
alg_values.cipher = TALER_DENOMINATION_RSA;
if (GNUNET_OK != if (GNUNET_OK !=
TALER_planchet_prepare (&md->fresh_pks[i], TALER_planchet_prepare (&md.fresh_pks[i],
&alg_values, &rrh->exchange_vals[i],
&md->fresh_coins[noreveal_index][i], &md.fresh_coins[noreveal_index][i],
&c_hash, &c_hash,
&pd)) &pd))
{ {
@ -374,6 +383,7 @@ TALER_EXCHANGE_refreshes_reveal (
GNUNET_break (0); GNUNET_break (0);
json_decref (new_denoms_h); json_decref (new_denoms_h);
json_decref (coin_evs); json_decref (coin_evs);
TALER_EXCHANGE_free_melt_data_ (&md);
return NULL; return NULL;
} }
GNUNET_assert (0 == GNUNET_assert (0 ==
@ -394,7 +404,7 @@ TALER_EXCHANGE_refreshes_reveal (
blinded_msg, blinded_msg,
pd.blinded_planchet.details.rsa_blinded_planchet. pd.blinded_planchet.details.rsa_blinded_planchet.
blinded_msg_size, blinded_msg_size,
&md->melted_coin.coin_priv, &md.melted_coin.coin_priv,
&link_sig); &link_sig);
GNUNET_assert (0 == GNUNET_assert (0 ==
json_array_append_new ( json_array_append_new (
@ -417,7 +427,7 @@ TALER_EXCHANGE_refreshes_reveal (
GNUNET_assert (0 == GNUNET_assert (0 ==
json_array_append_new (transfer_privs, json_array_append_new (transfer_privs,
GNUNET_JSON_from_data_auto ( GNUNET_JSON_from_data_auto (
&md->melted_coin.transfer_priv[j]))); &md.melted_coin.transfer_priv[j])));
} }
/* build main JSON request */ /* build main JSON request */
@ -436,9 +446,8 @@ TALER_EXCHANGE_refreshes_reveal (
char pub_str[sizeof (struct TALER_RefreshCommitmentP) * 2]; char pub_str[sizeof (struct TALER_RefreshCommitmentP) * 2];
char *end; char *end;
end = GNUNET_STRINGS_data_to_string (&md->rc, end = GNUNET_STRINGS_data_to_string (&md.rc,
sizeof (struct sizeof (md.rc),
TALER_RefreshCommitmentP),
pub_str, pub_str,
sizeof (pub_str)); sizeof (pub_str));
*end = '\0'; *end = '\0';
@ -459,6 +468,7 @@ TALER_EXCHANGE_refreshes_reveal (
if (NULL == rrh->url) if (NULL == rrh->url)
{ {
json_decref (reveal_obj); json_decref (reveal_obj);
TALER_EXCHANGE_free_melt_data_ (&md);
GNUNET_free (rrh); GNUNET_free (rrh);
return NULL; return NULL;
} }
@ -473,6 +483,7 @@ TALER_EXCHANGE_refreshes_reveal (
if (NULL != eh) if (NULL != eh)
curl_easy_cleanup (eh); curl_easy_cleanup (eh);
json_decref (reveal_obj); json_decref (reveal_obj);
TALER_EXCHANGE_free_melt_data_ (&md);
GNUNET_free (rrh->url); GNUNET_free (rrh->url);
GNUNET_free (rrh); GNUNET_free (rrh);
return NULL; return NULL;
@ -499,8 +510,8 @@ TALER_EXCHANGE_refreshes_reveal_cancel (
} }
GNUNET_free (rrh->url); GNUNET_free (rrh->url);
TALER_curl_easy_post_finished (&rrh->ctx); TALER_curl_easy_post_finished (&rrh->ctx);
TALER_EXCHANGE_free_melt_data_ (rrh->md); /* does not free 'md' itself */ TALER_EXCHANGE_free_melt_data_ (&rrh->md);
GNUNET_free (rrh->md); GNUNET_free (rrh->exchange_vals);
GNUNET_free (rrh); GNUNET_free (rrh);
} }