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 }