LCOV - code coverage report
Current view: top level - lib - exchange_api_refresh_common.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 88.2 % 136 120
Test Date: 2026-01-04 22:17:00 Functions: 100.0 % 2 2

            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 "taler/platform.h"
      24              : #include "exchange_api_refresh_common.h"
      25              : 
      26              : 
      27              : void
      28           44 : TALER_EXCHANGE_free_melt_data (struct MeltData *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          132 :     GNUNET_free (md->kappa_transfer_pubs[k]);
      36              :   }
      37           44 :   GNUNET_free (md->denoms_h);
      38           44 :   GNUNET_free (md->denom_pubs);
      39           44 :   TALER_denom_pub_free (&md->melted_coin.pub_key);
      40           44 :   TALER_denom_sig_free (&md->melted_coin.sig);
      41           44 :   if (NULL != md->fcds)
      42              :   {
      43          220 :     for (unsigned int j = 0; j<md->num_fresh_coins; j++)
      44              :     {
      45          176 :       struct FreshCoinData *fcd = &md->fcds[j];
      46              : 
      47          176 :       TALER_denom_pub_free (&fcd->fresh_pk);
      48          704 :       for (size_t i = 0; i < TALER_CNC_KAPPA; i++)
      49              :       {
      50          528 :         TALER_age_commitment_proof_free (fcd->age_commitment_proofs[i]);
      51          528 :         GNUNET_free (fcd->age_commitment_proofs[i]);
      52              :       }
      53              :     }
      54           44 :     GNUNET_free (md->fcds);
      55              :   }
      56              :   /* Finally, clean up a bit... */
      57           44 :   GNUNET_CRYPTO_zero_keys (md,
      58              :                            sizeof (struct MeltData));
      59           44 : }
      60              : 
      61              : 
      62              : enum GNUNET_GenericReturnValue
      63           44 : 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           44 : {
      70              :   struct TALER_Amount total;
      71              :   struct TALER_CoinSpendPublicKeyP coin_pub;
      72              :   struct TALER_KappaHashBlindedPlanchetsP k_h_bps;
      73           44 :   union GNUNET_CRYPTO_BlindSessionNonce nonces[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->refresh_seed = *rms;
      84           44 :   md->num_fresh_coins = rd->num_fresh_denom_pubs;
      85           44 :   md->melted_coin.coin_priv = rd->melt_priv;
      86           44 :   md->melted_coin.melt_amount_with_fee = rd->melt_amount;
      87           44 :   md->melted_coin.fee_melt = rd->melt_pk.fees.refresh;
      88           44 :   md->melted_coin.original_value = rd->melt_pk.value;
      89           44 :   md->melted_coin.expire_deposit = rd->melt_pk.expire_deposit;
      90           44 :   md->melted_coin.age_commitment_proof = rd->melt_age_commitment_proof;
      91           44 :   md->melted_coin.h_age_commitment = rd->melt_h_age_commitment;
      92           44 :   md->no_blinding_seed = (NULL == blinding_seed);
      93           44 :   if (NULL != blinding_seed)
      94           22 :     md->blinding_seed = *blinding_seed;
      95              : 
      96           44 :   GNUNET_assert (GNUNET_OK ==
      97              :                  TALER_amount_set_zero (rd->melt_amount.currency,
      98              :                                         &total));
      99           44 :   TALER_denom_pub_copy (&md->melted_coin.pub_key,
     100              :                         &rd->melt_pk.key);
     101           44 :   TALER_denom_sig_copy (&md->melted_coin.sig,
     102              :                         &rd->melt_sig);
     103           44 :   md->fcds = GNUNET_new_array (md->num_fresh_coins,
     104              :                                struct FreshCoinData);
     105           44 :   md->denoms_h =
     106           44 :     GNUNET_new_array (md->num_fresh_coins,
     107              :                       struct  TALER_DenominationHashP);
     108           44 :   md->denom_pubs =
     109           44 :     GNUNET_new_array (md->num_fresh_coins,
     110              :                       const struct  TALER_DenominationPublicKey*);
     111              : 
     112          220 :   for (unsigned int j = 0; j<md->num_fresh_coins; j++)
     113              :   {
     114          176 :     struct FreshCoinData *fcd = &md->fcds[j];
     115              : 
     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 (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 (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 (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 (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(), 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 :       md->num_fresh_coins,
     185              :       is_cs,
     186              :       nonces);
     187              :   }
     188              :   /**
     189              :    * Generate the kappa private seeds for the batches.
     190              :    */
     191           44 :   TALER_refresh_expand_seed_to_kappa_batch_seeds (
     192           44 :     &md->refresh_seed,
     193              :     &rd->melt_priv,
     194              :     &md->kappa_batch_seeds);
     195              :   /**
     196              :    * Build up all candidates for coin planchets
     197              :    */
     198          176 :   for (unsigned int k = 0; k<TALER_CNC_KAPPA; k++)
     199          132 :   {
     200              :     struct TALER_PlanchetMasterSecretP
     201          132 :       planchet_secrets[md->num_fresh_coins];
     202          132 :     struct TALER_PlanchetDetail planchet_details[md->num_fresh_coins];
     203              : 
     204          132 :     md->kappa_blinded_planchets[k] =
     205          132 :       GNUNET_new_array (md->num_fresh_coins,
     206              :                         struct TALER_BlindedPlanchet);
     207          132 :     md->kappa_transfer_pubs[k] =
     208          132 :       GNUNET_new_array (md->num_fresh_coins,
     209              :                         struct TALER_TransferPublicKeyP);
     210              : 
     211          132 :     TALER_refresh_expand_batch_seed_to_transfer_data (
     212          132 :       &md->kappa_batch_seeds.tuple[k],
     213              :       &coin_pub,
     214          132 :       md->num_fresh_coins,
     215              :       planchet_secrets,
     216              :       md->kappa_transfer_pubs[k]);
     217              : 
     218          660 :     for (unsigned int j = 0; j<md->num_fresh_coins; j++)
     219              :     {
     220          528 :       struct FreshCoinData *fcd = &md->fcds[j];
     221          528 :       struct TALER_CoinSpendPrivateKeyP *coin_priv = &fcd->coin_priv;
     222          528 :       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          528 :       fcd->ps[k] = planchet_secrets[j];
     228          528 :       TALER_planchet_setup_coin_priv (&planchet_secrets[j],
     229          528 :                                       &blinding_values[j],
     230              :                                       coin_priv);
     231          528 :       TALER_planchet_blinding_secret_create (&planchet_secrets[j],
     232          528 :                                              &blinding_values[j],
     233              :                                              bks);
     234          528 :       if (NULL != rd->melt_age_commitment_proof)
     235              :       {
     236          288 :         fcd->age_commitment_proofs[k] =
     237          288 :           GNUNET_new (struct TALER_AgeCommitmentProof);
     238          288 :         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          288 :         TALER_age_commitment_hash (
     244          288 :           &fcd->age_commitment_proofs[k]->commitment,
     245              :           &ach);
     246          288 :         pah = &ach;
     247              :       }
     248              :       else
     249              :       {
     250          240 :         pah = NULL;
     251              :       }
     252              : 
     253          528 :       if (GNUNET_OK !=
     254          528 :           TALER_planchet_prepare (&fcd->fresh_pk,
     255          528 :                                   &blinding_values[j],
     256              :                                   bks,
     257          528 :                                   is_cs[j] ? &nonces[j] : NULL,
     258              :                                   coin_priv,
     259              :                                   pah,
     260              :                                   &c_hash,
     261              :                                   &planchet_details[j]))
     262              :       {
     263            0 :         GNUNET_break_op (0);
     264            0 :         TALER_EXCHANGE_free_melt_data (md);
     265            0 :         return GNUNET_SYSERR;
     266              :       }
     267          528 :       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          132 :     TALER_wallet_blinded_planchet_details_hash (
     274          132 :       rd->num_fresh_denom_pubs,
     275              :       planchet_details,
     276              :       &k_h_bps.tuple[k]);
     277              :   }
     278              : 
     279              :   /* Finally, compute refresh commitment */
     280              :   {
     281           44 :     struct TALER_KappaTransferPublicKeys k_tr_pubs = {
     282           44 :       .num_transfer_pubs = md->num_fresh_coins,
     283              :     };
     284              : 
     285          176 :     for (uint8_t k=0; k<TALER_CNC_KAPPA; k++)
     286          132 :       k_tr_pubs.batch[k] = md->kappa_transfer_pubs[k];
     287              : 
     288           44 :     TALER_refresh_get_commitment (&md->rc,
     289           44 :                                   &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           44 :   return GNUNET_OK;
     299              : }
        

Generated by: LCOV version 2.0-1