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