commit b7f27ea64b64e2cf90ad959f77a0ab791375b0d7
parent b6594e0b1660e27ad2bdf41effb306d5cf51d2d2
Author: Özgür Kesim <oec@codeblau.de>
Date: Tue, 6 May 2025 17:03:16 +0200
Pre-v27 refresh protocol and batch-withdraw removed
The refresh protocol prior to v27 has been removed, from
the REST-API (endpoints /coin/$COIN/{melt,reveal}), the
C-API and the database plugin.
Also, the endpoint for /batch-withdraw has been removed, which
was deprecated since v26.
The auditor's taler-helper-auditor-coins.c had to be marked as
work-in-progress to adjust for the removal of the old and presence
of the new refresh protocol
Diffstat:
25 files changed, 44 insertions(+), 6783 deletions(-)
diff --git a/src/auditor/taler-helper-auditor-coins.c b/src/auditor/taler-helper-auditor-coins.c
@@ -1435,6 +1435,8 @@ refresh_session_cb (void *cls,
GNUNET_h2s (&issue->denom_hash.hash),
TALER_amount2s (amount_with_fee));
+#pragma message "auditor's reveal requires refactoring for new refresh protocol"
+#if FIXME_NEW_REFRESH
{
struct TALER_Amount refresh_cost;
struct RevealContext reveal_ctx = {
@@ -1602,6 +1604,7 @@ refresh_session_cb (void *cls,
}
GNUNET_free (reveal_ctx.new_issues);
}
+#endif
/* update old coin's denomination balance */
dso = get_denomination_summary (cc,
diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am
@@ -153,14 +153,12 @@ taler_exchange_httpd_SOURCES = \
taler-exchange-httpd_aml-transfer-get.c taler-exchange-httpd_aml-transfer-get.h \
taler-exchange-httpd_auditors.c taler-exchange-httpd_auditors.h \
taler-exchange-httpd_batch-deposit.c taler-exchange-httpd_batch-deposit.h \
- taler-exchange-httpd_batch-withdraw.c taler-exchange-httpd_batch-withdraw.h \
taler-exchange-httpd_blinding-prepare.c taler-exchange-httpd_blinding-prepare.h \
taler-exchange-httpd_coins_get.c taler-exchange-httpd_coins_get.h \
taler-exchange-httpd_common_deposit.c taler-exchange-httpd_common_deposit.h \
taler-exchange-httpd_common_kyc.c taler-exchange-httpd_common_kyc.h \
taler-exchange-httpd_config.c taler-exchange-httpd_config.h \
taler-exchange-httpd_contract.c taler-exchange-httpd_contract.h \
- taler-exchange-httpd_csr.c taler-exchange-httpd_csr.h \
taler-exchange-httpd_db.c taler-exchange-httpd_db.h \
taler-exchange-httpd_deposits_get.c taler-exchange-httpd_deposits_get.h \
taler-exchange-httpd_extensions.c taler-exchange-httpd_extensions.h \
@@ -187,7 +185,6 @@ taler_exchange_httpd_SOURCES = \
taler-exchange-httpd_management_wire_enable.c \
taler-exchange-httpd_management_wire_disable.c \
taler-exchange-httpd_management_wire_fees.c \
- taler-exchange-httpd_melt.c taler-exchange-httpd_melt.h \
taler-exchange-httpd_melt_v27.c taler-exchange-httpd_melt_v27.h \
taler-exchange-httpd_metrics.c taler-exchange-httpd_metrics.h \
taler-exchange-httpd_mhd.c taler-exchange-httpd_mhd.h \
@@ -198,7 +195,6 @@ taler_exchange_httpd_SOURCES = \
taler-exchange-httpd_purses_merge.c taler-exchange-httpd_purses_merge.h \
taler-exchange-httpd_recoup.c taler-exchange-httpd_recoup.h \
taler-exchange-httpd_recoup-refresh.c taler-exchange-httpd_recoup-refresh.h \
- taler-exchange-httpd_refreshes_reveal.c taler-exchange-httpd_refreshes_reveal.h \
taler-exchange-httpd_refund.c taler-exchange-httpd_refund.h \
taler-exchange-httpd_reserves_attest.c taler-exchange-httpd_reserves_attest.h \
taler-exchange-httpd_reserves_close.c taler-exchange-httpd_reserves_close.h \
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
@@ -32,7 +32,6 @@
#include "taler_templating_lib.h"
#include "taler_mhd_lib.h"
#include "taler-exchange-httpd_withdraw.h"
-#include "taler-exchange-httpd_batch-withdraw.h"
#include "taler-exchange-httpd_aml-attributes-get.h"
#include "taler-exchange-httpd_aml-decision.h"
#include "taler-exchange-httpd_aml-statistics-get.h"
@@ -44,7 +43,6 @@
#include "taler-exchange-httpd_coins_get.h"
#include "taler-exchange-httpd_config.h"
#include "taler-exchange-httpd_contract.h"
-#include "taler-exchange-httpd_csr.h"
#include "taler-exchange-httpd_deposits_get.h"
#include "taler-exchange-httpd_extensions.h"
#include "taler-exchange-httpd_keys.h"
@@ -58,7 +56,6 @@
#include "taler-exchange-httpd_aml-decision.h"
#include "taler-exchange-httpd_legitimization-measures-get.h"
#include "taler-exchange-httpd_management.h"
-#include "taler-exchange-httpd_melt.h"
#include "taler-exchange-httpd_melt_v27.h"
#include "taler-exchange-httpd_metrics.h"
#include "taler-exchange-httpd_mhd.h"
@@ -69,7 +66,6 @@
#include "taler-exchange-httpd_purses_merge.h"
#include "taler-exchange-httpd_recoup.h"
#include "taler-exchange-httpd_recoup-refresh.h"
-#include "taler-exchange-httpd_refreshes_reveal.h"
#include "taler-exchange-httpd_refund.h"
#include "taler-exchange-httpd_reserves_attest.h"
#include "taler-exchange-httpd_reserves_close.h"
@@ -380,10 +376,6 @@ handle_post_coins (struct TEH_RequestContext *rc,
CoinOpHandler handler;
} h[] = {
- {
- .op = "melt",
- .handler = &TEH_handler_melt
- },
#if FIXME_9828
{
.op = "recoup",
@@ -762,11 +754,6 @@ handle_post_reserves (struct TEH_RequestContext *rc,
} h[] = {
{
- /* deprecated since v26 */
- .op = "batch-withdraw",
- .handler = &TEH_handler_batch_withdraw
- },
- {
.op = "purse",
.handler = &TEH_handler_reserves_purse
},
@@ -1666,13 +1653,6 @@ handle_mhd_request (void *cls,
.handler.post = &TEH_handler_batch_deposit,
.nargs = 0
},
- /* request R, used in clause schnorr withdraw and refresh */
- {
- .url = "csr-melt",
- .method = MHD_HTTP_METHOD_POST,
- .handler.post = &TEH_handler_csr_melt,
- .nargs = 0
- },
/* request R's input for Clause-Schnorr signatures in batches */
{
.url = "blinding-prepare",
@@ -1680,12 +1660,6 @@ handle_mhd_request (void *cls,
.handler.post = &TEH_handler_blinding_prepare,
.nargs = 0
},
- {
- .url = "csr-withdraw",
- .method = MHD_HTTP_METHOD_POST,
- .handler.post = &TEH_handler_csr_withdraw,
- .nargs = 0
- },
/* withdraw request, available since v26 of the API */
{
.url = "withdraw",
@@ -1713,7 +1687,7 @@ handle_mhd_request (void *cls,
.handler.post = &TEH_handler_reveal_withdraw,
.nargs = 0
},
- /* reveal-melt operation, introduced with v26 */
+ /* reveal-melt operation, introduced with v27 */
{
.url = "reveal-melt",
.method = MHD_HTTP_METHOD_POST,
@@ -1753,13 +1727,6 @@ handle_mhd_request (void *cls,
.handler.post = &TEH_handler_melt_v27,
.nargs = 0
},
- /* refreshes/$RCH/reveal */
- {
- .url = "refreshes",
- .method = MHD_HTTP_METHOD_POST,
- .handler.post = &TEH_handler_reveal,
- .nargs = 2
- },
/* tracking transfers */
{
.url = "transfers",
@@ -2692,7 +2659,6 @@ do_shutdown (void *cls)
my_mhd = TALER_MHD_daemon_stop ();
TEH_resume_keys_requests (true);
TEH_batch_deposit_cleanup ();
- TEH_batch_withdraw_cleanup ();
TEH_withdraw_cleanup ();
TEH_melt_v27_cleanup ();
TEH_reserves_close_cleanup ();
diff --git a/src/exchange/taler-exchange-httpd_batch-withdraw.c b/src/exchange/taler-exchange-httpd_batch-withdraw.c
@@ -1,1460 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2024 Taler Systems SA
-
- 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 Foundation; either version 3,
- or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty
- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General
- Public License along with TALER; see the file COPYING. If not,
- see <http://www.gnu.org/licenses/>
-*/
-
-/*
- * NOTE: These endpoints are deprecated starting with v26 of the protocol and will be removed,
- * including this file.
- */
-
-/**
- * @file taler-exchange-httpd_batch-withdraw.c
- * @brief Common code to handle /reserves/$RESERVE_PUB/{age,batch}-withdraw requests
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- * @author Ozgur Kesim
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include "taler-exchange-httpd.h"
-#include "taler_json_lib.h"
-#include "taler_kyclogic_lib.h"
-#include "taler_mhd_lib.h"
-#include "taler-exchange-httpd_batch-withdraw.h"
-#include "taler-exchange-httpd_common_kyc.h"
-#include "taler-exchange-httpd_responses.h"
-#include "taler-exchange-httpd_keys.h"
-#include "taler_util.h"
-
-/**
- * Context for batch-withdraw requests
- */
-struct BatchWithdrawContext
-{
-
- /**
- * This struct is kept in a DLL.
- */
- struct BatchWithdrawContext *prev;
- struct BatchWithdrawContext *next;
-
- /**
- * Processing phase we are in for any of the withdraw types.
- * The ordering here partially matters, as we progress through
- * them by incrementing the phase in the happy path.
- */
- enum
- {
- PHASE_CHECK_KEYS,
- PHASE_CHECK_RESERVE_SIGNATURE,
- PHASE_RUN_LEGI_CHECK,
- PHASE_SUSPENDED,
- PHASE_CHECK_KYC_RESULT,
- PHASE_PREPARE_TRANSACTION,
- PHASE_RUN_TRANSACTION,
- PHASE_GENERATE_REPLY_SUCCESS,
- PHASE_GENERATE_REPLY_ERROR,
- PHASE_RETURN_NO,
- PHASE_RETURN_YES,
- } phase;
-
-
- /**
- * Handle for the legitimization check.
- */
- struct TEH_LegitimizationCheckHandle *lch;
-
- /**
- * Request context
- */
- const struct TEH_RequestContext *rc;
-
- /**
- * Public key of the reserve.
- */
- struct TALER_ReservePublicKeyP reserve_pub;
-
- /**
- * KYC status for the operation.
- */
- struct TALER_EXCHANGEDB_KycStatus kyc;
-
- /**
- * Current time for the DB transaction.
- */
- struct GNUNET_TIME_Timestamp now;
-
- /**
- * Set to the hash of the normalized payto URI that established
- * the reserve.
- */
- struct TALER_NormalizedPaytoHashP h_normalized_payto;
-
- /**
- * Number of coins, length of @e planchets array.
- */
- unsigned int num_coins;
-
- /**
- * Array of @e num_coins planchets we are processing,
- * containing the information per planchet in a batch withdraw.
- */
- struct PlanchetContext
- {
-
- /**
- * Value of the coin being exchanged (matching the denomination key)
- * plus the transaction fee. We include this in what is being
- * signed so that we can verify a reserve's remaining total balance
- * without needing to access the respective denomination key
- * information each time.
- */
- struct TALER_Amount amount_with_fee;
-
- /**
- * Blinded planchet.
- */
- struct TALER_BlindedPlanchet blinded_planchet;
-
- /**
- * Set to the resulting signed coin data to be returned to the client.
- */
- struct TALER_EXCHANGEDB_CollectableBlindcoin collectable;
-
- } *planchets;
-
- /**
- * Total amount from all coins with fees.
- */
- struct TALER_Amount batch_total;
-
- /**
- * Errors occurring during evaluation of the request are captured in this struct.
- * In phase PHASE_GENERATE_REPLY_ERROR an appropriate error message is prepared
- * and sent to the client.
- */
- struct
- {
- /**
- * The different type of errors that might occur, sorted by name.
- * Some of them require idempotency checks, which are marked
- * in array @a needs_idempotency_check_error below.
- */
- enum
- {
- ERROR_NONE,
-
- ERROR_AGE_RESTRICTION_REQUIRED,
- ERROR_BATCH_AMOUNT_FEE_OVERFLOW,
- ERROR_BATCH_IDEMPOTENT_PLANCHET,
- ERROR_BATCH_INSUFFICIENT_FUNDS,
- ERROR_BATCH_NONCE_RESUSE,
- ERROR_CIPHER_MISMATCH,
- ERROR_DB_FETCH_FAILED,
- ERROR_DB_INVARIANT_FAILURE,
- ERROR_DENOMINATION_BATCH_SIGN,
- ERROR_DENOMINATION_EXPIRED,
- ERROR_DENOMINATION_KEY_UNKNOWN,
- ERROR_DENOMINATION_REVOKED,
- ERROR_DENOMINATION_VALIDITY_IN_FUTURE,
- ERROR_INTERNAL_INVARIANT_FAILURE,
- ERROR_KEYS_MISSING,
- ERROR_KYC_REQUIRED,
- ERROR_LEGITIMIZATION_RESULT,
- ERROR_RESERVE_SIGNATURE_INVALID,
- ERROR_RESERVE_UNKNOWN,
- ERROR_REQUEST_PARAMETER_MALFORMED,
-
- ERROR_MAX
- } code;
-
- /**
- * Some errors require details to be sent to the client.
- * These are captured in this union.
- * Each field is marked with a comment, referring to the error(s)
- * that is/are using it.
- */
- union
- {
- /* ERROR_REQUEST_PARAMETER_MALFORMED */
- const char *hint;
-
- /* ERROR_DENOMINATION_KEY_UNKNOWN */
- const struct TALER_DenominationHashP *denom_h;
-
- /* ERROR_DB_FETCH_FAILED */
- const char *db_fetch_context;
-
- /* ERROR_AGE_RESTRICTION_REQUIRED */
- uint16_t lowest_age;
-
- /* ERROR_BATCH_INSUFFICIENT_FUNDS */
- struct TALER_Amount reserve_balance;
-
- /* ERROR_DENOMINATION_BATCH_SIGN */
- enum TALER_ErrorCode ec;
-
- /* ERROR_LEGITIMIZATION_RESULT */
- struct
- {
- struct MHD_Response *response;
- unsigned int http_status;
- } legi;
-
- } details;
- } error;
-};
-
-/**
- * This table marks which @a BatchWithdrawContext.error.code
- * needs a idempotency check prior to actually sending an error message.
- */
-static const bool
- needs_idempotency_check[] = {
- [ERROR_NONE] = false,
-
- [ERROR_AGE_RESTRICTION_REQUIRED] = false,
- [ERROR_BATCH_AMOUNT_FEE_OVERFLOW] = false,
- [ERROR_BATCH_NONCE_RESUSE] = false,
- [ERROR_CIPHER_MISMATCH] = false,
- [ERROR_DB_FETCH_FAILED] = false,
- [ERROR_DB_INVARIANT_FAILURE] = false,
- [ERROR_DENOMINATION_BATCH_SIGN] = false,
- [ERROR_DENOMINATION_VALIDITY_IN_FUTURE] = false,
- [ERROR_INTERNAL_INVARIANT_FAILURE] = false,
- [ERROR_LEGITIMIZATION_RESULT] = false,
- [ERROR_REQUEST_PARAMETER_MALFORMED] = false,
- [ERROR_RESERVE_SIGNATURE_INVALID] = false,
- [ERROR_RESERVE_UNKNOWN] = false,
-
- /* These require idempotency checks */
- [ERROR_BATCH_IDEMPOTENT_PLANCHET] = true,
- [ERROR_BATCH_INSUFFICIENT_FUNDS] = true,
- [ERROR_DENOMINATION_EXPIRED] = true,
- [ERROR_DENOMINATION_KEY_UNKNOWN] = true,
- [ERROR_DENOMINATION_REVOKED] = true,
- [ERROR_KEYS_MISSING] = true,
- [ERROR_KYC_REQUIRED] = true,
-};
-
-_Static_assert (
- (sizeof (needs_idempotency_check) ==
- ERROR_MAX),
- "needs_idempotency_check size mismatch with enum WithdrawErrorCode");
-
-/**
- * The following macros set the given error code,
- * set the phase to PHASE_GENERATE_REPLY_ERROR,
- * and optionally set the given field (with an optionally given value).
- */
-#define SET_ERROR(wc, ec) \
- do \
- { (wc)->error.code = (ec); \
- (wc)->phase = PHASE_GENERATE_REPLY_ERROR; } while (0)
-
-#define SET_ERROR_WITH_FIELD(wc, ec, field) \
- do \
- { (wc)->error.code = (ec); \
- (wc)->error.details.field = (field); \
- (wc)->phase = PHASE_GENERATE_REPLY_ERROR; } while (0)
-
-#define SET_ERROR_WITH_DETAIL(wc, ec, field, value) \
- do \
- { (wc)->error.code = (ec); \
- (wc)->error.details.field = (value); \
- (wc)->phase = PHASE_GENERATE_REPLY_ERROR; } while (0)
-
-
-/**
- * All withdraw context is kept in a DLL.
- */
-static struct BatchWithdrawContext *wc_head;
-static struct BatchWithdrawContext *wc_tail;
-
-void
-TEH_batch_withdraw_cleanup ()
-{
- struct BatchWithdrawContext *wc;
-
- while (NULL != (wc = wc_head))
- {
- GNUNET_CONTAINER_DLL_remove (wc_head,
- wc_tail,
- wc);
- MHD_resume_connection (wc->rc->connection);
- }
-}
-
-
-/**
- * Terminate the main loop by returning the final
- * result.
- *
- * @param[in,out] wc context to update phase for
- * @param mres MHD status to return
- */
-static void
-finish_loop (struct BatchWithdrawContext *wc,
- MHD_RESULT mres)
-{
- wc->phase = (MHD_YES == mres)
- ? PHASE_RETURN_YES
- : PHASE_RETURN_NO;
-}
-
-
-/**
- * Generates our final (successful) response to a batch withdraw request.
- *
- * @param wc operation context
- */
-static void
-phase_generate_reply_success (struct BatchWithdrawContext *wc)
-{
- const struct TEH_RequestContext *rc = wc->rc;
- json_t *sigs;
-
- sigs = json_array ();
- GNUNET_assert (NULL != sigs);
- for (unsigned int i = 0; i<wc->num_coins; i++)
- {
- struct PlanchetContext *pc = &wc->planchets[i];
-
- GNUNET_assert (
- 0 ==
- json_array_append_new (
- sigs,
- GNUNET_JSON_PACK (
- TALER_JSON_pack_blinded_denom_sig (
- "ev_sig",
- &pc->collectable.sig))));
- }
- TEH_METRICS_withdraw_num_coins += wc->num_coins;
- finish_loop (wc,
- TALER_MHD_REPLY_JSON_PACK (
- rc->connection,
- MHD_HTTP_OK,
- GNUNET_JSON_pack_array_steal ("ev_sigs",
- sigs)));
-}
-
-
-/**
- * Check if the batch withdraw in @a wc is replayed
- * and we already have an answer.
- * If so, replay the existing answer and return the HTTP response.
- *
- * @param wc parsed request data
- * @return true if the request is idempotent with an existing request
- * false if we did not find the request in the DB and did not set @a mret
- */
-static bool
-check_idempotency (
- struct BatchWithdrawContext *wc)
-{
-
- for (unsigned int i = 0; i<wc->num_coins; i++)
- {
- struct PlanchetContext *pc = &wc->planchets[i];
- enum GNUNET_DB_QueryStatus qs;
- struct TALER_EXCHANGEDB_CollectableBlindcoin collectable;
-
- qs = TEH_plugin->get_batch_withdraw_info (
- TEH_plugin->cls,
- &pc->collectable.h_coin_envelope,
- &collectable);
- if (0 > qs)
- {
- /* FIXME: soft error not handled correctly! */
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- SET_ERROR_WITH_DETAIL (wc,
- ERROR_DB_FETCH_FAILED,
- db_fetch_context,
- "get_batch_withdraw_info");
- return true; /* Well, kind-of. */
- }
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- return false;
- pc->collectable = collectable;
- }
-
- /* generate idempotent reply */
- TEH_METRICS_num_requests[TEH_MT_REQUEST_IDEMPOTENT_WITHDRAW]++;
- wc->phase = PHASE_GENERATE_REPLY_SUCCESS;
- return true;
-}
-
-
-/**
- * Function implementing withdraw transaction. Runs the
- * transaction logic; IF it returns a non-error code, the transaction
- * logic MUST NOT queue a MHD response. IF it returns an hard error,
- * the transaction logic MUST queue a MHD response and set @a mhd_ret.
- * IF it returns the soft error code, the function MAY be called again
- * to retry and MUST not queue a MHD response.
- *
- * Note that "wc->collectable.sig" is set before entering this function as we
- * signed before entering the transaction.
- *
- * @param cls a `struct BatchWithdrawContext *`, with @e withdraw_type set to WITHDRAW_TYPE_BATCH
- * @param connection MHD request which triggered the transaction
- * @param[out] mhd_ret set to MHD response status for @a connection,
- * if transaction failed (!)
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-batch_withdraw_transaction (
- void *cls,
- struct MHD_Connection *connection,
- MHD_RESULT *mhd_ret)
-{
- struct BatchWithdrawContext *wc = cls;
- uint64_t ruuid;
- enum GNUNET_DB_QueryStatus qs;
- bool found = false;
- bool balance_ok = false;
- bool age_ok = false;
- uint16_t allowed_maximum_age = 0;
- struct TALER_Amount reserve_balance;
-
- qs = TEH_plugin->do_batch_withdraw (
- TEH_plugin->cls,
- wc->now,
- &wc->reserve_pub,
- &wc->batch_total,
- TEH_age_restriction_enabled,
- &found,
- &balance_ok,
- &reserve_balance,
- &age_ok,
- &allowed_maximum_age,
- &ruuid);
-
- if (0 > qs)
- {
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- {
- GNUNET_break (0);
- SET_ERROR_WITH_DETAIL (wc,
- ERROR_DB_FETCH_FAILED,
- db_fetch_context,
- "update_reserve_batch_withdraw");
- }
- return qs;
- }
-
- if (! found)
- {
- GNUNET_break_op (0);
- SET_ERROR (wc,
- ERROR_RESERVE_UNKNOWN);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- if (! age_ok)
- {
- /* We respond with the lowest age in the corresponding age group
- * of the required age */
- uint16_t lowest_age = TALER_get_lowest_age (
- &TEH_age_restriction_config.mask,
- allowed_maximum_age);
- SET_ERROR_WITH_FIELD (wc,
- ERROR_AGE_RESTRICTION_REQUIRED,
- lowest_age);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- if (! balance_ok)
- {
- GNUNET_break_op (0);
- SET_ERROR_WITH_FIELD (wc,
- ERROR_BATCH_INSUFFICIENT_FUNDS,
- reserve_balance);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- /* Add information about each planchet in the batch */
- for (unsigned int i = 0; i<wc->num_coins; i++)
- {
- struct PlanchetContext *pc = &wc->planchets[i];
- const struct TALER_BlindedPlanchet *bp = &pc->blinded_planchet;
- const union GNUNET_CRYPTO_BlindSessionNonce *nonce = NULL;
- bool denom_unknown = true;
- bool conflict = true;
- bool nonce_reuse = true;
-
- switch (bp->blinded_message->cipher)
- {
- case GNUNET_CRYPTO_BSA_INVALID:
- break;
- case GNUNET_CRYPTO_BSA_RSA:
- break;
- case GNUNET_CRYPTO_BSA_CS:
- nonce = (const union GNUNET_CRYPTO_BlindSessionNonce *)
- &bp->blinded_message->details.cs_blinded_message.nonce;
- break;
- }
-
- qs = TEH_plugin->do_batch_withdraw_insert (
- TEH_plugin->cls,
- nonce,
- &pc->collectable,
- wc->now,
- ruuid,
- &denom_unknown,
- &conflict,
- &nonce_reuse);
-
- if (0 > qs)
- {
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- SET_ERROR_WITH_DETAIL (wc,
- ERROR_DB_FETCH_FAILED,
- db_fetch_context,
- "do_batch_withdraw_insert");
- return qs;
- }
-
- if (denom_unknown)
- {
- GNUNET_break (0);
- SET_ERROR (wc,
- ERROR_DB_INVARIANT_FAILURE);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) ||
- (conflict) )
- {
- SET_ERROR (wc,
- ERROR_BATCH_IDEMPOTENT_PLANCHET);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- if (nonce_reuse)
- {
- GNUNET_break_op (0);
- SET_ERROR (wc,
- ERROR_BATCH_NONCE_RESUSE);
-
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- }
- TEH_METRICS_num_success[TEH_MT_SUCCESS_WITHDRAW]++;
- return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
-}
-
-
-/**
- * The request was prepared successfully.
- * Run the main DB transaction.
- *
- * @param wc The context for the current withdraw request
- */
-static void
-phase_run_transaction (
- struct BatchWithdrawContext *wc)
-{
- MHD_RESULT mhd_ret;
- enum GNUNET_GenericReturnValue qs;
-
- GNUNET_assert (PHASE_RUN_TRANSACTION ==
- wc->phase);
-
- qs = TEH_DB_run_transaction (wc->rc->connection,
- "run batch withdraw",
- TEH_MT_REQUEST_WITHDRAW,
- &mhd_ret,
- &batch_withdraw_transaction,
- wc);
- if (GNUNET_OK != qs)
- {
- /* TODO[oec]: Logic still ok with new error handling? */
- if (PHASE_RUN_TRANSACTION == wc->phase)
- finish_loop (wc,
- mhd_ret);
- return;
- }
- wc->phase++;
-}
-
-
-/**
- * The request for batch withdraw was parsed successfully.
- * Prepare our side for the main DB transaction.
- *
- * @param wc context for request processing, with @e withdraw_type set to WITHDRAW_TYPE_BATCH
- * @return GNUNET_OK on success
- */
-static enum GNUNET_GenericReturnValue
-batch_withdraw_phase_prepare_transaction (struct BatchWithdrawContext *wc)
-{
- struct TALER_BlindedDenominationSignature bss[wc->num_coins];
- struct TEH_CoinSignData csds[wc->num_coins];
-
- for (unsigned int i = 0; i<wc->num_coins; i++)
- {
- struct PlanchetContext *pc = &wc->planchets[i];
- struct TEH_CoinSignData *csdsi = &csds[i];
-
- csdsi->h_denom_pub = &pc->collectable.denom_pub_hash;
- csdsi->bp = &pc->blinded_planchet;
- }
- {
- enum TALER_ErrorCode ec;
-
- ec = TEH_keys_denomination_batch_sign (
- wc->num_coins,
- csds,
- false,
- bss);
- if (TALER_EC_NONE != ec)
- {
- GNUNET_break (0);
- SET_ERROR_WITH_FIELD (wc,
- ERROR_DENOMINATION_BATCH_SIGN,
- ec);
- return GNUNET_SYSERR;
- }
- }
-
- for (unsigned int i = 0; i<wc->num_coins; i++)
- {
- struct PlanchetContext *pc = &wc->planchets[i];
-
- pc->collectable.sig = bss[i];
- }
-
- return GNUNET_OK;
-}
-
-
-/**
- * The request for withdraw was parsed successfully.
- * Choose the appropriate preparation step depending on @e withdraw_type
- */
-static void
-phase_prepare_transaction (
- struct BatchWithdrawContext *wc)
-{
- enum GNUNET_GenericReturnValue r;
- r = batch_withdraw_phase_prepare_transaction (wc);
- if (GNUNET_OK != r)
- return;
- wc->phase++;
-}
-
-
-/**
- * Check the KYC result.
- *
- * @param wc context for request processing
- */
-static void
-phase_check_kyc_result (struct BatchWithdrawContext *wc)
-{
- /* return final positive response */
- if (! wc->kyc.ok)
- {
- SET_ERROR (wc,
- ERROR_KYC_REQUIRED);
- return;
- }
- wc->phase++;
-}
-
-
-/**
- * Function called with the result of a legitimization
- * check.
- *
- * @param cls closure
- * @param lcr legitimization check result
- */
-static void
-withdraw_legi_cb (
- void *cls,
- const struct TEH_LegitimizationCheckResult *lcr)
-{
- struct BatchWithdrawContext *wc = cls;
-
- wc->lch = NULL;
- GNUNET_assert (PHASE_SUSPENDED ==
- wc->phase);
- MHD_resume_connection (wc->rc->connection);
- GNUNET_CONTAINER_DLL_remove (wc_head,
- wc_tail,
- wc);
- TALER_MHD_daemon_trigger ();
- if (NULL != lcr->response)
- {
- wc->error.details.legi.response = lcr->response;
- wc->error.details.legi.http_status = lcr->http_status;
- SET_ERROR (wc,
- ERROR_LEGITIMIZATION_RESULT);
- return;
- }
- wc->kyc = lcr->kyc;
- wc->phase = PHASE_CHECK_KYC_RESULT;
-}
-
-
-/**
- * Function called to iterate over KYC-relevant transaction amounts for a
- * particular time range. Called within a database transaction, so must
- * not start a new one.
- *
- * @param cls closure, identifies the event type and account to iterate
- * over events for
- * @param limit maximum time-range for which events should be fetched
- * (timestamp in the past)
- * @param cb function to call on each event found, events must be returned
- * in reverse chronological order
- * @param cb_cls closure for @a cb, of type struct BatchWithdrawContext
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-withdraw_amount_cb (
- void *cls,
- struct GNUNET_TIME_Absolute limit,
- TALER_EXCHANGEDB_KycAmountCallback cb,
- void *cb_cls)
-{
- struct BatchWithdrawContext *wc = cls;
- enum GNUNET_GenericReturnValue ret;
- enum GNUNET_DB_QueryStatus qs;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Signaling amount %s for KYC check during batch-withdrawal\n",
- TALER_amount2s (&wc->batch_total));
-
- ret = cb (cb_cls,
- &wc->batch_total,
- wc->now.abs_time);
-
- GNUNET_break (GNUNET_SYSERR != ret);
-
- if (GNUNET_OK != ret)
- return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
-
- qs = TEH_plugin->select_withdraw_amounts_for_kyc_check (
- TEH_plugin->cls,
- &wc->h_normalized_payto,
- limit,
- cb,
- cb_cls);
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Got %d additional transactions for this batch-withdrawal and limit %llu\n",
- qs,
- (unsigned long long) limit.abs_value_us);
-
- GNUNET_break (qs >= 0);
-
- return qs;
-}
-
-
-/**
- * Do legitimization check.
- *
- * @param wc operation context
- */
-static void
-phase_run_legi_check (struct BatchWithdrawContext *wc)
-{
- enum GNUNET_DB_QueryStatus qs;
- struct TALER_FullPayto payto_uri;
- struct TALER_FullPaytoHashP h_full_payto;
-
- /* Check if the money came from a wire transfer */
- qs = TEH_plugin->reserves_get_origin (
- TEH_plugin->cls,
- &wc->reserve_pub,
- &h_full_payto,
- &payto_uri);
- if (qs < 0)
- {
- SET_ERROR_WITH_DETAIL (wc,
- ERROR_DB_FETCH_FAILED,
- db_fetch_context,
- "reserves_get_origin");
- return;
- }
- /* If _no_ results, reserve was created by merge,
- in which case no KYC check is required as the
- merge already did that. */
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- {
- wc->phase = PHASE_PREPARE_TRANSACTION;
- return;
- }
- TALER_full_payto_normalize_and_hash (payto_uri,
- &wc->h_normalized_payto);
- wc->lch = TEH_legitimization_check (
- &wc->rc->async_scope_id,
- TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW,
- payto_uri,
- &wc->h_normalized_payto,
- NULL, /* no account pub: this is about the origin account */
- &withdraw_amount_cb,
- wc,
- &withdraw_legi_cb,
- wc);
- GNUNET_assert (NULL != wc->lch);
- GNUNET_free (payto_uri.full_payto);
- GNUNET_CONTAINER_DLL_insert (wc_head,
- wc_tail,
- wc);
- MHD_suspend_connection (wc->rc->connection);
- wc->phase = PHASE_SUSPENDED;
-}
-
-
-/**
- * Check if the given denomination is still or already valid, has not been
- * revoked and potentically supports age restriction.
- *
- * @param[in,out] wc context for the withdraw operation
- * @param ksh The handle to the current state of (denomination) keys in the exchange
- * @param denom_h Hash of the denomination key to check
- * @param[out] pdk denomination key found, might be NULL
- * @return GNUNET_OK when denomation was found and valid,
- * GNUNET_NO when denomination was not valid but request was idempotent,
- * GNUNET_SYSERR otherwise (denomination invalid), with finish_loop called.
- */
-static enum GNUNET_GenericReturnValue
-find_denomination (
- struct BatchWithdrawContext *wc,
- struct TEH_KeyStateHandle *ksh,
- const struct TALER_DenominationHashP *denom_h,
- struct TEH_DenominationKey **pdk)
-{
- struct TEH_DenominationKey *dk;
-
- *pdk = NULL;
-
- dk = TEH_keys_denomination_by_hash_from_state (
- ksh,
- denom_h,
- NULL,
- NULL);
-
- if (NULL == dk)
- {
- SET_ERROR_WITH_FIELD (wc,
- ERROR_DENOMINATION_KEY_UNKNOWN,
- denom_h);
- return GNUNET_NO;
- }
-
- if (GNUNET_TIME_absolute_is_past (
- dk->meta.expire_withdraw.abs_time))
- {
- SET_ERROR_WITH_FIELD (wc,
- ERROR_DENOMINATION_EXPIRED,
- denom_h);
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_TIME_absolute_is_future (
- dk->meta.start.abs_time))
- {
- GNUNET_break_op (0);
- SET_ERROR_WITH_FIELD (wc,
- ERROR_DENOMINATION_VALIDITY_IN_FUTURE,
- denom_h);
- return GNUNET_SYSERR;
- }
-
- if (dk->recoup_possible)
- {
- SET_ERROR (wc,
- ERROR_DENOMINATION_REVOKED);
- return GNUNET_SYSERR;
- }
-
- *pdk = dk;
- return GNUNET_OK;
-}
-
-
-/**
- * Check if the keys in the request are valid for batch withdrawal.
- *
- * @param[in,out] wc context for the batch withdraw request processing
- * @param ksh key state handle
- * @return GNUNET_OK on success,
- * GNUNET_NO on error (and response being sent)
- */
-static enum GNUNET_GenericReturnValue
-batch_withdraw_phase_check_keys (
- struct BatchWithdrawContext *wc,
- struct TEH_KeyStateHandle *ksh)
-{
- for (unsigned int i = 0; i<wc->num_coins; i++)
- {
- struct PlanchetContext *pc = &wc->planchets[i];
- struct TEH_DenominationKey *dk;
- enum GNUNET_GenericReturnValue r;
-
- r = find_denomination (wc,
- ksh,
- &pc->collectable.denom_pub_hash,
- &dk);
-
- if (GNUNET_OK != r)
- return GNUNET_NO;
-
- GNUNET_assert (NULL != dk);
-
- if (dk->denom_pub.bsign_pub_key->cipher !=
- pc->blinded_planchet.blinded_message->cipher)
- {
- /* denomination cipher and blinded planchet cipher not the same */
- GNUNET_break_op (0);
- SET_ERROR (wc,
- ERROR_CIPHER_MISMATCH);
- return GNUNET_NO;
- }
-
- if (0 >
- TALER_amount_add (&pc->collectable.amount_with_fee,
- &dk->meta.value,
- &dk->meta.fees.withdraw))
- {
- GNUNET_break (0);
- SET_ERROR (wc,
- ERROR_BATCH_AMOUNT_FEE_OVERFLOW);
- return GNUNET_NO;
- }
-
- if (0 >
- TALER_amount_add (&wc->batch_total,
- &wc->batch_total,
- &pc->collectable.amount_with_fee))
- {
- GNUNET_break (0);
- SET_ERROR (wc,
- ERROR_BATCH_AMOUNT_FEE_OVERFLOW);
- return GNUNET_NO;
- }
-
- TALER_coin_ev_hash (&pc->blinded_planchet,
- &pc->collectable.denom_pub_hash,
- &pc->collectable.h_coin_envelope);
-
- TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
- if (GNUNET_OK !=
- TALER_wallet_withdraw_verify_pre26 (
- &pc->collectable.denom_pub_hash,
- &pc->collectable.amount_with_fee,
- &pc->collectable.h_coin_envelope,
- &pc->collectable.reserve_pub,
- &pc->collectable.reserve_sig))
- {
- GNUNET_break_op (0);
- SET_ERROR (wc,
- ERROR_RESERVE_SIGNATURE_INVALID);
- return GNUNET_NO;
- }
- }
- /* everything parsed */
-
- return GNUNET_OK;
-}
-
-
-/**
- * Check if the keys in the request are valid for withdrawing.
- *
- * @param[in,out] wc context for request processing
- */
-static void
-phase_check_keys (struct BatchWithdrawContext *wc)
-{
- struct TEH_KeyStateHandle *ksh;
- enum GNUNET_GenericReturnValue r;
-
- ksh = TEH_keys_get_state ();
- if (NULL == ksh)
- {
- GNUNET_break (0);
- SET_ERROR (wc,
- ERROR_KEYS_MISSING);
- return;
- }
-
- r = batch_withdraw_phase_check_keys (wc, ksh);
-
- switch (r)
- {
- case GNUNET_OK:
- wc->phase++;
- break;
- case GNUNET_NO:
- /* error generated by function, simply return*/
- break;
- case GNUNET_SYSERR:
- GNUNET_break (0);
- SET_ERROR (wc,
- ERROR_KEYS_MISSING);
- break;
- default:
- GNUNET_break (0);
- }
-}
-
-
-/**
- * Cleanup routine for withdraw reqwuest.
- * The function is called upon completion of the request
- * that should clean up @a rh_ctx. Can be NULL.
- *
- * @param rc request context to clean up
- */
-static void
-clean_withdraw_rc (struct TEH_RequestContext *rc)
-{
- struct BatchWithdrawContext *wc = rc->rh_ctx;
-
- if (NULL != wc->lch)
- {
- TEH_legitimization_check_cancel (wc->lch);
- wc->lch = NULL;
- }
-
- for (unsigned int i = 0; i<wc->num_coins; i++)
- {
- struct PlanchetContext *pc = &wc->planchets[i];
-
- TALER_blinded_planchet_free (&pc->blinded_planchet);
- TALER_blinded_denom_sig_free (&pc->collectable.sig);
- }
- GNUNET_free (wc->planchets);
-
- if (ERROR_LEGITIMIZATION_RESULT == wc->error.code &&
- NULL != wc->error.details.legi.response)
- {
- MHD_destroy_response (wc->error.details.legi.response);
- wc->error.details.legi.response = NULL;
- }
-
- GNUNET_free (wc);
-}
-
-
-/**
- * Reports an error, potentially with details.
- * That is, it puts a error-type specific response into the MHD queue.
- * It will do a idempotency check first, if needed for the error type.
- *
- * @param wc withdraw context
- */
-static void
-phase_generate_reply_error (
- struct BatchWithdrawContext *wc)
-{
- GNUNET_assert (PHASE_GENERATE_REPLY_ERROR == wc->phase);
- GNUNET_assert (ERROR_NONE != wc->error.code);
- GNUNET_assert (ERROR_MAX != wc->error.code);
-
- if (needs_idempotency_check[wc->error.code] &&
- check_idempotency (wc))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "request is idempotent\n");
- return;
- }
-
- switch (wc->error.code)
- {
- case ERROR_MAX:
- case ERROR_NONE:
- {
- GNUNET_break (0);
- wc->phase = PHASE_RETURN_YES;
- return;
- }
-
- case ERROR_REQUEST_PARAMETER_MALFORMED:
- TALER_MHD_reply_with_error (
- wc->rc->connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- wc->error.details.hint);
- break;
-
- case ERROR_KEYS_MISSING:
- finish_loop (wc,
- TALER_MHD_reply_with_error (
- wc->rc->connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
- NULL));
- break;
-
- case ERROR_DB_FETCH_FAILED:
- finish_loop (wc,
- TALER_MHD_reply_with_error (
- wc->rc->connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- wc->error.details.db_fetch_context));
- break;
-
- case ERROR_DB_INVARIANT_FAILURE:
- finish_loop (wc,
- TALER_MHD_reply_with_error (
- wc->rc->connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
- NULL));
- break;
-
- case ERROR_INTERNAL_INVARIANT_FAILURE:
- finish_loop (wc,
- TALER_MHD_reply_with_error (
- wc->rc->connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- NULL));
- break;
-
- case ERROR_RESERVE_UNKNOWN:
- finish_loop (wc,
- TALER_MHD_reply_with_ec (
- wc->rc->connection,
- TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN,
- NULL));
- break;
-
- case ERROR_DENOMINATION_BATCH_SIGN:
- finish_loop (wc,
- TALER_MHD_reply_with_ec (
- wc->rc->connection,
- wc->error.details.ec,
- NULL));
- break;
-
- case ERROR_KYC_REQUIRED:
- finish_loop (wc,
- TEH_RESPONSE_reply_kyc_required (
- wc->rc->connection,
- &wc->h_normalized_payto,
- &wc->kyc,
- false));
- break;
-
- case ERROR_DENOMINATION_KEY_UNKNOWN:
- {
- GNUNET_break_op (0);
- finish_loop (wc,
- TEH_RESPONSE_reply_unknown_denom_pub_hash (
- wc->rc->connection,
- wc->error.details.denom_h));
- break;
- }
-
- case ERROR_DENOMINATION_EXPIRED:
- GNUNET_break_op (0);
- finish_loop (wc,
- TEH_RESPONSE_reply_expired_denom_pub_hash (
- wc->rc->connection,
- wc->error.details.denom_h,
- TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
- "batch-withdraw"));
- break;
-
- case ERROR_DENOMINATION_VALIDITY_IN_FUTURE:
- finish_loop (wc,
- TEH_RESPONSE_reply_expired_denom_pub_hash (
- wc->rc->connection,
- wc->error.details.denom_h,
- TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
- "batch-withdraw"));
- break;
-
- case ERROR_DENOMINATION_REVOKED:
- GNUNET_break_op (0);
- finish_loop (wc,
- TALER_MHD_reply_with_ec (
- wc->rc->connection,
- TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
- "batch-withdraw"));
- break;
-
- case ERROR_CIPHER_MISMATCH:
- finish_loop (wc,
- TALER_MHD_reply_with_ec (
- wc->rc->connection,
- TALER_EC_EXCHANGE_GENERIC_CIPHER_MISMATCH,
- NULL));
- break;
-
- case ERROR_AGE_RESTRICTION_REQUIRED:
- finish_loop (wc,
- TEH_RESPONSE_reply_reserve_age_restriction_required (
- wc->rc->connection,
- wc->error.details.lowest_age));
- break;
-
- case ERROR_BATCH_INSUFFICIENT_FUNDS:
- finish_loop (wc,
- TEH_RESPONSE_reply_reserve_insufficient_balance (
- wc->rc->connection,
- TALER_EC_EXCHANGE_WITHDRAW_INSUFFICIENT_FUNDS,
- &wc->error.details.reserve_balance,
- &wc->batch_total,
- &wc->reserve_pub));
- break;
-
- case ERROR_BATCH_IDEMPOTENT_PLANCHET:
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Idempotent coin in batch, not allowed. Aborting.\n");
- finish_loop (wc,
- TALER_MHD_reply_with_error (
- wc->rc->connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_EXCHANGE_WITHDRAW_IDEMPOTENT_PLANCHET,
- NULL));
- break;
- }
-
- case ERROR_BATCH_NONCE_RESUSE:
- finish_loop (wc,
- TALER_MHD_reply_with_error (
- wc->rc->connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_EXCHANGE_WITHDRAW_NONCE_REUSE,
- NULL));
- break;
-
- case ERROR_BATCH_AMOUNT_FEE_OVERFLOW:
- finish_loop (wc,
- TALER_MHD_reply_with_error (
- wc->rc->connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_EXCHANGE_WITHDRAW_AMOUNT_FEE_OVERFLOW,
- NULL));
- break;
-
- case ERROR_RESERVE_SIGNATURE_INVALID:
- finish_loop (wc,
- TALER_MHD_reply_with_ec (
- wc->rc->connection,
- TALER_EC_EXCHANGE_WITHDRAW_RESERVE_SIGNATURE_INVALID,
- NULL));
- break;
-
- case ERROR_LEGITIMIZATION_RESULT: {
- finish_loop (wc,
- MHD_queue_response (wc->rc->connection,
- wc->error.details.legi.http_status,
- wc->error.details.legi.response));
- break;
- }
- }
-}
-
-
-/**
- * Creates a new context for the incoming batch-withdraw request
- *
- * @param[in,out] wc context of the batch-witrhdraw, to be filled
- * @param root json body of the request
- * @return GNUNET_OK on success, GNUNET_SYSERR otherwise (response sent)
- */
-static enum GNUNET_GenericReturnValue
-batch_withdraw_new_request (
- struct BatchWithdrawContext *wc,
- const json_t *root)
-{
- const json_t *planchets;
-
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (TEH_currency,
- &wc->batch_total));
-
- {
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_array_const ("planchets",
- &planchets),
- GNUNET_JSON_spec_end ()
- };
-
- {
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_data (wc->rc->connection,
- root,
- spec);
- if (GNUNET_OK != res)
- return res;
- }
- }
-
- wc->num_coins = json_array_size (planchets);
- if (0 == wc->num_coins)
- {
- GNUNET_break_op (0);
- SET_ERROR_WITH_DETAIL (wc,
- ERROR_REQUEST_PARAMETER_MALFORMED,
- hint,
- "planchets");
- return GNUNET_SYSERR;
- }
-
- if (wc->num_coins > TALER_MAX_COINS)
- {
- GNUNET_break_op (0);
- SET_ERROR_WITH_DETAIL (wc,
- ERROR_REQUEST_PARAMETER_MALFORMED,
- hint,
- "too many planchets");
- return GNUNET_SYSERR;
- }
-
- wc->planchets
- = GNUNET_new_array (wc->num_coins,
- struct PlanchetContext);
-
- for (unsigned int i = 0; i<wc->num_coins; i++)
- {
- struct PlanchetContext *pc = &wc->planchets[i];
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_fixed_auto (
- "reserve_sig",
- &pc->collectable.reserve_sig),
- GNUNET_JSON_spec_fixed_auto (
- "denom_pub_hash",
- &pc->collectable.denom_pub_hash),
- TALER_JSON_spec_blinded_planchet (
- "coin_ev",
- &pc->blinded_planchet),
- GNUNET_JSON_spec_end ()
- };
-
- {
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_data (
- wc->rc->connection,
- json_array_get (planchets, i),
- ispec);
- if (GNUNET_OK != res)
- return res;
- }
-
- pc->collectable.reserve_pub = wc->reserve_pub;
- for (unsigned int k = 0; k<i; k++)
- {
- const struct PlanchetContext *kpc = &wc->planchets[k];
-
- if (0 ==
- TALER_blinded_planchet_cmp (
- &kpc->blinded_planchet,
- &pc->blinded_planchet))
- {
- GNUNET_break_op (0);
- SET_ERROR_WITH_DETAIL (wc,
- ERROR_REQUEST_PARAMETER_MALFORMED,
- hint,
- "duplicate planchet");
- return GNUNET_SYSERR;
- }
- }
- }
- return GNUNET_OK;
-}
-
-
-MHD_RESULT
-TEH_handler_batch_withdraw (
- struct TEH_RequestContext *rc,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const json_t *root)
-{
- struct BatchWithdrawContext *wc = rc->rh_ctx;
- enum GNUNET_GenericReturnValue r;
-
- if (NULL == wc)
- {
- wc = GNUNET_new (struct BatchWithdrawContext);
- rc->rh_ctx = wc;
- rc->rh_cleaner = &clean_withdraw_rc;
- wc->rc = rc;
- wc->now = GNUNET_TIME_timestamp_get ();
- wc->reserve_pub = *reserve_pub;
-
- r = batch_withdraw_new_request (wc, root);
-
- if (GNUNET_OK != r)
- return (GNUNET_SYSERR == r) ? MHD_NO : MHD_YES;
-
- wc->phase = PHASE_CHECK_KEYS;
- }
-
- while (true)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "batch-withdraw processing in phase %d\n",
- wc->phase);
-
- switch (wc->phase)
- {
- case PHASE_CHECK_KEYS:
- phase_check_keys (wc);
- break;
- case PHASE_CHECK_RESERVE_SIGNATURE:
- /* signature checks has occurred in batch_withdraw_phase_check_keys */
- wc->phase++;
- break;
- case PHASE_RUN_LEGI_CHECK:
- phase_run_legi_check (wc);
- break;
- case PHASE_SUSPENDED:
- return MHD_YES;
- case PHASE_CHECK_KYC_RESULT:
- phase_check_kyc_result (wc);
- break;
- case PHASE_PREPARE_TRANSACTION:
- phase_prepare_transaction (wc);
- break;
- case PHASE_RUN_TRANSACTION:
- phase_run_transaction (wc);
- break;
- case PHASE_GENERATE_REPLY_SUCCESS:
- phase_generate_reply_success (wc);
- break;
- case PHASE_GENERATE_REPLY_ERROR:
- phase_generate_reply_error (wc);
- break;
- case PHASE_RETURN_YES:
- return MHD_YES;
- case PHASE_RETURN_NO:
- return MHD_NO;
- }
- }
-}
-
-
-/* end of taler-exchange-httpd_batch-withdraw.c */
diff --git a/src/exchange/taler-exchange-httpd_batch-withdraw.h b/src/exchange/taler-exchange-httpd_batch-withdraw.h
@@ -1,62 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2024 Taler Systems SA
-
- 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
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-
-/*
- * NOTE: This endpoint is deprecated starting with v24 of the protocol and
- * will be removed, including this file.
- */
-
-/**
- * @file taler-exchange-httpd_batch-withdraw.h
- * @brief Handle /reserve/$RESERVE_PUB/batch-withdraw requests
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- * @author Özgür Kesim
- */
-#ifndef TALER_EXCHANGE_HTTPD_BATCH_WITHDRAW_H
-#define TALER_EXCHANGE_HTTPD_BATCH_WITHDRAW_H
-
-#include <microhttpd.h>
-#include "taler-exchange-httpd.h"
-
-/**
- * Resume suspended connections, we are shutting down.
- */
-void
-TEH_batch_withdraw_cleanup (void);
-
-
-/**
- * Handle a "/reserves/$RESERVE_PUB/batch-withdraw" request. Parses the batch of
- * requested "denom_pub" which specifies the key/value of the coin to be
- * withdrawn, and checks that the signature "reserve_sig" makes this a valid
- * withdrawal request from the specified reserve. If so, the envelope with
- * the blinded coin "coin_ev" is passed down to execute the withdrawal
- * operation.
- *
- * @param rc request context
- * @param root uploaded JSON data
- * @param reserve_pub public key of the reserve
- * @return MHD result code
- */
-MHD_RESULT
-TEH_handler_batch_withdraw (
- struct TEH_RequestContext *rc,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const json_t *root);
-
-#endif
diff --git a/src/exchange/taler-exchange-httpd_csr.c b/src/exchange/taler-exchange-httpd_csr.c
@@ -1,352 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2023 Taler Systems SA
-
- 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 Foundation; either version 3,
- or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty
- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General
- Public License along with TALER; see the file COPYING. If not,
- see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-exchange-httpd_csr.c
- * @brief Handle /csr requests
- * @author Lucien Heuzeveldt
- * @author Gian Demarmles
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include "taler_json_lib.h"
-#include "taler_mhd_lib.h"
-#include "taler-exchange-httpd_csr.h"
-#include "taler-exchange-httpd_responses.h"
-#include "taler-exchange-httpd_keys.h"
-
-
-MHD_RESULT
-TEH_handler_csr_melt (struct TEH_RequestContext *rc,
- const json_t *root,
- const char *const args[])
-{
- struct TALER_RefreshMasterSecretP rms;
- unsigned int csr_requests_num;
- const json_t *csr_requests;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("rms",
- &rms),
- GNUNET_JSON_spec_array_const ("nks",
- &csr_requests),
- GNUNET_JSON_spec_end ()
- };
- enum TALER_ErrorCode ec;
- struct TEH_DenominationKey *dk;
-
- (void) args;
- /* parse input */
- {
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_data (rc->connection,
- root,
- spec);
- if (GNUNET_OK != res)
- return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- }
- csr_requests_num = json_array_size (csr_requests);
- if ( (TALER_MAX_COINS <= csr_requests_num) ||
- (0 == csr_requests_num) )
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (
- rc->connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_EXCHANGE_GENERIC_NEW_DENOMS_ARRAY_SIZE_EXCESSIVE,
- NULL);
- }
-
- {
- struct GNUNET_CRYPTO_BlindingInputValues ewvs[csr_requests_num];
- {
- struct GNUNET_CRYPTO_CsSessionNonce nonces[csr_requests_num];
- struct TALER_DenominationHashP denom_pub_hashes[csr_requests_num];
- struct TEH_CsDeriveData cdds[csr_requests_num];
- struct GNUNET_CRYPTO_CSPublicRPairP r_pubs[csr_requests_num];
-
- for (unsigned int i = 0; i < csr_requests_num; i++)
- {
- uint32_t coin_off;
- struct TALER_DenominationHashP *denom_pub_hash = &denom_pub_hashes[i];
- struct GNUNET_JSON_Specification csr_spec[] = {
- GNUNET_JSON_spec_uint32 ("coin_offset",
- &coin_off),
- GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
- denom_pub_hash),
- GNUNET_JSON_spec_end ()
- };
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_array (rc->connection,
- csr_requests,
- csr_spec,
- i,
- -1);
- if (GNUNET_OK != res)
- {
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- }
- TALER_cs_refresh_nonce_derive (&rms,
- coin_off,
- &nonces[i]);
- }
-
- for (unsigned int i = 0; i < csr_requests_num; i++)
- {
- const struct GNUNET_CRYPTO_CsSessionNonce *nonce = &nonces[i];
- const struct TALER_DenominationHashP *denom_pub_hash =
- &denom_pub_hashes[i];
-
- ewvs[i].cipher = GNUNET_CRYPTO_BSA_CS;
- /* check denomination referenced by denom_pub_hash */
- {
- struct TEH_KeyStateHandle *ksh;
-
- ksh = TEH_keys_get_state ();
- if (NULL == ksh)
- {
- return TALER_MHD_reply_with_error (rc->connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
- NULL);
- }
- dk = TEH_keys_denomination_by_hash_from_state (ksh,
- denom_pub_hash,
- NULL,
- NULL);
- if (NULL == dk)
- {
- return TEH_RESPONSE_reply_unknown_denom_pub_hash (
- rc->connection,
- &denom_pub_hash[i]);
- }
- if (GNUNET_TIME_absolute_is_past (dk->meta.expire_withdraw.abs_time))
- {
- /* This denomination is past the expiration time for withdraws/refreshes*/
- return TEH_RESPONSE_reply_expired_denom_pub_hash (
- rc->connection,
- denom_pub_hash,
- TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
- "csr-melt");
- }
- if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time))
- {
- /* This denomination is not yet valid, no need to check
- for idempotency! */
- return TEH_RESPONSE_reply_expired_denom_pub_hash (
- rc->connection,
- denom_pub_hash,
- TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
- "csr-melt");
- }
- if (dk->recoup_possible)
- {
- /* This denomination has been revoked */
- return TEH_RESPONSE_reply_expired_denom_pub_hash (
- rc->connection,
- denom_pub_hash,
- TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
- "csr-melt");
- }
- if (GNUNET_CRYPTO_BSA_CS !=
- dk->denom_pub.bsign_pub_key->cipher)
- {
- /* denomination is valid but not for CS */
- return TEH_RESPONSE_reply_invalid_denom_cipher_for_operation (
- rc->connection,
- denom_pub_hash);
- }
- }
- cdds[i].h_denom_pub = denom_pub_hash;
- cdds[i].nonce = nonce;
- } /* for (i) */
- ec = TEH_keys_denomination_cs_batch_r_pub_simple (
- csr_requests_num,
- cdds,
- true,
- r_pubs);
- if (TALER_EC_NONE != ec)
- {
- GNUNET_break (0);
- return TALER_MHD_reply_with_ec (rc->connection,
- ec,
- NULL);
- }
- for (unsigned int i = 0; i < csr_requests_num; i++)
- ewvs[i].details.cs_values = r_pubs[i];
- } /* end scope */
-
- /* send response */
- {
- json_t *csr_response_ewvs;
- json_t *csr_response;
-
- csr_response_ewvs = json_array ();
- for (unsigned int i = 0; i < csr_requests_num; i++)
- {
- json_t *csr_obj;
- struct TALER_ExchangeBlindingValues exw = {
- .blinding_inputs = &ewvs[i]
- };
-
- csr_obj = GNUNET_JSON_PACK (
- TALER_JSON_pack_exchange_blinding_values ("ewv",
- &exw));
- GNUNET_assert (NULL != csr_obj);
- GNUNET_assert (0 ==
- json_array_append_new (csr_response_ewvs,
- csr_obj));
- }
- csr_response = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_array_steal ("ewvs",
- csr_response_ewvs));
- GNUNET_assert (NULL != csr_response);
- return TALER_MHD_reply_json_steal (rc->connection,
- csr_response,
- MHD_HTTP_OK);
- }
- }
-}
-
-
-MHD_RESULT
-TEH_handler_csr_withdraw (struct TEH_RequestContext *rc,
- const json_t *root,
- const char *const args[])
-{
- struct GNUNET_CRYPTO_CsSessionNonce nonce;
- struct TALER_DenominationHashP denom_pub_hash;
- struct GNUNET_CRYPTO_BlindingInputValues ewv = {
- .cipher = GNUNET_CRYPTO_BSA_CS
- };
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("nonce",
- &nonce),
- GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
- &denom_pub_hash),
- GNUNET_JSON_spec_end ()
- };
- struct TEH_DenominationKey *dk;
-
- (void) args;
- {
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_data (rc->connection,
- root,
- spec);
- if (GNUNET_OK != res)
- return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- }
-
- {
- struct TEH_KeyStateHandle *ksh;
-
- ksh = TEH_keys_get_state ();
- if (NULL == ksh)
- {
- return TALER_MHD_reply_with_error (rc->connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
- NULL);
- }
- dk = TEH_keys_denomination_by_hash_from_state (ksh,
- &denom_pub_hash,
- NULL,
- NULL);
- if (NULL == dk)
- {
- return TEH_RESPONSE_reply_unknown_denom_pub_hash (
- rc->connection,
- &denom_pub_hash);
- }
- if (GNUNET_TIME_absolute_is_past (dk->meta.expire_withdraw.abs_time))
- {
- /* This denomination is past the expiration time for withdraws/refreshes*/
- return TEH_RESPONSE_reply_expired_denom_pub_hash (
- rc->connection,
- &denom_pub_hash,
- TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
- "csr-withdraw");
- }
- if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time))
- {
- /* This denomination is not yet valid, no need to check
- for idempotency! */
- return TEH_RESPONSE_reply_expired_denom_pub_hash (
- rc->connection,
- &denom_pub_hash,
- TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
- "csr-withdraw");
- }
- if (dk->recoup_possible)
- {
- /* This denomination has been revoked */
- return TEH_RESPONSE_reply_expired_denom_pub_hash (
- rc->connection,
- &denom_pub_hash,
- TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
- "csr-withdraw");
- }
- if (GNUNET_CRYPTO_BSA_CS !=
- dk->denom_pub.bsign_pub_key->cipher)
- {
- /* denomination is valid but not for CS */
- return TEH_RESPONSE_reply_invalid_denom_cipher_for_operation (
- rc->connection,
- &denom_pub_hash);
- }
- }
-
- /* derive r_pub */
- {
- enum TALER_ErrorCode ec;
- const struct TEH_CsDeriveData cdd = {
- .h_denom_pub = &denom_pub_hash,
- .nonce = &nonce
- };
-
- ec = TEH_keys_denomination_cs_r_pub (&cdd,
- false,
- &ewv.details.cs_values);
- if (TALER_EC_NONE != ec)
- {
- GNUNET_break (0);
- return TALER_MHD_reply_with_ec (rc->connection,
- ec,
- NULL);
- }
- }
- {
- struct TALER_ExchangeBlindingValues exw = {
- .blinding_inputs = &ewv
- };
-
- return TALER_MHD_REPLY_JSON_PACK (
- rc->connection,
- MHD_HTTP_OK,
- TALER_JSON_pack_exchange_blinding_values ("ewv",
- &exw));
- }
-}
-
-
-/* end of taler-exchange-httpd_csr.c */
diff --git a/src/exchange/taler-exchange-httpd_csr.h b/src/exchange/taler-exchange-httpd_csr.h
@@ -1,56 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2021 Taler Systems SA
-
- 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
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-exchange-httpd_csr.h
- * @brief Handle /csr-* requests
- * @author Lucien Heuzeveldt
- * @author Gian Demarmles
- */
-#ifndef TALER_EXCHANGE_HTTPD_CSR_H
-#define TALER_EXCHANGE_HTTPD_CSR_H
-
-#include <microhttpd.h>
-#include "taler-exchange-httpd.h"
-
-
-/**
- * Handle a "/csr-melt" request.
- *
- * @param rc request context
- * @param root uploaded JSON data
- * @param args empty array
- * @return MHD result code
- */
-MHD_RESULT
-TEH_handler_csr_melt (struct TEH_RequestContext *rc,
- const json_t *root,
- const char *const args[]);
-
-
-/**
- * Handle a "/csr-withdraw" request.
- *
- * @param rc request context
- * @param root uploaded JSON data
- * @param args empty array
- * @return MHD result code
- */
-MHD_RESULT
-TEH_handler_csr_withdraw (struct TEH_RequestContext *rc,
- const json_t *root,
- const char *const args[]);
-
-#endif
diff --git a/src/exchange/taler-exchange-httpd_melt.c b/src/exchange/taler-exchange-httpd_melt.c
@@ -1,488 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2022 Taler Systems SA
-
- 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
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-exchange-httpd_melt.c
- * @brief Handle melt requests
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include <microhttpd.h>
-#include "taler_json_lib.h"
-#include "taler_mhd_lib.h"
-#include "taler-exchange-httpd_mhd.h"
-#include "taler-exchange-httpd_melt.h"
-#include "taler-exchange-httpd_responses.h"
-#include "taler-exchange-httpd_keys.h"
-#include "taler_exchangedb_lib.h"
-
-
-/**
- * Send a response to a "melt" request.
- *
- * @param connection the connection to send the response to
- * @param rc value the client committed to
- * @param noreveal_index which index will the client not have to reveal
- * @return a MHD status code
- */
-static MHD_RESULT
-reply_melt_success (struct MHD_Connection *connection,
- const struct TALER_RefreshCommitmentP *rc,
- uint32_t noreveal_index)
-{
- struct TALER_ExchangePublicKeyP pub;
- struct TALER_ExchangeSignatureP sig;
- enum TALER_ErrorCode ec;
-
- if (TALER_EC_NONE !=
- (ec = TALER_exchange_online_melt_confirmation_sign (
- &TEH_keys_exchange_sign_,
- rc,
- noreveal_index,
- &pub,
- &sig)))
- {
- GNUNET_break (0);
- return TALER_MHD_reply_with_ec (connection,
- ec,
- NULL);
- }
- return TALER_MHD_REPLY_JSON_PACK (
- connection,
- MHD_HTTP_OK,
- GNUNET_JSON_pack_uint64 ("noreveal_index",
- noreveal_index),
- GNUNET_JSON_pack_data_auto ("exchange_sig",
- &sig),
- GNUNET_JSON_pack_data_auto ("exchange_pub",
- &pub));
-}
-
-
-/**
- * Context for the melt operation.
- */
-struct MeltContext
-{
-
- /**
- * noreveal_index is only initialized during
- * #melt_transaction().
- */
- struct TALER_EXCHANGEDB_Refresh refresh_session;
-
- /**
- * UUID of the coin in the known_coins table.
- */
- uint64_t known_coin_id;
-
- /**
- * Information about the @e coin's value.
- */
- struct TALER_Amount coin_value;
-
- /**
- * Information about the @e coin's refresh fee.
- */
- struct TALER_Amount coin_refresh_fee;
-
- /**
- * Refresh master secret, if any of the fresh denominations use CS.
- */
- struct TALER_RefreshMasterSecretP rms;
-
- /**
- * Set to true if this coin's denomination was revoked and the operation
- * is thus only allowed for zombie coins where the transaction
- * history includes a #TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP.
- */
- bool zombie_required;
-
- /**
- * We already checked and noticed that the coin is known. Hence we
- * can skip the "ensure_coin_known" step of the transaction.
- */
- bool coin_is_dirty;
-
- /**
- * True if @e rms is missing.
- */
- bool no_rms;
-};
-
-
-/**
- * Execute a "melt". We have been given a list of valid
- * coins and a request to melt them into the given @a
- * refresh_session_pub. Check that the coins all have the required
- * value left and if so, store that they have been melted and confirm
- * the melting operation to the client.
- *
- * If it returns a non-error code, the transaction logic MUST NOT
- * queue a MHD response. IF it returns an hard error, the transaction
- * logic MUST queue a MHD response and set @a mhd_ret. If it returns
- * the soft error code, the function MAY be called again to retry and
- * MUST not queue a MHD response.
- *
- * @param cls our `struct MeltContext`
- * @param connection MHD request which triggered the transaction
- * @param[out] mhd_ret set to MHD response status for @a connection,
- * if transaction failed (!)
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-melt_transaction (void *cls,
- struct MHD_Connection *connection,
- MHD_RESULT *mhd_ret)
-{
- struct MeltContext *rmc = cls;
- enum GNUNET_DB_QueryStatus qs;
- bool balance_ok;
-
- /* pick challenge and persist it */
- rmc->refresh_session.noreveal_index
- = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
- TALER_CNC_KAPPA);
-
- if (0 >
- (qs = TEH_plugin->do_melt (TEH_plugin->cls,
- rmc->no_rms
- ? NULL
- : &rmc->rms,
- &rmc->refresh_session,
- rmc->known_coin_id,
- &rmc->zombie_required,
- &balance_ok)))
- {
- if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
- {
- *mhd_ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_STORE_FAILED,
- "melt");
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- return qs;
- }
- GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
- if (rmc->zombie_required)
- {
- GNUNET_break_op (0);
- *mhd_ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_EXCHANGE_MELT_COIN_EXPIRED_NO_ZOMBIE,
- NULL);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- if (! balance_ok)
- {
- GNUNET_break_op (0);
- *mhd_ret
- = TEH_RESPONSE_reply_coin_insufficient_funds (
- connection,
- TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
- &rmc->refresh_session.coin.denom_pub_hash,
- &rmc->refresh_session.coin.coin_pub);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- /* All good, commit, final response will be generated by caller */
- TEH_METRICS_num_success[TEH_MT_SUCCESS_MELT]++;
- return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
-}
-
-
-/**
- * Handle a "melt" request after the first parsing has
- * happened. Performs the database transactions.
- *
- * @param connection the MHD connection to handle
- * @param[in,out] rmc details about the melt request
- * @return MHD result code
- */
-static MHD_RESULT
-database_melt (struct MHD_Connection *connection,
- struct MeltContext *rmc)
-{
- if (GNUNET_SYSERR ==
- TEH_plugin->preflight (TEH_plugin->cls))
- {
- GNUNET_break (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_START_FAILED,
- "preflight failure");
- }
-
- /* first, make sure coin is known */
- if (! rmc->coin_is_dirty)
- {
- MHD_RESULT mhd_ret = MHD_NO;
- enum GNUNET_DB_QueryStatus qs;
-
- for (unsigned int tries = 0; tries<MAX_TRANSACTION_COMMIT_RETRIES; tries++)
- {
- qs = TEH_make_coin_known (&rmc->refresh_session.coin,
- connection,
- &rmc->known_coin_id,
- &mhd_ret);
- if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
- break;
- }
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- {
- GNUNET_break (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_COMMIT_FAILED,
- "make_coin_known");
- }
- if (qs < 0)
- return mhd_ret;
- }
-
- /* run main database transaction */
- {
- MHD_RESULT mhd_ret;
-
- if (GNUNET_OK !=
- TEH_DB_run_transaction (connection,
- "run melt",
- TEH_MT_REQUEST_MELT,
- &mhd_ret,
- &melt_transaction,
- rmc))
- return mhd_ret;
- }
-
- /* Success. Generate ordinary response. */
- return reply_melt_success (connection,
- &rmc->refresh_session.rc,
- rmc->refresh_session.noreveal_index);
-}
-
-
-/**
- * Check for information about the melted coin's denomination,
- * extracting its validity status and fee structure.
- *
- * @param connection HTTP connection we are handling
- * @param rmc parsed request information
- * @return MHD status code
- */
-static MHD_RESULT
-check_melt_valid (struct MHD_Connection *connection,
- struct MeltContext *rmc)
-{
- /* Baseline: check if deposits/refreshes are generally
- simply still allowed for this denomination */
- struct TEH_DenominationKey *dk;
- MHD_RESULT mret;
-
- dk = TEH_keys_denomination_by_hash (
- &rmc->refresh_session.coin.denom_pub_hash,
- connection,
- &mret);
- if (NULL == dk)
- return mret;
-
- if (GNUNET_TIME_absolute_is_past (dk->meta.expire_legal.abs_time))
- {
- /* Way too late now, even zombies have expired */
- return TEH_RESPONSE_reply_expired_denom_pub_hash (
- connection,
- &rmc->refresh_session.coin.denom_pub_hash,
- TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
- "MELT");
- }
-
- if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time))
- {
- /* This denomination is not yet valid */
- return TEH_RESPONSE_reply_expired_denom_pub_hash (
- connection,
- &rmc->refresh_session.coin.denom_pub_hash,
- TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
- "MELT");
- }
-
- rmc->coin_refresh_fee = dk->meta.fees.refresh;
- rmc->coin_value = dk->meta.value;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Melted coin's denomination is worth %s\n",
- TALER_amount2s (&dk->meta.value));
-
- /* sanity-check that "total melt amount > melt fee" */
- if (0 <
- TALER_amount_cmp (&rmc->coin_refresh_fee,
- &rmc->refresh_session.amount_with_fee))
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_EXCHANGE_MELT_FEES_EXCEED_CONTRIBUTION,
- NULL);
- }
- switch (dk->denom_pub.bsign_pub_key->cipher)
- {
- case GNUNET_CRYPTO_BSA_RSA:
- TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_RSA]++;
- break;
- case GNUNET_CRYPTO_BSA_CS:
- TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_CS]++;
- break;
- default:
- break;
- }
- if (GNUNET_OK !=
- TALER_test_coin_valid (&rmc->refresh_session.coin,
- &dk->denom_pub))
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_FORBIDDEN,
- TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID,
- NULL);
- }
-
- /* verify signature of coin for melt operation */
- TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
- if (GNUNET_OK !=
- TALER_wallet_melt_verify (&rmc->refresh_session.amount_with_fee,
- &rmc->coin_refresh_fee,
- &rmc->refresh_session.rc,
- &rmc->refresh_session.coin.denom_pub_hash,
- &rmc->refresh_session.coin.h_age_commitment,
- &rmc->refresh_session.coin.coin_pub,
- &rmc->refresh_session.coin_sig))
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_FORBIDDEN,
- TALER_EC_EXCHANGE_MELT_COIN_SIGNATURE_INVALID,
- NULL);
- }
-
- if (GNUNET_TIME_absolute_is_past (dk->meta.expire_deposit.abs_time))
- {
- /* We are past deposit expiration time, but maybe this is a zombie? */
- struct TALER_DenominationHashP denom_hash;
- enum GNUNET_DB_QueryStatus qs;
-
- /* Check that the coin is dirty (we have seen it before), as we will
- not just allow melting of a *fresh* coin where the denomination was
- revoked (those must be recouped) */
- qs = TEH_plugin->get_coin_denomination (
- TEH_plugin->cls,
- &rmc->refresh_session.coin.coin_pub,
- &rmc->known_coin_id,
- &denom_hash);
- if (0 > qs)
- {
- /* There is no good reason for a serialization failure here: */
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- "coin denomination");
- }
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
- {
- /* We never saw this coin before, so _this_ justification is not OK */
- return TEH_RESPONSE_reply_expired_denom_pub_hash (
- connection,
- &rmc->refresh_session.coin.denom_pub_hash,
- TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
- "MELT");
- }
- /* Minor optimization: no need to run the
- "ensure_coin_known" part of the transaction */
- rmc->coin_is_dirty = true;
- /* sanity check */
- if (0 !=
- GNUNET_memcmp (&denom_hash,
- &rmc->refresh_session.coin.denom_pub_hash))
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_ec (
- connection,
- TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY,
- TALER_B2S (&denom_hash));
- }
- rmc->zombie_required = true; /* check later that zombie is satisfied */
- }
-
- return database_melt (connection,
- rmc);
-}
-
-
-MHD_RESULT
-TEH_handler_melt (struct MHD_Connection *connection,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const json_t *root)
-{
- struct MeltContext rmc;
- struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_denom_sig ("denom_sig",
- &rmc.refresh_session.coin.denom_sig),
- GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
- &rmc.refresh_session.coin.denom_pub_hash),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_fixed_auto ("age_commitment_hash",
- &rmc.refresh_session.coin.h_age_commitment),
- &rmc.refresh_session.coin.no_age_commitment),
- GNUNET_JSON_spec_fixed_auto ("confirm_sig",
- &rmc.refresh_session.coin_sig),
- TALER_JSON_spec_amount ("value_with_fee",
- TEH_currency,
- &rmc.refresh_session.amount_with_fee),
- GNUNET_JSON_spec_fixed_auto ("rc",
- &rmc.refresh_session.rc),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_fixed_auto ("rms",
- &rmc.rms),
- &rmc.no_rms),
- GNUNET_JSON_spec_end ()
- };
-
- memset (&rmc, 0, sizeof (rmc));
- rmc.refresh_session.coin.coin_pub = *coin_pub;
-
- {
- enum GNUNET_GenericReturnValue ret;
- ret = TALER_MHD_parse_json_data (connection,
- root,
- spec);
- if (GNUNET_OK != ret)
- return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES;
- }
-
- {
- MHD_RESULT res;
-
- res = check_melt_valid (connection,
- &rmc);
- GNUNET_JSON_parse_free (spec);
- return res;
- }
-}
-
-
-/* end of taler-exchange-httpd_melt.c */
diff --git a/src/exchange/taler-exchange-httpd_melt.h b/src/exchange/taler-exchange-httpd_melt.h
@@ -1,48 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2017 Taler Systems SA
-
- 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
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-exchange-httpd_melt.h
- * @brief Handle /coins/$COIN_PUB/melt requests
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#ifndef TALER_EXCHANGE_HTTPD_MELT_H
-#define TALER_EXCHANGE_HTTPD_MELT_H
-
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler-exchange-httpd.h"
-
-
-/**
- * Handle a "/coins/$COIN_PUB/melt" request. Parses the request into the JSON
- * components and then hands things of to #check_melt_valid() to
- * validate the melted coins, the signature and execute the melt using
- * melt_transaction().
- *
- * @param connection the MHD connection to handle
- * @param coin_pub public key of the coin
- * @param root uploaded JSON data
- * @return MHD result code
- */
-MHD_RESULT
-TEH_handler_melt (struct MHD_Connection *connection,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const json_t *root);
-
-
-#endif
diff --git a/src/exchange/taler-exchange-httpd_refreshes_reveal.c b/src/exchange/taler-exchange-httpd_refreshes_reveal.c
@@ -1,1076 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2022 Taler Systems SA
-
- 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
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-exchange-httpd_refreshes_reveal.c
- * @brief Handle /refreshes/$RCH/reveal requests
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include <microhttpd.h>
-#include "taler_mhd_lib.h"
-#include "taler-exchange-httpd_mhd.h"
-#include "taler-exchange-httpd_refreshes_reveal.h"
-#include "taler-exchange-httpd_responses.h"
-#include "taler-exchange-httpd_keys.h"
-
-
-/**
- * Send a response for "/refreshes/$RCH/reveal".
- *
- * @param connection the connection to send the response to
- * @param num_freshcoins number of new coins for which we reveal data
- * @param rrcs array of @a num_freshcoins signatures revealed
- * @return a MHD result code
- */
-static MHD_RESULT
-reply_refreshes_reveal_success (
- struct MHD_Connection *connection,
- unsigned int num_freshcoins,
- const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs)
-{
- json_t *list;
-
- list = json_array ();
- GNUNET_assert (NULL != list);
- for (unsigned int freshcoin_index = 0;
- freshcoin_index < num_freshcoins;
- freshcoin_index++)
- {
- json_t *obj;
-
- obj = GNUNET_JSON_PACK (
- TALER_JSON_pack_blinded_denom_sig ("ev_sig",
- &rrcs[freshcoin_index].coin_sig));
- GNUNET_assert (0 ==
- json_array_append_new (list,
- obj));
- }
-
- return TALER_MHD_REPLY_JSON_PACK (
- connection,
- MHD_HTTP_OK,
- GNUNET_JSON_pack_array_steal ("ev_sigs",
- list));
-}
-
-
-/**
- * State for a /refreshes/$RCH/reveal operation.
- */
-struct RevealContext
-{
-
- /**
- * Commitment of the refresh operation.
- */
- struct TALER_RefreshCommitmentP rc;
-
- /**
- * Transfer public key at gamma.
- */
- struct TALER_TransferPublicKeyP gamma_tp;
-
- /**
- * Transfer private keys revealed to us.
- */
- struct TALER_TransferPrivateKeyP transfer_privs[TALER_CNC_KAPPA - 1];
-
- /**
- * Melt data for our session we got from the database for @e rc.
- */
- struct TALER_EXCHANGEDB_Melt melt;
-
- /**
- * Denominations being requested.
- */
- const struct TEH_DenominationKey **dks;
-
- /**
- * Age commitment that was used for the original coin. If not NULL, its hash
- * should be the same as melt.session.h_age_commitment.
- */
- struct TALER_AgeCommitment *old_age_commitment;
-
- /**
- * Array of information about fresh coins being revealed.
- */
- struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs;
-
- /**
- * Envelopes to be signed.
- */
- struct TALER_RefreshCoinData *rcds;
-
- /**
- * Refresh master secret.
- */
- struct TALER_RefreshMasterSecretP rms;
-
- /**
- * Size of the @e dks, @e rcds and @e ev_sigs arrays (if non-NULL).
- */
- unsigned int num_fresh_coins;
-
- /**
- * True if @e rms was not provided.
- */
- bool no_rms;
-};
-
-
-/**
- * Check client's revelation against the original commitment.
- * The client is revealing to us the
- * transfer keys for @a #TALER_CNC_KAPPA-1 sets of coins. Verify that the
- * revealed transfer keys would allow linkage to the blinded coins.
- *
- * IF it returns #GNUNET_OK, the transaction logic MUST
- * NOT queue a MHD response. IF it returns an error, the
- * transaction logic MUST queue a MHD response and set @a mhd_ret.
- *
- * @param rctx our operation context
- * @param connection MHD request which triggered the transaction
- * @param[out] mhd_ret set to MHD response status for @a connection,
- * if transaction failed (!)
- * @return #GNUNET_OK if commitment was OK
- */
-static enum GNUNET_GenericReturnValue
-check_commitment (struct RevealContext *rctx,
- struct MHD_Connection *connection,
- MHD_RESULT *mhd_ret)
-{
- const union GNUNET_CRYPTO_BlindSessionNonce *nonces[rctx->num_fresh_coins];
-
- memset (nonces,
- 0,
- sizeof (nonces));
- for (unsigned int j = 0; j<rctx->num_fresh_coins; j++)
- {
- const struct TALER_DenominationPublicKey *dk = &rctx->dks[j]->denom_pub;
-
- if (dk->bsign_pub_key->cipher !=
- rctx->rcds[j].blinded_planchet.blinded_message->cipher)
- {
- GNUNET_break (0);
- *mhd_ret = TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_EXCHANGE_GENERIC_CIPHER_MISMATCH,
- NULL);
- return GNUNET_SYSERR;
- }
- switch (dk->bsign_pub_key->cipher)
- {
- case GNUNET_CRYPTO_BSA_INVALID:
- GNUNET_break (0);
- *mhd_ret = TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- NULL);
- return GNUNET_SYSERR;
- case GNUNET_CRYPTO_BSA_RSA:
- continue;
- case GNUNET_CRYPTO_BSA_CS:
- nonces[j]
- = (const union GNUNET_CRYPTO_BlindSessionNonce *)
- &rctx->rcds[j].blinded_planchet.blinded_message->details.
- cs_blinded_message.nonce;
- break;
- }
- }
-
- // OPTIMIZE: do this in batch later!
- for (unsigned int j = 0; j<rctx->num_fresh_coins; j++)
- {
- const struct TALER_DenominationPublicKey *dk = &rctx->dks[j]->denom_pub;
- struct TALER_ExchangeBlindingValues *alg_values
- = &rctx->rrcs[j].exchange_vals;
- struct GNUNET_CRYPTO_BlindingInputValues *bi;
-
- bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues);
- alg_values->blinding_inputs = bi;
- bi->rc = 1;
- bi->cipher = dk->bsign_pub_key->cipher;
- switch (dk->bsign_pub_key->cipher)
- {
- case GNUNET_CRYPTO_BSA_INVALID:
- GNUNET_assert (0);
- return GNUNET_SYSERR;
- case GNUNET_CRYPTO_BSA_RSA:
- continue;
- case GNUNET_CRYPTO_BSA_CS:
- {
- enum TALER_ErrorCode ec;
- const struct TEH_CsDeriveData cdd = {
- .h_denom_pub = &rctx->rrcs[j].h_denom_pub,
- .nonce = &nonces[j]->cs_nonce
- };
-
- ec = TEH_keys_denomination_cs_r_pub (
- &cdd,
- true,
- &bi->details.cs_values);
- if (TALER_EC_NONE != ec)
- {
- *mhd_ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- ec,
- NULL);
- return GNUNET_SYSERR;
- }
- }
- }
- }
- /* Verify commitment */
- {
- /* Note that the contents of rcs[melt.session.noreveal_index]
- will be aliased and are *not* allocated (or deallocated) in
- this function -- in contrast to the other offsets! */
- struct TALER_RefreshCommitmentEntry rcs[TALER_CNC_KAPPA];
- struct TALER_RefreshCommitmentP rc_expected;
- unsigned int off;
-
- off = 0; /* did we pass session.noreveal_index yet? */
- for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++)
- {
- struct TALER_RefreshCommitmentEntry *rce = &rcs[i];
-
- if (i == rctx->melt.session.noreveal_index)
- {
- /* Take these coin envelopes from the client */
- rce->transfer_pub = rctx->gamma_tp;
- rce->new_coins = rctx->rcds;
- off = 1;
- }
- else
- {
- /* Reconstruct coin envelopes from transfer private key */
- const struct TALER_TransferPrivateKeyP *tpriv
- = &rctx->transfer_privs[i - off];
- struct TALER_TransferSecretP ts;
- struct TALER_AgeCommitmentHash h = {0};
- struct TALER_AgeCommitmentHash *hac = NULL;
-
- GNUNET_CRYPTO_ecdhe_key_get_public (&tpriv->ecdhe_priv,
- &rce->transfer_pub.ecdhe_pub);
- TEH_METRICS_num_keyexchanges[TEH_MT_KEYX_ECDH]++;
- TALER_link_reveal_transfer_secret (tpriv,
- &rctx->melt.session.coin.coin_pub,
- &ts);
- rce->new_coins = GNUNET_new_array (rctx->num_fresh_coins,
- struct TALER_RefreshCoinData);
- for (unsigned int j = 0; j<rctx->num_fresh_coins; j++)
- {
- struct TALER_RefreshCoinData *rcd = &rce->new_coins[j];
- struct TALER_CoinSpendPrivateKeyP coin_priv;
- union GNUNET_CRYPTO_BlindingSecretP bks;
- const struct TALER_ExchangeBlindingValues *alg_value
- = &rctx->rrcs[j].exchange_vals;
- struct TALER_PlanchetDetail pd = {0};
- struct TALER_CoinPubHashP c_hash;
- struct TALER_PlanchetMasterSecretP ps;
-
- rcd->dk = &rctx->dks[j]->denom_pub;
- TALER_transfer_secret_to_planchet_secret (&ts,
- j,
- &ps);
- TALER_planchet_setup_coin_priv (&ps,
- alg_value,
- &coin_priv);
- TALER_planchet_blinding_secret_create (&ps,
- alg_value,
- &bks);
- /* Calculate, if applicable, the age commitment and its hash, from
- * the transfer_secret and the old age commitment. */
- if (NULL != rctx->old_age_commitment)
- {
- struct TALER_AgeCommitmentProof acp = {
- /* we only need the commitment, not the proof, for the call to
- * TALER_age_commitment_derive. */
- .commitment = *(rctx->old_age_commitment)
- };
- struct TALER_AgeCommitmentProof nacp = {0};
-
- GNUNET_assert (GNUNET_OK ==
- TALER_age_commitment_proof_derive (
- &acp,
- &ts.key,
- &nacp));
- TALER_age_commitment_hash (&nacp.commitment,
- &h);
- TALER_age_commitment_proof_free (&nacp);
- hac = &h;
- }
-
- GNUNET_assert (GNUNET_OK ==
- TALER_planchet_prepare (rcd->dk,
- alg_value,
- &bks,
- nonces[j],
- &coin_priv,
- hac,
- &c_hash,
- &pd));
- rcd->blinded_planchet = pd.blinded_planchet;
- }
- }
- }
- TALER_refresh_get_commitment (&rc_expected,
- TALER_CNC_KAPPA,
- rctx->no_rms
- ? NULL
- : &rctx->rms,
- rctx->num_fresh_coins,
- rcs,
- &rctx->melt.session.coin.coin_pub,
- &rctx->melt.session.amount_with_fee);
-
- /* Free resources allocated above */
- for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++)
- {
- struct TALER_RefreshCommitmentEntry *rce = &rcs[i];
-
- if (i == rctx->melt.session.noreveal_index)
- continue; /* This offset is special: not allocated! */
- for (unsigned int j = 0; j<rctx->num_fresh_coins; j++)
- {
- struct TALER_RefreshCoinData *rcd = &rce->new_coins[j];
-
- TALER_blinded_planchet_free (&rcd->blinded_planchet);
- }
- GNUNET_free (rce->new_coins);
- }
-
- /* Verify rc_expected matches rc */
- if (0 != GNUNET_memcmp (&rctx->rc,
- &rc_expected))
- {
- GNUNET_break_op (0);
- *mhd_ret = TALER_MHD_REPLY_JSON_PACK (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_JSON_pack_ec (
- TALER_EC_EXCHANGE_REFRESHES_REVEAL_COMMITMENT_VIOLATION),
- GNUNET_JSON_pack_data_auto ("rc_expected",
- &rc_expected));
- return GNUNET_SYSERR;
- }
- } /* end of checking "rc_expected" */
-
- /* check amounts add up! */
- {
- struct TALER_Amount refresh_cost;
-
- refresh_cost = rctx->melt.melt_fee;
- for (unsigned int i = 0; i<rctx->num_fresh_coins; i++)
- {
- struct TALER_Amount total;
-
- if ( (0 >
- TALER_amount_add (&total,
- &rctx->dks[i]->meta.fees.withdraw,
- &rctx->dks[i]->meta.value)) ||
- (0 >
- TALER_amount_add (&refresh_cost,
- &refresh_cost,
- &total)) )
- {
- GNUNET_break_op (0);
- *mhd_ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_EXCHANGE_REFRESHES_REVEAL_COST_CALCULATION_OVERFLOW,
- NULL);
- return GNUNET_SYSERR;
- }
- }
- if (0 < TALER_amount_cmp (&refresh_cost,
- &rctx->melt.session.amount_with_fee))
- {
- GNUNET_break_op (0);
- *mhd_ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_EXCHANGE_REFRESHES_REVEAL_AMOUNT_INSUFFICIENT,
- NULL);
- return GNUNET_SYSERR;
- }
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Resolve denomination hashes.
- *
- * @param connection the MHD connection to handle
- * @param rctx context for the operation, partially built at this time
- * @param link_sigs_json link signatures in JSON format
- * @param new_denoms_h_json requests for fresh coins to be created
- * @param old_age_commitment_json age commitment that went into the withdrawal, maybe NULL
- * @param coin_evs envelopes of gamma-selected coins to be signed
- * @return MHD result code
- */
-static MHD_RESULT
-resolve_refreshes_reveal_denominations (
- struct MHD_Connection *connection,
- struct RevealContext *rctx,
- const json_t *link_sigs_json,
- const json_t *new_denoms_h_json,
- const json_t *old_age_commitment_json,
- const json_t *coin_evs)
-{
- unsigned int num_fresh_coins = json_array_size (new_denoms_h_json);
- /* We know num_fresh_coins is bounded by #TALER_MAX_COINS, so this is safe */
- const struct TEH_DenominationKey *dks[num_fresh_coins];
- const struct TEH_DenominationKey *old_dk;
- struct TALER_RefreshCoinData rcds[num_fresh_coins];
- struct TALER_EXCHANGEDB_RefreshRevealedCoin rrcs[num_fresh_coins];
- MHD_RESULT ret;
- struct TEH_KeyStateHandle *ksh;
- uint64_t melt_serial_id;
-
- memset (dks, 0, sizeof (dks));
- memset (rrcs, 0, sizeof (rrcs));
- memset (rcds, 0, sizeof (rcds));
- rctx->num_fresh_coins = num_fresh_coins;
-
- ksh = TEH_keys_get_state ();
- if (NULL == ksh)
- {
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
- NULL);
- }
-
- /* lookup old_coin_pub in database */
- {
- enum GNUNET_DB_QueryStatus qs;
-
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- (qs = TEH_plugin->get_melt (TEH_plugin->cls,
- &rctx->rc,
- &rctx->melt,
- &melt_serial_id)))
- {
- switch (qs)
- {
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_NOT_FOUND,
- TALER_EC_EXCHANGE_REFRESHES_REVEAL_SESSION_UNKNOWN,
- NULL);
- break;
- case GNUNET_DB_STATUS_HARD_ERROR:
- ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- "melt");
- break;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- default:
- GNUNET_break (0); /* should be impossible */
- ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- NULL);
- break;
- }
- goto cleanup;
- }
- if (rctx->melt.session.noreveal_index >= TALER_CNC_KAPPA)
- {
- GNUNET_break (0);
- ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- "melt");
- goto cleanup;
- }
- }
-
- old_dk = TEH_keys_denomination_by_hash_from_state (
- ksh,
- &rctx->melt.session.coin.denom_pub_hash,
- connection,
- &ret);
- if (NULL == old_dk)
- return ret;
-
- /* Parse denomination key hashes */
- for (unsigned int i = 0; i<num_fresh_coins; i++)
- {
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto (NULL,
- &rrcs[i].h_denom_pub),
- GNUNET_JSON_spec_end ()
- };
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_array (connection,
- new_denoms_h_json,
- spec,
- i,
- -1);
- if (GNUNET_OK != res)
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- dks[i] = TEH_keys_denomination_by_hash_from_state (ksh,
- &rrcs[i].h_denom_pub,
- connection,
- &ret);
- if (NULL == dks[i])
- return ret;
- if ( (GNUNET_CRYPTO_BSA_CS ==
- dks[i]->denom_pub.bsign_pub_key->cipher) &&
- (rctx->no_rms) )
- {
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MISSING,
- "rms");
- }
- if (GNUNET_TIME_absolute_is_past (dks[i]->meta.expire_withdraw.abs_time))
- {
- /* This denomination is past the expiration time for withdraws */
- return TEH_RESPONSE_reply_expired_denom_pub_hash (
- connection,
- &rrcs[i].h_denom_pub,
- TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
- "REVEAL");
- }
- if (GNUNET_TIME_absolute_is_future (dks[i]->meta.start.abs_time))
- {
- /* This denomination is not yet valid */
- return TEH_RESPONSE_reply_expired_denom_pub_hash (
- connection,
- &rrcs[i].h_denom_pub,
- TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
- "REVEAL");
- }
- if (dks[i]->recoup_possible)
- {
- /* This denomination has been revoked */
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_GONE,
- TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
- NULL);
- }
- }
-
- /* Parse coin envelopes */
- for (unsigned int i = 0; i<num_fresh_coins; i++)
- {
- struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &rrcs[i];
- struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_blinded_planchet (NULL,
- &rrc->blinded_planchet),
- GNUNET_JSON_spec_end ()
- };
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_array (connection,
- coin_evs,
- spec,
- i,
- -1);
- if (GNUNET_OK != res)
- {
- for (unsigned int j = 0; j<i; j++)
- TALER_blinded_planchet_free (&rrcs[j].blinded_planchet);
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- }
- TALER_coin_ev_hash (&rrc->blinded_planchet,
- &rrcs[i].h_denom_pub,
- &rrc->coin_envelope_hash);
- }
-
- if (TEH_age_restriction_enabled &&
- ((NULL == old_age_commitment_json) !=
- TALER_AgeCommitmentHash_isNullOrZero (
- &rctx->melt.session.coin.h_age_commitment)))
- {
- GNUNET_break (0);
- return MHD_NO;
- }
-
- /* Reconstruct the old age commitment and verify its hash matches the one
- * from the melt request */
- if (TEH_age_restriction_enabled &&
- (NULL != old_age_commitment_json))
- {
- enum GNUNET_GenericReturnValue res;
- struct TALER_AgeCommitment *oac;
- size_t ng = json_array_size (old_age_commitment_json);
- bool failed = true;
-
- /* Has been checked in handle_refreshes_reveal_json() */
- GNUNET_assert (ng == TEH_age_restriction_config.num_groups);
-
- rctx->old_age_commitment = GNUNET_new (struct TALER_AgeCommitment);
- oac = rctx->old_age_commitment;
- oac->mask = old_dk->meta.age_mask;
- oac->num = ng;
- oac->pubs = GNUNET_new_array (ng, struct TALER_AgeCommitmentPublicKeyP);
-
- /* Extract old age commitment */
- for (unsigned int i = 0; i< ng; i++)
- {
- struct GNUNET_JSON_Specification ac_spec[] = {
- GNUNET_JSON_spec_fixed_auto (NULL,
- &oac->pubs[i]),
- GNUNET_JSON_spec_end ()
- };
-
- res = TALER_MHD_parse_json_array (connection,
- old_age_commitment_json,
- ac_spec,
- i,
- -1);
-
- GNUNET_break_op (GNUNET_OK == res);
- if (GNUNET_OK != res)
- goto clean_age;
- }
-
- /* Sanity check: Compare hash from melting with hash of this age commitment */
- {
- struct TALER_AgeCommitmentHash hac = {0};
- TALER_age_commitment_hash (oac, &hac);
- if (0 != memcmp (&hac,
- &rctx->melt.session.coin.h_age_commitment,
- sizeof(struct TALER_AgeCommitmentHash)))
- goto clean_age;
- }
-
- failed = false;
-
-clean_age:
- if (failed)
- {
- TALER_age_commitment_free (oac);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_EXCHANGE_REFRESHES_REVEAL_AGE_RESTRICTION_COMMITMENT_INVALID,
- "old_age_commitment");
- }
- }
-
- /* Parse link signatures array */
- for (unsigned int i = 0; i<num_fresh_coins; i++)
- {
- struct GNUNET_JSON_Specification link_spec[] = {
- GNUNET_JSON_spec_fixed_auto (NULL,
- &rrcs[i].orig_coin_link_sig),
- GNUNET_JSON_spec_end ()
- };
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_array (connection,
- link_sigs_json,
- link_spec,
- i,
- -1);
- if (GNUNET_OK != res)
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
-
- /* Check signature */
- TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
- if (GNUNET_OK !=
- TALER_wallet_link_verify (
- &rrcs[i].h_denom_pub,
- &rctx->gamma_tp,
- &rrcs[i].coin_envelope_hash,
- &rctx->melt.session.coin.coin_pub,
- &rrcs[i].orig_coin_link_sig))
- {
- GNUNET_break_op (0);
- ret = TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_FORBIDDEN,
- TALER_EC_EXCHANGE_REFRESHES_REVEAL_LINK_SIGNATURE_INVALID,
- NULL);
- goto cleanup;
- }
- }
-
- /* prepare for check_commitment */
- for (unsigned int i = 0; i<rctx->num_fresh_coins; i++)
- {
- const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &rrcs[i];
- struct TALER_RefreshCoinData *rcd = &rcds[i];
-
- rcd->blinded_planchet = rrc->blinded_planchet;
- rcd->dk = &dks[i]->denom_pub;
- if (rcd->blinded_planchet.blinded_message->cipher !=
- rcd->dk->bsign_pub_key->cipher)
- {
- GNUNET_break_op (0);
- ret = TALER_MHD_REPLY_JSON_PACK (
- connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_JSON_pack_ec (
- TALER_EC_EXCHANGE_GENERIC_CIPHER_MISMATCH));
- goto cleanup;
- }
- }
-
- rctx->dks = dks;
- rctx->rcds = rcds;
- rctx->rrcs = rrcs;
- if (GNUNET_OK !=
- check_commitment (rctx,
- connection,
- &ret))
- goto cleanup;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Creating %u signatures\n",
- (unsigned int) rctx->num_fresh_coins);
-
- /* create fresh coin signatures */
- {
- struct TEH_CoinSignData csds[rctx->num_fresh_coins];
- struct TALER_BlindedDenominationSignature bss[rctx->num_fresh_coins];
- enum TALER_ErrorCode ec;
-
- for (unsigned int i = 0; i<rctx->num_fresh_coins; i++)
- {
- csds[i].h_denom_pub = &rrcs[i].h_denom_pub;
- csds[i].bp = &rcds[i].blinded_planchet;
- }
- ec = TEH_keys_denomination_batch_sign (
- rctx->num_fresh_coins,
- csds,
- true,
- bss);
- if (TALER_EC_NONE != ec)
- {
- GNUNET_break (0);
- ret = TALER_MHD_reply_with_ec (connection,
- ec,
- NULL);
- goto cleanup;
- }
-
- for (unsigned int i = 0; i<rctx->num_fresh_coins; i++)
- {
- rrcs[i].coin_sig = bss[i];
- rrcs[i].blinded_planchet = rcds[i].blinded_planchet;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Signatures ready, starting DB interaction\n");
-
- {
- enum GNUNET_DB_QueryStatus qs;
-
- for (unsigned int r = 0; r<MAX_TRANSACTION_COMMIT_RETRIES; r++)
- {
- bool changed;
-
- /* Persist operation result in DB */
- if (GNUNET_OK !=
- TEH_plugin->start (TEH_plugin->cls,
- "insert_refresh_reveal batch"))
- {
- GNUNET_break (0);
- ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_START_FAILED,
- NULL);
- goto cleanup;
- }
-
- qs = TEH_plugin->insert_refresh_reveal (
- TEH_plugin->cls,
- melt_serial_id,
- num_fresh_coins,
- rrcs,
- TALER_CNC_KAPPA - 1,
- rctx->transfer_privs,
- &rctx->gamma_tp);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- {
- TEH_plugin->rollback (TEH_plugin->cls);
- continue;
- }
- /* 0 == qs is ok, as we did not check for repeated requests */
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- {
- GNUNET_break (0);
- TEH_plugin->rollback (TEH_plugin->cls);
- ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_STORE_FAILED,
- "insert_refresh_reveal");
- goto cleanup;
- }
- changed = (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
- qs = TEH_plugin->commit (TEH_plugin->cls);
- if (qs >= 0)
- {
- if (changed)
- TEH_METRICS_num_success[TEH_MT_SUCCESS_REFRESH_REVEAL]++;
- break; /* success */
- }
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- {
- GNUNET_break (0);
- TEH_plugin->rollback (TEH_plugin->cls);
- ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_COMMIT_FAILED,
- NULL);
- goto cleanup;
- }
- TEH_plugin->rollback (TEH_plugin->cls);
- }
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- {
- GNUNET_break (0);
- TEH_plugin->rollback (TEH_plugin->cls);
- ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_SOFT_FAILURE,
- NULL);
- goto cleanup;
- }
- }
- /* Generate final (positive) response */
- ret = reply_refreshes_reveal_success (connection,
- num_fresh_coins,
- rrcs);
-cleanup:
- GNUNET_break (MHD_NO != ret);
- /* free resources */
- for (unsigned int i = 0; i<num_fresh_coins; i++)
- {
- struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &rrcs[i];
- struct TALER_ExchangeBlindingValues *alg_values
- = &rrcs[i].exchange_vals;
-
- GNUNET_free (alg_values->blinding_inputs);
- TALER_blinded_denom_sig_free (&rrc->coin_sig);
- TALER_blinded_planchet_free (&rrc->blinded_planchet);
- }
- return ret;
-}
-
-
-/**
- * Handle a "/refreshes/$RCH/reveal" request. Parses the given JSON
- * transfer private keys and if successful, passes everything to
- * #resolve_refreshes_reveal_denominations() which will verify that the
- * revealed information is valid then returns the signed refreshed
- * coins.
- *
- * If the denomination has age restriction support, the array of EDDSA public
- * keys, one for each age group that was activated during the withdrawal
- * by the parent/ward, must be provided in old_age_commitment. The hash of
- * this array must be the same as the h_age_commitment of the persisted reveal
- * request.
- *
- * @param connection the MHD connection to handle
- * @param rctx context for the operation, partially built at this time
- * @param tp_json private transfer keys in JSON format
- * @param link_sigs_json link signatures in JSON format
- * @param new_denoms_h_json requests for fresh coins to be created
- * @param old_age_commitment_json array of EDDSA public keys in JSON, used for age restriction, maybe NULL
- * @param coin_evs envelopes of gamma-selected coins to be signed
- * @return MHD result code
- */
-static MHD_RESULT
-handle_refreshes_reveal_json (struct MHD_Connection *connection,
- struct RevealContext *rctx,
- const json_t *tp_json,
- const json_t *link_sigs_json,
- const json_t *new_denoms_h_json,
- const json_t *old_age_commitment_json,
- const json_t *coin_evs)
-{
- unsigned int num_fresh_coins = json_array_size (new_denoms_h_json);
- unsigned int num_tprivs = json_array_size (tp_json);
-
- GNUNET_assert (num_tprivs == TALER_CNC_KAPPA - 1); /* checked just earlier */
- if ( (num_fresh_coins >= TALER_MAX_COINS) ||
- (0 == num_fresh_coins) )
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_EXCHANGE_GENERIC_NEW_DENOMS_ARRAY_SIZE_EXCESSIVE,
- NULL);
-
- }
- if (json_array_size (new_denoms_h_json) !=
- json_array_size (coin_evs))
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_EXCHANGE_REFRESHES_REVEAL_NEW_DENOMS_ARRAY_SIZE_MISMATCH,
- "new_denoms/coin_evs");
- }
- if (json_array_size (new_denoms_h_json) !=
- json_array_size (link_sigs_json))
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_EXCHANGE_REFRESHES_REVEAL_NEW_DENOMS_ARRAY_SIZE_MISMATCH,
- "new_denoms/link_sigs");
- }
-
- /* Sanity check of age commitment: If it was provided, it _must_ be an array
- * of the size the # of age groups */
- if (NULL != old_age_commitment_json
- && TEH_age_restriction_config.num_groups !=
- json_array_size (old_age_commitment_json))
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_EXCHANGE_REFRESHES_REVEAL_AGE_RESTRICTION_COMMITMENT_INVALID,
- "old_age_commitment");
- }
-
- /* Parse transfer private keys array */
- for (unsigned int i = 0; i<num_tprivs; i++)
- {
- struct GNUNET_JSON_Specification trans_spec[] = {
- GNUNET_JSON_spec_fixed_auto (NULL,
- &rctx->transfer_privs[i]),
- GNUNET_JSON_spec_end ()
- };
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_array (connection,
- tp_json,
- trans_spec,
- i,
- -1);
- if (GNUNET_OK != res)
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- }
-
- return resolve_refreshes_reveal_denominations (connection,
- rctx,
- link_sigs_json,
- new_denoms_h_json,
- old_age_commitment_json,
- coin_evs);
-}
-
-
-MHD_RESULT
-TEH_handler_reveal (struct TEH_RequestContext *rc,
- const json_t *root,
- const char *const args[2])
-{
- const json_t *coin_evs;
- const json_t *transfer_privs;
- const json_t *link_sigs;
- const json_t *new_denoms_h;
- const json_t *old_age_commitment;
- struct RevealContext rctx;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("transfer_pub",
- &rctx.gamma_tp),
- GNUNET_JSON_spec_array_const ("transfer_privs",
- &transfer_privs),
- GNUNET_JSON_spec_array_const ("link_sigs",
- &link_sigs),
- GNUNET_JSON_spec_array_const ("coin_evs",
- &coin_evs),
- GNUNET_JSON_spec_array_const ("new_denoms_h",
- &new_denoms_h),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_array_const ("old_age_commitment",
- &old_age_commitment),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_fixed_auto ("rms",
- &rctx.rms),
- &rctx.no_rms),
- GNUNET_JSON_spec_end ()
- };
-
- memset (&rctx,
- 0,
- sizeof (rctx));
- if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (args[0],
- strlen (args[0]),
- &rctx.rc,
- sizeof (rctx.rc)))
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (rc->connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_EXCHANGE_REFRESHES_REVEAL_INVALID_RCH,
- args[0]);
- }
- if (0 != strcmp (args[1],
- "reveal"))
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (rc->connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_EXCHANGE_REFRESHES_REVEAL_OPERATION_INVALID,
- args[1]);
- }
-
- {
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_data (rc->connection,
- root,
- spec);
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- }
- }
-
- /* Check we got enough transfer private keys */
- /* Note we do +1 as 1 row (cut-and-choose!) is missing! */
- if (TALER_CNC_KAPPA != json_array_size (transfer_privs) + 1)
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (rc->connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_EXCHANGE_REFRESHES_REVEAL_CNC_TRANSFER_ARRAY_SIZE_INVALID,
- NULL);
- }
-
- return handle_refreshes_reveal_json (rc->connection,
- &rctx,
- transfer_privs,
- link_sigs,
- new_denoms_h,
- old_age_commitment,
- coin_evs);
-}
-
-
-/* end of taler-exchange-httpd_refreshes_reveal.c */
diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am
@@ -208,7 +208,6 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_get_global_fees.h pg_get_global_fees.c \
pg_get_known_coin.h pg_get_known_coin.c \
pg_get_kyc_rules.h pg_get_kyc_rules.c \
- pg_get_melt.h pg_get_melt.c \
pg_get_refresh.h pg_get_refresh.c \
pg_get_old_coin_by_h_blind.h pg_get_old_coin_by_h_blind.c \
pg_get_pending_kyc_requirement_process.h pg_get_pending_kyc_requirement_process.c \
@@ -247,7 +246,6 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_insert_partner.h pg_insert_partner.c \
pg_insert_purse_request.h pg_insert_purse_request.c \
pg_insert_records_by_table.c pg_insert_records_by_table.h \
- pg_insert_refresh_reveal.h pg_insert_refresh_reveal.c \
pg_insert_refund.h pg_insert_refund.c \
pg_insert_reserve_closed.h pg_insert_reserve_closed.c \
pg_insert_reserve_open_deposit.c pg_insert_reserve_open_deposit.h \
diff --git a/src/exchangedb/perf_get_link_data.c b/src/exchangedb/perf_get_link_data.c
@@ -1,546 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2023 Taler Systems SA
-
- 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
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file exchangedb/perf_get_link_data.c
- * @brief benchmark for get_link_data
- * @author Joseph Xu
- */
-#include "platform.h"
-#include "taler_exchangedb_lib.h"
-#include "taler_json_lib.h"
-#include "taler_exchangedb_plugin.h"
-#include "math.h"
-
-/**
- * Report line of error if @a cond is true, and jump to label "drop".
- */
-#define FAILIF(cond) \
- do { \
- if (! (cond)) {break;} \
- GNUNET_break (0); \
- goto drop; \
- } while (0)
-
-
-/**
- * Initializes @a ptr with random data.
- */
-#define RND_BLK(ptr) \
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, sizeof (* \
- ptr))
-
-/**
- * Initializes @a ptr with zeros.
- */
-#define ZR_BLK(ptr) \
- memset (ptr, 0, sizeof (*ptr))
-
-#define CURRENCY "EUR"
-#define RSA_KEY_SIZE 1024
-#define ROUNDS 100
-#define NUM_ROWS 1000
-#define MELT_NEW_COINS 5
-#define DENOMINATIONS 5
-#define MELT_NOREVEAL_INDEX 1
-/**
- * Database plugin under test.
- */
-static struct TALER_EXCHANGEDB_Plugin *plugin;
-/**
- * Denomination keys used for fresh coins in melt test.
- */
-static struct DenomKeyPair **new_dkp;
-static int result;
-
-static struct TALER_TransferPrivateKeyP tprivs[TALER_CNC_KAPPA];
-static struct TALER_TransferPublicKeyP tpub;
-struct DenomKeyPair
-{
- struct TALER_DenominationPrivateKey priv;
- struct TALER_DenominationPublicKey pub;
-};
-
-
-/**
- * Destroy a denomination key pair. The key is not necessarily removed from the DB.
- *
- * @param dkp the key pair to destroy
- */
-static void
-destroy_denom_key_pair (struct DenomKeyPair *dkp)
-{
- TALER_denom_pub_free (&dkp->pub);
- TALER_denom_priv_free (&dkp->priv);
- GNUNET_free (dkp);
-}
-
-
-/**
- * Create a denomination key pair by registering the denomination in the DB.
- *
- * @param size the size of the denomination key
- * @param now time to use for key generation, legal expiration will be 3h later.
- * @param fees fees to use
- * @return the denominaiton key pair; NULL upon error
- */
-static struct DenomKeyPair *
-create_denom_key_pair (unsigned int size,
- struct GNUNET_TIME_Timestamp now,
- const struct TALER_Amount *value,
- const struct TALER_DenomFeeSet *fees)
-{
- struct DenomKeyPair *dkp;
- struct TALER_EXCHANGEDB_DenominationKey dki;
- struct TALER_EXCHANGEDB_DenominationKeyInformation issue2;
-
- dkp = GNUNET_new (struct DenomKeyPair);
- GNUNET_assert (GNUNET_OK ==
- TALER_denom_priv_create (&dkp->priv,
- &dkp->pub,
- GNUNET_CRYPTO_BSA_RSA,
- size));
- memset (&dki,
- 0,
- sizeof (struct TALER_EXCHANGEDB_DenominationKey));
- dki.denom_pub = dkp->pub;
- dki.issue.start = now;
- dki.issue.expire_withdraw
- = GNUNET_TIME_absolute_to_timestamp (
- GNUNET_TIME_absolute_add (
- now.abs_time,
- GNUNET_TIME_UNIT_HOURS));
- dki.issue.expire_deposit
- = GNUNET_TIME_absolute_to_timestamp (
- GNUNET_TIME_absolute_add (
- now.abs_time,
- GNUNET_TIME_relative_multiply (
- GNUNET_TIME_UNIT_HOURS, 2)));
- dki.issue.expire_legal
- = GNUNET_TIME_absolute_to_timestamp (
- GNUNET_TIME_absolute_add (
- now.abs_time,
- GNUNET_TIME_relative_multiply (
- GNUNET_TIME_UNIT_HOURS, 3)));
- dki.issue.value = *value;
- dki.issue.fees = *fees;
- TALER_denom_pub_hash (&dkp->pub,
- &dki.issue.denom_hash);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->insert_denomination_info (plugin->cls,
- &dki.denom_pub,
- &dki.issue))
- {
- GNUNET_break (0);
- destroy_denom_key_pair (dkp);
- return NULL;
- }
- memset (&issue2, 0, sizeof (issue2));
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->get_denomination_info (plugin->cls,
- &dki.issue.denom_hash,
- NULL,
- &issue2))
- {
- GNUNET_break (0);
- destroy_denom_key_pair (dkp);
- return NULL;
- }
- if (0 != GNUNET_memcmp (&dki.issue,
- &issue2))
- {
- GNUNET_break (0);
- destroy_denom_key_pair (dkp);
- return NULL;
- }
- return dkp;
-}
-
-
-/**
- * Function called with the session hashes and transfer secret
- * information for a given coin.
- *
- * @param cls closure
- * @param transfer_pub public transfer key for the session
- * @param ldl link data for @a transfer_pub
- */
-static void
-handle_link_data_cb (void *cls,
- const struct TALER_TransferPublicKeyP *transfer_pub,
- const struct TALER_EXCHANGEDB_LinkList *ldl)
-{
- (void) cls;
- (void) transfer_pub;
- (void) ldl;
-}
-
-
-/**
- * Main function that will be run by the scheduler.
- *
- * @param cls closure with config
- */
-
-static void
-run (void *cls)
-{
- struct TALER_EXCHANGEDB_Refresh *refresh;
- uint64_t melt_serial_id;
- struct GNUNET_CONFIGURATION_Handle *cfg = cls;
- const uint32_t num_partitions = 10;
- struct DenomKeyPair *dkp = NULL;
- struct TALER_EXCHANGEDB_Deposit *depos = NULL;
- struct TALER_Amount value;
- struct GNUNET_TIME_Relative times = GNUNET_TIME_UNIT_ZERO;
- unsigned long long sqrs = 0;
- struct TALER_EXCHANGEDB_Refund *ref = NULL;
- unsigned int *perm;
- unsigned long long duration_sq;
- struct GNUNET_CRYPTO_BlindingInputValues bi = {
- .cipher = GNUNET_CRYPTO_BSA_RSA,
- .rc = 0
- };
- struct TALER_ExchangeBlindingValues alg_values = {
- .blinding_inputs = &bi
- };
- struct TALER_DenomFeeSet fees;
-
- ref = GNUNET_new_array (ROUNDS + 1,
- struct TALER_EXCHANGEDB_Refund);
- depos = GNUNET_new_array (ROUNDS + 1,
- struct TALER_EXCHANGEDB_Deposit);
- refresh = GNUNET_new_array (ROUNDS + 1,
- struct TALER_EXCHANGEDB_Refresh);
-
- if (NULL ==
- (plugin = TALER_EXCHANGEDB_plugin_load (cfg,
- true)))
- {
- GNUNET_break (0);
- result = 77;
- return;
- }
- (void) plugin->drop_tables (plugin->cls);
- if (GNUNET_OK !=
- plugin->create_tables (plugin->cls,
- true,
- num_partitions))
- {
- GNUNET_break (0);
- result = 77;
- goto cleanup;
- }
- if (GNUNET_OK !=
- plugin->preflight (plugin->cls))
- {
- GNUNET_break (0);
- goto cleanup;
- }
-
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":1.000010",
- &value));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":0.000010",
- &fees.withdraw));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":0.000010",
- &fees.deposit));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":0.000010",
- &fees.refresh));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":0.000010",
- &fees.refund));
- {
- new_dkp = GNUNET_new_array (MELT_NEW_COINS,
- struct DenomKeyPair *);
-
- for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++)
- {
- struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
-
- new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE,
- now,
- &value,
- &fees);
- GNUNET_assert (NULL != new_dkp[cnt]);
- }
- }
- perm = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_NONCE,
- NUM_ROWS);
- FAILIF (GNUNET_OK !=
- plugin->start (plugin->cls,
- "Transaction"));
- for (unsigned int j = 0; j < NUM_ROWS; j++)
- {
- union GNUNET_CRYPTO_BlindingSecretP bks;
- struct TALER_CoinPubHashP c_hash;
- unsigned int i = perm[j];
- uint64_t known_coin_id;
- struct TALER_EXCHANGEDB_CollectableBlindcoin cbc;
- if (i >= ROUNDS)
- i = ROUNDS; /* throw-away slot, do not keep around */
- RND_BLK (&depos[i].coin.coin_pub);
- ZR_BLK (&cbc);
- TALER_denom_pub_hash (&new_dkp[(unsigned int) rand ()
- % MELT_NEW_COINS]->pub,
- &depos[i].coin.denom_pub_hash);
-
-
- {
- struct TALER_EXCHANGEDB_RefreshRevealedCoin
- revealed_coins[MELT_NEW_COINS];
-
- for (unsigned int p = 0; p<MELT_NEW_COINS; p++)
- {
- struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coin =
- &revealed_coins[p];
- struct TALER_BlindedPlanchet *bp = &revealed_coin->blinded_planchet;
- struct GNUNET_CRYPTO_RsaBlindedMessage *rp;
-
- bp->blinded_message = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
- rp = &bp->blinded_message->details.rsa_blinded_message;
- /* h_coin_ev must be unique, but we only have MELT_NEW_COINS created
- above for NUM_ROWS iterations; instead of making "all new" coins,
- we simply randomize the hash here as nobody is checking for consistency
- anyway ;-) */
- bp->blinded_message->rc = 1;
- bp->blinded_message->cipher = GNUNET_CRYPTO_BSA_RSA;
- rp->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 (
- GNUNET_CRYPTO_QUALITY_WEAK,
- (RSA_KEY_SIZE / 8) - 1);
- rp->blinded_msg = GNUNET_malloc (rp->blinded_msg_size);
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
- rp->blinded_msg,
- rp->blinded_msg_size);
- TALER_denom_pub_hash (&new_dkp[(unsigned int) rand ()
- % MELT_NEW_COINS]->pub,
- &revealed_coin->h_denom_pub);
- revealed_coin->exchange_vals = alg_values;
- TALER_coin_ev_hash (bp,
- &revealed_coin->h_denom_pub,
- &revealed_coin->coin_envelope_hash);
- GNUNET_assert (GNUNET_OK ==
- TALER_denom_sign_blinded (&revealed_coin->coin_sig,
- &new_dkp[(unsigned
- int) rand ()
- % MELT_NEW_COINS]->
- priv,
- true,
- bp));
- GNUNET_assert (
- GNUNET_OK ==
- TALER_denom_sign_blinded (
- &cbc.sig,
- &new_dkp[(unsigned int) rand () % MELT_NEW_COINS]->priv,
- false,
- bp));
- }
- GNUNET_assert (GNUNET_OK ==
- TALER_denom_sig_unblind (&depos[i].coin.denom_sig,
- &cbc.sig,
- &bks,
- &c_hash,
- &alg_values,
- &new_dkp[(unsigned int) rand ()
- % MELT_NEW_COINS]->pub));
- {
- /* ENSURE_COIN_KNOWN */
- struct TALER_DenominationHashP dph;
- struct TALER_AgeCommitmentHash agh;
- bool zombie_required = false;
- bool balance_ok;
-
- FAILIF (TALER_EXCHANGEDB_CKS_ADDED !=
- plugin->ensure_coin_known (plugin->cls,
- &depos[i].coin,
- &known_coin_id,
- &dph,
- &agh));
- /**** INSERT REFRESH COMMITMENTS ****/
- refresh[i].coin = depos[i].coin;
- RND_BLK (&refresh[i].coin_sig);
- RND_BLK (&refresh[i].rc);
- refresh[i].amount_with_fee = value;
- refresh[i].noreveal_index = MELT_NOREVEAL_INDEX;
- FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->do_melt (plugin->cls,
- NULL,
- &refresh[i],
- known_coin_id,
- &zombie_required,
- &balance_ok));
- }
- /****GET melt_serial_id generated by default****/
- {
- struct TALER_EXCHANGEDB_Melt ret_refresh_session;
-
- FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->get_melt (plugin->cls,
- &refresh[i].rc,
- &ret_refresh_session,
- &melt_serial_id));
- }
- /**** INSERT REFRESH_REVEAL + TRANSFER_KEYS *****/
- {
- static unsigned int cnt;
-
- RND_BLK (&tprivs);
- RND_BLK (&tpub);
- FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->insert_refresh_reveal (plugin->cls,
- melt_serial_id,
- MELT_NEW_COINS,
- revealed_coins,
- TALER_CNC_KAPPA - 1,
- tprivs,
- &tpub));
- cnt++;
- // fprintf (stderr, "CNT: %u - %llu\n", cnt, (unsigned long long) melt_serial_id);
- }
- for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++)
- {
- TALER_blinded_denom_sig_free (&revealed_coins[cnt].coin_sig);
- TALER_blinded_planchet_free (&revealed_coins[cnt].blinded_planchet);
- }
-
- /* {
- struct TALER_CoinSpendPublicKeyP ocp;
- uint64_t rrc_serial;
-
- FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->get_old_coin_by_h_blind (plugin->cls,
- &revealed_coins->coin_envelope_hash,
- &ocp,
- &rrc_serial));
- }*/
- }
- if (ROUNDS == i)
- TALER_denom_sig_free (&depos[i].coin.denom_sig);
- }
- /* End of benchmark setup */
- GNUNET_free (perm);
- FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
- plugin->commit (plugin->cls));
- for (unsigned int r = 0; r< ROUNDS; r++)
- {
- struct GNUNET_TIME_Absolute time;
- struct GNUNET_TIME_Relative duration;
- enum GNUNET_DB_QueryStatus qs;
- time = GNUNET_TIME_absolute_get ();
-
- qs = plugin->get_link_data (plugin->cls,
- &refresh[r].coin.coin_pub,
- &handle_link_data_cb,
- NULL);
- FAILIF (qs < 0);
-
- duration = GNUNET_TIME_absolute_get_duration (time);
- times = GNUNET_TIME_relative_add (times,
- duration);
- duration_sq = duration.rel_value_us * duration.rel_value_us;
- GNUNET_assert (duration_sq / duration.rel_value_us ==
- duration.rel_value_us);
- GNUNET_assert (sqrs + duration_sq >= sqrs);
- sqrs += duration_sq;
- }
-
- /* evaluation of performance */
- {
- struct GNUNET_TIME_Relative avg;
- double avg_dbl;
- double variance;
-
- avg = GNUNET_TIME_relative_divide (times,
- ROUNDS);
- avg_dbl = avg.rel_value_us;
- variance = sqrs - (avg_dbl * avg_dbl * ROUNDS);
- fprintf (stdout,
- "%8llu ± %6.0f\n",
- (unsigned long long) avg.rel_value_us,
- sqrt (variance / (ROUNDS - 1)));
- }
- result = 0;
-drop:
- // GNUNET_break (GNUNET_OK == plugin->drop_tables (plugin->cls));
-cleanup:
- if (NULL != dkp)
- destroy_denom_key_pair (dkp);
- for (unsigned int cnt = 0;
- (NULL != new_dkp) && (cnt < MELT_NEW_COINS) && (NULL != new_dkp[cnt]);
- cnt++)
- destroy_denom_key_pair (new_dkp[cnt]);
- GNUNET_free (new_dkp);
- for (unsigned int i = 0; i< ROUNDS; i++)
- {
- TALER_denom_sig_free (&depos[i].coin.denom_sig);
- }
- GNUNET_free (depos);
- GNUNET_free (ref);
- GNUNET_free (refresh);
- dkp = NULL;
- TALER_EXCHANGEDB_plugin_unload (plugin);
- plugin = NULL;
-}
-
-
-int
-main (int argc,
- char *const argv[])
-{
- const char *plugin_name;
- char *config_filename;
- char *testname;
- struct GNUNET_CONFIGURATION_Handle *cfg;
-
- (void) argc;
- result = -1;
- if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
- {
- GNUNET_break (0);
- return -1;
- }
- GNUNET_log_setup (argv[0],
- "WARNING",
- NULL);
- plugin_name++;
- (void) GNUNET_asprintf (&testname,
- "test-exchange-db-%s",
- plugin_name);
- (void) GNUNET_asprintf (&config_filename,
- "%s.conf",
- testname);
- cfg = GNUNET_CONFIGURATION_create (TALER_EXCHANGE_project_data ());
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_parse (cfg,
- config_filename))
- {
- GNUNET_break (0);
- GNUNET_free (config_filename);
- GNUNET_free (testname);
- return 2;
- }
- GNUNET_SCHEDULER_run (&run,
- cfg);
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_free (config_filename);
- GNUNET_free (testname);
- return result;
-}
-
-
-/* end of test_exchangedb_by_j.c */
diff --git a/src/exchangedb/pg_get_melt.c b/src/exchangedb/pg_get_melt.c
@@ -1,124 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
-
- 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
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file exchangedb/pg_get_melt.c
- * @brief Implementation of the get_melt function for Postgres
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_error_codes.h"
-#include "taler_dbevents.h"
-#include "taler_pq_lib.h"
-#include "pg_get_melt.h"
-#include "pg_helper.h"
-
-
-enum GNUNET_DB_QueryStatus
-TEH_PG_get_melt (void *cls,
- const struct TALER_RefreshCommitmentP *rc,
- struct TALER_EXCHANGEDB_Melt *melt,
- uint64_t *melt_serial_id)
-{
- struct PostgresClosure *pg = cls;
- bool h_age_commitment_is_null;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (rc),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
- &melt->session.coin.
- denom_pub_hash),
- TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refresh",
- &melt->melt_fee),
- GNUNET_PQ_result_spec_uint32 ("noreveal_index",
- &melt->session.noreveal_index),
- GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
- &melt->session.coin.coin_pub),
- GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
- &melt->session.coin_sig),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
- &melt->session.coin.h_age_commitment),
- &h_age_commitment_is_null),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
- &melt->session.amount_with_fee),
- GNUNET_PQ_result_spec_uint64 ("melt_serial_id",
- melt_serial_id),
- GNUNET_PQ_result_spec_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- memset (&melt->session.coin.denom_sig,
- 0,
- sizeof (melt->session.coin.denom_sig));
-
- /* Used in #postgres_get_melt() to fetch
- high-level information about a melt operation */
- PREPARE (pg,
- "get_melt",
- /* "SELECT"
- " denoms.denom_pub_hash"
- ",denoms.fee_refresh"
- ",old_coin_pub"
- ",old_coin_sig"
- ",kc.age_commitment_hash"
- ",amount_with_fee"
- ",noreveal_index"
- ",melt_serial_id"
- " FROM refresh_commitments"
- " JOIN known_coins kc"
- " ON (old_coin_pub = kc.coin_pub)"
- " JOIN denominations denoms"
- " ON (kc.denominations_serial = denoms.denominations_serial)"
- " WHERE rc=$1;", */
- "WITH rc AS MATERIALIZED ( "
- " SELECT"
- " * FROM refresh_commitments"
- " WHERE rc=$1"
- ")"
- "SELECT"
- " denoms.denom_pub_hash"
- ",denoms.fee_refresh"
- ",rc.old_coin_pub"
- ",rc.old_coin_sig"
- ",kc.age_commitment_hash"
- ",amount_with_fee"
- ",noreveal_index"
- ",melt_serial_id "
- "FROM ("
- " SELECT"
- " * "
- " FROM known_coins"
- " WHERE coin_pub=(SELECT old_coin_pub from rc)"
- ") kc "
- "JOIN rc"
- " ON (kc.coin_pub=rc.old_coin_pub) "
- "JOIN denominations denoms"
- " USING (denominations_serial);");
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "get_melt",
- params,
- rs);
- if (h_age_commitment_is_null)
- memset (&melt->session.coin.h_age_commitment,
- 0,
- sizeof(melt->session.coin.h_age_commitment));
-
- melt->session.rc = *rc;
- return qs;
-}
diff --git a/src/exchangedb/pg_get_melt.h b/src/exchangedb/pg_get_melt.h
@@ -1,44 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
-
- 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
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file exchangedb/pg_get_melt.h
- * @brief implementation of the get_melt function for Postgres
- * @author Christian Grothoff
- */
-#ifndef PG_GET_MELT_H
-#define PG_GET_MELT_H
-
-#include "taler_util.h"
-#include "taler_json_lib.h"
-#include "taler_exchangedb_plugin.h"
-/**
- * Lookup refresh melt commitment data under the given @a rc.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param rc commitment hash to use to locate the operation
- * @param[out] melt where to store the result; note that
- * melt->session.coin.denom_sig will be set to NULL
- * and is not fetched by this routine (as it is not needed by the client)
- * @param[out] melt_serial_id set to the row ID of @a rc in the refresh_commitments table
- * @return transaction status
- */
-enum GNUNET_DB_QueryStatus
-TEH_PG_get_melt (void *cls,
- const struct TALER_RefreshCommitmentP *rc,
- struct TALER_EXCHANGEDB_Melt *melt,
- uint64_t *melt_serial_id);
-
-#endif
diff --git a/src/exchangedb/pg_insert_refresh_reveal.c b/src/exchangedb/pg_insert_refresh_reveal.c
@@ -1,109 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
-
- 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
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file exchangedb/pg_insert_refresh_reveal.c
- * @brief Implementation of the insert_refresh_reveal function for Postgres
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_error_codes.h"
-#include "taler_dbevents.h"
-#include "taler_pq_lib.h"
-#include "pg_insert_refresh_reveal.h"
-#include "pg_helper.h"
-
-
-enum GNUNET_DB_QueryStatus
-TEH_PG_insert_refresh_reveal (
- void *cls,
- uint64_t melt_serial_id,
- uint32_t num_rrcs,
- const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs,
- unsigned int num_tprivs,
- const struct TALER_TransferPrivateKeyP *tprivs,
- const struct TALER_TransferPublicKeyP *tp)
-{
- struct PostgresClosure *pg = cls;
-
- if (TALER_CNC_KAPPA != num_tprivs + 1)
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- PREPARE (pg,
- "insert_refresh_revealed_coin",
- "INSERT INTO refresh_revealed_coins "
- "(melt_serial_id "
- ",freshcoin_index "
- ",link_sig "
- ",denominations_serial "
- ",coin_ev"
- ",ewv"
- ",h_coin_ev"
- ",ev_sig"
- ") SELECT $1, $2, $3, "
- " denominations_serial, $5, $6, $7, $8"
- " FROM denominations"
- " WHERE denom_pub_hash=$4"
- " ON CONFLICT DO NOTHING;");
- for (uint32_t i = 0; i<num_rrcs; i++)
- {
- const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &rrcs[i];
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&melt_serial_id),
- GNUNET_PQ_query_param_uint32 (&i),
- GNUNET_PQ_query_param_auto_from_type (&rrc->orig_coin_link_sig),
- GNUNET_PQ_query_param_auto_from_type (&rrc->h_denom_pub),
- TALER_PQ_query_param_blinded_planchet (&rrc->blinded_planchet),
- TALER_PQ_query_param_exchange_blinding_values (&rrc->exchange_vals),
- GNUNET_PQ_query_param_auto_from_type (&rrc->coin_envelope_hash),
- TALER_PQ_query_param_blinded_denom_sig (&rrc->coin_sig),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_refresh_revealed_coin",
- params);
- if (0 > qs)
- return qs;
- }
-
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&melt_serial_id),
- GNUNET_PQ_query_param_auto_from_type (tp),
- GNUNET_PQ_query_param_fixed_size (
- tprivs,
- num_tprivs * sizeof (struct TALER_TransferPrivateKeyP)),
- GNUNET_PQ_query_param_end
- };
-
- /* Used in #postgres_insert_refresh_reveal() to store the transfer
- keys we learned */
- PREPARE (pg,
- "insert_refresh_transfer_keys",
- "INSERT INTO refresh_transfer_keys "
- "(melt_serial_id"
- ",transfer_pub"
- ",transfer_privs"
- ") VALUES ($1, $2, $3)"
- " ON CONFLICT DO NOTHING;");
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_refresh_transfer_keys",
- params);
- }
-}
diff --git a/src/exchangedb/pg_insert_refresh_reveal.h b/src/exchangedb/pg_insert_refresh_reveal.h
@@ -1,51 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
-
- 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
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file exchangedb/pg_insert_refresh_reveal.h
- * @brief implementation of the insert_refresh_reveal function for Postgres
- * @author Christian Grothoff
- */
-#ifndef PG_INSERT_REFRESH_REVEAL_H
-#define PG_INSERT_REFRESH_REVEAL_H
-
-#include "taler_util.h"
-#include "taler_json_lib.h"
-#include "taler_exchangedb_plugin.h"
-/**
- * Store in the database which coin(s) the wallet wanted to create
- * in a given refresh operation and all of the other information
- * we learned or created in the /refresh/reveal step.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param melt_serial_id row ID of the commitment / melt operation in refresh_commitments
- * @param num_rrcs number of coins to generate, size of the @a rrcs array
- * @param rrcs information about the new coins
- * @param num_tprivs number of entries in @a tprivs, should be #TALER_CNC_KAPPA - 1
- * @param tprivs transfer private keys to store
- * @param tp public key to store
- * @return query status for the transaction
- */
-enum GNUNET_DB_QueryStatus
-TEH_PG_insert_refresh_reveal (
- void *cls,
- uint64_t melt_serial_id,
- uint32_t num_rrcs,
- const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs,
- unsigned int num_tprivs,
- const struct TALER_TransferPrivateKeyP *tprivs,
- const struct TALER_TransferPublicKeyP *tp);
-
-#endif
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -83,7 +83,6 @@
#include "pg_get_global_fees.h"
#include "pg_get_known_coin.h"
#include "pg_get_kyc_rules.h"
-#include "pg_get_melt.h"
#include "pg_get_old_coin_by_h_blind.h"
#include "pg_get_pending_kyc_requirement_process.h"
#include "pg_get_policy_details.h"
@@ -122,7 +121,6 @@
#include "pg_insert_partner.h"
#include "pg_insert_purse_request.h"
#include "pg_insert_records_by_table.h"
-#include "pg_insert_refresh_reveal.h"
#include "pg_insert_refund.h"
#include "pg_insert_reserve_closed.h"
#include "pg_insert_reserve_open_deposit.h"
@@ -566,8 +564,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_add_policy_fulfillment_proof;
plugin->do_refresh
= &TEH_PG_do_refresh;
- plugin->do_melt
- = &TEH_PG_do_melt;
plugin->do_refund
= &TEH_PG_do_refund;
plugin->do_recoup
@@ -606,14 +602,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_select_refunds_by_coin;
plugin->select_aml_measures
= &TEH_PG_select_aml_measures;
- plugin->get_melt
- = &TEH_PG_get_melt;
- plugin->insert_refresh_reveal
- = &TEH_PG_insert_refresh_reveal;
plugin->get_refresh
= &TEH_PG_get_refresh;
- plugin->get_refresh_reveal
- = &TEH_PG_get_refresh_reveal;
plugin->lookup_wire_transfer
= &TEH_PG_lookup_wire_transfer;
plugin->lookup_transfer_by_deposit
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
@@ -1598,79 +1598,13 @@ void
TALER_EXCHANGE_refund_cancel (struct TALER_EXCHANGE_RefundHandle *refund);
-/* ********************* POST /csr-melt *********************** */
-
-
-/**
- * @brief A /csr-melt Handle
- */
-struct TALER_EXCHANGE_CsRMeltHandle;
-
-
/**
- * Details about a response for a CS R request.
- */
-struct TALER_EXCHANGE_CsRMeltResponse
-{
- /**
- * HTTP response data.
- */
- struct TALER_EXCHANGE_HttpResponse hr;
-
- /**
- * Details about the response.
- */
- union
- {
- /**
- * Details if the status is #MHD_HTTP_OK.
- */
- struct
- {
- /**
- * Length of the @e blinding_values array.
- */
- unsigned int blinding_values_len;
-
- /**
- * Values contributed by the exchange for the
- * respective coin's withdraw operation.
- */
- const struct TALER_ExchangeBlindingValues *blinding_values;
- } ok;
-
- /**
- * Details if the status is #MHD_HTTP_GONE.
- */
- struct
- {
- /* FIXME: returning full details is not implemented */
- } gone;
-
- } details;
-};
-
-
-/**
- * Callbacks of this type are used to serve the result of submitting a
- * CS R request to a exchange.
- *
- * @param cls closure
- * @param csrr response details
- */
-typedef void
-(*TALER_EXCHANGE_CsRMeltCallback) (
- void *cls,
- const struct TALER_EXCHANGE_CsRMeltResponse *csrr);
-
-
-/**
- * Information we pass per coin to a /csr-melt request.
+ * Information we pass per coin to a /blinding-prepare request.
*/
struct TALER_EXCHANGE_NonceKey
{
/**
- * Which denomination key is the /csr-melt request for?
+ * Which denomination key is the /blinding-prepare request for?
*/
const struct TALER_EXCHANGE_DenomPublicKey *pk;
@@ -1682,42 +1616,6 @@ struct TALER_EXCHANGE_NonceKey
};
-/**
- * Get a set of CS R values using a /csr-melt request.
- *
- * @param ctx curl context
- * @param url exchange base URL
- * @param rms master key used for the derivation of the CS values
- * @param nks_len length of the @a nks array
- * @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_cls closure for the above callback
- * @return handle for the operation on success, NULL on error, i.e.
- * if the inputs are invalid (i.e. denomination key not with this exchange).
- * In this case, the callback is not called.
- */
-struct TALER_EXCHANGE_CsRMeltHandle *
-TALER_EXCHANGE_csr_melt (
- struct GNUNET_CURL_Context *ctx,
- const char *url,
- const struct TALER_RefreshMasterSecretP *rms,
- unsigned int nks_len,
- struct TALER_EXCHANGE_NonceKey nks[static nks_len],
- TALER_EXCHANGE_CsRMeltCallback res_cb,
- void *res_cb_cls);
-
-
-/**
- *
- * Cancel a CS R melt request. This function cannot be used
- * on a request handle if a response is already served for it.
- *
- * @param csrh the withdraw handle
- */
-void
-TALER_EXCHANGE_csr_melt_cancel (struct TALER_EXCHANGE_CsRMeltHandle *csrh);
-
-
/* ********************* GET /coins/$COIN_PUB *********************** */
/**
@@ -3426,6 +3324,41 @@ TALER_EXCHANGE_reveal_withdraw_cancel (
/* ********************* /reveal-melt ************************ */
+
+/**
+ * Information about a coin obtained via /reveal-melt.
+ */
+struct TALER_EXCHANGE_RevealedCoinInfo
+{
+ /**
+ * Private key of the coin.
+ */
+ struct TALER_CoinSpendPrivateKeyP coin_priv;
+
+ /**
+ * Master secret of this coin.
+ */
+ struct TALER_PlanchetMasterSecretP ps;
+
+ /**
+ * Age commitment and its hash of the coin, might be NULL.
+ */
+ struct TALER_AgeCommitmentProof *age_commitment_proof;
+ struct TALER_AgeCommitmentHash h_age_commitment;
+
+ /**
+ * Blinding keys used to blind the fresh coin.
+ */
+ union GNUNET_CRYPTO_BlindingSecretP bks;
+
+ /**
+ * Signature affirming the validity of the coin.
+ */
+ struct TALER_DenominationSignature sig;
+
+};
+
+
/**
* @brief A handle to a /reveal-melt request
*/
@@ -3624,187 +3557,6 @@ TALER_EXCHANGE_reveal_melt_cancel (
struct TALER_EXCHANGE_RevealMeltHandle *awrh);
-/* ********************* /refresh/melt+reveal ***************************** */
-
-
-/**
- * Information needed to melt (partially spent) coins to obtain fresh coins
- * 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.
- */
-struct TALER_EXCHANGE_RefreshData
-{
- /**
- * private key of the coin to melt
- */
- struct TALER_CoinSpendPrivateKeyP melt_priv;
-
- /**
- * age commitment and proof that went into the original coin,
- * might be NULL.
- */
- const struct TALER_AgeCommitmentProof *melt_age_commitment_proof;
-
- /**
- * Hash of age commitment and proof that went into the original coin,
- * might be NULL.
- */
- const struct TALER_AgeCommitmentHash *melt_h_age_commitment;
-
- /**
- * 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 ***************************** */
-
-/**
- * @brief A /coins/$COIN_PUB/melt Handle
- */
-struct TALER_EXCHANGE_MeltHandle;
-
-
-/**
- * Information we obtain per coin during melting.
- */
-struct TALER_EXCHANGE_MeltBlindingDetail
-{
- /**
- * Exchange values contributed to the refresh operation
- */
- struct TALER_ExchangeBlindingValues alg_value;
-
-};
-
-
-/**
- * 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_OK.
- */
- struct
- {
-
- /**
- * Information returned per coin.
- */
- const struct TALER_EXCHANGE_MeltBlindingDetail *mbds;
-
- /**
- * Key used by the exchange to sign the response.
- */
- struct TALER_ExchangePublicKeyP sign_key;
-
- /**
- * Length of the @a mbds array with the exchange values
- * and blinding keys we are using.
- */
- unsigned int num_mbds;
-
- /**
- * Gamma value chosen by the exchange.
- */
- uint32_t noreveal_index;
- } ok;
-
- } 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
- * should be committed to disk prior to proceeding
- * #TALER_EXCHANGE_refreshes_reveal().
- *
- * @param cls closure
- * @param mr response details
- */
-typedef void
-(*TALER_EXCHANGE_MeltCallback) (
- void *cls,
- const struct TALER_EXCHANGE_MeltResponse *mr);
-
-
-/**
- * Submit a melt request to the exchange and get the exchange's
- * response.
- *
- * This API is typically used by a wallet. Note that to ensure that
- * no money is lost in case of hardware failures, the provided
- * argument @a rd should be committed to persistent storage
- * prior to calling this function.
- *
- * @param ctx curl context
- * @param url exchange base URL
- * @param keys exchange keys
- * @param rms the fresh secret that defines the refresh operation
- * @param rd the refresh data specifying the characteristics of the operation
- * @param melt_cb the callback to call with the result
- * @param melt_cb_cls closure for @a melt_cb
- * @return a handle for this request; NULL if the argument was invalid.
- * In this case, neither callback will be called.
- */
-struct TALER_EXCHANGE_MeltHandle *
-TALER_EXCHANGE_melt (
- struct GNUNET_CURL_Context *ctx,
- const char *url,
- struct TALER_EXCHANGE_Keys *keys,
- const struct TALER_RefreshMasterSecretP *rms,
- const struct TALER_EXCHANGE_RefreshData *rd,
- TALER_EXCHANGE_MeltCallback melt_cb,
- void *melt_cb_cls);
-
-
-/**
- * Cancel a melt request. This function cannot be used
- * on a request handle if the callback was already invoked.
- *
- * @param mh the melt handle
- */
-void
-TALER_EXCHANGE_melt_cancel (struct TALER_EXCHANGE_MeltHandle *mh);
-
/* ********************* /melt (starting with v27) **************************** */
/**
@@ -3919,151 +3671,6 @@ void
TALER_EXCHANGE_melt_v27_cancel (struct TALER_EXCHANGE_MeltHandle_v27 *mh);
-/* ********************* /refreshes/$RCH/reveal ***************************** */
-
-
-/**
- * Information about a coin obtained via /refreshes/$RCH/reveal.
- */
-struct TALER_EXCHANGE_RevealedCoinInfo
-{
- /**
- * Private key of the coin.
- */
- struct TALER_CoinSpendPrivateKeyP coin_priv;
-
- /**
- * Master secret of this coin.
- */
- struct TALER_PlanchetMasterSecretP ps;
-
- /**
- * Age commitment and its hash of the coin, might be NULL.
- */
- struct TALER_AgeCommitmentProof *age_commitment_proof;
- struct TALER_AgeCommitmentHash h_age_commitment;
-
- /**
- * Blinding keys used to blind the fresh coin.
- */
- union GNUNET_CRYPTO_BlindingSecretP bks;
-
- /**
- * Signature affirming the validity of the coin.
- */
- struct TALER_DenominationSignature sig;
-
-};
-
-
-/**
- * Result of a /refreshes/$RCH/reveal request.
- */
-struct TALER_EXCHANGE_RevealResult
-{
- /**
- * HTTP status.
- */
- struct TALER_EXCHANGE_HttpResponse hr;
-
- /**
- * Parsed response details, variant depending on the
- * @e hr.http_status.
- */
- union
- {
- /**
- * Results for status #MHD_HTTP_OK.
- */
- struct
- {
- /**
- * 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;
-
- /**
- * Number of coins returned.
- */
- unsigned int num_coins;
- } ok;
-
- } details;
-
-};
-
-
-/**
- * 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.
- *
- * @param cls closure
- * @param rr result of the reveal operation
- */
-typedef void
-(*TALER_EXCHANGE_RefreshesRevealCallback)(
- void *cls,
- const struct TALER_EXCHANGE_RevealResult *rr);
-
-
-/**
- * @brief A /refreshes/$RCH/reveal Handle
- */
-struct TALER_EXCHANGE_RefreshesRevealHandle;
-
-
-/**
- * Submit a /refreshes/$RCH/reval request to the exchange and get the exchange's
- * response.
- *
- * This API is typically used by a wallet. Note that to ensure that
- * no money is lost in case of hardware failures, the provided
- * arguments should have been committed to persistent storage
- * prior to calling this function.
- *
- * @param ctx curl context
- * @param url exchange base URL
- * @param rms the fresh secret that defines the refresh operation
- * @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 blinding_values array @a num_coins of exchange values contributed to the refresh operation
- * @param noreveal_index response from the exchange to the
- * #TALER_EXCHANGE_melt() invocation
- * @param reveal_cb the callback to call with the final result of the
- * refresh operation
- * @param reveal_cb_cls closure for the above callback
- * @return a handle for this request; NULL if the argument was invalid.
- * In this case, neither callback will be called.
- */
-struct TALER_EXCHANGE_RefreshesRevealHandle *
-TALER_EXCHANGE_refreshes_reveal (
- struct GNUNET_CURL_Context *ctx,
- const char *url,
- const struct TALER_RefreshMasterSecretP *rms,
- const struct TALER_EXCHANGE_RefreshData *rd,
- unsigned int num_coins,
- const struct TALER_ExchangeBlindingValues blinding_values[static num_coins],
- uint32_t noreveal_index,
- TALER_EXCHANGE_RefreshesRevealCallback reveal_cb,
- void *reveal_cb_cls);
-
-
-/**
- * Cancel a refresh reveal request. This function cannot be used
- * on a request handle if the callback was already invoked.
- *
- * @param rrh the refresh reval handle
- */
-void
-TALER_EXCHANGE_refreshes_reveal_cancel (
- struct TALER_EXCHANGE_RefreshesRevealHandle *rrh);
-
-
/* ********************* /transfers/$WTID *********************** */
/**
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
@@ -2650,7 +2650,7 @@ struct TALER_EXCHANGEDB_Refresh_v27
/**
* [out]-Array of @a num_coins hashes of the public keys of the denominations
* identified by @e denom_serials. This field is set when calling
- * get_melt_v27
+ * get_refresh
*/
struct TALER_DenominationHashP *denom_pub_hashes;
};
@@ -3151,7 +3151,7 @@ struct TALER_EXCHANGEDB_RefreshRevealedCoin
/**
* Values contributed from the exchange to the
- * coin generation (see /csr).
+ * coin generation (see /blinding-prepare).
*/
struct TALER_ExchangeBlindingValues exchange_vals;
@@ -4567,30 +4567,6 @@ struct TALER_EXCHANGEDB_Plugin
struct GNUNET_TIME_Timestamp *exchange_timestamp,
bool *is_idempotent);
-
- /**
- * Perform melt operation, checking for sufficient balance
- * of the coin and possibly persisting the melt details.
- *
- * @param cls the plugin-specific state
- * @param rms client-contributed input for CS denominations that must be checked for idempotency, or NULL for non-CS withdrawals
- * @param[in,out] refresh refresh operation details; the noreveal_index
- * is set in case the coin was already melted before
- * @param known_coin_id row of the coin in the known_coins table
- * @param[in,out] zombie_required true if the melt must only succeed if the coin is a zombie, set to false if the requirement was satisfied
- * @param[out] balance_ok set to true if the balance was sufficient
- * @return query execution status
- */
- enum GNUNET_DB_QueryStatus
- (*do_melt)(
- void *cls,
- const struct TALER_RefreshMasterSecretP *rms,
- struct TALER_EXCHANGEDB_Refresh *refresh,
- uint64_t known_coin_id,
- bool *zombie_required,
- bool *balance_ok);
-
-
/**
* Perform refresh operation--introduced with v27 of the API--,
* checking for sufficient balance of the coin and possibly persisting the melt/refresh details.
@@ -4652,28 +4628,6 @@ struct TALER_EXCHANGEDB_Plugin
/**
- * Check if the given @a nonce was properly locked to the given @a old_coin_pub. If so, check if we already
- * created CS signatures for the given @a nonce and @a new_denom_pub_hashes,
- * and if so, return them in @a s_scalars. Otherwise, persist the
- * signatures from @a s_scalars in the database.
- *
- * @param cls the plugin-specific state
- * @param nonce the client-provided nonce where we must prevent reuse
- * @param old_coin_pub public key the nonce was locked to
- * @param num_fresh_coins array length, number of fresh coins revealed
- * @param[in,out] crfcds array of data about the fresh coins, of length @a num_fresh_coins
- * @return query execution status
- */
- enum GNUNET_DB_QueryStatus
- (*cs_refreshes_reveal)(
- void *cls,
- const struct GNUNET_CRYPTO_CsSessionNonce *nonce,
- const struct TALER_CoinSpendPublicKeyP *old_coin_pub,
- unsigned int num_fresh_coins,
- struct TALER_EXCHANGEDB_CsRevealFreshCoinData *crfcds);
-
-
- /**
* Perform refund operation, checking for sufficient deposits
* of the coin and possibly persisting the refund details.
*
@@ -5175,66 +5129,6 @@ struct TALER_EXCHANGEDB_Plugin
const struct TALER_FullPaytoHashP *h_payto,
const struct TALER_WireTransferIdentifierRawP *wtid);
-
- /**
- * Lookup melt commitment data under the given @a rc.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param rc commitment to use for the lookup
- * @param[out] melt where to store the result; note that
- * melt->session.coin.denom_sig will be set to NULL
- * and is not fetched by this routine (as it is not needed by the client)
- * @param[out] melt_serial_id set to the row ID of @a rc in the refresh_commitments table
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*get_melt)(void *cls,
- const struct TALER_RefreshCommitmentP *rc,
- struct TALER_EXCHANGEDB_Melt *melt,
- uint64_t *melt_serial_id);
-
-
- /**
- * Store in the database which coin(s) the wallet wanted to create
- * in a given refresh operation and all of the other information
- * we learned or created in the reveal step.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param melt_serial_id row ID of the commitment / melt operation in refresh_commitments
- * @param num_rrcs number of coins to generate, size of the @a rrcs array
- * @param rrcs information about the new coins
- * @param num_tprivs number of entries in @a tprivs, should be #TALER_CNC_KAPPA - 1
- * @param tprivs transfer private keys to store
- * @param tp public key to store
- * @return query status for the transaction
- */
- enum GNUNET_DB_QueryStatus
- (*insert_refresh_reveal)(
- void *cls,
- uint64_t melt_serial_id,
- uint32_t num_rrcs,
- const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs,
- unsigned int num_tprivs,
- const struct TALER_TransferPrivateKeyP *tprivs,
- const struct TALER_TransferPublicKeyP *tp);
-
-
- /**
- * Lookup in the database for the fresh coins that we
- * created in the given refresh operation.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param rc identify commitment and thus refresh operation
- * @param cb function to call with the results
- * @param cb_cls closure for @a cb
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*get_refresh_reveal)(void *cls,
- const struct TALER_RefreshCommitmentP *rc,
- TALER_EXCHANGEDB_RefreshCallback cb,
- void *cb_cls);
-
/**
* Compile a list of (historic) transactions performed with the given coin
* (melt, refund, recoup and deposit operations). Should return 0 if the @a
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
@@ -28,7 +28,6 @@ libtalerexchange_la_SOURCES = \
exchange_api_coins_history.c \
exchange_api_common.c exchange_api_common.h \
exchange_api_contracts_get.c \
- exchange_api_csr_melt.c \
exchange_api_curl_defaults.c exchange_api_curl_defaults.h \
exchange_api_deposits_get.c \
exchange_api_get_aml_measures.c \
@@ -55,7 +54,6 @@ libtalerexchange_la_SOURCES = \
exchange_api_management_update_aml_officer.c \
exchange_api_management_wire_disable.c \
exchange_api_management_wire_enable.c \
- exchange_api_melt.c \
exchange_api_melt_v27.c \
exchange_api_purse_create_with_deposit.c \
exchange_api_purse_create_with_merge.c \
@@ -66,7 +64,6 @@ libtalerexchange_la_SOURCES = \
exchange_api_recoup.c \
exchange_api_recoup_refresh.c \
exchange_api_refresh_common.c exchange_api_refresh_common.h \
- exchange_api_refreshes_reveal.c \
exchange_api_refund.c \
exchange_api_reserves_attest.c \
exchange_api_reserves_close.c \
diff --git a/src/lib/exchange_api_csr_melt.c b/src/lib/exchange_api_csr_melt.c
@@ -1,320 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2022 Taler Systems SA
-
- 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
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file lib/exchange_api_csr_melt.c
- * @brief Implementation of /csr-melt requests (get R in exchange used for Clause Schnorr refresh)
- * @author Lucien Heuzeveldt
- * @author Gian Demarmels
- */
-#include "platform.h"
-#include <jansson.h>
-#include <microhttpd.h> /* just for HTTP status codes */
-#include <gnunet/gnunet_util_lib.h>
-#include <gnunet/gnunet_json_lib.h>
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_exchange_service.h"
-#include "taler_json_lib.h"
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "exchange_api_curl_defaults.h"
-
-
-/**
- * @brief A Clause Schnorr R Handle
- */
-struct TALER_EXCHANGE_CsRMeltHandle
-{
-
- /**
- * Function to call with the result.
- */
- TALER_EXCHANGE_CsRMeltCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * Handle for the request.
- */
- struct GNUNET_CURL_Job *job;
-
- /**
- * Context for #TEH_curl_easy_post(). Keeps the data that must
- * persist for Curl to make the upload.
- */
- struct TALER_CURL_PostContext post_ctx;
-};
-
-
-/**
- * We got a 200 OK response for the /reserves/$RESERVE_PUB/withdraw operation.
- * Extract the coin's signature and return it to the caller. The signature we
- * get from the exchange is for the blinded value. Thus, we first must
- * unblind it and then should verify its validity against our coin's hash.
- *
- * If everything checks out, we return the unblinded signature
- * to the application via the callback.
- *
- * @param csrh operation handle
- * @param arr reply from the exchange
- * @param hr http response details
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
- */
-static enum GNUNET_GenericReturnValue
-csr_ok (struct TALER_EXCHANGE_CsRMeltHandle *csrh,
- const json_t *arr,
- struct TALER_EXCHANGE_HttpResponse *hr)
-{
- size_t alen = json_array_size (arr);
- struct TALER_ExchangeBlindingValues blinding_values[GNUNET_NZL (alen)];
- struct TALER_EXCHANGE_CsRMeltResponse csrr = {
- .hr = *hr,
- .details.ok.blinding_values_len = alen,
- .details.ok.blinding_values = blinding_values
- };
-
- for (size_t i = 0; i<alen; i++)
- {
- json_t *av = json_array_get (arr,
- i);
- struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_exchange_blinding_values (
- "ewv",
- &blinding_values[i]),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (av,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- }
- csrh->cb (csrh->cb_cls,
- &csrr);
- for (size_t i = 0; i<alen; i++)
- TALER_denom_ewv_free (&blinding_values[i]);
- return GNUNET_OK;
-}
-
-
-/**
- * Function called when we're done processing the HTTP /csr request.
- *
- * @param cls the `struct TALER_EXCHANGE_CsRMeltHandle`
- * @param response_code HTTP response code, 0 on error
- * @param response parsed JSON result, NULL on error
- */
-static void
-handle_csr_finished (void *cls,
- long response_code,
- const void *response)
-{
- struct TALER_EXCHANGE_CsRMeltHandle *csrh = cls;
- const json_t *j = response;
- struct TALER_EXCHANGE_HttpResponse hr = {
- .reply = j,
- .http_status = (unsigned int) response_code
- };
- struct TALER_EXCHANGE_CsRMeltResponse csrr = {
- .hr = hr
- };
-
- csrh->job = NULL;
- switch (response_code)
- {
- case 0:
- csrr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- case MHD_HTTP_OK:
- {
- json_t *arr;
-
- arr = json_object_get (j,
- "ewvs");
- if ( (NULL == arr) ||
- (0 == json_array_size (arr)) ||
- (GNUNET_OK !=
- csr_ok (csrh,
- arr,
- &hr)) )
- {
- GNUNET_break_op (0);
- csrr.hr.http_status = 0;
- csrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- break;
- }
- }
- TALER_EXCHANGE_csr_melt_cancel (csrh);
- 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 */
- csrr.hr.ec = TALER_JSON_get_error_code (j);
- csrr.hr.hint = TALER_JSON_get_error_hint (j);
- break;
- case MHD_HTTP_NOT_FOUND:
- /* Nothing really to verify, the exchange basically just says
- that it doesn't know the /csr endpoint or denomination.
- Can happen if the exchange doesn't support Clause Schnorr.
- We should simply pass the JSON reply to the application. */
- csrr.hr.ec = TALER_JSON_get_error_code (j);
- csrr.hr.hint = TALER_JSON_get_error_hint (j);
- break;
- case MHD_HTTP_GONE:
- /* could happen if denomination was revoked */
- /* Note: one might want to check /keys for revocation
- signature here, alas tricky in case our /keys
- is outdated => left to clients */
- csrr.hr.ec = TALER_JSON_get_error_code (j);
- csrr.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 */
- csrr.hr.ec = TALER_JSON_get_error_code (j);
- csrr.hr.hint = TALER_JSON_get_error_hint (j);
- break;
- default:
- /* unexpected response code */
- GNUNET_break_op (0);
- csrr.hr.ec = TALER_JSON_get_error_code (j);
- csrr.hr.hint = TALER_JSON_get_error_hint (j);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d for CS R request\n",
- (unsigned int) response_code,
- (int) hr.ec);
- break;
- }
- csrh->cb (csrh->cb_cls,
- &csrr);
- csrh->cb = NULL;
- TALER_EXCHANGE_csr_melt_cancel (csrh);
-}
-
-
-struct TALER_EXCHANGE_CsRMeltHandle *
-TALER_EXCHANGE_csr_melt (
- struct GNUNET_CURL_Context *ctx,
- const char *url,
- const struct TALER_RefreshMasterSecretP *rms,
- unsigned int nks_len,
- struct TALER_EXCHANGE_NonceKey nks[static nks_len],
- TALER_EXCHANGE_CsRMeltCallback res_cb,
- void *res_cb_cls)
-{
- struct TALER_EXCHANGE_CsRMeltHandle *csrh;
- json_t *csr_arr;
-
- if (0 == nks_len)
- {
- GNUNET_break (0);
- return NULL;
- }
- for (unsigned int i = 0; i<nks_len; i++)
- if (GNUNET_CRYPTO_BSA_CS !=
- nks[i].pk->key.bsign_pub_key->cipher)
- {
- GNUNET_break (0);
- return NULL;
- }
- csrh = GNUNET_new (struct TALER_EXCHANGE_CsRMeltHandle);
- csrh->cb = res_cb;
- csrh->cb_cls = res_cb_cls;
- csr_arr = json_array ();
- GNUNET_assert (NULL != csr_arr);
- for (unsigned int i = 0; i<nks_len; i++)
- {
- const struct TALER_EXCHANGE_NonceKey *nk = &nks[i];
- json_t *csr_obj;
-
- csr_obj = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_uint64 ("coin_offset",
- nk->cnc_num),
- GNUNET_JSON_pack_data_auto ("denom_pub_hash",
- &nk->pk->h_key));
- GNUNET_assert (NULL != csr_obj);
- GNUNET_assert (0 ==
- json_array_append_new (csr_arr,
- csr_obj));
- }
- csrh->url = TALER_url_join (url,
- "csr-melt",
- NULL);
- if (NULL == csrh->url)
- {
- json_decref (csr_arr);
- GNUNET_free (csrh);
- return NULL;
- }
- {
- CURL *eh;
- json_t *req;
-
- req = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_data_auto ("rms",
- rms),
- GNUNET_JSON_pack_array_steal ("nks",
- csr_arr));
- eh = TALER_EXCHANGE_curl_easy_get_ (csrh->url);
- if ( (NULL == eh) ||
- (GNUNET_OK !=
- TALER_curl_easy_post (&csrh->post_ctx,
- eh,
- req)) )
- {
- GNUNET_break (0);
- if (NULL != eh)
- curl_easy_cleanup (eh);
- json_decref (req);
- GNUNET_free (csrh->url);
- GNUNET_free (csrh);
- return NULL;
- }
- json_decref (req);
- csrh->job = GNUNET_CURL_job_add2 (ctx,
- eh,
- csrh->post_ctx.headers,
- &handle_csr_finished,
- csrh);
- }
- return csrh;
-}
-
-
-void
-TALER_EXCHANGE_csr_melt_cancel (struct TALER_EXCHANGE_CsRMeltHandle *csrh)
-{
- if (NULL != csrh->job)
- {
- GNUNET_CURL_job_cancel (csrh->job);
- csrh->job = NULL;
- }
- GNUNET_free (csrh->url);
- TALER_curl_easy_post_finished (&csrh->post_ctx);
- GNUNET_free (csrh);
-}
diff --git a/src/lib/exchange_api_melt.c b/src/lib/exchange_api_melt.c
@@ -1,602 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2015-2023 Taler Systems SA
-
- 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
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file lib/exchange_api_melt.c
- * @brief Implementation of the /coins/$COIN_PUB/melt request
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <jansson.h>
-#include <microhttpd.h> /* just for HTTP status codes */
-#include <gnunet/gnunet_util_lib.h>
-#include <gnunet/gnunet_json_lib.h>
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_json_lib.h"
-#include "taler_exchange_service.h"
-#include "exchange_api_common.h"
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "exchange_api_curl_defaults.h"
-#include "exchange_api_refresh_common.h"
-
-
-/**
- * @brief A /coins/$COIN_PUB/melt Handle
- */
-struct TALER_EXCHANGE_MeltHandle
-{
-
- /**
- * The keys of the this request handle will use
- */
- struct TALER_EXCHANGE_Keys *keys;
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * The exchange base url.
- */
- char *exchange_url;
-
- /**
- * Curl context.
- */
- struct GNUNET_CURL_Context *cctx;
-
- /**
- * Context for #TEH_curl_easy_post(). Keeps the data that must
- * persist for Curl to make the upload.
- */
- struct TALER_CURL_PostContext ctx;
-
- /**
- * Handle for the request.
- */
- struct GNUNET_CURL_Job *job;
-
- /**
- * Function to call with refresh melt failure results.
- */
- TALER_EXCHANGE_MeltCallback melt_cb;
-
- /**
- * Closure for @e result_cb and @e melt_failure_cb.
- */
- void *melt_cb_cls;
-
- /**
- * Actual information about the melt operation.
- */
- struct MeltData md;
-
- /**
- * The secret the entire melt operation is seeded from.
- */
- struct TALER_RefreshMasterSecretP rms;
-
- /**
- * Details about the characteristics of the requested melt operation.
- */
- const struct TALER_EXCHANGE_RefreshData *rd;
-
- /**
- * Array of `num_fresh_coins` per-coin values
- * returned from melt operation.
- */
- struct TALER_EXCHANGE_MeltBlindingDetail *mbds;
-
- /**
- * Handle for the preflight request, or NULL.
- */
- struct TALER_EXCHANGE_CsRMeltHandle *csr;
-
- /**
- * Public key of the coin being melted.
- */
- struct TALER_CoinSpendPublicKeyP coin_pub;
-
- /**
- * Signature affirming the melt.
- */
- struct TALER_CoinSpendSignatureP coin_sig;
-
- /**
- * @brief Public information about the coin's denomination key
- */
- const struct TALER_EXCHANGE_DenomPublicKey *dki;
-
- /**
- * Gamma value chosen by the exchange during melt.
- */
- uint32_t noreveal_index;
-
- /**
- * True if we need to include @e rms in our melt request.
- */
- bool send_rms;
-};
-
-
-/**
- * Verify that the signature on the "200 OK" response
- * from the exchange is valid.
- *
- * @param[in,out] mh melt handle
- * @param json json reply with the signature
- * @param[out] exchange_pub public key of the exchange used for the signature
- * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
- */
-static enum GNUNET_GenericReturnValue
-verify_melt_signature_ok (struct TALER_EXCHANGE_MeltHandle *mh,
- const json_t *json,
- struct TALER_ExchangePublicKeyP *exchange_pub)
-{
- struct TALER_ExchangeSignatureP exchange_sig;
- const struct TALER_EXCHANGE_Keys *key_state;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("exchange_sig",
- &exchange_sig),
- GNUNET_JSON_spec_fixed_auto ("exchange_pub",
- exchange_pub),
- GNUNET_JSON_spec_uint32 ("noreveal_index",
- &mh->noreveal_index),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- /* check that exchange signing key is permitted */
- key_state = mh->keys;
- if (GNUNET_OK !=
- TALER_EXCHANGE_test_signing_key (key_state,
- exchange_pub))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- /* check that noreveal index is in permitted range */
- if (TALER_CNC_KAPPA <= mh->noreveal_index)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- TALER_exchange_online_melt_confirmation_verify (
- &mh->md.rc,
- mh->noreveal_index,
- exchange_pub,
- &exchange_sig))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Function called when we're done processing the
- * HTTP /coins/$COIN_PUB/melt request.
- *
- * @param cls the `struct TALER_EXCHANGE_MeltHandle`
- * @param response_code HTTP response code, 0 on error
- * @param response parsed JSON result, NULL on error
- */
-static void
-handle_melt_finished (void *cls,
- long response_code,
- const void *response)
-{
- struct TALER_EXCHANGE_MeltHandle *mh = cls;
- const json_t *j = response;
- struct TALER_EXCHANGE_MeltResponse mr = {
- .hr.reply = j,
- .hr.http_status = (unsigned int) response_code
- };
-
- mh->job = NULL;
- switch (response_code)
- {
- case 0:
- mr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- case MHD_HTTP_OK:
- if (GNUNET_OK !=
- verify_melt_signature_ok (mh,
- j,
- &mr.details.ok.sign_key))
- {
- GNUNET_break_op (0);
- mr.hr.http_status = 0;
- mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE;
- break;
- }
- mr.details.ok.noreveal_index = mh->noreveal_index;
- mr.details.ok.num_mbds = mh->rd->fresh_pks_len;
- mr.details.ok.mbds = mh->mbds;
- mh->melt_cb (mh->melt_cb_cls,
- &mr);
- mh->melt_cb = NULL;
- break;
- 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 */
- mr.hr.ec = TALER_JSON_get_error_code (j);
- mr.hr.hint = TALER_JSON_get_error_hint (j);
- break;
- case MHD_HTTP_CONFLICT:
- mr.hr.ec = TALER_JSON_get_error_code (j);
- mr.hr.hint = TALER_JSON_get_error_hint (j);
- break;
- case MHD_HTTP_FORBIDDEN:
- /* Nothing really to verify, exchange says one of the signatures is
- invalid; assuming we checked them, this should never happen, we
- should pass the JSON reply to the application */
- mr.hr.ec = TALER_JSON_get_error_code (j);
- mr.hr.hint = TALER_JSON_get_error_hint (j);
- break;
- case MHD_HTTP_NOT_FOUND:
- /* Nothing really to verify, this should never
- happen, we should pass the JSON reply to the application */
- mr.hr.ec = TALER_JSON_get_error_code (j);
- mr.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 */
- mr.hr.ec = TALER_JSON_get_error_code (j);
- mr.hr.hint = TALER_JSON_get_error_hint (j);
- break;
- default:
- /* unexpected response code */
- mr.hr.ec = TALER_JSON_get_error_code (j);
- mr.hr.hint = TALER_JSON_get_error_hint (j);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d for exchange melt\n",
- (unsigned int) response_code,
- mr.hr.ec);
- GNUNET_break_op (0);
- break;
- }
- if (NULL != mh->melt_cb)
- mh->melt_cb (mh->melt_cb_cls,
- &mr);
- TALER_EXCHANGE_melt_cancel (mh);
-}
-
-
-/**
- * Start the actual melt operation, now that we have
- * the exchange's input values.
- *
- * @param[in,out] mh melt operation to run
- * @return #GNUNET_OK if we could start the operation
- */
-static enum GNUNET_GenericReturnValue
-start_melt (struct TALER_EXCHANGE_MeltHandle *mh)
-{
- const struct TALER_EXCHANGE_Keys *key_state;
- json_t *melt_obj;
- CURL *eh;
- char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32];
- struct TALER_DenominationHashP h_denom_pub;
- struct TALER_ExchangeBlindingValues blinding_values[mh->rd->fresh_pks_len];
-
- for (unsigned int i = 0; i<mh->rd->fresh_pks_len; i++)
- {
- if (GNUNET_CRYPTO_BSA_RSA ==
- mh->rd->fresh_pks[i].key.bsign_pub_key->cipher)
- blinding_values[i] = *TALER_denom_ewv_rsa_singleton ();
- else
- blinding_values[i] = mh->mbds[i].alg_value;
- }
- if (GNUNET_OK !=
- TALER_EXCHANGE_get_melt_data_ (&mh->rms,
- mh->rd,
- blinding_values,
- &mh->md))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- TALER_denom_pub_hash (&mh->md.melted_coin.pub_key,
- &h_denom_pub);
- TALER_wallet_melt_sign (
- &mh->md.melted_coin.melt_amount_with_fee,
- &mh->md.melted_coin.fee_melt,
- &mh->md.rc,
- &h_denom_pub,
- mh->md.melted_coin.h_age_commitment,
- &mh->md.melted_coin.coin_priv,
- &mh->coin_sig);
- GNUNET_CRYPTO_eddsa_key_get_public (&mh->md.melted_coin.coin_priv.eddsa_priv,
- &mh->coin_pub.eddsa_pub);
- melt_obj = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_data_auto ("denom_pub_hash",
- &h_denom_pub),
- TALER_JSON_pack_denom_sig ("denom_sig",
- &mh->md.melted_coin.sig),
- GNUNET_JSON_pack_data_auto ("confirm_sig",
- &mh->coin_sig),
- TALER_JSON_pack_amount ("value_with_fee",
- &mh->md.melted_coin.melt_amount_with_fee),
- GNUNET_JSON_pack_data_auto ("rc",
- &mh->md.rc),
- GNUNET_JSON_pack_allow_null (
- (NULL != mh->md.melted_coin.h_age_commitment)
- ? GNUNET_JSON_pack_data_auto ("age_commitment_hash",
- mh->md.melted_coin.h_age_commitment)
- : GNUNET_JSON_pack_string ("age_commitment_hash",
- NULL)),
- GNUNET_JSON_pack_allow_null (
- mh->send_rms
- ? GNUNET_JSON_pack_data_auto ("rms",
- &mh->rms)
- : GNUNET_JSON_pack_string ("rms",
- NULL)));
- {
- char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2];
- char *end;
-
- end = GNUNET_STRINGS_data_to_string (
- &mh->coin_pub,
- sizeof (struct TALER_CoinSpendPublicKeyP),
- pub_str,
- sizeof (pub_str));
- *end = '\0';
- GNUNET_snprintf (arg_str,
- sizeof (arg_str),
- "coins/%s/melt",
- pub_str);
- }
-
- key_state = mh->keys;
- mh->dki = TALER_EXCHANGE_get_denomination_key (key_state,
- &mh->md.melted_coin.pub_key);
-
- /* and now we can at last begin the actual request handling */
-
- mh->url = TALER_url_join (mh->exchange_url,
- arg_str,
- NULL);
- if (NULL == mh->url)
- {
- json_decref (melt_obj);
- return GNUNET_SYSERR;
- }
- eh = TALER_EXCHANGE_curl_easy_get_ (mh->url);
- if ( (NULL == eh) ||
- (GNUNET_OK !=
- TALER_curl_easy_post (&mh->ctx,
- eh,
- melt_obj)) )
- {
- GNUNET_break (0);
- if (NULL != eh)
- curl_easy_cleanup (eh);
- json_decref (melt_obj);
- return GNUNET_SYSERR;
- }
- json_decref (melt_obj);
- mh->job = GNUNET_CURL_job_add2 (mh->cctx,
- eh,
- mh->ctx.headers,
- &handle_melt_finished,
- mh);
- return GNUNET_OK;
-}
-
-
-/**
- * The melt request @a mh failed, return an error to
- * the application and cancel the operation.
- *
- * @param[in] mh melt request that failed
- * @param ec error code to fail with
- */
-static void
-fail_mh (struct TALER_EXCHANGE_MeltHandle *mh,
- enum TALER_ErrorCode ec)
-{
- struct TALER_EXCHANGE_MeltResponse mr = {
- .hr.ec = ec
- };
-
- mh->melt_cb (mh->melt_cb_cls,
- &mr);
- 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_CsRMeltResponse *csrr)
-{
- struct TALER_EXCHANGE_MeltHandle *mh = cls;
- unsigned int nks_off = 0;
-
- mh->csr = NULL;
- if (MHD_HTTP_OK != csrr->hr.http_status)
- {
- struct TALER_EXCHANGE_MeltResponse mr = {
- .hr = csrr->hr
- };
-
- mr.hr.hint = "/csr-melt failed";
- mh->melt_cb (mh->melt_cb_cls,
- &mr);
- TALER_EXCHANGE_melt_cancel (mh);
- return;
- }
- for (unsigned int i = 0; i<mh->rd->fresh_pks_len; i++)
- {
- const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk =
- &mh->rd->fresh_pks[i];
- struct TALER_ExchangeBlindingValues *wv = &mh->mbds[i].alg_value;
-
- switch (fresh_pk->key.bsign_pub_key->cipher)
- {
- case GNUNET_CRYPTO_BSA_INVALID:
- GNUNET_break (0);
- fail_mh (mh,
- TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR);
- return;
- case GNUNET_CRYPTO_BSA_RSA:
- break;
- case GNUNET_CRYPTO_BSA_CS:
- TALER_denom_ewv_copy (wv,
- &csrr->details.ok.blinding_values[nks_off]);
- nks_off++;
- break;
- }
- }
- mh->send_rms = true;
- if (GNUNET_OK !=
- start_melt (mh))
- {
- GNUNET_break (0);
- fail_mh (mh,
- TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR);
- return;
- }
-}
-
-
-struct TALER_EXCHANGE_MeltHandle *
-TALER_EXCHANGE_melt (
- struct GNUNET_CURL_Context *ctx,
- const char *url,
- struct TALER_EXCHANGE_Keys *keys,
- const struct TALER_RefreshMasterSecretP *rms,
- const struct TALER_EXCHANGE_RefreshData *rd,
- TALER_EXCHANGE_MeltCallback melt_cb,
- void *melt_cb_cls)
-{
- struct TALER_EXCHANGE_NonceKey nks[GNUNET_NZL (rd->fresh_pks_len)];
- unsigned int nks_off = 0;
- struct TALER_EXCHANGE_MeltHandle *mh;
-
- if (0 == rd->fresh_pks_len)
- {
- GNUNET_break (0);
- return NULL;
- }
- mh = GNUNET_new (struct TALER_EXCHANGE_MeltHandle);
- mh->noreveal_index = TALER_CNC_KAPPA; /* invalid value */
- mh->cctx = ctx;
- mh->exchange_url = GNUNET_strdup (url);
- mh->rd = rd;
- mh->rms = *rms;
- mh->melt_cb = melt_cb;
- mh->melt_cb_cls = melt_cb_cls;
- mh->mbds = GNUNET_new_array (rd->fresh_pks_len,
- struct TALER_EXCHANGE_MeltBlindingDetail);
- for (unsigned int i = 0; i<rd->fresh_pks_len; i++)
- {
- const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk = &rd->fresh_pks[i];
-
- switch (fresh_pk->key.bsign_pub_key->cipher)
- {
- case GNUNET_CRYPTO_BSA_INVALID:
- GNUNET_break (0);
- GNUNET_free (mh->mbds);
- GNUNET_free (mh);
- return NULL;
- case GNUNET_CRYPTO_BSA_RSA:
- TALER_denom_ewv_copy (&mh->mbds[i].alg_value,
- TALER_denom_ewv_rsa_singleton ());
- break;
- case GNUNET_CRYPTO_BSA_CS:
- nks[nks_off].pk = fresh_pk;
- nks[nks_off].cnc_num = nks_off;
- nks_off++;
- break;
- }
- }
- mh->keys = TALER_EXCHANGE_keys_incref (keys);
- if (0 != nks_off)
- {
- mh->csr = TALER_EXCHANGE_csr_melt (ctx,
- url,
- rms,
- nks_off,
- nks,
- &csr_cb,
- mh);
- if (NULL == mh->csr)
- {
- GNUNET_break (0);
- TALER_EXCHANGE_melt_cancel (mh);
- return NULL;
- }
- return mh;
- }
- if (GNUNET_OK !=
- start_melt (mh))
- {
- GNUNET_break (0);
- TALER_EXCHANGE_melt_cancel (mh);
- return NULL;
- }
- return mh;
-}
-
-
-void
-TALER_EXCHANGE_melt_cancel (struct TALER_EXCHANGE_MeltHandle *mh)
-{
- for (unsigned int i = 0; i<mh->rd->fresh_pks_len; i++)
- TALER_denom_ewv_free (&mh->mbds[i].alg_value);
- if (NULL != mh->job)
- {
- GNUNET_CURL_job_cancel (mh->job);
- mh->job = NULL;
- }
- if (NULL != mh->csr)
- {
- TALER_EXCHANGE_csr_melt_cancel (mh->csr);
- mh->csr = NULL;
- }
- TALER_EXCHANGE_free_melt_data_ (&mh->md); /* does not free 'md' itself */
- GNUNET_free (mh->mbds);
- GNUNET_free (mh->url);
- GNUNET_free (mh->exchange_url);
- TALER_curl_easy_post_finished (&mh->ctx);
- TALER_EXCHANGE_keys_decref (mh->keys);
- GNUNET_free (mh);
-}
-
-
-/* end of exchange_api_melt.c */
diff --git a/src/lib/exchange_api_refresh_common.c b/src/lib/exchange_api_refresh_common.c
@@ -23,240 +23,6 @@
#include "platform.h"
#include "exchange_api_refresh_common.h"
-
-void
-TALER_EXCHANGE_free_melt_data_ (struct MeltData *md)
-{
- for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)
- {
- struct TALER_RefreshCoinData *rcds = md->rcd[i];
-
- if (NULL == rcds)
- continue;
- for (unsigned int j = 0; j < md->num_fresh_coins; j++)
- TALER_blinded_planchet_free (&rcds[j].blinded_planchet);
- GNUNET_free (rcds);
- }
- TALER_denom_pub_free (&md->melted_coin.pub_key);
- TALER_denom_sig_free (&md->melted_coin.sig);
- if (NULL != md->fcds)
- {
- for (unsigned int j = 0; j<md->num_fresh_coins; j++)
- {
- struct FreshCoinData *fcd = &md->fcds[j];
-
- TALER_denom_pub_free (&fcd->fresh_pk);
- for (size_t i = 0; i < TALER_CNC_KAPPA; i++)
- {
- TALER_age_commitment_proof_free (fcd->age_commitment_proofs[i]);
- GNUNET_free (fcd->age_commitment_proofs[i]);
- }
- }
- GNUNET_free (md->fcds);
- }
- /* Finally, clean up a bit... */
- GNUNET_CRYPTO_zero_keys (md,
- sizeof (struct MeltData));
-}
-
-
-enum GNUNET_GenericReturnValue
-TALER_EXCHANGE_get_melt_data_ (
- const struct TALER_RefreshMasterSecretP *rms,
- const struct TALER_EXCHANGE_RefreshData *rd,
- const struct TALER_ExchangeBlindingValues *alg_values,
- struct MeltData *md)
-{
- struct TALER_Amount total;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- union GNUNET_CRYPTO_BlindSessionNonce nonces[rd->fresh_pks_len];
- bool uses_cs = false;
-
- GNUNET_CRYPTO_eddsa_key_get_public (&rd->melt_priv.eddsa_priv,
- &coin_pub.eddsa_pub);
- /* build up melt data structure */
- memset (md,
- 0,
- sizeof (*md));
- 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.fees.refresh;
- md->melted_coin.original_value = rd->melt_pk.value;
- md->melted_coin.expire_deposit = rd->melt_pk.expire_deposit;
- md->melted_coin.age_commitment_proof = rd->melt_age_commitment_proof;
- md->melted_coin.h_age_commitment = rd->melt_h_age_commitment;
-
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (rd->melt_amount.currency,
- &total));
- TALER_denom_pub_copy (&md->melted_coin.pub_key,
- &rd->melt_pk.key);
- TALER_denom_sig_copy (&md->melted_coin.sig,
- &rd->melt_sig);
- md->fcds = GNUNET_new_array (md->num_fresh_coins,
- struct FreshCoinData);
- for (unsigned int j = 0; j<rd->fresh_pks_len; j++)
- {
- struct FreshCoinData *fcd = &md->fcds[j];
-
- TALER_denom_pub_copy (&fcd->fresh_pk,
- &rd->fresh_pks[j].key);
- GNUNET_assert (NULL != fcd->fresh_pk.bsign_pub_key);
- if (alg_values[j].blinding_inputs->cipher !=
- fcd->fresh_pk.bsign_pub_key->cipher)
- {
- GNUNET_break (0);
- TALER_EXCHANGE_free_melt_data_ (md);
- return GNUNET_SYSERR;
- }
- switch (fcd->fresh_pk.bsign_pub_key->cipher)
- {
- case GNUNET_CRYPTO_BSA_INVALID:
- GNUNET_break (0);
- TALER_EXCHANGE_free_melt_data_ (md);
- return GNUNET_SYSERR;
- case GNUNET_CRYPTO_BSA_RSA:
- break;
- case GNUNET_CRYPTO_BSA_CS:
- uses_cs = true;
- TALER_cs_refresh_nonce_derive (rms,
- j,
- &nonces[j].cs_nonce);
- break;
- }
- if ( (0 >
- TALER_amount_add (&total,
- &total,
- &rd->fresh_pks[j].value)) ||
- (0 >
- TALER_amount_add (&total,
- &total,
- &rd->fresh_pks[j].fees.withdraw)) )
- {
- GNUNET_break (0);
- TALER_EXCHANGE_free_melt_data_ (md);
- return GNUNET_SYSERR;
- }
- }
-
- /* verify that melt_amount is above total cost */
- if (1 ==
- TALER_amount_cmp (&total,
- &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 GNUNET_SYSERR;
- }
-
- /* build up coins */
- for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++)
- {
- struct TALER_TransferSecretP trans_sec;
-
- TALER_planchet_secret_to_transfer_priv (
- rms,
- &rd->melt_priv,
- i,
- &md->transfer_priv[i]);
-
- GNUNET_CRYPTO_ecdhe_key_get_public (
- &md->transfer_priv[i].ecdhe_priv,
- &md->transfer_pub[i].ecdhe_pub);
-
- TALER_link_derive_transfer_secret (&rd->melt_priv,
- &md->transfer_priv[i],
- &trans_sec);
-
- md->rcd[i] = GNUNET_new_array (rd->fresh_pks_len,
- struct TALER_RefreshCoinData);
-
- for (unsigned int j = 0; j<rd->fresh_pks_len; j++)
- {
- struct FreshCoinData *fcd = &md->fcds[j];
- struct TALER_CoinSpendPrivateKeyP *coin_priv = &fcd->coin_priv;
- struct TALER_PlanchetMasterSecretP *ps = &fcd->ps[i];
- struct TALER_RefreshCoinData *rcd = &md->rcd[i][j];
- union GNUNET_CRYPTO_BlindingSecretP *bks = &fcd->bks[i];
- struct TALER_PlanchetDetail pd;
- struct TALER_CoinPubHashP c_hash;
- struct TALER_AgeCommitmentHash ach;
- struct TALER_AgeCommitmentHash *pah = NULL;
-
- TALER_transfer_secret_to_planchet_secret (&trans_sec,
- j,
- ps);
-
- TALER_planchet_setup_coin_priv (ps,
- &alg_values[j],
- coin_priv);
-
- TALER_planchet_blinding_secret_create (ps,
- &alg_values[j],
- bks);
-
- if (NULL != rd->melt_age_commitment_proof)
- {
- fcd->age_commitment_proofs[i] = GNUNET_new (struct
- TALER_AgeCommitmentProof);
-
- GNUNET_assert (GNUNET_OK ==
- TALER_age_commitment_proof_derive (
- md->melted_coin.age_commitment_proof,
- &trans_sec.key,
- fcd->age_commitment_proofs[i]));
-
- TALER_age_commitment_hash (
- &fcd->age_commitment_proofs[i]->commitment,
- &ach);
- pah = &ach;
- }
-
- if (GNUNET_OK !=
- TALER_planchet_prepare (&fcd->fresh_pk,
- &alg_values[j],
- bks,
- &nonces[j],
- coin_priv,
- pah,
- &c_hash,
- &pd))
- {
- GNUNET_break_op (0);
- TALER_EXCHANGE_free_melt_data_ (md);
- return GNUNET_SYSERR;
- }
- rcd->blinded_planchet = pd.blinded_planchet;
- rcd->dk = &fcd->fresh_pk;
- }
- }
-
- /* Finally, compute refresh commitment */
- {
- struct TALER_RefreshCommitmentEntry rce[TALER_CNC_KAPPA];
-
- for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++)
- {
- rce[i].transfer_pub = md->transfer_pub[i];
- rce[i].new_coins = md->rcd[i];
- }
- TALER_refresh_get_commitment (&md->rc,
- TALER_CNC_KAPPA,
- uses_cs
- ? rms
- : NULL,
- rd->fresh_pks_len,
- rce,
- &coin_pub,
- &rd->melt_amount);
- }
- return GNUNET_OK;
-}
-
-
void
TALER_EXCHANGE_free_melt_data_v27 (struct MeltData_v27 *md)
{
@@ -286,7 +52,7 @@ TALER_EXCHANGE_free_melt_data_v27 (struct MeltData_v27 *md)
}
/* Finally, clean up a bit... */
GNUNET_CRYPTO_zero_keys (md,
- sizeof (struct MeltData));
+ sizeof (struct MeltData_v27));
}
diff --git a/src/lib/exchange_api_refresh_common.h b/src/lib/exchange_api_refresh_common.h
@@ -117,62 +117,6 @@ struct FreshCoinData
/**
* Melt data in non-serialized format for convenient processing.
*/
-struct MeltData
-{
-
- /**
- * Hash over the committed data during refresh operation.
- */
- struct TALER_RefreshCommitmentP rc;
-
- /**
- * Information about the melted coin.
- */
- struct MeltedCoin melted_coin;
-
- /**
- * Array of length @e num_fresh_coins with information
- * about each fresh coin.
- */
- struct FreshCoinData *fcds;
-
- /**
- * Transfer secrets, one per cut and choose.
- */
- struct TALER_TransferSecretP trans_sec[TALER_CNC_KAPPA];
-
- /**
- * Transfer private keys for each cut-and-choose dimension.
- */
- struct TALER_TransferPrivateKeyP transfer_priv[TALER_CNC_KAPPA];
-
- /**
- * Transfer public key of this commitment.
- */
- struct TALER_TransferPublicKeyP transfer_pub[TALER_CNC_KAPPA];
-
- /**
- * Transfer secrets, one per cut and choose.
- */
- struct TALER_RefreshCommitmentEntry rce[TALER_CNC_KAPPA];
-
- /**
- * Blinded planchets and denominations of the fresh coins, depending on the cut-and-choose. Array of length
- * @e num_fresh_coins.
- */
- struct TALER_RefreshCoinData *rcd[TALER_CNC_KAPPA];
-
- /**
- * Number of coins we are creating
- */
- uint16_t num_fresh_coins;
-
-};
-
-
-/**
- * Melt data in non-serialized format for convenient processing.
- */
struct MeltData_v27
{
@@ -245,21 +189,6 @@ struct MeltData_v27
};
/**
- * Compute the melt data from the refresh data and secret.
- *
- * @param rms secret internals of the refresh-reveal operation
- * @param rd refresh data with the characteristics of the operation
- * @param alg_values contributions from the exchange into the melt
- * @param[out] md where to write the derived melt data
- */
-enum GNUNET_GenericReturnValue
-TALER_EXCHANGE_get_melt_data_ (
- const struct TALER_RefreshMasterSecretP *rms,
- const struct TALER_EXCHANGE_RefreshData *rd,
- const struct TALER_ExchangeBlindingValues *alg_values,
- struct MeltData *md);
-
-/**
* Compute the melt data from the refresh data and secret
* for v27 of the protocol.
*
@@ -277,20 +206,6 @@ TALER_EXCHANGE_get_melt_data_v27 (
const struct TALER_ExchangeBlindingValues *alg_values,
struct MeltData_v27 *md);
-
-/**
- * Free all information associated with a melting session. Note
- * that we allow the melting session to be only partially initialized,
- * as we use this function also when freeing melt data that was not
- * fully initialized.
- *
- * @param[in] md melting data to release, the pointer itself is NOT
- * freed (as it is typically not allocated by itself)
- */
-void
-TALER_EXCHANGE_free_melt_data_ (struct MeltData *md);
-
-
/**
* Free all information associated with a melting session. Note
* that we allow the melting session to be only partially initialized,
diff --git a/src/lib/exchange_api_refreshes_reveal.c b/src/lib/exchange_api_refreshes_reveal.c
@@ -1,533 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2015-2023 Taler Systems SA
-
- 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
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file lib/exchange_api_refreshes_reveal.c
- * @brief Implementation of the /refreshes/$RCH/reveal requests
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <jansson.h>
-#include <microhttpd.h> /* just for HTTP status codes */
-#include <gnunet/gnunet_util_lib.h>
-#include <gnunet/gnunet_json_lib.h>
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_json_lib.h"
-#include "taler_exchange_service.h"
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "exchange_api_curl_defaults.h"
-#include "exchange_api_refresh_common.h"
-
-
-/**
- * @brief A /refreshes/$RCH/reveal Handle
- */
-struct TALER_EXCHANGE_RefreshesRevealHandle
-{
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * Context for #TEH_curl_easy_post(). Keeps the data that must
- * persist for Curl to make the upload.
- */
- struct TALER_CURL_PostContext ctx;
-
- /**
- * Handle for the request.
- */
- struct GNUNET_CURL_Job *job;
-
- /**
- * Exchange-contributed values to the operation.
- */
- struct TALER_ExchangeBlindingValues *alg_values;
-
- /**
- * Function to call with the result.
- */
- TALER_EXCHANGE_RefreshesRevealCallback reveal_cb;
-
- /**
- * Closure for @e reveal_cb.
- */
- void *reveal_cb_cls;
-
- /**
- * Actual information about the melt operation.
- */
- struct MeltData md;
-
- /**
- * The index selected by the exchange in cut-and-choose to not be revealed.
- */
- uint16_t noreveal_index;
-
-};
-
-
-/**
- * We got a 200 OK response for the /refreshes/$RCH/reveal operation. Extract
- * the coin signatures and return them to the caller. The signatures we get
- * from the exchange is for the blinded value. Thus, we first must unblind
- * them and then should verify their validity.
- *
- * If everything checks out, we return the unblinded signatures
- * to the application via the callback.
- *
- * @param rrh operation handle
- * @param json reply from the exchange
- * @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_EXCHANGE_RevealedCoinInfo *rcis)
-{
- const json_t *jsona;
- struct GNUNET_JSON_Specification outer_spec[] = {
- GNUNET_JSON_spec_array_const ("ev_sigs",
- &jsona),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- outer_spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (rrh->md.num_fresh_coins != json_array_size (jsona))
- {
- /* Number of coins generated does not match our expectation */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- for (unsigned int i = 0; i<rrh->md.num_fresh_coins; i++)
- {
- struct TALER_EXCHANGE_RevealedCoinInfo *rci = &rcis[i];
- const struct FreshCoinData *fcd = &rrh->md.fcds[i];
- const struct TALER_DenominationPublicKey *pk;
- json_t *jsonai;
- struct TALER_BlindedDenominationSignature blind_sig;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_CoinPubHashP coin_hash;
- struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_blinded_denom_sig ("ev_sig",
- &blind_sig),
- GNUNET_JSON_spec_end ()
- };
- struct TALER_FreshCoin coin;
- union GNUNET_CRYPTO_BlindingSecretP bks;
- const struct TALER_AgeCommitmentHash *pah = NULL;
-
- rci->ps = fcd->ps[rrh->noreveal_index];
- rci->bks = fcd->bks[rrh->noreveal_index];
- rci->age_commitment_proof = NULL;
- pk = &fcd->fresh_pk;
- jsonai = json_array_get (jsona, i);
- GNUNET_assert (NULL != jsonai);
- if (NULL != rrh->md.melted_coin.age_commitment_proof)
- {
- rci->age_commitment_proof
- = fcd->age_commitment_proofs[rrh->noreveal_index];
- TALER_age_commitment_hash (&rci->age_commitment_proof->commitment,
- &rci->h_age_commitment);
- pah = &rci->h_age_commitment;
- }
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (jsonai,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- TALER_planchet_setup_coin_priv (&rci->ps,
- &rrh->alg_values[i],
- &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 (&rci->coin_priv.eddsa_priv,
- &coin_pub.eddsa_pub);
- TALER_coin_pub_hash (
- &coin_pub,
- pah,
- &coin_hash);
- if (GNUNET_OK !=
- TALER_planchet_to_coin (
- pk,
- &blind_sig,
- &bks,
- &rci->coin_priv,
- pah,
- &coin_hash,
- &rrh->alg_values[i],
- &coin))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return GNUNET_SYSERR;
- }
- GNUNET_JSON_parse_free (spec);
- rci->sig = coin.sig;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Function called when we're done processing the
- * HTTP /refreshes/$RCH/reveal request.
- *
- * @param cls the `struct TALER_EXCHANGE_RefreshHandle`
- * @param response_code HTTP response code, 0 on error
- * @param response parsed JSON result, NULL on error
- */
-static void
-handle_refresh_reveal_finished (void *cls,
- long response_code,
- const void *response)
-{
- struct TALER_EXCHANGE_RefreshesRevealHandle *rrh = cls;
- const json_t *j = response;
- struct TALER_EXCHANGE_RevealResult rr = {
- .hr.reply = j,
- .hr.http_status = (unsigned int) response_code
- };
-
- rrh->job = NULL;
- switch (response_code)
- {
- case 0:
- rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- case MHD_HTTP_OK:
- {
- struct TALER_EXCHANGE_RevealedCoinInfo rcis[rrh->md.num_fresh_coins];
- enum GNUNET_GenericReturnValue ret;
-
- memset (rcis,
- 0,
- sizeof (rcis));
- ret = refresh_reveal_ok (rrh,
- j,
- rcis);
- if (GNUNET_OK != ret)
- {
- 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.ok.num_coins = rrh->md.num_fresh_coins;
- rr.details.ok.coins = rcis;
- rrh->reveal_cb (rrh->reveal_cb_cls,
- &rr);
- rrh->reveal_cb = NULL;
- }
- for (unsigned int i = 0; i<rrh->md.num_fresh_coins; i++)
- {
- TALER_denom_sig_free (&rcis[i].sig);
- TALER_age_commitment_proof_free (rcis[i].age_commitment_proof);
- }
- 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 */
- 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 */
- 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 */
- 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 */
- 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);
- 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) rr.hr.ec);
- break;
- }
- if (NULL != rrh->reveal_cb)
- rrh->reveal_cb (rrh->reveal_cb_cls,
- &rr);
- TALER_EXCHANGE_refreshes_reveal_cancel (rrh);
-}
-
-
-struct TALER_EXCHANGE_RefreshesRevealHandle *
-TALER_EXCHANGE_refreshes_reveal (
- struct GNUNET_CURL_Context *ctx,
- const char *url,
- const struct TALER_RefreshMasterSecretP *rms,
- const struct TALER_EXCHANGE_RefreshData *rd,
- unsigned int num_coins,
- const struct TALER_ExchangeBlindingValues alg_values[static num_coins],
- uint32_t noreveal_index,
- TALER_EXCHANGE_RefreshesRevealCallback reveal_cb,
- void *reveal_cb_cls)
-{
- struct TALER_EXCHANGE_RefreshesRevealHandle *rrh;
- json_t *transfer_privs;
- json_t *new_denoms_h;
- json_t *coin_evs;
- json_t *reveal_obj;
- json_t *link_sigs;
- json_t *old_age_commitment = NULL;
- CURL *eh;
- struct MeltData md;
- char arg_str[sizeof (struct TALER_RefreshCommitmentP) * 2 + 32];
- bool send_rms = false;
-
- GNUNET_assert (num_coins == rd->fresh_pks_len);
- if (noreveal_index >= TALER_CNC_KAPPA)
- {
- /* We check this here, as it would be really bad to below just
- disclose all the transfer keys. Note that this error should
- have been caught way earlier when the exchange replied, but maybe
- we had some internal corruption that changed the value... */
- GNUNET_break (0);
- return NULL;
- }
- if (GNUNET_OK !=
- TALER_EXCHANGE_get_melt_data_ (rms,
- rd,
- alg_values,
- &md))
- {
- GNUNET_break (0);
- return NULL;
- }
-
- /* 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; i<md.num_fresh_coins; i++)
- {
- const struct TALER_RefreshCoinData *rcd = &md.rcd[noreveal_index][i];
- struct TALER_DenominationHashP denom_hash;
-
- if (GNUNET_CRYPTO_BSA_CS ==
- md.fcds[i].fresh_pk.bsign_pub_key->cipher)
- send_rms = true;
- TALER_denom_pub_hash (&md.fcds[i].fresh_pk,
- &denom_hash);
- GNUNET_assert (0 ==
- json_array_append_new (new_denoms_h,
- GNUNET_JSON_from_data_auto (
- &denom_hash)));
- GNUNET_assert (0 ==
- json_array_append_new (
- coin_evs,
- GNUNET_JSON_PACK (
- TALER_JSON_pack_blinded_planchet (
- NULL,
- &rcd->blinded_planchet))));
- {
- struct TALER_CoinSpendSignatureP link_sig;
- struct TALER_BlindedCoinHashP bch;
-
- TALER_coin_ev_hash (&rcd->blinded_planchet,
- &denom_hash,
- &bch);
- TALER_wallet_link_sign (
- &denom_hash,
- &md.transfer_pub[noreveal_index],
- &bch,
- &md.melted_coin.coin_priv,
- &link_sig);
- GNUNET_assert (0 ==
- json_array_append_new (
- link_sigs,
- GNUNET_JSON_from_data_auto (&link_sig)));
- }
- }
-
- /* build array of transfer private keys */
- GNUNET_assert (NULL != (transfer_privs = json_array ()));
- for (unsigned int j = 0; j<TALER_CNC_KAPPA; j++)
- {
- if (j == noreveal_index)
- {
- /* This is crucial: exclude the transfer key for the noreval index! */
- continue;
- }
- GNUNET_assert (0 ==
- json_array_append_new (transfer_privs,
- GNUNET_JSON_from_data_auto (
- &md.transfer_priv[j])));
- }
-
- /* build array of old age commitment, if applicable */
- if (NULL != rd->melt_age_commitment_proof)
- {
- GNUNET_assert (NULL != rd->melt_h_age_commitment);
- GNUNET_assert (NULL != (old_age_commitment = json_array ()));
-
- for (size_t i = 0; i < rd->melt_age_commitment_proof->commitment.num; i++)
- {
- enum GNUNET_GenericReturnValue ret;
-
- ret = json_array_append_new (
- old_age_commitment,
- GNUNET_JSON_from_data_auto (
- &rd->melt_age_commitment_proof->commitment.pubs[i]));
- GNUNET_assert (0 == ret);
- }
- }
-
- /* build main JSON request */
- reveal_obj = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_data_auto ("transfer_pub",
- &md.transfer_pub[noreveal_index]),
- GNUNET_JSON_pack_allow_null (
- send_rms
- ? GNUNET_JSON_pack_data_auto ("rms",
- rms)
- : GNUNET_JSON_pack_string ("rms",
- NULL)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_array_steal ("old_age_commitment",
- old_age_commitment)),
- GNUNET_JSON_pack_array_steal ("transfer_privs",
- transfer_privs),
- GNUNET_JSON_pack_array_steal ("link_sigs",
- link_sigs),
- GNUNET_JSON_pack_array_steal ("new_denoms_h",
- new_denoms_h),
- GNUNET_JSON_pack_array_steal ("coin_evs",
- coin_evs));
- {
- char pub_str[sizeof (struct TALER_RefreshCommitmentP) * 2];
- char *end;
-
- end = GNUNET_STRINGS_data_to_string (&md.rc,
- sizeof (md.rc),
- pub_str,
- sizeof (pub_str));
- *end = '\0';
- GNUNET_snprintf (arg_str,
- sizeof (arg_str),
- "refreshes/%s/reveal",
- pub_str);
- }
- /* finally, we can actually issue the request */
- rrh = GNUNET_new (struct TALER_EXCHANGE_RefreshesRevealHandle);
- rrh->noreveal_index = noreveal_index;
- rrh->reveal_cb = reveal_cb;
- rrh->reveal_cb_cls = reveal_cb_cls;
- rrh->md = md;
- rrh->alg_values
- = GNUNET_new_array (md.num_fresh_coins,
- struct TALER_ExchangeBlindingValues);
- for (unsigned int i = 0; i<md.num_fresh_coins; i++)
- TALER_denom_ewv_copy (&rrh->alg_values[i],
- &alg_values[i]);
- rrh->url = TALER_url_join (url,
- arg_str,
- NULL);
- if (NULL == rrh->url)
- {
- json_decref (reveal_obj);
- TALER_EXCHANGE_free_melt_data_ (&md);
- GNUNET_free (rrh->alg_values);
- GNUNET_free (rrh);
- return NULL;
- }
-
- eh = TALER_EXCHANGE_curl_easy_get_ (rrh->url);
- if ( (NULL == eh) ||
- (GNUNET_OK !=
- TALER_curl_easy_post (&rrh->ctx,
- eh,
- reveal_obj)) )
- {
- GNUNET_break (0);
- if (NULL != eh)
- curl_easy_cleanup (eh);
- json_decref (reveal_obj);
- TALER_EXCHANGE_free_melt_data_ (&md);
- GNUNET_free (rrh->alg_values);
- GNUNET_free (rrh->url);
- GNUNET_free (rrh);
- return NULL;
- }
- json_decref (reveal_obj);
- rrh->job = GNUNET_CURL_job_add2 (ctx,
- eh,
- rrh->ctx.headers,
- &handle_refresh_reveal_finished,
- rrh);
- return rrh;
-}
-
-
-void
-TALER_EXCHANGE_refreshes_reveal_cancel (
- struct TALER_EXCHANGE_RefreshesRevealHandle *rrh)
-{
- if (NULL != rrh->job)
- {
- GNUNET_CURL_job_cancel (rrh->job);
- rrh->job = NULL;
- }
- for (unsigned int i = 0; i<rrh->md.num_fresh_coins; i++)
- TALER_denom_ewv_free (&rrh->alg_values[i]);
- GNUNET_free (rrh->alg_values);
- GNUNET_free (rrh->url);
- TALER_curl_easy_post_finished (&rrh->ctx);
- TALER_EXCHANGE_free_melt_data_ (&rrh->md);
- GNUNET_free (rrh);
-}
-
-
-/* exchange_api_refreshes_reveal.c */