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 "exchange_api_refresh_common.h"
24 :
25 :
26 : void
27 44 : TALER_EXCHANGE_free_melt_data (struct MeltData *md)
28 : {
29 176 : for (unsigned int k = 0; k < TALER_CNC_KAPPA; k++)
30 : {
31 660 : for (unsigned int i = 0; i < md->num_fresh_coins; i++)
32 528 : TALER_blinded_planchet_free (&md->kappa_blinded_planchets[k][i]);
33 132 : GNUNET_free (md->kappa_blinded_planchets[k]);
34 132 : GNUNET_free (md->kappa_transfer_pubs[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));
58 44 : }
59 :
60 :
61 : enum GNUNET_GenericReturnValue
62 44 : 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 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 : bool is_cs[rd->num_fresh_denom_pubs];
74 44 : bool uses_cs = false;
75 :
76 44 : GNUNET_CRYPTO_eddsa_key_get_public (&rd->melt_priv.eddsa_priv,
77 : &coin_pub.eddsa_pub);
78 44 : memset (md,
79 : 0,
80 : sizeof (*md));
81 : /* build up melt data structure */
82 44 : md->refresh_seed = *rms;
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<md->num_fresh_coins; j++)
112 : {
113 176 : struct FreshCoinData *fcd = &md->fcds[j];
114 :
115 176 : md->denoms_h[j] = rd->fresh_denom_pubs[j].h_key;
116 176 : md->denom_pubs[j] = &rd->fresh_denom_pubs[j].key;
117 :
118 176 : TALER_denom_pub_copy (&fcd->fresh_pk,
119 176 : &rd->fresh_denom_pubs[j].key);
120 176 : GNUNET_assert (NULL != fcd->fresh_pk.bsign_pub_key);
121 176 : if (blinding_values[j].blinding_inputs->cipher !=
122 176 : fcd->fresh_pk.bsign_pub_key->cipher)
123 : {
124 0 : GNUNET_break (0);
125 0 : TALER_EXCHANGE_free_melt_data (md);
126 0 : return GNUNET_SYSERR;
127 : }
128 176 : switch (fcd->fresh_pk.bsign_pub_key->cipher)
129 : {
130 0 : case GNUNET_CRYPTO_BSA_INVALID:
131 0 : GNUNET_break (0);
132 0 : TALER_EXCHANGE_free_melt_data (md);
133 0 : return GNUNET_SYSERR;
134 88 : case GNUNET_CRYPTO_BSA_RSA:
135 88 : is_cs[j] = false;
136 88 : break;
137 88 : case GNUNET_CRYPTO_BSA_CS:
138 88 : uses_cs = true;
139 88 : is_cs[j] = true;
140 88 : break;
141 : }
142 176 : if ( (0 >
143 176 : TALER_amount_add (&total,
144 : &total,
145 352 : &rd->fresh_denom_pubs[j].value)) ||
146 : (0 >
147 176 : TALER_amount_add (&total,
148 : &total,
149 176 : &rd->fresh_denom_pubs[j].fees.withdraw)) )
150 : {
151 0 : GNUNET_break (0);
152 0 : TALER_EXCHANGE_free_melt_data (md);
153 0 : return GNUNET_SYSERR;
154 : }
155 : }
156 :
157 : /* verify that melt_amount is above total cost */
158 44 : if (1 ==
159 44 : 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 0 : GNUNET_break (0);
165 0 : TALER_EXCHANGE_free_melt_data (md);
166 0 : 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 44 : memset (nonces,
175 : 0,
176 : sizeof(*nonces));
177 44 : if (uses_cs)
178 : {
179 22 : GNUNET_assert (! md->no_blinding_seed);
180 22 : TALER_cs_derive_blind_nonces_from_seed (
181 : blinding_seed,
182 : true, /* for melt */
183 22 : md->num_fresh_coins,
184 : is_cs,
185 : nonces);
186 : }
187 : /**
188 : * Generate the kappa private seeds for the batches.
189 : */
190 44 : TALER_refresh_expand_seed_to_kappa_batch_seeds (
191 44 : &md->refresh_seed,
192 : &rd->melt_priv,
193 : &md->kappa_batch_seeds);
194 : /**
195 : * Build up all candidates for coin planchets
196 : */
197 176 : for (unsigned int k = 0; k<TALER_CNC_KAPPA; k++)
198 132 : {
199 : struct TALER_PlanchetMasterSecretP
200 132 : planchet_secrets[md->num_fresh_coins];
201 132 : struct TALER_PlanchetDetail planchet_details[md->num_fresh_coins];
202 :
203 132 : md->kappa_blinded_planchets[k] =
204 132 : GNUNET_new_array (md->num_fresh_coins,
205 : struct TALER_BlindedPlanchet);
206 132 : md->kappa_transfer_pubs[k] =
207 132 : GNUNET_new_array (md->num_fresh_coins,
208 : struct TALER_TransferPublicKeyP);
209 :
210 132 : TALER_refresh_expand_batch_seed_to_transfer_data (
211 132 : &md->kappa_batch_seeds.tuple[k],
212 : &coin_pub,
213 132 : md->num_fresh_coins,
214 : planchet_secrets,
215 : md->kappa_transfer_pubs[k]);
216 :
217 660 : for (unsigned int j = 0; j<md->num_fresh_coins; j++)
218 : {
219 528 : struct FreshCoinData *fcd = &md->fcds[j];
220 528 : struct TALER_CoinSpendPrivateKeyP *coin_priv = &fcd->coin_priv;
221 528 : 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 528 : fcd->ps[k] = planchet_secrets[j];
227 528 : TALER_planchet_setup_coin_priv (&planchet_secrets[j],
228 528 : &blinding_values[j],
229 : coin_priv);
230 528 : TALER_planchet_blinding_secret_create (&planchet_secrets[j],
231 528 : &blinding_values[j],
232 : bks);
233 528 : if (NULL != rd->melt_age_commitment_proof)
234 : {
235 288 : fcd->age_commitment_proofs[k] =
236 288 : GNUNET_new (struct TALER_AgeCommitmentProof);
237 288 : 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 288 : TALER_age_commitment_hash (
243 288 : &fcd->age_commitment_proofs[k]->commitment,
244 : &ach);
245 288 : pah = &ach;
246 : }
247 : else
248 : {
249 240 : pah = NULL;
250 : }
251 :
252 528 : if (GNUNET_OK !=
253 528 : TALER_planchet_prepare (&fcd->fresh_pk,
254 528 : &blinding_values[j],
255 : bks,
256 528 : is_cs[j] ? &nonces[j] : NULL,
257 : coin_priv,
258 : pah,
259 : &c_hash,
260 : &planchet_details[j]))
261 : {
262 0 : GNUNET_break_op (0);
263 0 : TALER_EXCHANGE_free_melt_data (md);
264 0 : return GNUNET_SYSERR;
265 : }
266 528 : 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 132 : TALER_wallet_blinded_planchet_details_hash (
273 132 : rd->num_fresh_denom_pubs,
274 : planchet_details,
275 : &k_h_bps.tuple[k]);
276 : }
277 :
278 : /* Finally, compute refresh commitment */
279 : {
280 44 : struct TALER_KappaTransferPublicKeys k_tr_pubs = {
281 44 : .num_transfer_pubs = md->num_fresh_coins,
282 : };
283 :
284 176 : for (uint8_t k=0; k<TALER_CNC_KAPPA; k++)
285 132 : k_tr_pubs.batch[k] = md->kappa_transfer_pubs[k];
286 :
287 44 : TALER_refresh_get_commitment (&md->rc,
288 44 : &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 44 : return GNUNET_OK;
298 : }
|