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 (10066B)


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