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 : }
|