From 7cedf3f0bf0bd9c4f89c26bfbb4e276423860f65 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 12 Feb 2022 14:00:58 +0100 Subject: [PATCH] -clean up refresh reveal API --- src/include/taler_exchange_service.h | 104 ++++++++++++++++++++---- src/lib/exchange_api_refreshes_reveal.c | 83 +++++++++---------- src/testing/testing_api_cmd_refresh.c | 25 +++--- 3 files changed, 137 insertions(+), 75 deletions(-) diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 6c3d86ee3..3b227fe3e 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -1637,6 +1637,72 @@ struct TALER_EXCHANGE_RefreshData struct TALER_EXCHANGE_MeltHandle; +/** + * Information we obtain per coin during melting. + */ +struct TALER_EXCHANGE_MeltBlindingDetail +{ + /** + * Exchange values contributed to the refresh operation + */ + struct TALER_ExchangeWithdrawValues alg_value; + + /** + * Blinding keys used to blind the fresh coins + */ + union TALER_DenominationBlindingKeyP bks; + +}; + + +/** + * Response returned to a /melt request. + */ +struct TALER_EXCHANGE_MeltResponse +{ + /** + * Full HTTP response details. + */ + struct TALER_EXCHANGE_HttpResponse hr; + + /** + * Parsed response details, variant depending on the + * @e hr.http_status. + */ + union + { + /** + * Results for status #MHD_HTTP_SUCCESS. + */ + struct + { + + /** + * Length of the @a mbds array with the exchange values + * and blinding keys we are using. + */ + unsigned int num_mbds; + + /** + * Information returned per coin. + */ + const struct TALER_EXCHANGE_MeltBlindingDetail *mbds; + + /** + * Key used by the exchange to sign the response. + */ + struct TALER_ExchangePublicKeyP sign_key; + + /** + * Gamma value chosen by the exchange. + */ + uint32_t noreveal_index; + } success; + + } details; +}; + + /** * Callbacks of this type are used to notify the application about the result * of the /coins/$COIN_PUB/melt stage. If successful, the @a noreveal_index @@ -1650,7 +1716,7 @@ struct TALER_EXCHANGE_MeltHandle; * @param bks array of @a num_coins blinding keys used to blind the fresh coins * @param noreveal_index choice by the exchange in the cut-and-choose protocol, * 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 the response, or NULL */ typedef void (*TALER_EXCHANGE_MeltCallback) ( @@ -1734,13 +1800,22 @@ struct TALER_EXCHANGE_RevealResult */ struct TALER_EXCHANGE_HttpResponse hr; + /** + * Parsed response details, variant depending on the + * @e hr.http_status. + */ union { + /** + * Results for status #MHD_HTTP_SUCCESS. + */ struct { /** - * Array of @e num_coins values about the - * coins obtained via the refresh operation. + * Array of @e num_coins values about the coins obtained via the refresh + * operation. The array give the coins in the same order (and should + * have the same length) in which the original melt request specified the + * respective denomination keys. */ const struct TALER_EXCHANGE_RevealedCoinInfo *coins; @@ -1759,25 +1834,15 @@ struct TALER_EXCHANGE_RevealResult * Callbacks of this type are used to return the final result of * submitting a refresh request to a exchange. If the operation was * successful, this function returns the signatures over the coins - * that were remelted. The @a coin_privs and @a sigs arrays give the - * coins in the same order (and should have the same length) in which - * the original request specified the respective denomination keys. + * that were remelted. * * @param cls closure - * @param hr HTTP response data - * @param num_coins number of fresh coins created, length of the @a sigs, @a psa and @a coin_privs arrays, 0 if the operation failed - * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error - * @param psa array of @a num_coins planchet secrets (derived from the transfer secret) for each of the coins - * @param sigs array of signature over @a num_coins coins, NULL on error + * @param rr result of the reveal operation */ typedef void (*TALER_EXCHANGE_RefreshesRevealCallback)( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - unsigned int num_coins, - const struct TALER_CoinSpendPrivateKeyP *coin_privs, - const struct TALER_PlanchetMasterSecretP *psa, - const struct TALER_DenominationSignature *sigs); + const struct TALER_EXCHANGE_RevealResult *rr); /** @@ -1877,8 +1942,15 @@ struct TALER_EXCHANGE_LinkResult */ struct TALER_EXCHANGE_HttpResponse hr; + /** + * Parsed response details, variant depending on the + * @e hr.http_status. + */ union { + /** + * Results for status #MHD_HTTP_SUCCESS. + */ struct { /** diff --git a/src/lib/exchange_api_refreshes_reveal.c b/src/lib/exchange_api_refreshes_reveal.c index 0b44aa355..b17720768 100644 --- a/src/lib/exchange_api_refreshes_reveal.c +++ b/src/lib/exchange_api_refreshes_reveal.c @@ -99,15 +99,13 @@ struct TALER_EXCHANGE_RefreshesRevealHandle * * @param rrh operation handle * @param json reply from the exchange - * @param[out] coin_privs 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 + * @param[out] rcis array of length `num_fresh_coins`, initialized to contain the coin data * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors */ static enum GNUNET_GenericReturnValue refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh, const json_t *json, - struct TALER_CoinSpendPrivateKeyP *coin_privs, - struct TALER_DenominationSignature *sigs) + struct TALER_EXCHANGE_RevealedCoinInfo *rcis) { json_t *jsona; struct GNUNET_JSON_Specification outer_spec[] = { @@ -140,7 +138,8 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh, } for (unsigned int i = 0; imd.num_fresh_coins; i++) { - const struct TALER_PlanchetMasterSecretP *fc; + struct TALER_EXCHANGE_RevealedCoinInfo *rci = + &rcis[i]; struct TALER_DenominationPublicKey *pk; json_t *jsonai; struct TALER_BlindedDenominationSignature blind_sig; @@ -154,7 +153,7 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh, struct TALER_FreshCoin coin; union TALER_DenominationBlindingKeyP bks; - fc = &rrh->md.fresh_coins[rrh->noreveal_index][i]; + rci->ps = rrh->md.fresh_coins[rrh->noreveal_index][i]; pk = &rrh->md.fresh_pks[i]; jsonai = json_array_get (jsona, i); GNUNET_assert (NULL != jsonai); @@ -169,15 +168,15 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh, return GNUNET_SYSERR; } - TALER_planchet_setup_coin_priv (fc, + TALER_planchet_setup_coin_priv (&rci->ps, &rrh->alg_values[i], - &coin_privs[i]); - TALER_planchet_blinding_secret_create (fc, + &rci->coin_priv); + TALER_planchet_blinding_secret_create (&rci->ps, &rrh->alg_values[i], &bks); /* needed to verify the signature, and we didn't store it earlier, hence recomputing it here... */ - GNUNET_CRYPTO_eddsa_key_get_public (&coin_privs[i].eddsa_priv, + GNUNET_CRYPTO_eddsa_key_get_public (&rci->coin_priv.eddsa_priv, &coin_pub.eddsa_pub); /* FIXME-Oec: Age commitment hash. */ TALER_coin_pub_hash (&coin_pub, @@ -187,7 +186,7 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh, TALER_planchet_to_coin (pk, &blind_sig, &bks, - &coin_privs[i], + &rci->coin_priv, &coin_hash, &rrh->alg_values[i], &coin)) @@ -198,7 +197,7 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh, return GNUNET_SYSERR; } GNUNET_JSON_parse_free (spec); - sigs[i] = coin.sig; + rci->sig = coin.sig; } GNUNET_JSON_parse_free (outer_spec); return GNUNET_OK; @@ -220,94 +219,86 @@ handle_refresh_reveal_finished (void *cls, { struct TALER_EXCHANGE_RefreshesRevealHandle *rrh = cls; const json_t *j = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = j, - .http_status = (unsigned int) response_code + struct TALER_EXCHANGE_RevealResult rr = { + .hr.reply = j, + .hr.http_status = (unsigned int) response_code }; rrh->job = NULL; switch (response_code) { case 0: - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; case MHD_HTTP_OK: { - struct TALER_DenominationSignature sigs[rrh->md.num_fresh_coins]; - struct TALER_CoinSpendPrivateKeyP coin_privs[rrh->md.num_fresh_coins]; + struct TALER_EXCHANGE_RevealedCoinInfo rcis[rrh->md.num_fresh_coins]; enum GNUNET_GenericReturnValue ret; - memset (sigs, + memset (rcis, 0, - sizeof (sigs)); + sizeof (rcis)); ret = refresh_reveal_ok (rrh, j, - coin_privs, - sigs); + rcis); if (GNUNET_OK != ret) { - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + rr.hr.http_status = 0; + rr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } else { GNUNET_assert (rrh->noreveal_index < TALER_CNC_KAPPA); + rr.details.success.num_coins = rrh->md.num_fresh_coins; + rr.details.success.coins = rcis; rrh->reveal_cb (rrh->reveal_cb_cls, - &hr, - rrh->md.num_fresh_coins, - coin_privs, - rrh->md.fresh_coins[rrh->noreveal_index], - sigs); + &rr); rrh->reveal_cb = NULL; } for (unsigned int i = 0; imd.num_fresh_coins; i++) - TALER_denom_sig_free (&sigs[i]); + TALER_denom_sig_free (&rcis[i].sig); TALER_EXCHANGE_refreshes_reveal_cancel (rrh); return; } case MHD_HTTP_BAD_REQUEST: /* This should never happen, either us or the exchange is buggy (or API version conflict); just pass JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_CONFLICT: /* Nothing really to verify, exchange says our reveal is inconsistent with our commitment, so either side is buggy; we should pass the JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_GONE: /* Server claims key expired or has been revoked */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_INTERNAL_SERVER_ERROR: /* Server had an internal issue; we should retry, but this API leaves this to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); break; default: /* unexpected response code */ GNUNET_break_op (0); - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange refreshes reveal\n", (unsigned int) response_code, - (int) hr.ec); + (int) rr.hr.ec); break; } if (NULL != rrh->reveal_cb) rrh->reveal_cb (rrh->reveal_cb_cls, - &hr, - 0, - NULL, - NULL, - NULL); + &rr); TALER_EXCHANGE_refreshes_reveal_cancel (rrh); } diff --git a/src/testing/testing_api_cmd_refresh.c b/src/testing/testing_api_cmd_refresh.c index a36e20084..8b0329b38 100644 --- a/src/testing/testing_api_cmd_refresh.c +++ b/src/testing/testing_api_cmd_refresh.c @@ -358,13 +358,10 @@ do_reveal_retry (void *cls) */ static void reveal_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - unsigned int num_coins, - const struct TALER_CoinSpendPrivateKeyP *coin_privs, - const struct TALER_PlanchetMasterSecretP *psa, - const struct TALER_DenominationSignature *sigs) + const struct TALER_EXCHANGE_RevealResult *rr) { struct RefreshRevealState *rrs = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &rr->hr; const struct TALER_TESTING_Command *melt_cmd; rrs->rrh = NULL; @@ -417,20 +414,22 @@ reveal_cb (void *cls, TALER_TESTING_interpreter_fail (rrs->is); return; } - rrs->num_fresh_coins = num_coins; switch (hr->http_status) { case MHD_HTTP_OK: - rrs->psa = GNUNET_memdup (psa, - num_coins - * sizeof (struct TALER_PlanchetMasterSecretP)); - rrs->fresh_coins = GNUNET_new_array (num_coins, + rrs->num_fresh_coins = rr->details.success.num_coins; + rrs->psa = GNUNET_new_array (rrs->num_fresh_coins, + struct TALER_PlanchetMasterSecretP); + rrs->fresh_coins = GNUNET_new_array (rrs->num_fresh_coins, struct TALER_TESTING_FreshCoinData); - for (unsigned int i = 0; inum_fresh_coins; i++) { + const struct TALER_EXCHANGE_RevealedCoinInfo *coin + = &rr->details.success.coins[i]; struct TALER_TESTING_FreshCoinData *fc = &rrs->fresh_coins[i]; const union TALER_DenominationBlindingKeyP *bks; + rrs->psa[i] = coin->ps; if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub (melt_cmd, i, @@ -449,10 +448,10 @@ reveal_cb (void *cls, TALER_TESTING_interpreter_fail (rrs->is); return; } - fc->coin_priv = coin_privs[i]; + fc->coin_priv = coin->coin_priv; fc->blinding_key = *bks; TALER_denom_sig_deep_copy (&fc->sig, - &sigs[i]); + &coin->sig); } if (0 != rrs->total_backoff.rel_value_us) {