LCOV - code coverage report
Current view: top level - lib - exchange_api_post-melt.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 65.4 % 246 161
Test Date: 2026-03-10 12:10:57 Functions: 87.5 % 8 7

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2025 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it under the
       6              :   terms of the GNU General Public License as published by the Free Software
       7              :   Foundation; either version 3, or (at your option) any later version.
       8              : 
       9              :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10              :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11              :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12              : 
      13              :   You should have received a copy of the GNU General Public License along with
      14              :   TALER; see the file COPYING.  If not, see
      15              :   <http://www.gnu.org/licenses/>
      16              : */
      17              : /**
      18              :  * @file lib/exchange_api_post-melt.c
      19              :  * @brief Implementation of the /melt request
      20              :  * @author Özgür Kesim
      21              :  */
      22              : #include "taler/platform.h"
      23              : #include <jansson.h>
      24              : #include <microhttpd.h> /* just for HTTP status codes */
      25              : #include <gnunet/gnunet_util_lib.h>
      26              : #include <gnunet/gnunet_json_lib.h>
      27              : #include <gnunet/gnunet_curl_lib.h>
      28              : #include "taler/taler_json_lib.h"
      29              : #include "taler/taler_exchange_service.h"
      30              : #include "exchange_api_common.h"
      31              : #include "exchange_api_handle.h"
      32              : #include "taler/taler_signatures.h"
      33              : #include "exchange_api_curl_defaults.h"
      34              : #include "exchange_api_refresh_common.h"
      35              : 
      36              : 
      37              : /**
      38              :  * @brief A /melt Handle
      39              :  */
      40              : struct TALER_EXCHANGE_PostMeltHandle
      41              : {
      42              : 
      43              :   /**
      44              :    * The keys of the this request handle will use
      45              :    */
      46              :   struct TALER_EXCHANGE_Keys *keys;
      47              : 
      48              :   /**
      49              :    * The url for this request.
      50              :    */
      51              :   char *url;
      52              : 
      53              :   /**
      54              :    * The exchange base url.
      55              :    */
      56              :   char *exchange_url;
      57              : 
      58              :   /**
      59              :    * Curl context.
      60              :    */
      61              :   struct GNUNET_CURL_Context *cctx;
      62              : 
      63              :   /**
      64              :    * Context for #TEH_curl_easy_post(). Keeps the data that must
      65              :    * persist for Curl to make the upload.
      66              :    */
      67              :   struct TALER_CURL_PostContext ctx;
      68              : 
      69              :   /**
      70              :    * Handle for the request.
      71              :    */
      72              :   struct GNUNET_CURL_Job *job;
      73              : 
      74              :   /**
      75              :    * Function to call with refresh melt failure results.
      76              :    */
      77              :   TALER_EXCHANGE_PostMeltCallback melt_cb;
      78              : 
      79              :   /**
      80              :    * Closure for @e result_cb and @e melt_failure_cb.
      81              :    */
      82              :   void *melt_cb_cls;
      83              : 
      84              :   /**
      85              :    * Actual information about the melt operation.
      86              :    */
      87              :   struct MeltData md;
      88              : 
      89              :   /**
      90              :    * The seed for the melt operation.
      91              :    */
      92              :   struct TALER_PublicRefreshMasterSeedP rms;
      93              : 
      94              :   /**
      95              :    * Details about the characteristics of the requested melt operation.
      96              :    */
      97              :   const struct TALER_EXCHANGE_MeltInput *rd;
      98              : 
      99              :   /**
     100              :    * True, if no blinding_seed is needed (no CS denominations involved)
     101              :    */
     102              :   bool no_blinding_seed;
     103              : 
     104              :   /**
     105              :    * If @e no_blinding_seed is false, the blinding seed for the intermediate
     106              :    * call to /blinding-prepare, in order to retrieve the R-values from the
     107              :    * exchange for the blind Clause-Schnorr signature.
     108              :    */
     109              :   struct TALER_BlindingMasterSeedP blinding_seed;
     110              : 
     111              :   /**
     112              :    * Array of `num_fresh_denom_pubs` per-coin values
     113              :    * returned from melt operation.
     114              :    */
     115              :   struct TALER_ExchangeBlindingValues *melt_blinding_values;
     116              : 
     117              :   /**
     118              :    * Handle for the preflight request, or NULL.
     119              :    */
     120              :   struct TALER_EXCHANGE_PostBlindingPrepareHandle *bpr;
     121              : 
     122              :   /**
     123              :    * Public key of the coin being melted.
     124              :    */
     125              :   struct TALER_CoinSpendPublicKeyP coin_pub;
     126              : 
     127              :   /**
     128              :    * Signature affirming the melt.
     129              :    */
     130              :   struct TALER_CoinSpendSignatureP coin_sig;
     131              : 
     132              :   /**
     133              :    * @brief Public information about the coin's denomination key
     134              :    */
     135              :   const struct TALER_EXCHANGE_DenomPublicKey *dki;
     136              : 
     137              :   /**
     138              :    * Gamma value chosen by the exchange during melt.
     139              :    */
     140              :   uint32_t noreveal_index;
     141              : 
     142              : };
     143              : 
     144              : 
     145              : /**
     146              :  * Verify that the signature on the "200 OK" response
     147              :  * from the exchange is valid.
     148              :  *
     149              :  * @param[in,out] mh melt handle
     150              :  * @param json json reply with the signature
     151              :  * @param[out] exchange_pub public key of the exchange used for the signature
     152              :  * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
     153              :  */
     154              : static enum GNUNET_GenericReturnValue
     155           16 : verify_melt_signature_ok (struct TALER_EXCHANGE_PostMeltHandle *mh,
     156              :                           const json_t *json,
     157              :                           struct TALER_ExchangePublicKeyP *exchange_pub)
     158              : {
     159              :   struct TALER_ExchangeSignatureP exchange_sig;
     160              :   struct GNUNET_JSON_Specification spec[] = {
     161           16 :     GNUNET_JSON_spec_fixed_auto ("exchange_sig",
     162              :                                  &exchange_sig),
     163           16 :     GNUNET_JSON_spec_fixed_auto ("exchange_pub",
     164              :                                  exchange_pub),
     165           16 :     GNUNET_JSON_spec_uint32 ("noreveal_index",
     166              :                              &mh->noreveal_index),
     167           16 :     GNUNET_JSON_spec_end ()
     168              :   };
     169              : 
     170           16 :   if (GNUNET_OK !=
     171           16 :       GNUNET_JSON_parse (json,
     172              :                          spec,
     173              :                          NULL, NULL))
     174              :   {
     175            0 :     GNUNET_break_op (0);
     176            0 :     return GNUNET_SYSERR;
     177              :   }
     178              :   /* check that exchange signing key is permitted */
     179           16 :   if (GNUNET_OK !=
     180           16 :       TALER_EXCHANGE_test_signing_key (mh->keys,
     181              :                                        exchange_pub))
     182              :   {
     183            0 :     GNUNET_break_op (0);
     184            0 :     return GNUNET_SYSERR;
     185              :   }
     186              : 
     187              :   /* check that noreveal index is in permitted range */
     188           16 :   if (TALER_CNC_KAPPA <= mh->noreveal_index)
     189              :   {
     190            0 :     GNUNET_break_op (0);
     191            0 :     return GNUNET_SYSERR;
     192              :   }
     193              : 
     194           16 :   if (GNUNET_OK !=
     195           16 :       TALER_exchange_online_melt_confirmation_verify (
     196           16 :         &mh->md.rc,
     197              :         mh->noreveal_index,
     198              :         exchange_pub,
     199              :         &exchange_sig))
     200              :   {
     201            0 :     GNUNET_break_op (0);
     202            0 :     return GNUNET_SYSERR;
     203              :   }
     204           16 :   return GNUNET_OK;
     205              : }
     206              : 
     207              : 
     208              : /**
     209              :  * Function called when we're done processing the
     210              :  * HTTP /melt request.
     211              :  *
     212              :  * @param cls the `struct TALER_EXCHANGE_MeltHandle`
     213              :  * @param response_code HTTP response code, 0 on error
     214              :  * @param response parsed JSON result, NULL on error
     215              :  */
     216              : static void
     217           30 : handle_melt_finished (void *cls,
     218              :                       long response_code,
     219              :                       const void *response)
     220              : {
     221           30 :   struct TALER_EXCHANGE_PostMeltHandle *mh = cls;
     222           30 :   const json_t *j = response;
     223           30 :   struct TALER_EXCHANGE_PostMeltResponse mr = {
     224              :     .hr.reply = j,
     225           30 :     .hr.http_status = (unsigned int) response_code
     226              :   };
     227              : 
     228           30 :   mh->job = NULL;
     229           30 :   switch (response_code)
     230              :   {
     231            0 :   case 0:
     232            0 :     mr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     233            0 :     break;
     234           16 :   case MHD_HTTP_OK:
     235           16 :     if (GNUNET_OK !=
     236           16 :         verify_melt_signature_ok (mh,
     237              :                                   j,
     238              :                                   &mr.details.ok.sign_key))
     239              :     {
     240            0 :       GNUNET_break_op (0);
     241            0 :       mr.hr.http_status = 0;
     242            0 :       mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE;
     243            0 :       break;
     244              :     }
     245           16 :     mr.details.ok.noreveal_index = mh->noreveal_index;
     246           16 :     mr.details.ok.num_melt_blinding_values = mh->rd->num_fresh_denom_pubs;
     247           16 :     mr.details.ok.melt_blinding_values = mh->melt_blinding_values;
     248           32 :     mr.details.ok.blinding_seed = mh->no_blinding_seed
     249              :                                                ? NULL
     250           16 :                                                : &mh->blinding_seed;
     251           16 :     mh->melt_cb (mh->melt_cb_cls,
     252              :                  &mr);
     253           16 :     mh->melt_cb = NULL;
     254           16 :     break;
     255            0 :   case MHD_HTTP_BAD_REQUEST:
     256              :     /* This should never happen, either us or the exchange is buggy
     257              :        (or API version conflict); just pass JSON reply to the application */
     258            0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     259            0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     260            0 :     break;
     261           14 :   case MHD_HTTP_CONFLICT:
     262           14 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     263           14 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     264           14 :     break;
     265            0 :   case MHD_HTTP_FORBIDDEN:
     266              :     /* Nothing really to verify, exchange says one of the signatures is
     267              :        invalid; assuming we checked them, this should never happen, we
     268              :        should pass the JSON reply to the application */
     269            0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     270            0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     271            0 :     break;
     272            0 :   case MHD_HTTP_NOT_FOUND:
     273              :     /* Nothing really to verify, this should never
     274              :        happen, we should pass the JSON reply to the application */
     275            0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     276            0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     277            0 :     break;
     278            0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     279              :     /* Server had an internal issue; we should retry, but this API
     280              :        leaves this to the application */
     281            0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     282            0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     283            0 :     break;
     284            0 :   default:
     285              :     /* unexpected response code */
     286            0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     287            0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     288            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     289              :                 "Unexpected response code %u/%d for exchange melt\n",
     290              :                 (unsigned int) response_code,
     291              :                 mr.hr.ec);
     292            0 :     GNUNET_break_op (0);
     293            0 :     break;
     294              :   }
     295           30 :   if (NULL != mh->melt_cb)
     296           14 :     mh->melt_cb (mh->melt_cb_cls,
     297              :                  &mr);
     298           30 :   TALER_EXCHANGE_post_melt_cancel (mh);
     299           30 : }
     300              : 
     301              : 
     302              : /**
     303              :  * Start the actual melt operation, now that we have
     304              :  * the exchange's input values.
     305              :  *
     306              :  * @param[in,out] mh melt operation to run
     307              :  * @return #GNUNET_OK if we could start the operation
     308              :  */
     309              : static enum GNUNET_GenericReturnValue
     310           30 : start_melt (struct TALER_EXCHANGE_PostMeltHandle *mh)
     311              : {
     312              :   json_t *j_request_body;
     313              :   json_t *j_transfer_pubs;
     314              :   json_t *j_coin_evs;
     315              :   CURL *eh;
     316              :   struct TALER_DenominationHashP h_denom_pub;
     317              : 
     318           30 :   if (GNUNET_OK !=
     319           30 :       TALER_EXCHANGE_get_melt_data (&mh->rms,
     320              :                                     mh->rd,
     321           30 :                                     mh->no_blinding_seed
     322              :                                         ? NULL
     323              :                                         : &mh->blinding_seed,
     324           30 :                                     mh->melt_blinding_values,
     325              :                                     &mh->md))
     326              :   {
     327            0 :     GNUNET_break (0);
     328            0 :     return GNUNET_SYSERR;
     329              :   }
     330           30 :   TALER_denom_pub_hash (
     331           30 :     &mh->md.melted_coin.pub_key,
     332              :     &h_denom_pub);
     333           30 :   TALER_wallet_melt_sign (
     334           30 :     &mh->md.melted_coin.melt_amount_with_fee,
     335           30 :     &mh->md.melted_coin.fee_melt,
     336           30 :     &mh->md.rc,
     337              :     &h_denom_pub,
     338              :     mh->md.melted_coin.h_age_commitment,
     339           30 :     &mh->md.melted_coin.coin_priv,
     340              :     &mh->coin_sig);
     341           30 :   GNUNET_CRYPTO_eddsa_key_get_public (
     342           30 :     &mh->md.melted_coin.coin_priv.eddsa_priv,
     343              :     &mh->coin_pub.eddsa_pub);
     344           60 :   mh->dki = TALER_EXCHANGE_get_denomination_key (
     345           30 :     mh->keys,
     346           30 :     &mh->md.melted_coin.pub_key);
     347           30 :   j_request_body = GNUNET_JSON_PACK (
     348              :     GNUNET_JSON_pack_data_auto ("old_coin_pub",
     349              :                                 &mh->coin_pub),
     350              :     GNUNET_JSON_pack_data_auto ("old_denom_pub_h",
     351              :                                 &h_denom_pub),
     352              :     TALER_JSON_pack_denom_sig ("old_denom_sig",
     353              :                                &mh->md.melted_coin.sig),
     354              :     GNUNET_JSON_pack_data_auto ("confirm_sig",
     355              :                                 &mh->coin_sig),
     356              :     TALER_JSON_pack_amount ("value_with_fee",
     357              :                             &mh->md.melted_coin.melt_amount_with_fee),
     358              :     GNUNET_JSON_pack_allow_null (
     359              :       (NULL != mh->md.melted_coin.h_age_commitment)
     360              :       ? GNUNET_JSON_pack_data_auto ("old_age_commitment_h",
     361              :                                     mh->md.melted_coin.h_age_commitment)
     362              :       : GNUNET_JSON_pack_string ("old_age_commitment_h",
     363              :                                  NULL)),
     364              :     GNUNET_JSON_pack_data_auto ("refresh_seed",
     365              :                                 &mh->md.refresh_seed),
     366              :     GNUNET_JSON_pack_allow_null (
     367              :       (mh->md.no_blinding_seed)
     368              :       ? GNUNET_JSON_pack_string ("blinding_seed",
     369              :                                  NULL)
     370              :       : GNUNET_JSON_pack_data_auto ("blinding_seed",
     371              :                                     &mh->md.blinding_seed)),
     372              :     TALER_JSON_pack_array_of_data_auto ("denoms_h",
     373              :                                         mh->md.num_fresh_coins,
     374              :                                         mh->md.denoms_h)
     375              :     );
     376           30 :   GNUNET_assert (NULL != j_request_body);
     377           30 :   GNUNET_assert (NULL !=
     378              :                  (j_transfer_pubs = json_array ()));
     379           30 :   GNUNET_assert (NULL !=
     380              :                  (j_coin_evs = json_array ()));
     381              :   /**
     382              :    * Fill the kappa array of coin envelopes and
     383              :    * the array of transfer pubs.
     384              :    */
     385          120 :   for (uint8_t k=0; k<TALER_CNC_KAPPA; k++)
     386              :   {
     387              :     json_t *j_envs;
     388           90 :     json_t *j_tbs = GNUNET_JSON_PACK (
     389              :       TALER_JSON_pack_array_of_data_auto (NULL,
     390              :                                           mh->md.num_fresh_coins,
     391              :                                           mh->md.kappa_transfer_pubs[k])
     392              :       );
     393              : 
     394           90 :     GNUNET_assert (NULL != (j_envs = json_array ()));
     395           90 :     GNUNET_assert (NULL !=j_tbs);
     396              : 
     397          450 :     for (size_t i = 0; i < mh->md.num_fresh_coins; i++)
     398              :     {
     399          360 :       json_t *j_coin = GNUNET_JSON_PACK (
     400              :         TALER_JSON_pack_blinded_planchet (NULL,
     401              :                                           &mh->md.kappa_blinded_planchets[k][i])
     402              :         );
     403          360 :       GNUNET_assert (NULL != j_coin);
     404          360 :       GNUNET_assert (0 ==
     405              :                      json_array_append_new (j_envs, j_coin));
     406              :     }
     407           90 :     GNUNET_assert (0 ==
     408              :                    json_array_append_new (j_coin_evs, j_envs));
     409           90 :     GNUNET_assert (0 ==
     410              :                    json_array_append_new (j_transfer_pubs, j_tbs));
     411              :   }
     412           30 :   GNUNET_assert (0 ==
     413              :                  json_object_set_new (j_request_body,
     414              :                                       "coin_evs",
     415              :                                       j_coin_evs));
     416           30 :   GNUNET_assert (0 ==
     417              :                  json_object_set_new (j_request_body,
     418              :                                       "transfer_pubs",
     419              :                                       j_transfer_pubs));
     420              :   /* and now we can at last begin the actual request handling */
     421           30 :   mh->url = TALER_url_join (mh->exchange_url,
     422              :                             "melt",
     423              :                             NULL);
     424           30 :   if (NULL == mh->url)
     425              :   {
     426            0 :     json_decref (j_request_body);
     427            0 :     return GNUNET_SYSERR;
     428              :   }
     429           30 :   eh = TALER_EXCHANGE_curl_easy_get_ (mh->url);
     430           60 :   if ( (NULL == eh) ||
     431              :        (GNUNET_OK !=
     432           30 :         TALER_curl_easy_post (&mh->ctx,
     433              :                               eh,
     434              :                               j_request_body)) )
     435              :   {
     436            0 :     GNUNET_break (0);
     437            0 :     if (NULL != eh)
     438            0 :       curl_easy_cleanup (eh);
     439            0 :     json_decref (j_request_body);
     440            0 :     return GNUNET_SYSERR;
     441              :   }
     442           30 :   json_decref (j_request_body);
     443           60 :   mh->job = GNUNET_CURL_job_add2 (mh->cctx,
     444              :                                   eh,
     445           30 :                                   mh->ctx.headers,
     446              :                                   &handle_melt_finished,
     447              :                                   mh);
     448           30 :   return GNUNET_OK;
     449              : }
     450              : 
     451              : 
     452              : /**
     453              :  * The melt request @a mh failed, return an error to
     454              :  * the application and cancel the operation.
     455              :  *
     456              :  * @param[in] mh melt request that failed
     457              :  * @param ec error code to fail with
     458              :  */
     459              : static void
     460            0 : fail_mh (struct TALER_EXCHANGE_PostMeltHandle *mh,
     461              :          enum TALER_ErrorCode ec)
     462              : {
     463            0 :   struct TALER_EXCHANGE_PostMeltResponse mr = {
     464              :     .hr.ec = ec
     465              :   };
     466              : 
     467            0 :   mh->melt_cb (mh->melt_cb_cls,
     468              :                &mr);
     469            0 :   TALER_EXCHANGE_post_melt_cancel (mh);
     470            0 : }
     471              : 
     472              : 
     473              : /**
     474              :  * Callbacks of this type are used to serve the result of submitting a
     475              :  * /blinding-prepare request to a exchange.
     476              :  *
     477              :  * @param cls closure with our `struct TALER_EXCHANGE_MeltHandle *`
     478              :  * @param bpr response details
     479              :  */
     480              : static void
     481           15 : blinding_prepare_cb (void *cls,
     482              :                      const struct TALER_EXCHANGE_PostBlindingPrepareResponse *
     483              :                      bpr)
     484              : {
     485           15 :   struct TALER_EXCHANGE_PostMeltHandle *mh = cls;
     486           15 :   unsigned int nks_off = 0;
     487              : 
     488           15 :   mh->bpr = NULL;
     489           15 :   if (MHD_HTTP_OK != bpr->hr.http_status)
     490              :   {
     491            0 :     struct TALER_EXCHANGE_PostMeltResponse mr = {
     492              :       .hr = bpr->hr
     493              :     };
     494              : 
     495            0 :     mr.hr.hint = "/blinding-prepare failed";
     496            0 :     mh->melt_cb (mh->melt_cb_cls,
     497              :                  &mr);
     498            0 :     TALER_EXCHANGE_post_melt_cancel (mh);
     499            0 :     return;
     500              :   }
     501           75 :   for (unsigned int i = 0; i<mh->rd->num_fresh_denom_pubs; i++)
     502              :   {
     503           60 :     const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk =
     504           60 :       &mh->rd->fresh_denom_pubs[i];
     505           60 :     struct TALER_ExchangeBlindingValues *wv = &mh->melt_blinding_values[i];
     506              : 
     507           60 :     switch (fresh_pk->key.bsign_pub_key->cipher)
     508              :     {
     509            0 :     case GNUNET_CRYPTO_BSA_INVALID:
     510            0 :       GNUNET_break (0);
     511            0 :       fail_mh (mh,
     512              :                TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR);
     513            0 :       return;
     514            0 :     case GNUNET_CRYPTO_BSA_RSA:
     515            0 :       break;
     516           60 :     case GNUNET_CRYPTO_BSA_CS:
     517           60 :       TALER_denom_ewv_copy (wv,
     518           60 :                             &bpr->details.ok.blinding_values[nks_off]);
     519           60 :       nks_off++;
     520           60 :       break;
     521              :     }
     522              :   }
     523           15 :   if (GNUNET_OK !=
     524           15 :       start_melt (mh))
     525              :   {
     526            0 :     GNUNET_break (0);
     527            0 :     fail_mh (mh,
     528              :              TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR);
     529            0 :     return;
     530              :   }
     531              : }
     532              : 
     533              : 
     534              : struct TALER_EXCHANGE_PostMeltHandle *
     535           30 : TALER_EXCHANGE_post_melt_create (
     536              :   struct GNUNET_CURL_Context *ctx,
     537              :   const char *url,
     538              :   struct TALER_EXCHANGE_Keys *keys,
     539              :   const struct TALER_PublicRefreshMasterSeedP *rms,
     540              :   const struct TALER_EXCHANGE_MeltInput *rd)
     541              : {
     542              :   struct TALER_EXCHANGE_PostMeltHandle *mh;
     543              : 
     544           30 :   if (0 == rd->num_fresh_denom_pubs)
     545              :   {
     546            0 :     GNUNET_break (0);
     547            0 :     return NULL;
     548              :   }
     549           30 :   mh = GNUNET_new (struct TALER_EXCHANGE_PostMeltHandle);
     550           30 :   mh->noreveal_index = TALER_CNC_KAPPA; /* invalid value */
     551           30 :   mh->cctx = ctx;
     552           30 :   mh->exchange_url = GNUNET_strdup (url);
     553           30 :   mh->rd = rd;
     554           30 :   mh->rms = *rms;
     555           30 :   mh->no_blinding_seed = true;
     556           30 :   mh->melt_blinding_values =
     557           30 :     GNUNET_new_array (rd->num_fresh_denom_pubs,
     558              :                       struct TALER_ExchangeBlindingValues);
     559          150 :   for (unsigned int i = 0; i < rd->num_fresh_denom_pubs; i++)
     560              :   {
     561          120 :     const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk =
     562          120 :       &rd->fresh_denom_pubs[i];
     563              : 
     564          120 :     switch (fresh_pk->key.bsign_pub_key->cipher)
     565              :     {
     566            0 :     case GNUNET_CRYPTO_BSA_INVALID:
     567            0 :       GNUNET_break (0);
     568            0 :       GNUNET_free (mh->melt_blinding_values);
     569            0 :       GNUNET_free (mh->exchange_url);
     570            0 :       GNUNET_free (mh);
     571            0 :       return NULL;
     572           60 :     case GNUNET_CRYPTO_BSA_RSA:
     573           60 :       TALER_denom_ewv_copy (&mh->melt_blinding_values[i],
     574              :                             TALER_denom_ewv_rsa_singleton ());
     575           60 :       break;
     576           60 :     case GNUNET_CRYPTO_BSA_CS:
     577           60 :       mh->no_blinding_seed = false;
     578           60 :       break;
     579              :     }
     580              :   }
     581           30 :   mh->keys = TALER_EXCHANGE_keys_incref (keys);
     582           30 :   return mh;
     583              : }
     584              : 
     585              : 
     586              : enum TALER_ErrorCode
     587           30 : TALER_EXCHANGE_post_melt_start (
     588              :   struct TALER_EXCHANGE_PostMeltHandle *mh,
     589              :   TALER_EXCHANGE_PostMeltCallback melt_cb,
     590              :   TALER_EXCHANGE_POST_MELT_RESULT_CLOSURE *melt_cb_cls)
     591              : {
     592           30 :   mh->melt_cb = melt_cb;
     593           30 :   mh->melt_cb_cls = melt_cb_cls;
     594              : 
     595           30 :   if (! mh->no_blinding_seed)
     596           15 :   {
     597           15 :     struct TALER_EXCHANGE_NonceKey nks[GNUNET_NZL (
     598              :                                          mh->rd->num_fresh_denom_pubs)];
     599           15 :     unsigned int nks_off = 0;
     600              : 
     601           75 :     for (unsigned int i = 0; i < mh->rd->num_fresh_denom_pubs; i++)
     602              :     {
     603           60 :       const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk =
     604           60 :         &mh->rd->fresh_denom_pubs[i];
     605              : 
     606           60 :       if (GNUNET_CRYPTO_BSA_CS ==
     607           60 :           fresh_pk->key.bsign_pub_key->cipher)
     608              :       {
     609           60 :         nks[nks_off].pk = fresh_pk;
     610           60 :         nks[nks_off].cnc_num = i;
     611           60 :         nks_off++;
     612              :       }
     613              :     }
     614           15 :     TALER_cs_refresh_seed_to_blinding_seed (
     615           15 :       &mh->rms,
     616           15 :       &mh->md.melted_coin.coin_priv,
     617              :       &mh->blinding_seed);
     618           15 :     mh->bpr = TALER_EXCHANGE_post_blinding_prepare_for_melt_create (
     619              :       mh->cctx,
     620              :       mh->exchange_url,
     621              :       &mh->blinding_seed,
     622              :       nks_off,
     623              :       nks);
     624           15 :     if (NULL == mh->bpr)
     625              :     {
     626            0 :       GNUNET_break (0);
     627            0 :       return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     628              :     }
     629              :     {
     630              :       enum TALER_ErrorCode ec;
     631              : 
     632           15 :       ec = TALER_EXCHANGE_post_blinding_prepare_start (mh->bpr,
     633              :                                                        &blinding_prepare_cb,
     634              :                                                        mh);
     635           15 :       if (TALER_EC_NONE != ec)
     636              :       {
     637            0 :         GNUNET_break (0);
     638            0 :         TALER_EXCHANGE_post_blinding_prepare_cancel (mh->bpr);
     639            0 :         mh->bpr = NULL;
     640            0 :         return ec;
     641              :       }
     642              :     }
     643           15 :     return TALER_EC_NONE;
     644              :   }
     645           15 :   if (GNUNET_OK !=
     646           15 :       start_melt (mh))
     647              :   {
     648            0 :     GNUNET_break (0);
     649            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     650              :   }
     651           15 :   return TALER_EC_NONE;
     652              : }
     653              : 
     654              : 
     655              : void
     656           30 : TALER_EXCHANGE_post_melt_cancel (struct TALER_EXCHANGE_PostMeltHandle *mh)
     657              : {
     658          150 :   for (unsigned int i = 0; i < mh->rd->num_fresh_denom_pubs; i++)
     659          120 :     TALER_denom_ewv_free (&mh->melt_blinding_values[i]);
     660           30 :   if (NULL != mh->job)
     661              :   {
     662            0 :     GNUNET_CURL_job_cancel (mh->job);
     663            0 :     mh->job = NULL;
     664              :   }
     665           30 :   if (NULL != mh->bpr)
     666              :   {
     667            0 :     TALER_EXCHANGE_post_blinding_prepare_cancel (mh->bpr);
     668            0 :     mh->bpr = NULL;
     669              :   }
     670           30 :   TALER_EXCHANGE_free_melt_data (&mh->md); /* does not free 'md' itself */
     671           30 :   GNUNET_free (mh->melt_blinding_values);
     672           30 :   GNUNET_free (mh->url);
     673           30 :   GNUNET_free (mh->exchange_url);
     674           30 :   TALER_curl_easy_post_finished (&mh->ctx);
     675           30 :   TALER_EXCHANGE_keys_decref (mh->keys);
     676           30 :   GNUNET_free (mh);
     677           30 : }
     678              : 
     679              : 
     680              : /* end of exchange_api_melt.c */
        

Generated by: LCOV version 2.0-1