LCOV - code coverage report
Current view: top level - lib - exchange_api_refresh_common.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 117 133 88.0 %
Date: 2025-06-05 21:03:14 Functions: 2 2 100.0 %

          Line data    Source code
       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 "platform.h"
      24             : #include "exchange_api_refresh_common.h"
      25             : 
      26             : 
      27             : void
      28          44 : TALER_EXCHANGE_free_melt_data_v27 (struct MeltData_v27 *md)
      29             : {
      30         176 :   for (unsigned int k = 0; k < TALER_CNC_KAPPA; k++)
      31             :   {
      32         660 :     for (unsigned int i = 0; i < md->num_fresh_coins; i++)
      33         528 :       TALER_blinded_planchet_free (&md->kappa_blinded_planchets[k][i]);
      34         132 :     GNUNET_free (md->kappa_blinded_planchets[k]);
      35             :   }
      36          44 :   GNUNET_free (md->denoms_h);
      37          44 :   GNUNET_free (md->denom_pubs);
      38          44 :   TALER_denom_pub_free (&md->melted_coin.pub_key);
      39          44 :   TALER_denom_sig_free (&md->melted_coin.sig);
      40          44 :   if (NULL != md->fcds)
      41             :   {
      42         220 :     for (unsigned int j = 0; j<md->num_fresh_coins; j++)
      43             :     {
      44         176 :       struct FreshCoinData *fcd = &md->fcds[j];
      45             : 
      46         176 :       TALER_denom_pub_free (&fcd->fresh_pk);
      47         704 :       for (size_t i = 0; i < TALER_CNC_KAPPA; i++)
      48             :       {
      49         528 :         TALER_age_commitment_proof_free (fcd->age_commitment_proofs[i]);
      50         528 :         GNUNET_free (fcd->age_commitment_proofs[i]);
      51             :       }
      52             :     }
      53          44 :     GNUNET_free (md->fcds);
      54             :   }
      55             :   /* Finally, clean up a bit... */
      56          44 :   GNUNET_CRYPTO_zero_keys (md,
      57             :                            sizeof (struct MeltData_v27));
      58          44 : }
      59             : 
      60             : 
      61             : enum GNUNET_GenericReturnValue
      62          44 : 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          44 : {
      69             :   struct TALER_Amount total;
      70             :   struct TALER_CoinSpendPublicKeyP coin_pub;
      71             :   struct TALER_KappaHashBlindedPlanchetsP k_h_bps;
      72          44 :   union GNUNET_CRYPTO_BlindSessionNonce nonces[rd->num_fresh_denom_pubs];
      73          44 :   const struct TALER_DenominationHashP *denoms_h[rd->num_fresh_denom_pubs];
      74          44 :   bool is_cs[rd->num_fresh_denom_pubs];
      75          44 :   bool uses_cs = false;
      76             : 
      77          44 :   GNUNET_CRYPTO_eddsa_key_get_public (&rd->melt_priv.eddsa_priv,
      78             :                                       &coin_pub.eddsa_pub);
      79          44 :   memset (md,
      80             :           0,
      81             :           sizeof (*md));
      82             :   /* build up melt data structure */
      83          44 :   md->num_fresh_coins = rd->num_fresh_denom_pubs;
      84          44 :   md->melted_coin.coin_priv = rd->melt_priv;
      85          44 :   md->melted_coin.melt_amount_with_fee = rd->melt_amount;
      86          44 :   md->melted_coin.fee_melt = rd->melt_pk.fees.refresh;
      87          44 :   md->melted_coin.original_value = rd->melt_pk.value;
      88          44 :   md->melted_coin.expire_deposit = rd->melt_pk.expire_deposit;
      89          44 :   md->melted_coin.age_commitment_proof = rd->melt_age_commitment_proof;
      90          44 :   md->melted_coin.h_age_commitment = rd->melt_h_age_commitment;
      91          44 :   md->no_blinding_seed = (NULL == blinding_seed);
      92          44 :   if (NULL != blinding_seed)
      93          22 :     md->blinding_seed = *blinding_seed;
      94             : 
      95          44 :   GNUNET_assert (GNUNET_OK ==
      96             :                  TALER_amount_set_zero (rd->melt_amount.currency,
      97             :                                         &total));
      98          44 :   TALER_denom_pub_copy (&md->melted_coin.pub_key,
      99             :                         &rd->melt_pk.key);
     100          44 :   TALER_denom_sig_copy (&md->melted_coin.sig,
     101             :                         &rd->melt_sig);
     102          44 :   md->fcds = GNUNET_new_array (md->num_fresh_coins,
     103             :                                struct FreshCoinData);
     104          44 :   md->denoms_h =
     105          44 :     GNUNET_new_array (md->num_fresh_coins,
     106             :                       struct  TALER_DenominationHashP);
     107          44 :   md->denom_pubs =
     108          44 :     GNUNET_new_array (md->num_fresh_coins,
     109             :                       const struct  TALER_DenominationPublicKey*);
     110             : 
     111         220 :   for (unsigned int j = 0; j<rd->num_fresh_denom_pubs; j++)
     112             :   {
     113         176 :     struct FreshCoinData *fcd = &md->fcds[j];
     114             : 
     115         176 :     denoms_h[j] = &rd->fresh_denom_pubs[j].h_key;
     116         176 :     md->denoms_h[j] = rd->fresh_denom_pubs[j].h_key;
     117         176 :     md->denom_pubs[j] = &rd->fresh_denom_pubs[j].key;
     118             : 
     119         176 :     TALER_denom_pub_copy (&fcd->fresh_pk,
     120         176 :                           &rd->fresh_denom_pubs[j].key);
     121         176 :     GNUNET_assert (NULL != fcd->fresh_pk.bsign_pub_key);
     122         176 :     if (blinding_values[j].blinding_inputs->cipher !=
     123         176 :         fcd->fresh_pk.bsign_pub_key->cipher)
     124             :     {
     125           0 :       GNUNET_break (0);
     126           0 :       TALER_EXCHANGE_free_melt_data_v27 (md);
     127           0 :       return GNUNET_SYSERR;
     128             :     }
     129         176 :     switch (fcd->fresh_pk.bsign_pub_key->cipher)
     130             :     {
     131           0 :     case GNUNET_CRYPTO_BSA_INVALID:
     132           0 :       GNUNET_break (0);
     133           0 :       TALER_EXCHANGE_free_melt_data_v27 (md);
     134           0 :       return GNUNET_SYSERR;
     135          88 :     case GNUNET_CRYPTO_BSA_RSA:
     136          88 :       is_cs[j] = false;
     137          88 :       break;
     138          88 :     case GNUNET_CRYPTO_BSA_CS:
     139          88 :       uses_cs = true;
     140          88 :       is_cs[j] = true;
     141          88 :       break;
     142             :     }
     143         176 :     if ( (0 >
     144         176 :           TALER_amount_add (&total,
     145             :                             &total,
     146         352 :                             &rd->fresh_denom_pubs[j].value)) ||
     147             :          (0 >
     148         176 :           TALER_amount_add (&total,
     149             :                             &total,
     150         176 :                             &rd->fresh_denom_pubs[j].fees.withdraw)) )
     151             :     {
     152           0 :       GNUNET_break (0);
     153           0 :       TALER_EXCHANGE_free_melt_data_v27 (md);
     154           0 :       return GNUNET_SYSERR;
     155             :     }
     156             :   }
     157             : 
     158             :   /* verify that melt_amount is above total cost */
     159          44 :   if (1 ==
     160          44 :       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           0 :     GNUNET_break (0);
     166           0 :     TALER_EXCHANGE_free_melt_data_v27 (md);
     167           0 :     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          44 :   memset (nonces,
     176             :           0,
     177             :           sizeof(*nonces));
     178          44 :   if (uses_cs)
     179             :   {
     180          22 :     GNUNET_assert (! md->no_blinding_seed);
     181          22 :     TALER_cs_derive_blind_nonces_from_seed (
     182             :       blinding_seed,
     183             :       true, /* for melt */
     184          22 :       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          44 :   TALER_refresh_master_secret_to_refresh_seed (
     193             :     rms,
     194             :     &md->refresh_seed);
     195          44 :   TALER_refresh_expand_kappa_nonces (
     196          44 :     &md->refresh_seed,
     197             :     &md->kappa_nonces);
     198             :   /**
     199             :    * Build up all candidates for coin planchets
     200             :    */
     201         176 :   for (unsigned int k = 0; k<TALER_CNC_KAPPA; k++)
     202         132 :   {
     203             :     struct TALER_PlanchetMasterSecretP
     204         132 :       planchet_secrets[rd->num_fresh_denom_pubs];
     205         132 :     struct TALER_PlanchetDetail planchet_details[rd->num_fresh_denom_pubs];
     206             : 
     207         132 :     TALER_wallet_refresh_nonce_sign (
     208             :       &rd->melt_priv,
     209         132 :       &md->kappa_nonces.tuple[k],
     210         132 :       rd->num_fresh_denom_pubs,
     211             :       denoms_h,
     212             :       k,
     213             :       &md->signatures[k]);
     214         132 :     TALER_refresh_signature_to_secrets (
     215         132 :       &md->signatures[k],
     216         132 :       rd->num_fresh_denom_pubs,
     217             :       planchet_secrets);
     218             : 
     219         132 :     md->kappa_blinded_planchets[k] =
     220         132 :       GNUNET_new_array (rd->num_fresh_denom_pubs,
     221             :                         struct  TALER_BlindedPlanchet);
     222             : 
     223         660 :     for (unsigned int j = 0; j<rd->num_fresh_denom_pubs; j++)
     224             :     {
     225         528 :       struct FreshCoinData *fcd = &md->fcds[j];
     226         528 :       struct TALER_CoinSpendPrivateKeyP *coin_priv = &fcd->coin_priv;
     227         528 :       union GNUNET_CRYPTO_BlindingSecretP *bks = &fcd->bks[k];
     228             :       struct TALER_CoinPubHashP c_hash;
     229             :       struct TALER_AgeCommitmentHash ach;
     230             :       struct TALER_AgeCommitmentHash *pah;
     231             : 
     232         528 :       fcd->ps[k] = planchet_secrets[j];
     233         528 :       TALER_planchet_setup_coin_priv (&planchet_secrets[j],
     234         528 :                                       &blinding_values[j],
     235             :                                       coin_priv);
     236         528 :       TALER_planchet_blinding_secret_create (&planchet_secrets[j],
     237         528 :                                              &blinding_values[j],
     238             :                                              bks);
     239         528 :       if (NULL != rd->melt_age_commitment_proof)
     240             :       {
     241         288 :         fcd->age_commitment_proofs[k] = GNUNET_new (struct
     242             :                                                     TALER_AgeCommitmentProof);
     243         288 :         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         288 :         TALER_age_commitment_hash (
     249         288 :           &fcd->age_commitment_proofs[k]->commitment,
     250             :           &ach);
     251         288 :         pah = &ach;
     252             :       }
     253             :       else
     254             :       {
     255         240 :         pah = NULL;
     256             :       }
     257             : 
     258         528 :       if (GNUNET_OK !=
     259         528 :           TALER_planchet_prepare (&fcd->fresh_pk,
     260         528 :                                   &blinding_values[j],
     261             :                                   bks,
     262         528 :                                   is_cs[j] ? &nonces[j] : NULL,
     263             :                                   coin_priv,
     264             :                                   pah,
     265             :                                   &c_hash,
     266             :                                   &planchet_details[j]))
     267             :       {
     268           0 :         GNUNET_break_op (0);
     269           0 :         TALER_EXCHANGE_free_melt_data_v27 (md);
     270           0 :         return GNUNET_SYSERR;
     271             :       }
     272         528 :       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         132 :     TALER_wallet_blinded_planchet_details_hash (
     279         132 :       rd->num_fresh_denom_pubs,
     280             :       planchet_details,
     281             :       &k_h_bps.tuple[k]);
     282             :   }
     283             : 
     284             :   /* Finally, compute refresh commitment */
     285          44 :   TALER_refresh_get_commitment_v27 (&md->rc,
     286          44 :                                     &md->refresh_seed,
     287             :                                     uses_cs
     288             :                                          ? &md->blinding_seed
     289             :                                          : NULL,
     290             :                                     &k_h_bps,
     291             :                                     &coin_pub,
     292             :                                     &rd->melt_amount);
     293          44 :   return GNUNET_OK;
     294             : }

Generated by: LCOV version 1.16