exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

exchange_api_refresh_common.c (10094B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2015-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_refresh_common.c
     19  * @brief Serialization logic shared between melt and reveal steps during refreshing
     20  * @author Christian Grothoff
     21  * @author Özgür Kesim
     22  */
     23 #include "taler/platform.h"
     24 #include "exchange_api_refresh_common.h"
     25 
     26 
     27 void
     28 TALER_EXCHANGE_free_melt_data (struct MeltData *md)
     29 {
     30   for (unsigned int k = 0; k < TALER_CNC_KAPPA; k++)
     31   {
     32     for (unsigned int i = 0; i < md->num_fresh_coins; i++)
     33       TALER_blinded_planchet_free (&md->kappa_blinded_planchets[k][i]);
     34     GNUNET_free (md->kappa_blinded_planchets[k]);
     35     GNUNET_free (md->kappa_transfer_pubs[k]);
     36   }
     37   GNUNET_free (md->denoms_h);
     38   GNUNET_free (md->denom_pubs);
     39   TALER_denom_pub_free (&md->melted_coin.pub_key);
     40   TALER_denom_sig_free (&md->melted_coin.sig);
     41   if (NULL != md->fcds)
     42   {
     43     for (unsigned int j = 0; j<md->num_fresh_coins; j++)
     44     {
     45       struct FreshCoinData *fcd = &md->fcds[j];
     46 
     47       TALER_denom_pub_free (&fcd->fresh_pk);
     48       for (size_t i = 0; i < TALER_CNC_KAPPA; i++)
     49       {
     50         TALER_age_commitment_proof_free (fcd->age_commitment_proofs[i]);
     51         GNUNET_free (fcd->age_commitment_proofs[i]);
     52       }
     53     }
     54     GNUNET_free (md->fcds);
     55   }
     56   /* Finally, clean up a bit... */
     57   GNUNET_CRYPTO_zero_keys (md,
     58                            sizeof (struct MeltData));
     59 }
     60 
     61 
     62 enum GNUNET_GenericReturnValue
     63 TALER_EXCHANGE_get_melt_data (
     64   const struct TALER_PublicRefreshMasterSeedP *rms,
     65   const struct TALER_EXCHANGE_MeltInput *rd,
     66   const struct TALER_BlindingMasterSeedP *blinding_seed,
     67   const struct TALER_ExchangeBlindingValues *blinding_values,
     68   struct MeltData *md)
     69 {
     70   struct TALER_Amount total;
     71   struct TALER_CoinSpendPublicKeyP coin_pub;
     72   struct TALER_KappaHashBlindedPlanchetsP k_h_bps;
     73   union GNUNET_CRYPTO_BlindSessionNonce nonces[rd->num_fresh_denom_pubs];
     74   bool is_cs[rd->num_fresh_denom_pubs];
     75   bool uses_cs = false;
     76 
     77   GNUNET_CRYPTO_eddsa_key_get_public (&rd->melt_priv.eddsa_priv,
     78                                       &coin_pub.eddsa_pub);
     79   memset (md,
     80           0,
     81           sizeof (*md));
     82   /* build up melt data structure */
     83   md->refresh_seed = *rms;
     84   md->num_fresh_coins = rd->num_fresh_denom_pubs;
     85   md->melted_coin.coin_priv = rd->melt_priv;
     86   md->melted_coin.melt_amount_with_fee = rd->melt_amount;
     87   md->melted_coin.fee_melt = rd->melt_pk.fees.refresh;
     88   md->melted_coin.original_value = rd->melt_pk.value;
     89   md->melted_coin.expire_deposit = rd->melt_pk.expire_deposit;
     90   md->melted_coin.age_commitment_proof = rd->melt_age_commitment_proof;
     91   md->melted_coin.h_age_commitment = rd->melt_h_age_commitment;
     92   md->no_blinding_seed = (NULL == blinding_seed);
     93   if (NULL != blinding_seed)
     94     md->blinding_seed = *blinding_seed;
     95 
     96   GNUNET_assert (GNUNET_OK ==
     97                  TALER_amount_set_zero (rd->melt_amount.currency,
     98                                         &total));
     99   TALER_denom_pub_copy (&md->melted_coin.pub_key,
    100                         &rd->melt_pk.key);
    101   TALER_denom_sig_copy (&md->melted_coin.sig,
    102                         &rd->melt_sig);
    103   md->fcds = GNUNET_new_array (md->num_fresh_coins,
    104                                struct FreshCoinData);
    105   md->denoms_h =
    106     GNUNET_new_array (md->num_fresh_coins,
    107                       struct  TALER_DenominationHashP);
    108   md->denom_pubs =
    109     GNUNET_new_array (md->num_fresh_coins,
    110                       const struct  TALER_DenominationPublicKey*);
    111 
    112   for (unsigned int j = 0; j<md->num_fresh_coins; j++)
    113   {
    114     struct FreshCoinData *fcd = &md->fcds[j];
    115 
    116     md->denoms_h[j] = rd->fresh_denom_pubs[j].h_key;
    117     md->denom_pubs[j] = &rd->fresh_denom_pubs[j].key;
    118 
    119     TALER_denom_pub_copy (&fcd->fresh_pk,
    120                           &rd->fresh_denom_pubs[j].key);
    121     GNUNET_assert (NULL != fcd->fresh_pk.bsign_pub_key);
    122     if (blinding_values[j].blinding_inputs->cipher !=
    123         fcd->fresh_pk.bsign_pub_key->cipher)
    124     {
    125       GNUNET_break (0);
    126       TALER_EXCHANGE_free_melt_data (md);
    127       return GNUNET_SYSERR;
    128     }
    129     switch (fcd->fresh_pk.bsign_pub_key->cipher)
    130     {
    131     case GNUNET_CRYPTO_BSA_INVALID:
    132       GNUNET_break (0);
    133       TALER_EXCHANGE_free_melt_data (md);
    134       return GNUNET_SYSERR;
    135     case GNUNET_CRYPTO_BSA_RSA:
    136       is_cs[j] = false;
    137       break;
    138     case GNUNET_CRYPTO_BSA_CS:
    139       uses_cs = true;
    140       is_cs[j] = true;
    141       break;
    142     }
    143     if ( (0 >
    144           TALER_amount_add (&total,
    145                             &total,
    146                             &rd->fresh_denom_pubs[j].value)) ||
    147          (0 >
    148           TALER_amount_add (&total,
    149                             &total,
    150                             &rd->fresh_denom_pubs[j].fees.withdraw)) )
    151     {
    152       GNUNET_break (0);
    153       TALER_EXCHANGE_free_melt_data (md);
    154       return GNUNET_SYSERR;
    155     }
    156   }
    157 
    158   /* verify that melt_amount is above total cost */
    159   if (1 ==
    160       TALER_amount_cmp (&total,
    161                         &rd->melt_amount) )
    162   {
    163     /* Eh, this operation is more expensive than the
    164        @a melt_amount. This is not OK. */
    165     GNUNET_break (0);
    166     TALER_EXCHANGE_free_melt_data (md);
    167     return GNUNET_SYSERR;
    168   }
    169   /**
    170    * Generate the blinding seeds and nonces for CS.
    171    * Note that blinding_seed was prepared upstream,
    172    * in TALER_EXCHANGE_melt(), as preparation for
    173    * the request to `/blinding-prepare`.
    174    */
    175   memset (nonces,
    176           0,
    177           sizeof(*nonces));
    178   if (uses_cs)
    179   {
    180     GNUNET_assert (! md->no_blinding_seed);
    181     TALER_cs_derive_blind_nonces_from_seed (
    182       blinding_seed,
    183       true, /* for melt */
    184       md->num_fresh_coins,
    185       is_cs,
    186       nonces);
    187   }
    188   /**
    189    * Generate the kappa private seeds for the batches.
    190    */
    191   TALER_refresh_expand_seed_to_kappa_batch_seeds (
    192     &md->refresh_seed,
    193     &rd->melt_priv,
    194     &md->kappa_batch_seeds);
    195   /**
    196    * Build up all candidates for coin planchets
    197    */
    198   for (unsigned int k = 0; k<TALER_CNC_KAPPA; k++)
    199   {
    200     struct TALER_PlanchetMasterSecretP
    201       planchet_secrets[md->num_fresh_coins];
    202     struct TALER_PlanchetDetail planchet_details[md->num_fresh_coins];
    203 
    204     md->kappa_blinded_planchets[k] =
    205       GNUNET_new_array (md->num_fresh_coins,
    206                         struct TALER_BlindedPlanchet);
    207     md->kappa_transfer_pubs[k] =
    208       GNUNET_new_array (md->num_fresh_coins,
    209                         struct TALER_TransferPublicKeyP);
    210 
    211     TALER_refresh_expand_batch_seed_to_transfer_data (
    212       &md->kappa_batch_seeds.tuple[k],
    213       &coin_pub,
    214       md->num_fresh_coins,
    215       planchet_secrets,
    216       md->kappa_transfer_pubs[k]);
    217 
    218     for (unsigned int j = 0; j<md->num_fresh_coins; j++)
    219     {
    220       struct FreshCoinData *fcd = &md->fcds[j];
    221       struct TALER_CoinSpendPrivateKeyP *coin_priv = &fcd->coin_priv;
    222       union GNUNET_CRYPTO_BlindingSecretP *bks = &fcd->bks[k];
    223       struct TALER_CoinPubHashP c_hash;
    224       struct TALER_AgeCommitmentHashP ach;
    225       struct TALER_AgeCommitmentHashP *pah;
    226 
    227       fcd->ps[k] = planchet_secrets[j];
    228       TALER_planchet_setup_coin_priv (&planchet_secrets[j],
    229                                       &blinding_values[j],
    230                                       coin_priv);
    231       TALER_planchet_blinding_secret_create (&planchet_secrets[j],
    232                                              &blinding_values[j],
    233                                              bks);
    234       if (NULL != rd->melt_age_commitment_proof)
    235       {
    236         fcd->age_commitment_proofs[k] =
    237           GNUNET_new (struct TALER_AgeCommitmentProof);
    238         GNUNET_assert (GNUNET_OK ==
    239                        TALER_age_commitment_proof_derive_from_secret (
    240                          md->melted_coin.age_commitment_proof,
    241                          &planchet_secrets[j],
    242                          fcd->age_commitment_proofs[k]));
    243         TALER_age_commitment_hash (
    244           &fcd->age_commitment_proofs[k]->commitment,
    245           &ach);
    246         pah = &ach;
    247       }
    248       else
    249       {
    250         pah = NULL;
    251       }
    252 
    253       if (GNUNET_OK !=
    254           TALER_planchet_prepare (&fcd->fresh_pk,
    255                                   &blinding_values[j],
    256                                   bks,
    257                                   is_cs[j] ? &nonces[j] : NULL,
    258                                   coin_priv,
    259                                   pah,
    260                                   &c_hash,
    261                                   &planchet_details[j]))
    262       {
    263         GNUNET_break_op (0);
    264         TALER_EXCHANGE_free_melt_data (md);
    265         return GNUNET_SYSERR;
    266       }
    267       md->kappa_blinded_planchets[k][j] =
    268         planchet_details[j].blinded_planchet;
    269     }
    270     /**
    271      * Compute the hash of this batch of blinded planchets
    272      */
    273     TALER_wallet_blinded_planchet_details_hash (
    274       rd->num_fresh_denom_pubs,
    275       planchet_details,
    276       &k_h_bps.tuple[k]);
    277   }
    278 
    279   /* Finally, compute refresh commitment */
    280   {
    281     struct TALER_KappaTransferPublicKeys k_tr_pubs = {
    282       .num_transfer_pubs = md->num_fresh_coins,
    283     };
    284 
    285     for (uint8_t k=0; k<TALER_CNC_KAPPA; k++)
    286       k_tr_pubs.batch[k] = md->kappa_transfer_pubs[k];
    287 
    288     TALER_refresh_get_commitment (&md->rc,
    289                                   &md->refresh_seed,
    290                                   uses_cs
    291                                          ? &md->blinding_seed
    292                                          : NULL,
    293                                   &k_tr_pubs,
    294                                   &k_h_bps,
    295                                   &coin_pub,
    296                                   &rd->melt_amount);
    297   }
    298   return GNUNET_OK;
    299 }