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 "platform.h"
24 : #include "exchange_api_refresh_common.h"
25 :
26 :
27 : void
28 44 : TALER_EXCHANGE_free_melt_data_v27 (struct MeltData_v27 *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 : }
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_v27));
58 44 : }
59 :
60 :
61 : enum GNUNET_GenericReturnValue
62 44 : 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 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 : const struct TALER_DenominationHashP *denoms_h[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->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<rd->num_fresh_denom_pubs; j++)
112 : {
113 176 : struct FreshCoinData *fcd = &md->fcds[j];
114 :
115 176 : denoms_h[j] = &rd->fresh_denom_pubs[j].h_key;
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_v27 (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_v27 (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_v27 (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_v27 (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_v27(), 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 : 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 44 : TALER_refresh_master_secret_to_refresh_seed (
193 : rms,
194 : &md->refresh_seed);
195 44 : TALER_refresh_expand_kappa_nonces (
196 44 : &md->refresh_seed,
197 : &md->kappa_nonces);
198 : /**
199 : * Build up all candidates for coin planchets
200 : */
201 176 : for (unsigned int k = 0; k<TALER_CNC_KAPPA; k++)
202 132 : {
203 : struct TALER_PlanchetMasterSecretP
204 132 : planchet_secrets[rd->num_fresh_denom_pubs];
205 132 : struct TALER_PlanchetDetail planchet_details[rd->num_fresh_denom_pubs];
206 :
207 132 : TALER_wallet_refresh_nonce_sign (
208 : &rd->melt_priv,
209 132 : &md->kappa_nonces.tuple[k],
210 132 : rd->num_fresh_denom_pubs,
211 : denoms_h,
212 : k,
213 : &md->signatures[k]);
214 132 : TALER_refresh_signature_to_secrets (
215 132 : &md->signatures[k],
216 132 : rd->num_fresh_denom_pubs,
217 : planchet_secrets);
218 :
219 132 : md->kappa_blinded_planchets[k] =
220 132 : GNUNET_new_array (rd->num_fresh_denom_pubs,
221 : struct TALER_BlindedPlanchet);
222 :
223 660 : for (unsigned int j = 0; j<rd->num_fresh_denom_pubs; j++)
224 : {
225 528 : struct FreshCoinData *fcd = &md->fcds[j];
226 528 : struct TALER_CoinSpendPrivateKeyP *coin_priv = &fcd->coin_priv;
227 528 : union GNUNET_CRYPTO_BlindingSecretP *bks = &fcd->bks[k];
228 : struct TALER_CoinPubHashP c_hash;
229 : struct TALER_AgeCommitmentHash ach;
230 : struct TALER_AgeCommitmentHash *pah;
231 :
232 528 : fcd->ps[k] = planchet_secrets[j];
233 528 : TALER_planchet_setup_coin_priv (&planchet_secrets[j],
234 528 : &blinding_values[j],
235 : coin_priv);
236 528 : TALER_planchet_blinding_secret_create (&planchet_secrets[j],
237 528 : &blinding_values[j],
238 : bks);
239 528 : if (NULL != rd->melt_age_commitment_proof)
240 : {
241 288 : fcd->age_commitment_proofs[k] = GNUNET_new (struct
242 : TALER_AgeCommitmentProof);
243 288 : 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 288 : TALER_age_commitment_hash (
249 288 : &fcd->age_commitment_proofs[k]->commitment,
250 : &ach);
251 288 : pah = &ach;
252 : }
253 : else
254 : {
255 240 : pah = NULL;
256 : }
257 :
258 528 : if (GNUNET_OK !=
259 528 : TALER_planchet_prepare (&fcd->fresh_pk,
260 528 : &blinding_values[j],
261 : bks,
262 528 : is_cs[j] ? &nonces[j] : NULL,
263 : coin_priv,
264 : pah,
265 : &c_hash,
266 : &planchet_details[j]))
267 : {
268 0 : GNUNET_break_op (0);
269 0 : TALER_EXCHANGE_free_melt_data_v27 (md);
270 0 : return GNUNET_SYSERR;
271 : }
272 528 : 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 132 : TALER_wallet_blinded_planchet_details_hash (
279 132 : rd->num_fresh_denom_pubs,
280 : planchet_details,
281 : &k_h_bps.tuple[k]);
282 : }
283 :
284 : /* Finally, compute refresh commitment */
285 44 : TALER_refresh_get_commitment_v27 (&md->rc,
286 44 : &md->refresh_seed,
287 : uses_cs
288 : ? &md->blinding_seed
289 : : NULL,
290 : &k_h_bps,
291 : &coin_pub,
292 : &rd->melt_amount);
293 44 : return GNUNET_OK;
294 : }
|