diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 5eedecdc5..ba80da3e4 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -1392,6 +1392,12 @@ struct TALER_EXCHANGE_WithdrawResponse * Signature over the coin. */ struct TALER_DenominationSignature sig; + + /** + * Values contributed from the exchange during the + * withdraw protocol. + */ + struct TALER_ExchangeWithdrawValues exchange_vals; } success; /** @@ -1664,7 +1670,8 @@ TALER_EXCHANGE_melt_cancel (struct TALER_EXCHANGE_MeltHandle *mh); * * @param cls closure * @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 exchange_vals, @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 sigs array of signature over @a num_coins coins, NULL on error */ @@ -1674,6 +1681,7 @@ typedef void const struct TALER_EXCHANGE_HttpResponse *hr, unsigned int num_coins, const struct TALER_CoinSpendPrivateKeyP *coin_privs, + const struct TALER_ExchangeWithdrawValues *exchange_vals, const struct TALER_DenominationSignature *sigs); @@ -2126,6 +2134,7 @@ typedef void * @param exchange the exchange handle; the exchange must be ready to operate * @param pk kind of coin to pay back * @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 recoup_cb the callback to call when the final result for this request is available * @param recoup_cb_cls closure for @a recoup_cb @@ -2137,6 +2146,7 @@ struct TALER_EXCHANGE_RecoupHandle * TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange, const struct TALER_EXCHANGE_DenomPublicKey *pk, const struct TALER_DenominationSignature *denom_sig, + const struct TALER_ExchangeWithdrawValues *exchange_vals, const struct TALER_PlanchetSecretsP *ps, TALER_EXCHANGE_RecoupResultCallback recoup_cb, void *recoup_cb_cls); @@ -2186,6 +2196,7 @@ typedef void * @param exchange the exchange handle; the exchange must be ready to operate * @param pk kind of coin to pay back * @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 refresh-reveal operation * @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 @@ -2198,6 +2209,7 @@ TALER_EXCHANGE_recoup_refresh ( struct TALER_EXCHANGE_Handle *exchange, const struct TALER_EXCHANGE_DenomPublicKey *pk, const struct TALER_DenominationSignature *denom_sig, + const struct TALER_ExchangeWithdrawValues *exchange_vals, const struct TALER_PlanchetSecretsP *ps, TALER_EXCHANGE_RecoupRefreshResultCallback recoup_cb, void *recoup_cb_cls); diff --git a/src/lib/exchange_api_melt.c b/src/lib/exchange_api_melt.c index f375171b9..204e52546 100644 --- a/src/lib/exchange_api_melt.c +++ b/src/lib/exchange_api_melt.c @@ -427,7 +427,8 @@ handle_melt_finished (void *cls, struct TALER_EXCHANGE_MeltHandle * 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, void *melt_cb_cls) { @@ -445,9 +446,10 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange, GNUNET_assert (GNUNET_YES == TEAH_handle_is_ready (exchange)); - md = TALER_EXCHANGE_deserialize_melt_data_ (refresh_data, - exchange->key_data.currency); - if (NULL == md) + if (GNUNET_OK != + TALER_EXCHANGE_get_melt_data (ps, + rd, + &md)) { GNUNET_break (0); return NULL; @@ -510,6 +512,7 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange, if (NULL == mh->url) { json_decref (melt_obj); + TALER_EXCHANGE_free_melt_data_ (&md); GNUNET_free (mh); return NULL; } @@ -523,6 +526,7 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange, GNUNET_break (0); if (NULL != eh) curl_easy_cleanup (eh); + TALER_EXCHANGE_free_melt_data_ (&md); json_decref (melt_obj); GNUNET_free (mh->url); GNUNET_free (mh); diff --git a/src/lib/exchange_api_refresh_common.c b/src/lib/exchange_api_refresh_common.c index 65c7d6ba4..9fcc26877 100644 --- a/src/lib/exchange_api_refresh_common.c +++ b/src/lib/exchange_api_refresh_common.c @@ -23,24 +23,11 @@ #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 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) { for (unsigned int i = 0; inum_fresh_coins; i++) @@ -55,296 +42,11 @@ TALER_EXCHANGE_free_melt_data_ (struct MeltData *md) } -/** - * Serialize information about a coin we are melting. - * - * @param mc information to serialize - * @return NULL on error - */ -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; itransfer_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; itransfer_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; inum_fresh_coins; i++) - { - json_t *planchet_secrets; - - planchet_secrets = json_array (); - GNUNET_assert (NULL != planchet_secrets); - for (unsigned int j = 0; jfresh_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; ifresh_coins[i] = GNUNET_new_array (md->num_fresh_coins, - struct TALER_PlanchetSecretsP); - ok = true; - for (unsigned int i = 0; inum_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; jfresh_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) +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_get_melt_data_ ( + const struct TALER_PlanchetSecretsP *ps, + const struct struct TALER_EXCHANGE_RefreshData *rd, + struct MeltData *md) { struct MeltData md; json_t *ret; @@ -359,68 +61,68 @@ TALER_EXCHANGE_refresh_prepare ( memset (&md, 0, sizeof (md)); - md.num_fresh_coins = fresh_pks_len; - md.melted_coin.coin_priv = *melt_priv; - md.melted_coin.melt_amount_with_fee = *melt_amount; - md.melted_coin.fee_melt = melt_pk->fee_refresh; - md.melted_coin.original_value = melt_pk->value; - md.melted_coin.expire_deposit - = melt_pk->expire_deposit; + md.num_fresh_coins = rd->fresh_pks_len; + md.melted_coin.coin_priv = rd->melt_priv; + md.melted_coin.melt_amount_with_fee = rd->melt_amount; + md.melted_coin.fee_melt = rd->melt_pk->fee_refresh; + md.melted_coin.original_value = rd->melt_pk->value; + md.melted_coin.expire_deposit = rd->melt_pk->expire_deposit; GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (melt_amount->currency, &total)); 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, - melt_sig); - md.fresh_pks = GNUNET_new_array (fresh_pks_len, + rd->melt_sig); + md.fresh_pks = GNUNET_new_array (rd->fresh_pks_len, struct TALER_DenominationPublicKey); - for (unsigned int i = 0; ifresh_pks_len; i++) { TALER_denom_pub_deep_copy (&md.fresh_pks[i], &fresh_pks[i].key); if ( (0 > TALER_amount_add (&total, &total, - &fresh_pks[i].value)) || + &rd->fresh_pks[i].value)) || (0 > TALER_amount_add (&total, &total, - &fresh_pks[i].fee_withdraw)) ) + &rd->fresh_pks[i].fee_withdraw)) ) { GNUNET_break (0); TALER_EXCHANGE_free_melt_data_ (&md); - return NULL; + return GNUNET_SYSERR; } } /* verify that melt_amount is above total cost */ if (1 == TALER_amount_cmp (&total, - melt_amount) ) + rd->melt_amount) ) { /* Eh, this operation is more expensive than the @a melt_amount. This is not OK. */ GNUNET_break (0); TALER_EXCHANGE_free_melt_data_ (&md); - return NULL; + return GNUNET_SYSERR; } /* build up coins */ for (unsigned int i = 0; imelt_priv, + &md.melted_coin.transfer_priv[i], + &trans_sec[i]); + md.fresh_coins[i] = GNUNET_new_array (rd->fresh_pks_len, 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); - for (unsigned int j = 0; jfresh_pks_len; j++) { struct TALER_PlanchetSecretsP *fc = &md.fresh_coins[i][j]; struct TALER_RefreshCoinData *rcd = &rce[i].new_coins[j]; @@ -458,15 +160,12 @@ TALER_EXCHANGE_refresh_prepare ( fresh_pks_len, rce, &coin_pub, - melt_amount); - /* finally, serialize everything */ - ret = serialize_melt_data (&md); + &rd->melt_amount); for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++) { 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); } - TALER_EXCHANGE_free_melt_data_ (&md); - return ret; + return GNUNET_OK; } diff --git a/src/lib/exchange_api_refresh_common.h b/src/lib/exchange_api_refresh_common.h index 1c037d966..1ce513efb 100644 --- a/src/lib/exchange_api_refresh_common.h +++ b/src/lib/exchange_api_refresh_common.h @@ -111,15 +111,17 @@ struct MeltData /** - * Deserialize melt data. + * Compute the melt data from the refresh data and secret. * - * @param data json data to deserialize - * @param currency expected currency for the coins - * @return deserialized melt data, NULL on error + * @param ps secret internals of the refresh-reveal operation + * @param rd refresh data with the characteristics of the operation + * @param[out] rd where to write the derived melt data */ -struct MeltData * -TALER_EXCHANGE_deserialize_melt_data_ (const json_t *data, - const char *currency); +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_get_melt_data_ ( + const struct TALER_PlanchetSecretsP *ps, + const struct struct TALER_EXCHANGE_RefreshData *rd, + struct MeltData *md); /** diff --git a/src/lib/exchange_api_refreshes_reveal.c b/src/lib/exchange_api_refreshes_reveal.c index 82f92322a..85d20e55d 100644 --- a/src/lib/exchange_api_refreshes_reveal.c +++ b/src/lib/exchange_api_refreshes_reveal.c @@ -73,7 +73,7 @@ struct TALER_EXCHANGE_RefreshesRevealHandle /** * 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. @@ -298,7 +298,8 @@ handle_refresh_reveal_finished (void *cls, struct TALER_EXCHANGE_RefreshesRevealHandle * TALER_EXCHANGE_refreshes_reveal ( struct TALER_EXCHANGE_Handle *exchange, - const json_t *refresh_data, + const struct TALER_PlanchetSecretsP *ps, + const struct TALER_EXCHANGE_RefreshData *rd, uint32_t noreveal_index, TALER_EXCHANGE_RefreshesRevealCallback reveal_cb, void *reveal_cb_cls) @@ -311,7 +312,7 @@ TALER_EXCHANGE_refreshes_reveal ( json_t *link_sigs; CURL *eh; struct GNUNET_CURL_Context *ctx; - struct MeltData *md; + struct MeltData md; struct TALER_TransferPublicKeyP transfer_pub; char arg_str[sizeof (struct TALER_RefreshCommitmentP) * 2 + 32]; @@ -330,9 +331,10 @@ TALER_EXCHANGE_refreshes_reveal ( GNUNET_break (0); return NULL; } - md = TALER_EXCHANGE_deserialize_melt_data_ (refresh_data, - exchange->key_data.currency); - if (NULL == md) + if (GNUNET_OK != + TALER_EXCHANGE_get_melt_data (ps, + rd, + &md)) { GNUNET_break (0); return NULL; @@ -340,21 +342,21 @@ TALER_EXCHANGE_refreshes_reveal ( /* now transfer_pub */ 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); /* now new_denoms */ GNUNET_assert (NULL != (new_denoms_h = json_array ())); GNUNET_assert (NULL != (coin_evs = json_array ())); GNUNET_assert (NULL != (link_sigs = json_array ())); - for (unsigned int i = 0; inum_fresh_coins; i++) + for (unsigned int i = 0; ifresh_pks[i], + TALER_denom_pub_hash (&md.fresh_pks[i], &denom_hash); GNUNET_assert (0 == json_array_append_new (new_denoms_h, @@ -364,9 +366,9 @@ TALER_EXCHANGE_refreshes_reveal ( // TODO: implement cipher handling alg_values.cipher = TALER_DENOMINATION_RSA; if (GNUNET_OK != - TALER_planchet_prepare (&md->fresh_pks[i], + TALER_planchet_prepare (&md.fresh_pks[i], &alg_values, - &md->fresh_coins[noreveal_index][i], + &md.fresh_coins[noreveal_index][i], &c_hash, &pd)) { @@ -374,6 +376,7 @@ TALER_EXCHANGE_refreshes_reveal ( GNUNET_break (0); json_decref (new_denoms_h); json_decref (coin_evs); + TALER_EXCHANGE_free_melt_data_ (&md); return NULL; } GNUNET_assert (0 == @@ -394,7 +397,7 @@ TALER_EXCHANGE_refreshes_reveal ( blinded_msg, pd.blinded_planchet.details.rsa_blinded_planchet. blinded_msg_size, - &md->melted_coin.coin_priv, + &md.melted_coin.coin_priv, &link_sig); GNUNET_assert (0 == json_array_append_new ( @@ -417,7 +420,7 @@ TALER_EXCHANGE_refreshes_reveal ( GNUNET_assert (0 == json_array_append_new (transfer_privs, GNUNET_JSON_from_data_auto ( - &md->melted_coin.transfer_priv[j]))); + &md.melted_coin.transfer_priv[j]))); } /* build main JSON request */ @@ -436,7 +439,7 @@ TALER_EXCHANGE_refreshes_reveal ( char pub_str[sizeof (struct TALER_RefreshCommitmentP) * 2]; char *end; - end = GNUNET_STRINGS_data_to_string (&md->rc, + end = GNUNET_STRINGS_data_to_string (&md.rc, sizeof (struct TALER_RefreshCommitmentP), pub_str, @@ -459,6 +462,7 @@ TALER_EXCHANGE_refreshes_reveal ( if (NULL == rrh->url) { json_decref (reveal_obj); + TALER_EXCHANGE_free_melt_data_ (&md); GNUNET_free (rrh); return NULL; } @@ -473,6 +477,7 @@ TALER_EXCHANGE_refreshes_reveal ( if (NULL != eh) curl_easy_cleanup (eh); json_decref (reveal_obj); + TALER_EXCHANGE_free_melt_data_ (&md); GNUNET_free (rrh->url); GNUNET_free (rrh); return NULL;