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 }