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


      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_v27 (struct MeltData_v27 *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   }
     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_v27));
     58 }
     59 
     60 
     61 enum GNUNET_GenericReturnValue
     62 TALER_EXCHANGE_get_melt_data_v27 (
     63   const struct TALER_RefreshMasterSecretP *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_v27 *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   const struct TALER_DenominationHashP *denoms_h[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->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<rd->num_fresh_denom_pubs; j++)
    112   {
    113     struct FreshCoinData *fcd = &md->fcds[j];
    114 
    115     denoms_h[j] = &rd->fresh_denom_pubs[j].h_key;
    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_v27 (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_v27 (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_v27 (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_v27 (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_v27(), 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       rd->num_fresh_denom_pubs,
    185       is_cs,
    186       nonces);
    187   }
    188   /**
    189    * Generate from the master secret the refresh seed
    190    * and kappa nonces
    191    */
    192   TALER_refresh_master_secret_to_refresh_seed (
    193     rms,
    194     &md->refresh_seed);
    195   TALER_refresh_expand_kappa_nonces (
    196     &md->refresh_seed,
    197     &md->kappa_nonces);
    198   /**
    199    * Build up all candidates for coin planchets
    200    */
    201   for (unsigned int k = 0; k<TALER_CNC_KAPPA; k++)
    202   {
    203     struct TALER_PlanchetMasterSecretP
    204       planchet_secrets[rd->num_fresh_denom_pubs];
    205     struct TALER_PlanchetDetail planchet_details[rd->num_fresh_denom_pubs];
    206 
    207     TALER_wallet_refresh_nonce_sign (
    208       &rd->melt_priv,
    209       &md->kappa_nonces.tuple[k],
    210       rd->num_fresh_denom_pubs,
    211       denoms_h,
    212       k,
    213       &md->signatures[k]);
    214     TALER_refresh_signature_to_secrets (
    215       &md->signatures[k],
    216       rd->num_fresh_denom_pubs,
    217       planchet_secrets);
    218 
    219     md->kappa_blinded_planchets[k] =
    220       GNUNET_new_array (rd->num_fresh_denom_pubs,
    221                         struct  TALER_BlindedPlanchet);
    222 
    223     for (unsigned int j = 0; j<rd->num_fresh_denom_pubs; j++)
    224     {
    225       struct FreshCoinData *fcd = &md->fcds[j];
    226       struct TALER_CoinSpendPrivateKeyP *coin_priv = &fcd->coin_priv;
    227       union GNUNET_CRYPTO_BlindingSecretP *bks = &fcd->bks[k];
    228       struct TALER_CoinPubHashP c_hash;
    229       struct TALER_AgeCommitmentHashP ach;
    230       struct TALER_AgeCommitmentHashP *pah;
    231 
    232       fcd->ps[k] = planchet_secrets[j];
    233       TALER_planchet_setup_coin_priv (&planchet_secrets[j],
    234                                       &blinding_values[j],
    235                                       coin_priv);
    236       TALER_planchet_blinding_secret_create (&planchet_secrets[j],
    237                                              &blinding_values[j],
    238                                              bks);
    239       if (NULL != rd->melt_age_commitment_proof)
    240       {
    241         fcd->age_commitment_proofs[k] = GNUNET_new (struct
    242                                                     TALER_AgeCommitmentProof);
    243         GNUNET_assert (GNUNET_OK ==
    244                        TALER_age_commitment_proof_derive_from_secret (
    245                          md->melted_coin.age_commitment_proof,
    246                          &planchet_secrets[j],
    247                          fcd->age_commitment_proofs[k]));
    248         TALER_age_commitment_hash (
    249           &fcd->age_commitment_proofs[k]->commitment,
    250           &ach);
    251         pah = &ach;
    252       }
    253       else
    254       {
    255         pah = NULL;
    256       }
    257 
    258       if (GNUNET_OK !=
    259           TALER_planchet_prepare (&fcd->fresh_pk,
    260                                   &blinding_values[j],
    261                                   bks,
    262                                   is_cs[j] ? &nonces[j] : NULL,
    263                                   coin_priv,
    264                                   pah,
    265                                   &c_hash,
    266                                   &planchet_details[j]))
    267       {
    268         GNUNET_break_op (0);
    269         TALER_EXCHANGE_free_melt_data_v27 (md);
    270         return GNUNET_SYSERR;
    271       }
    272       md->kappa_blinded_planchets[k][j] =
    273         planchet_details[j].blinded_planchet;
    274     }
    275     /**
    276      * Compute the hash of this batch of blinded planchets
    277      */
    278     TALER_wallet_blinded_planchet_details_hash (
    279       rd->num_fresh_denom_pubs,
    280       planchet_details,
    281       &k_h_bps.tuple[k]);
    282   }
    283 
    284   /* Finally, compute refresh commitment */
    285   TALER_refresh_get_commitment_v27 (&md->rc,
    286                                     &md->refresh_seed,
    287                                     uses_cs
    288                                          ? &md->blinding_seed
    289                                          : NULL,
    290                                     &k_h_bps,
    291                                     &coin_pub,
    292                                     &rd->melt_amount);
    293   return GNUNET_OK;
    294 }