diff options
Diffstat (limited to 'src/lib/exchange_api_refresh_common.c')
-rw-r--r-- | src/lib/exchange_api_refresh_common.c | 546 |
1 files changed, 168 insertions, 378 deletions
diff --git a/src/lib/exchange_api_refresh_common.c b/src/lib/exchange_api_refresh_common.c index 4f2a2cf18..4369367e4 100644 --- a/src/lib/exchange_api_refresh_common.c +++ b/src/lib/exchange_api_refresh_common.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2015-2021 Taler Systems SA + Copyright (C) 2015-2022 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -23,444 +23,234 @@ #include "exchange_api_refresh_common.h" -/** - * Free all information associated with a melted coin session. - * - * @param mc melted coin to release, the pointer itself is NOT - * freed (as it is typically not allocated by itself) - */ -static void -free_melted_coin (struct MeltedCoin *mc) -{ - TALER_denom_pub_free (&mc->pub_key); - TALER_denom_sig_free (&mc->sig); -} - - void TALER_EXCHANGE_free_melt_data_ (struct MeltData *md) { - free_melted_coin (&md->melted_coin); - if (NULL != md->fresh_pks) - { - for (unsigned int i = 0; i<md->num_fresh_coins; i++) - TALER_denom_pub_free (&md->fresh_pks[i]); - GNUNET_free (md->fresh_pks); - } - for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++) - GNUNET_free (md->fresh_coins[i]); - /* Finally, clean up a bit... */ - GNUNET_CRYPTO_zero_keys (md, - sizeof (struct MeltData)); -} - - -/** - * Serialize information about a coin we are melting. - * - * @param mc information to serialize - * @return NULL on error - */ -static json_t * -serialize_melted_coin (const struct MeltedCoin *mc) -{ - json_t *tprivs; - - tprivs = json_array (); - GNUNET_assert (NULL != tprivs); - for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++) - GNUNET_assert (0 == - json_array_append_new ( - tprivs, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto ( - "transfer_priv", - &mc->transfer_priv[i])))); - return GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto ("coin_priv", - &mc->coin_priv), - TALER_JSON_pack_denom_sig ("denom_sig", - &mc->sig), - TALER_JSON_pack_denom_pub ("denom_pub", - &mc->pub_key), - TALER_JSON_pack_amount ("melt_amount_with_fee", - &mc->melt_amount_with_fee), - TALER_JSON_pack_amount ("original_value", - &mc->original_value), - TALER_JSON_pack_amount ("melt_fee", - &mc->fee_melt), - GNUNET_JSON_pack_time_abs ("expire_deposit", - mc->expire_deposit), - GNUNET_JSON_pack_array_steal ("transfer_privs", - tprivs)); -} - - -/** - * Deserialize information about a coin we are melting. - * - * @param[out] mc information to deserialize - * @param currency expected currency - * @param in JSON object to read data from - * @return #GNUNET_NO to report errors - */ -static enum GNUNET_GenericReturnValue -deserialize_melted_coin (struct MeltedCoin *mc, - const char *currency, - const json_t *in) -{ - json_t *trans_privs; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("coin_priv", - &mc->coin_priv), - TALER_JSON_spec_denom_sig ("denom_sig", - &mc->sig), - TALER_JSON_spec_denom_pub ("denom_pub", - &mc->pub_key), - TALER_JSON_spec_amount ("melt_amount_with_fee", - currency, - &mc->melt_amount_with_fee), - TALER_JSON_spec_amount ("original_value", - currency, - &mc->original_value), - TALER_JSON_spec_amount ("melt_fee", - currency, - &mc->fee_melt), - TALER_JSON_spec_absolute_time ("expire_deposit", - &mc->expire_deposit), - GNUNET_JSON_spec_json ("transfer_privs", - &trans_privs), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (in, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_NO; - } - if (TALER_CNC_KAPPA != json_array_size (trans_privs)) - { - GNUNET_JSON_parse_free (spec); - GNUNET_break_op (0); - return GNUNET_NO; - } - for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++) - { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("transfer_priv", - &mc->transfer_priv[i]), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (json_array_get (trans_privs, - i), - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - return GNUNET_NO; - } - } - json_decref (trans_privs); - return GNUNET_OK; -} - - -/** - * Serialize melt data. - * - * @param md data to serialize - * @return serialized melt data - */ -static json_t * -serialize_melt_data (const struct MeltData *md) -{ - json_t *fresh_coins; - - fresh_coins = json_array (); - GNUNET_assert (NULL != fresh_coins); - for (int i = 0; i<md->num_fresh_coins; i++) + for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++) { - json_t *planchet_secrets; - - planchet_secrets = json_array (); - GNUNET_assert (NULL != planchet_secrets); - for (unsigned int j = 0; j<TALER_CNC_KAPPA; j++) - { - json_t *ps; - - ps = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto ("ps", - &md->fresh_coins[j][i])); - GNUNET_assert (0 == - json_array_append_new (planchet_secrets, - ps)); - } - GNUNET_assert (0 == - json_array_append_new ( - fresh_coins, - GNUNET_JSON_PACK ( - TALER_JSON_pack_denom_pub ("denom_pub", - &md->fresh_pks[i]), - GNUNET_JSON_pack_array_steal ("planchet_secrets", - planchet_secrets))) - ); - } - return GNUNET_JSON_PACK ( - GNUNET_JSON_pack_array_steal ("fresh_coins", - fresh_coins), - GNUNET_JSON_pack_object_steal ("melted_coin", - serialize_melted_coin (&md->melted_coin)), - GNUNET_JSON_pack_data_auto ("rc", - &md->rc)); -} - + struct TALER_RefreshCoinData *rcds = md->rcd[i]; -struct MeltData * -TALER_EXCHANGE_deserialize_melt_data_ (const json_t *melt_data, - const char *currency) -{ - struct MeltData *md = GNUNET_new (struct MeltData); - json_t *fresh_coins; - json_t *melted_coin; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("rc", - &md->rc), - GNUNET_JSON_spec_json ("melted_coin", - &melted_coin), - GNUNET_JSON_spec_json ("fresh_coins", - &fresh_coins), - GNUNET_JSON_spec_end () - }; - bool ok; - - if (GNUNET_OK != - GNUNET_JSON_parse (melt_data, - spec, - NULL, NULL)) - { - GNUNET_break (0); - GNUNET_JSON_parse_free (spec); - GNUNET_free (md); - return NULL; - } - if (! (json_is_array (fresh_coins) && - json_is_object (melted_coin)) ) - { - GNUNET_break (0); - GNUNET_JSON_parse_free (spec); - return NULL; - } - if (GNUNET_OK != - deserialize_melted_coin (&md->melted_coin, - currency, - melted_coin)) - { - GNUNET_break (0); - GNUNET_JSON_parse_free (spec); - return NULL; + if (NULL == rcds) + continue; + for (unsigned int j = 0; j < md->num_fresh_coins; j++) + TALER_blinded_planchet_free (&rcds[j].blinded_planchet); + GNUNET_free (rcds); } - md->num_fresh_coins = json_array_size (fresh_coins); - md->fresh_pks = GNUNET_new_array (md->num_fresh_coins, - struct TALER_DenominationPublicKey); - for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++) - md->fresh_coins[i] = GNUNET_new_array (md->num_fresh_coins, - struct TALER_PlanchetSecretsP); - ok = true; - for (unsigned int i = 0; i<md->num_fresh_coins; i++) + TALER_denom_pub_free (&md->melted_coin.pub_key); + TALER_denom_sig_free (&md->melted_coin.sig); + if (NULL != md->fcds) { - const json_t *ji = json_array_get (fresh_coins, - i); - json_t *planchet_secrets; - struct GNUNET_JSON_Specification ispec[] = { - GNUNET_JSON_spec_json ("planchet_secrets", - &planchet_secrets), - TALER_JSON_spec_denom_pub ("denom_pub", - &md->fresh_pks[i]), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (ji, - ispec, - NULL, NULL)) - { - GNUNET_break (0); - ok = false; - break; - } - if ( (! json_is_array (planchet_secrets)) || - (TALER_CNC_KAPPA != json_array_size (planchet_secrets)) ) - { - GNUNET_break (0); - ok = false; - GNUNET_JSON_parse_free (ispec); - break; - } - for (unsigned int j = 0; j<TALER_CNC_KAPPA; j++) + for (unsigned int j = 0; j<md->num_fresh_coins; j++) { - struct GNUNET_JSON_Specification jspec[] = { - GNUNET_JSON_spec_fixed_auto ("ps", - &md->fresh_coins[j][i]), - GNUNET_JSON_spec_end () - }; + struct FreshCoinData *fcd = &md->fcds[j]; - if (GNUNET_OK != - GNUNET_JSON_parse (json_array_get (planchet_secrets, - j), - jspec, - NULL, NULL)) + TALER_denom_pub_free (&fcd->fresh_pk); + for (size_t i = 0; i < TALER_CNC_KAPPA; i++) { - GNUNET_break (0); - ok = false; - break; + TALER_age_commitment_proof_free (fcd->age_commitment_proofs[i]); + GNUNET_free (fcd->age_commitment_proofs[i]); } } - json_decref (planchet_secrets); - if (! ok) - break; - } - - GNUNET_JSON_parse_free (spec); - if (! ok) - { - TALER_EXCHANGE_free_melt_data_ (md); - GNUNET_free (md); - return NULL; + GNUNET_free (md->fcds); } - return md; + /* Finally, clean up a bit... */ + GNUNET_CRYPTO_zero_keys (md, + sizeof (struct MeltData)); } -json_t * -TALER_EXCHANGE_refresh_prepare ( - const struct TALER_CoinSpendPrivateKeyP *melt_priv, - const struct TALER_Amount *melt_amount, - const struct TALER_DenominationSignature *melt_sig, - const struct TALER_EXCHANGE_DenomPublicKey *melt_pk, - unsigned int fresh_pks_len, - const struct TALER_EXCHANGE_DenomPublicKey *fresh_pks) +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_get_melt_data_ ( + const struct TALER_RefreshMasterSecretP *rms, + const struct TALER_EXCHANGE_RefreshData *rd, + const struct TALER_ExchangeWithdrawValues *alg_values, + struct MeltData *md) { - struct MeltData md; - json_t *ret; struct TALER_Amount total; struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_TransferSecretP trans_sec[TALER_CNC_KAPPA]; - struct TALER_RefreshCommitmentEntry rce[TALER_CNC_KAPPA]; + union GNUNET_CRYPTO_BlindSessionNonce nonces[rd->fresh_pks_len]; + bool uses_cs = false; - GNUNET_CRYPTO_eddsa_key_get_public (&melt_priv->eddsa_priv, + GNUNET_CRYPTO_eddsa_key_get_public (&rd->melt_priv.eddsa_priv, &coin_pub.eddsa_pub); /* build up melt data structure */ - memset (&md, + memset (md, 0, - sizeof (md)); - md.num_fresh_coins = fresh_pks_len; - md.melted_coin.coin_priv = *melt_priv; - md.melted_coin.melt_amount_with_fee = *melt_amount; - md.melted_coin.fee_melt = melt_pk->fee_refresh; - md.melted_coin.original_value = melt_pk->value; - md.melted_coin.expire_deposit - = melt_pk->expire_deposit; + sizeof (*md)); + md->num_fresh_coins = rd->fresh_pks_len; + md->melted_coin.coin_priv = rd->melt_priv; + md->melted_coin.melt_amount_with_fee = rd->melt_amount; + md->melted_coin.fee_melt = rd->melt_pk.fees.refresh; + md->melted_coin.original_value = rd->melt_pk.value; + md->melted_coin.expire_deposit = rd->melt_pk.expire_deposit; + md->melted_coin.age_commitment_proof = rd->melt_age_commitment_proof; + md->melted_coin.h_age_commitment = rd->melt_h_age_commitment; + GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero (melt_amount->currency, + TALER_amount_set_zero (rd->melt_amount.currency, &total)); - TALER_denom_pub_deep_copy (&md.melted_coin.pub_key, - &melt_pk->key); - TALER_denom_sig_deep_copy (&md.melted_coin.sig, - melt_sig); - md.fresh_pks = GNUNET_new_array (fresh_pks_len, - struct TALER_DenominationPublicKey); - for (unsigned int i = 0; i<fresh_pks_len; i++) + TALER_denom_pub_copy (&md->melted_coin.pub_key, + &rd->melt_pk.key); + TALER_denom_sig_copy (&md->melted_coin.sig, + &rd->melt_sig); + md->fcds = GNUNET_new_array (md->num_fresh_coins, + struct FreshCoinData); + for (unsigned int j = 0; j<rd->fresh_pks_len; j++) { - TALER_denom_pub_deep_copy (&md.fresh_pks[i], - &fresh_pks[i].key); + struct FreshCoinData *fcd = &md->fcds[j]; + + TALER_denom_pub_copy (&fcd->fresh_pk, + &rd->fresh_pks[j].key); + GNUNET_assert (NULL != fcd->fresh_pk.bsign_pub_key); + if (alg_values[j].blinding_inputs->cipher != + fcd->fresh_pk.bsign_pub_key->cipher) + { + GNUNET_break (0); + TALER_EXCHANGE_free_melt_data_ (md); + return GNUNET_SYSERR; + } + switch (fcd->fresh_pk.bsign_pub_key->cipher) + { + case GNUNET_CRYPTO_BSA_INVALID: + GNUNET_break (0); + TALER_EXCHANGE_free_melt_data_ (md); + return GNUNET_SYSERR; + case GNUNET_CRYPTO_BSA_RSA: + break; + case GNUNET_CRYPTO_BSA_CS: + uses_cs = true; + TALER_cs_refresh_nonce_derive (rms, + j, + &nonces[j].cs_nonce); + break; + } if ( (0 > TALER_amount_add (&total, &total, - &fresh_pks[i].value)) || + &rd->fresh_pks[j].value)) || (0 > TALER_amount_add (&total, &total, - &fresh_pks[i].fee_withdraw)) ) + &rd->fresh_pks[j].fees.withdraw)) ) { GNUNET_break (0); - TALER_EXCHANGE_free_melt_data_ (&md); - return NULL; + TALER_EXCHANGE_free_melt_data_ (md); + return GNUNET_SYSERR; } } + /* verify that melt_amount is above total cost */ if (1 == TALER_amount_cmp (&total, - melt_amount) ) + &rd->melt_amount) ) { /* Eh, this operation is more expensive than the @a melt_amount. This is not OK. */ GNUNET_break (0); - TALER_EXCHANGE_free_melt_data_ (&md); - return NULL; + TALER_EXCHANGE_free_melt_data_ (md); + return GNUNET_SYSERR; } /* build up coins */ for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++) { - GNUNET_CRYPTO_ecdhe_key_create ( - &md.melted_coin.transfer_priv[i].ecdhe_priv); + struct TALER_TransferSecretP trans_sec; + + TALER_planchet_secret_to_transfer_priv ( + rms, + &rd->melt_priv, + i, + &md->transfer_priv[i]); + GNUNET_CRYPTO_ecdhe_key_get_public ( - &md.melted_coin.transfer_priv[i].ecdhe_priv, - &rce[i].transfer_pub.ecdhe_pub); - TALER_link_derive_transfer_secret (melt_priv, - &md.melted_coin.transfer_priv[i], - &trans_sec[i]); - md.fresh_coins[i] = GNUNET_new_array (fresh_pks_len, - struct TALER_PlanchetSecretsP); - rce[i].new_coins = GNUNET_new_array (fresh_pks_len, - struct TALER_RefreshCoinData); - for (unsigned int j = 0; j<fresh_pks_len; j++) + &md->transfer_priv[i].ecdhe_priv, + &md->transfer_pub[i].ecdhe_pub); + + TALER_link_derive_transfer_secret (&rd->melt_priv, + &md->transfer_priv[i], + &trans_sec); + + md->rcd[i] = GNUNET_new_array (rd->fresh_pks_len, + struct TALER_RefreshCoinData); + + for (unsigned int j = 0; j<rd->fresh_pks_len; j++) { - struct TALER_PlanchetSecretsP *fc = &md.fresh_coins[i][j]; - struct TALER_RefreshCoinData *rcd = &rce[i].new_coins[j]; + struct FreshCoinData *fcd = &md->fcds[j]; + struct TALER_CoinSpendPrivateKeyP *coin_priv = &fcd->coin_priv; + struct TALER_PlanchetMasterSecretP *ps = &fcd->ps[i]; + struct TALER_RefreshCoinData *rcd = &md->rcd[i][j]; + union GNUNET_CRYPTO_BlindingSecretP *bks = &fcd->bks[i]; struct TALER_PlanchetDetail pd; - struct TALER_CoinPubHash c_hash; + struct TALER_CoinPubHashP c_hash; + struct TALER_AgeCommitmentHash ach; + struct TALER_AgeCommitmentHash *pah = NULL; + + TALER_transfer_secret_to_planchet_secret (&trans_sec, + j, + ps); + + TALER_planchet_setup_coin_priv (ps, + &alg_values[j], + coin_priv); + + TALER_planchet_blinding_secret_create (ps, + &alg_values[j], + bks); + + if (NULL != rd->melt_age_commitment_proof) + { + fcd->age_commitment_proofs[i] = GNUNET_new (struct + TALER_AgeCommitmentProof); + + GNUNET_assert (GNUNET_OK == + TALER_age_commitment_derive ( + md->melted_coin.age_commitment_proof, + &trans_sec.key, + fcd->age_commitment_proofs[i])); + + TALER_age_commitment_hash ( + &fcd->age_commitment_proofs[i]->commitment, + &ach); + pah = &ach; + } - TALER_planchet_setup_refresh (&trans_sec[i], - j, - fc); if (GNUNET_OK != - TALER_planchet_prepare (&md.fresh_pks[j], - fc, + TALER_planchet_prepare (&fcd->fresh_pk, + &alg_values[j], + bks, + &nonces[j], + coin_priv, + pah, &c_hash, &pd)) { GNUNET_break_op (0); - TALER_EXCHANGE_free_melt_data_ (&md); - return NULL; + TALER_EXCHANGE_free_melt_data_ (md); + return GNUNET_SYSERR; } - rcd->dk = &md.fresh_pks[j]; - rcd->coin_ev = pd.coin_ev; - rcd->coin_ev_size = pd.coin_ev_size; + rcd->blinded_planchet = pd.blinded_planchet; + rcd->dk = &fcd->fresh_pk; } } - /* Compute refresh commitment */ - TALER_refresh_get_commitment (&md.rc, - TALER_CNC_KAPPA, - fresh_pks_len, - rce, - &coin_pub, - melt_amount); - /* finally, serialize everything */ - ret = serialize_melt_data (&md); - for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++) + /* Finally, compute refresh commitment */ { - for (unsigned int j = 0; j < fresh_pks_len; j++) - GNUNET_free (rce[i].new_coins[j].coin_ev); - GNUNET_free (rce[i].new_coins); + struct TALER_RefreshCommitmentEntry rce[TALER_CNC_KAPPA]; + + for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++) + { + rce[i].transfer_pub = md->transfer_pub[i]; + rce[i].new_coins = md->rcd[i]; + } + TALER_refresh_get_commitment (&md->rc, + TALER_CNC_KAPPA, + uses_cs + ? rms + : NULL, + rd->fresh_pks_len, + rce, + &coin_pub, + &rd->melt_amount); } - TALER_EXCHANGE_free_melt_data_ (&md); - return ret; + return GNUNET_OK; } |