This commit is contained in:
Christian Grothoff 2017-11-27 23:42:17 +01:00
parent 9041840d6e
commit 499247a480
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
27 changed files with 2503 additions and 3795 deletions

View File

@ -753,6 +753,45 @@ reserve expired.
{% endif %}
\subsection{Hanging refresh operations}
This section describes cases where the exchange booked a
coin as spent from {\tt /refresh/melt} but where the
wallet did not yet complete {\tt /refresh/reveal}. This
may happen even if the exchange is correct.
{% if data.refresh_hanging|length() == 0 %}
{\bf All melted coins were refreshed.}
{% else %}
\begin{longtable}{p{1.5cm}|c|rl}
{\bf Key} & {\bf row} & \multicolumn{2}{|c|}{ {\bf Amount}} \\
\hline \hline
\endfirsthead
{\bf Key} & {\bf row} & \multicolumn{2}{|c|}{ {\bf Amount}} \\
\hline \hline
\endhead
\hline \hline
{\bf Key} & {\bf row} & \multicolumn{2}{|c|}{ {\bf Amount}} \\
\endfoot
\hline
{\bf Sum} & &
{{ data.total_refresh_hanging.value}}.{{ data.total_refresh_hanging.fraction}} & {{ data.total_refresh_hanging.currency}} \\
\caption{Refresh operations hanging.}
\label{table:refresh:hanging}
\endlastfoot
{% for item in data.refresh_hanging %}
\multicolumn{4}{l}{ {\tt {{ item.coin_pub }} } } \\
\nopagebreak
&
{{ item.row }} &
{{ item.amount.value }}.{{ item.amount.fraction }} &
{{ item.amount.currency }} \\ \hline
{% endfor %}
\end{longtable}
{% endif %}
\subsection{Denomination key invalid at time of withdrawal}
This section lists cases where a denomination key was not valid for

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2016, 2017 Inria
Copyright (C) 2016, 2017 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero Public License as published by the Free Software
@ -275,6 +275,17 @@ static json_t *report_bad_sig_losses;
*/
static struct TALER_Amount total_bad_sig_loss;
/**
* Array of refresh transactions where the /refresh/reveal has not yet
* happened (and may of course never happen).
*/
static json_t *report_refreshs_hanging;
/**
* Total amount lost by operations for which signatures were invalid.
*/
static struct TALER_Amount total_refresh_hanging;
/* ***************************** Report logic **************************** */
@ -1893,7 +1904,7 @@ check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
}
break;
case TALER_EXCHANGEDB_TT_REFRESH_MELT:
amount_with_fee = &tl->details.melt->amount_with_fee;
amount_with_fee = &tl->details.melt->session.amount_with_fee;
fee = &tl->details.melt->melt_fee;
fee_dki = &dki->properties.fee_refresh;
if (GNUNET_OK !=
@ -2104,7 +2115,7 @@ wire_transfer_information_cb (void *cls,
coin = &tl->details.deposit->coin;
break;
case TALER_EXCHANGEDB_TT_REFRESH_MELT:
coin = &tl->details.melt->coin;
coin = &tl->details.melt->session.coin;
break;
case TALER_EXCHANGEDB_TT_REFUND:
coin = &tl->details.refund->coin;
@ -2967,6 +2978,54 @@ withdraw_cb (void *cls,
}
/**
* Closure for #reveal_data_cb().
*/
struct RevealContext
{
/**
* Denomination public keys of the new coins.
*/
struct TALER_DenominationPublicKey *new_dps;
/**
* Size of the @a new_dp and @a new_dki arrays.
*/
unsigned int num_newcoins;
};
/**
* Function called with information about a refresh order.
*
* @param cls closure
* @param rowid unique serial ID for the row in our database
* @param num_newcoins size of the @a rrcs array
* @param rrcs array of @a num_newcoins information about coins to be created
* @param num_tprivs number of entries in @a tprivs, should be #TALER_CNC_KAPPA - 1
* @param tprivs array of @e num_tprivs transfer private keys
* @param tp transfer public key information
*/
static void
reveal_data_cb (void *cls,
uint32_t num_newcoins,
const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs,
unsigned int num_tprivs,
const struct TALER_TransferPrivateKeyP *tprivs,
const struct TALER_TransferPublicKeyP *tp)
{
struct RevealContext *rctx = cls;
rctx->num_newcoins = num_newcoins;
rctx->new_dps = GNUNET_new_array (num_newcoins,
struct TALER_DenominationPublicKey);
for (unsigned int i=0;i<num_newcoins;i++)
rctx->new_dps[i].rsa_public_key
= GNUNET_CRYPTO_rsa_public_key_dup (rrcs[i].denom_pub.rsa_public_key);
}
/**
* Function called with details about coins that were melted, with the
* goal of auditing the refresh's execution. Verifies the signature
@ -2980,7 +3039,6 @@ withdraw_cb (void *cls,
* @param coin_pub public key of the coin
* @param coin_sig signature from the coin
* @param amount_with_fee amount that was deposited including fee
* @param num_newcoins how many coins were issued
* @param noreveal_index which index was picked by the exchange in cut-and-choose
* @param session_hash what is the session hash
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
@ -2992,9 +3050,8 @@ refresh_session_cb (void *cls,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_CoinSpendSignatureP *coin_sig,
const struct TALER_Amount *amount_with_fee,
uint16_t num_newcoins,
uint16_t noreveal_index,
const struct GNUNET_HashCode *session_hash)
uint32_t noreveal_index,
const struct TALER_RefreshCommitmentP *rc)
{
struct CoinContext *cc = cls;
struct TALER_RefreshMeltCoinAffirmationPS rmc;
@ -3020,7 +3077,7 @@ refresh_session_cb (void *cls,
/* verify melt signature */
rmc.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT);
rmc.purpose.size = htonl (sizeof (rmc));
rmc.session_hash = *session_hash;
rmc.rc = *rc;
TALER_amount_hton (&rmc.amount_with_fee,
amount_with_fee);
rmc.melt_fee = dki->properties.fee_refresh;
@ -3050,33 +3107,57 @@ refresh_session_cb (void *cls,
TALER_amount2s (amount_with_fee));
{
struct TALER_DenominationPublicKey new_dp[num_newcoins];
const struct TALER_EXCHANGEDB_DenominationKeyInformationP *new_dki[num_newcoins];
struct RevealContext reveal_ctx;
struct TALER_Amount refresh_cost;
int err;
GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (amount_with_fee->currency,
&refresh_cost));
qs = edb->get_refresh_order (edb->cls,
memset (&reveal_ctx,
0,
sizeof (reveal_ctx));
qs = edb->get_refresh_reveal (edb->cls,
esession,
session_hash,
num_newcoins,
new_dp);
if (0 >= qs)
rc,
&reveal_data_cb,
&reveal_ctx);
if (0 > qs)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
cc->qs = GNUNET_DB_STATUS_HARD_ERROR;
return GNUNET_SYSERR;
}
if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) ||
(0 == reveal_ctx.num_newcoins) )
{
/* This can happen if /refresh/reveal was not yet called or only
with invalid data, even if the exchange is correctly
operating. We still report it. */
report (report_refreshs_hanging,
json_pack ("{s:I, s:o, s:o}",
"row", (json_int_t) rowid,
"amount", TALER_JSON_from_amount (amount_with_fee),
"coin_pub", GNUNET_JSON_from_data_auto (coin_pub)));
GNUNET_break (GNUNET_OK ==
TALER_amount_add (&total_refresh_hanging,
&total_refresh_hanging,
amount_with_fee));
return GNUNET_OK;
}
// FIXME: free reveal_ctx.num_newcoins later!
{
const struct TALER_EXCHANGEDB_DenominationKeyInformationP *new_dkis[reveal_ctx.num_newcoins];
/* Update outstanding amounts for all new coin's denominations, and check
that the resulting amounts are consistent with the value being refreshed. */
err = GNUNET_NO;
for (unsigned int i=0;i<num_newcoins;i++)
for (unsigned int i=0;i<reveal_ctx.num_newcoins;i++)
{
/* lookup new coin denomination key */
qs = get_denomination_info (&new_dp[i],
&new_dki[i],
qs = get_denomination_info (&reveal_ctx.new_dps[i],
&new_dkis[i],
NULL);
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
{
@ -3084,23 +3165,26 @@ refresh_session_cb (void *cls,
cc->qs = qs;
err = GNUNET_YES;
}
GNUNET_CRYPTO_rsa_public_key_free (new_dp[i].rsa_public_key);
new_dp[i].rsa_public_key = NULL;
GNUNET_CRYPTO_rsa_public_key_free (reveal_ctx.new_dps[i].rsa_public_key);
reveal_ctx.new_dps[i].rsa_public_key = NULL;
}
GNUNET_free (reveal_ctx.new_dps);
reveal_ctx.new_dps = NULL;
if (err)
return GNUNET_SYSERR;
/* calculate total refresh cost */
for (unsigned int i=0;i<num_newcoins;i++)
for (unsigned int i=0;i<reveal_ctx.num_newcoins;i++)
{
/* update cost of refresh */
struct TALER_Amount fee;
struct TALER_Amount value;
TALER_amount_ntoh (&fee,
&new_dki[i]->properties.fee_withdraw);
&new_dkis[i]->properties.fee_withdraw);
TALER_amount_ntoh (&value,
&new_dki[i]->properties.value);
&new_dkis[i]->properties.value);
if ( (GNUNET_OK !=
TALER_amount_add (&refresh_cost,
&refresh_cost,
@ -3147,24 +3231,24 @@ refresh_session_cb (void *cls,
}
/* update outstanding denomination amounts */
for (unsigned int i=0;i<num_newcoins;i++)
for (unsigned int i=0;i<reveal_ctx.num_newcoins;i++)
{
struct DenominationSummary *dsi;
struct TALER_Amount value;
dsi = get_denomination_summary (cc,
new_dki[i],
&new_dki[i]->properties.denom_hash);
new_dkis[i],
&new_dkis[i]->properties.denom_hash);
if (NULL == dsi)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
TALER_amount_ntoh (&value,
&new_dki[i]->properties.value);
&new_dkis[i]->properties.value);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Created fresh coin in denomination `%s' of value %s\n",
GNUNET_h2s (&new_dki[i]->properties.denom_hash),
GNUNET_h2s (&new_dkis[i]->properties.denom_hash),
TALER_amount2s (&value));
if (GNUNET_OK !=
TALER_amount_add (&dsi->denom_balance,
@ -3186,7 +3270,7 @@ refresh_session_cb (void *cls,
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"New balance of denomination `%s' is %s\n",
GNUNET_h2s (&new_dki[i]->properties.denom_hash),
GNUNET_h2s (&new_dkis[i]->properties.denom_hash),
TALER_amount2s (&dsi->denom_balance));
if (GNUNET_OK !=
TALER_amount_add (&total_escrow_balance,
@ -3208,6 +3292,7 @@ refresh_session_cb (void *cls,
}
}
}
}
/* update old coin's denomination balance */
dso = get_denomination_summary (cc,
@ -4081,6 +4166,9 @@ run (void *cls,
GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (currency,
&total_bad_sig_loss));
GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (currency,
&total_refresh_hanging));
GNUNET_assert (NULL !=
(report_emergencies = json_array ()));
GNUNET_assert (NULL !=
@ -4103,6 +4191,8 @@ run (void *cls,
(report_amount_arithmetic_inconsistencies = json_array ()));
GNUNET_assert (NULL !=
(report_bad_sig_losses = json_array ()));
GNUNET_assert (NULL !=
(report_refreshs_hanging = json_array ()));
GNUNET_assert (NULL !=
(report_fee_time_inconsistencies = json_array ()));
setup_sessions_and_run ();
@ -4129,7 +4219,7 @@ run (void *cls,
" s:o, s:o, s:o, s:o, s:o,"
" s:o, s:o, s:o, s:o, s:o,"
" s:o, s:o, s:o, s:o, s:o,"
" s:o }",
" s:o, s:o, s:o }",
/* blocks of 5 for easier counting/matching to format string */
/* block */
"reserve_balance_insufficient_inconsistencies",
@ -4199,7 +4289,11 @@ run (void *cls,
TALER_JSON_from_amount (&total_aggregation_fee_income),
/* block */
"wire_fee_time_inconsistencies",
report_fee_time_inconsistencies);
report_fee_time_inconsistencies,
"total_refresh_hanging",
TALER_JSON_from_amount (&total_refresh_hanging),
"refresh_hanging",
report_refreshs_hanging);
GNUNET_break (NULL != report);
json_dumpf (report,
stdout,

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014, 2015, 2016 GNUnet e.V. and INRIA
Copyright (C) 2014, 2015, 2016, 2017 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
@ -623,7 +623,7 @@ static void
melt_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
uint16_t noreveal_index,
uint32_t noreveal_index,
const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *full_response)
{

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2015-2017 Inria & GNUnet e.V.
Copyright (C) 2015-2017 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
@ -143,8 +143,8 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("coin_sig",
&sig),
GNUNET_JSON_spec_fixed_auto ("session_hash",
&rm.session_hash),
GNUNET_JSON_spec_fixed_auto ("rc",
&rm.rc),
TALER_JSON_spec_amount_nbo ("melt_fee",
&rm.melt_fee),
GNUNET_JSON_spec_end()

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2015, 2016 GNUnet e.V.
Copyright (C) 2015, 2016, 2017 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
@ -101,7 +101,7 @@ struct MeltDataP
/**
* Hash over the melting session.
*/
struct GNUNET_HashCode melt_session_hash;
struct TALER_RefreshCommitmentP rc;
/**
* Number of coins we are melting, in NBO
@ -180,9 +180,9 @@ struct MeltData
{
/**
* Hash over the melting session.
* Hash over the committed data during refresh operation.
*/
struct GNUNET_HashCode melt_session_hash;
struct TALER_RefreshCommitmentP rc;
/**
* Number of coins we are creating
@ -466,7 +466,6 @@ deserialize_denomination_key (struct TALER_DenominationPublicKey *dk,
dk->rsa_public_key
= GNUNET_CRYPTO_rsa_public_key_decode (&buf[sizeof (uint32_t)],
pbuf_size);
if (NULL == dk->rsa_public_key)
{
GNUNET_break (0);
@ -542,8 +541,6 @@ serialize_melt_data (const struct MeltData *md,
size_t size;
size_t asize;
char *buf;
unsigned int i;
unsigned int j;
size = 0;
asize = (size_t) -1; /* make the compiler happy */
@ -563,18 +560,18 @@ serialize_melt_data (const struct MeltData *md,
asize = size; /* just for invariant check later */
size = sizeof (struct MeltDataP);
mdp = (struct MeltDataP *) buf;
mdp->melt_session_hash = md->melt_session_hash;
mdp->rc = md->rc;
mdp->num_fresh_coins = htons (md->num_fresh_coins);
}
size += serialize_melted_coin (&md->melted_coin,
buf,
size);
for (i=0;i<md->num_fresh_coins;i++)
for (unsigned int i=0;i<md->num_fresh_coins;i++)
size += serialize_denomination_key (&md->fresh_pks[i],
buf,
size);
for (i=0;i<TALER_CNC_KAPPA;i++)
for(j=0;j<md->num_fresh_coins;j++)
for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
for(unsigned int j=0;j<md->num_fresh_coins;j++)
size += serialize_fresh_coin (&md->fresh_coins[i][j],
buf,
size);
@ -607,7 +604,7 @@ deserialize_melt_data (const char *buf,
buf,
sizeof (struct MeltDataP));
md = GNUNET_new (struct MeltData);
md->melt_session_hash = mdp.melt_session_hash;
md->rc = mdp.rc;
md->num_fresh_coins = ntohs (mdp.num_fresh_coins);
md->fresh_pks = GNUNET_new_array (md->num_fresh_coins,
struct TALER_DenominationPublicKey);
@ -700,34 +697,14 @@ TALER_EXCHANGE_refresh_prepare (const struct TALER_CoinSpendPrivateKeyP *melt_pr
{
struct MeltData md;
char *buf;
struct GNUNET_HashContext *hash_context;
struct TALER_Amount total;
struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_TransferSecretP trans_sec[TALER_CNC_KAPPA];
struct TALER_RefreshCommitmentEntry rce[TALER_CNC_KAPPA];
GNUNET_CRYPTO_eddsa_key_get_public (&melt_priv->eddsa_priv,
&coin_pub.eddsa_pub);
hash_context = GNUNET_CRYPTO_hash_context_start ();
/* build up melt data structure */
for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
{
struct GNUNET_CRYPTO_EcdhePrivateKey *tpk;
struct TALER_TransferPublicKeyP tp;
tpk = GNUNET_CRYPTO_ecdhe_key_create ();
md.melted_coin.transfer_priv[i].ecdhe_priv = *tpk;
GNUNET_free (tpk);
GNUNET_CRYPTO_ecdhe_key_get_public (&md.melted_coin.transfer_priv[i].ecdhe_priv,
&tp.ecdhe_pub);
GNUNET_CRYPTO_hash_context_read (hash_context,
&tp,
sizeof (struct TALER_TransferPublicKeyP));
/* DH */
TALER_link_derive_transfer_secret (melt_priv,
&md.melted_coin.transfer_priv[i],
&trans_sec[i]);
}
md.num_fresh_coins = fresh_pks_len;
md.melted_coin.coin_priv = *melt_priv;
md.melted_coin.melt_amount_with_fee = *melt_amount;
@ -735,6 +712,9 @@ TALER_EXCHANGE_refresh_prepare (const struct TALER_CoinSpendPrivateKeyP *melt_pr
md.melted_coin.original_value = melt_pk->value;
md.melted_coin.expire_deposit
= melt_pk->expire_deposit;
GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (melt_amount->currency,
&total));
md.melted_coin.pub_key.rsa_public_key
= GNUNET_CRYPTO_rsa_public_key_dup (melt_pk->key.rsa_public_key);
md.melted_coin.sig.rsa_signature
@ -742,40 +722,24 @@ TALER_EXCHANGE_refresh_prepare (const struct TALER_CoinSpendPrivateKeyP *melt_pr
md.fresh_pks = GNUNET_new_array (fresh_pks_len,
struct TALER_DenominationPublicKey);
for (unsigned int i=0;i<fresh_pks_len;i++)
{
md.fresh_pks[i].rsa_public_key
= GNUNET_CRYPTO_rsa_public_key_dup (fresh_pks[i].key.rsa_public_key);
for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
{
md.fresh_coins[i] = GNUNET_new_array (fresh_pks_len,
struct TALER_PlanchetSecretsP);
for (unsigned int j=0;j<fresh_pks_len;j++)
{
TALER_planchet_setup_refresh (&trans_sec[i],
j,
&md.fresh_coins[i][j]);
}
}
/* verify that melt_amount is above total cost */
GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (melt_amount->currency,
&total));
for (unsigned int j=0;j<fresh_pks_len;j++)
{
if ( (GNUNET_OK !=
TALER_amount_add (&total,
&total,
&fresh_pks[j].value)) ||
&fresh_pks[i].value)) ||
(GNUNET_OK !=
TALER_amount_add (&total,
&total,
&fresh_pks[j].fee_withdraw)) )
&fresh_pks[i].fee_withdraw)) )
{
GNUNET_break (0);
free_melt_data (&md);
return NULL;
}
}
/* verify that melt_amount is above total cost */
if (1 ==
TALER_amount_cmp (&total,
melt_amount) )
@ -787,63 +751,64 @@ TALER_EXCHANGE_refresh_prepare (const struct TALER_CoinSpendPrivateKeyP *melt_pr
return NULL;
}
/* next, add all of the hashes from the denomination keys to the
hash_context */
for (unsigned int i=0;i<fresh_pks_len;i++)
/* build up coins */
for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
{
char *buf;
size_t buf_size;
struct GNUNET_CRYPTO_EcdhePrivateKey *tpk;
buf_size = GNUNET_CRYPTO_rsa_public_key_encode (fresh_pks[i].key.rsa_public_key,
&buf);
GNUNET_CRYPTO_hash_context_read (hash_context,
buf,
buf_size);
GNUNET_free (buf);
}
{
struct TALER_AmountNBO melt_amountn;
tpk = GNUNET_CRYPTO_ecdhe_key_create ();
md.melted_coin.transfer_priv[i].ecdhe_priv = *tpk;
GNUNET_free (tpk);
GNUNET_CRYPTO_hash_context_read (hash_context,
&coin_pub,
sizeof (struct TALER_CoinSpendPublicKeyP));
TALER_amount_hton (&melt_amountn,
melt_amount);
GNUNET_CRYPTO_hash_context_read (hash_context,
&melt_amountn,
sizeof (struct TALER_AmountNBO));
}
for (unsigned int i = 0; i < TALER_CNC_KAPPA; 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++)
{
for (unsigned int j = 0; j < fresh_pks_len; j++)
{
const struct TALER_PlanchetSecretsP *fc; /* coin this is about */
struct TALER_PlanchetSecretsP *fc = &md.fresh_coins[i][j];
struct TALER_RefreshCoinData *rcd = &rce[i].new_coins[j];
struct TALER_PlanchetDetail pd;
fc = &md.fresh_coins[i][j];
TALER_planchet_setup_refresh (&trans_sec[i],
j,
fc);
if (GNUNET_OK !=
TALER_planchet_prepare (&md.fresh_pks[j],
fc,
&pd))
{
GNUNET_break_op (0);
GNUNET_CRYPTO_hash_context_abort (hash_context);
free_melt_data (&md);
return NULL;
}
GNUNET_CRYPTO_hash_context_read (hash_context,
pd.coin_ev,
pd.coin_ev_size);
GNUNET_free (pd.coin_ev);
rcd->dk = &md.fresh_pks[j];
rcd->coin_ev = pd.coin_ev;
rcd->coin_ev_size = pd.coin_ev_size;
}
}
GNUNET_CRYPTO_hash_context_finish (hash_context,
&md.melt_session_hash);
/* Compute refresh commitment */
TALER_refresh_get_commitment (&md.rc,
TALER_CNC_KAPPA,
fresh_pks_len,
rce,
&coin_pub,
melt_amount);
/* finally, serialize everything */
buf = serialize_melt_data (&md,
res_size);
for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)
{
for (unsigned int j = 0; j < fresh_pks_len; j++)
GNUNET_free_non_null (rce[i].new_coins[j].coin_ev);
GNUNET_free_non_null (rce[i].new_coins);
}
free_melt_data (&md);
return buf;
}
@ -909,14 +874,14 @@ static int
verify_refresh_melt_signature_ok (struct TALER_EXCHANGE_RefreshMeltHandle *rmh,
const json_t *json,
struct TALER_ExchangePublicKeyP *exchange_pub,
uint16_t *noreveal_index)
uint32_t *noreveal_index)
{
struct TALER_ExchangeSignatureP exchange_sig;
const struct TALER_EXCHANGE_Keys *key_state;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub", exchange_pub),
GNUNET_JSON_spec_uint16 ("noreveal_index", noreveal_index),
GNUNET_JSON_spec_uint32 ("noreveal_index", noreveal_index),
GNUNET_JSON_spec_end()
};
struct TALER_RefreshMeltConfirmationPS confirm;
@ -950,9 +915,8 @@ verify_refresh_melt_signature_ok (struct TALER_EXCHANGE_RefreshMeltHandle *rmh,
/* verify signature by exchange */
confirm.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT);
confirm.purpose.size = htonl (sizeof (struct TALER_RefreshMeltConfirmationPS));
confirm.session_hash = rmh->md->melt_session_hash;
confirm.noreveal_index = htons (*noreveal_index);
confirm.reserved = htons (0);
confirm.rc = rmh->md->rc;
confirm.noreveal_index = htonl (*noreveal_index);
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT,
&confirm.purpose,
@ -1076,7 +1040,7 @@ handle_refresh_melt_finished (void *cls,
const json_t *json)
{
struct TALER_EXCHANGE_RefreshMeltHandle *rmh = cls;
uint16_t noreveal_index = TALER_CNC_KAPPA; /* invalid value */
uint32_t noreveal_index = TALER_CNC_KAPPA; /* invalid value */
struct TALER_ExchangePublicKeyP exchange_pub;
rmh->job = NULL;
@ -1145,53 +1109,13 @@ handle_refresh_melt_finished (void *cls,
rmh->melt_cb (rmh->melt_cb_cls,
response_code,
TALER_JSON_get_error_code (json),
UINT16_MAX,
UINT32_MAX,
NULL,
json);
TALER_EXCHANGE_refresh_melt_cancel (rmh);
}
/**
* Convert a coin to be melted to the respective JSON encoding.
*
* @param melt_session_hash session hash to use
* @param mc coin to be melted
* @return JSON encoding of the melting request
*/
static json_t *
melted_coin_to_json (const struct GNUNET_HashCode *melt_session_hash,
const struct MeltedCoin *mc)
{
struct TALER_CoinSpendSignatureP confirm_sig;
struct TALER_RefreshMeltCoinAffirmationPS melt;
melt.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT);
melt.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
melt.session_hash = *melt_session_hash;
TALER_amount_hton (&melt.amount_with_fee,
&mc->melt_amount_with_fee);
TALER_amount_hton (&melt.melt_fee,
&mc->fee_melt);
GNUNET_CRYPTO_eddsa_key_get_public (&mc->coin_priv.eddsa_priv,
&melt.coin_pub.eddsa_pub);
GNUNET_CRYPTO_eddsa_sign (&mc->coin_priv.eddsa_priv,
&melt.purpose,
&confirm_sig.eddsa_signature);
return json_pack ("{s:o, s:o, s:o, s:o, s:o}",
"coin_pub",
GNUNET_JSON_from_data_auto (&melt.coin_pub),
"denom_pub",
GNUNET_JSON_from_rsa_public_key (mc->pub_key.rsa_public_key),
"denom_sig",
GNUNET_JSON_from_rsa_signature (mc->sig.rsa_signature),
"confirm_sig",
GNUNET_JSON_from_data_auto (&confirm_sig),
"value_with_fee",
TALER_JSON_from_amount (&mc->melt_amount_with_fee));
}
/**
* Submit a melt request to the exchange and get the exchange's
* response.
@ -1220,17 +1144,12 @@ TALER_EXCHANGE_refresh_melt (struct TALER_EXCHANGE_Handle *exchange,
void *melt_cb_cls)
{
json_t *melt_obj;
json_t *new_denoms;
json_t *melt_coin;
json_t *coin_evs;
json_t *transfer_pubs;
json_t *tmp;
struct TALER_EXCHANGE_RefreshMeltHandle *rmh;
CURL *eh;
struct GNUNET_CURL_Context *ctx;
struct MeltData *md;
unsigned int i;
unsigned int j;
struct TALER_CoinSpendSignatureP confirm_sig;
struct TALER_RefreshMeltCoinAffirmationPS melt;
GNUNET_assert (GNUNET_YES ==
MAH_handle_is_ready (exchange));
@ -1242,78 +1161,35 @@ TALER_EXCHANGE_refresh_melt (struct TALER_EXCHANGE_Handle *exchange,
return NULL;
}
/* build JSON request, each of the 4 arrays first */
new_denoms = json_array ();
melt_coin = melted_coin_to_json (&md->melt_session_hash,
&md->melted_coin);
coin_evs = json_array ();
transfer_pubs = json_array ();
/* now transfer_pubs */
for (j=0;j<TALER_CNC_KAPPA;j++)
{
const struct MeltedCoin *mc = &md->melted_coin;
struct TALER_TransferPublicKeyP transfer_pub;
GNUNET_CRYPTO_ecdhe_key_get_public (&mc->transfer_priv[j].ecdhe_priv,
&transfer_pub.ecdhe_pub);
GNUNET_assert (0 ==
json_array_append_new (transfer_pubs,
GNUNET_JSON_from_data_auto (&transfer_pub)));
}
/* now new_denoms */
for (i=0;i<md->num_fresh_coins;i++)
{
GNUNET_assert (0 ==
json_array_append_new (new_denoms,
GNUNET_JSON_from_rsa_public_key
(md->fresh_pks[i].rsa_public_key)));
}
/* now coin_evs */
for (j=0;j<TALER_CNC_KAPPA;j++)
{
tmp = json_array ();
for (i=0;i<md->num_fresh_coins;i++)
{
const struct TALER_PlanchetSecretsP *fc = &md->fresh_coins[j][i];
struct TALER_PlanchetDetail pd;
if (GNUNET_OK !=
TALER_planchet_prepare (&md->fresh_pks[i],
fc,
&pd))
{
/* This should have been noticed during the preparation stage. */
GNUNET_break (0);
json_decref (new_denoms);
json_decref (tmp);
json_decref (coin_evs);
json_decref (melt_coin);
json_decref (transfer_pubs);
return NULL;
}
GNUNET_assert (0 ==
json_array_append_new (tmp,
GNUNET_JSON_from_data (pd.coin_ev,
pd.coin_ev_size)));
GNUNET_free (pd.coin_ev);
}
GNUNET_assert (0 ==
json_array_append_new (coin_evs,
tmp));
}
/* finally, assemble main JSON request from constitutent arrays */
melt_obj = json_pack ("{s:o, s:o, s:o, s:o}",
"new_denoms", new_denoms,
"melt_coin", melt_coin,
"coin_evs", coin_evs,
"transfer_pubs", transfer_pubs);
melt.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT);
melt.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
melt.rc = md->rc;
TALER_amount_hton (&melt.amount_with_fee,
&md->melted_coin.melt_amount_with_fee);
TALER_amount_hton (&melt.melt_fee,
&md->melted_coin.fee_melt);
GNUNET_CRYPTO_eddsa_key_get_public (&md->melted_coin.coin_priv.eddsa_priv,
&melt.coin_pub.eddsa_pub);
GNUNET_CRYPTO_eddsa_sign (&md->melted_coin.coin_priv.eddsa_priv,
&melt.purpose,
&confirm_sig.eddsa_signature);
melt_obj = json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o}",
"coin_pub",
GNUNET_JSON_from_data_auto (&melt.coin_pub),
"denom_pub",
GNUNET_JSON_from_rsa_public_key (md->melted_coin.pub_key.rsa_public_key),
"denom_sig",
GNUNET_JSON_from_rsa_signature (md->melted_coin.sig.rsa_signature),
"confirm_sig",
GNUNET_JSON_from_data_auto (&confirm_sig),
"value_with_fee",
TALER_JSON_from_amount (&md->melted_coin.melt_amount_with_fee),
"rc",
GNUNET_JSON_from_data_auto (&melt.rc));
if (NULL == melt_obj)
{
GNUNET_break (0);
free_melt_data (md);
return NULL;
}
@ -1325,7 +1201,6 @@ TALER_EXCHANGE_refresh_melt (struct TALER_EXCHANGE_Handle *exchange,
rmh->md = md;
rmh->url = MAH_path_to_url (exchange,
"/refresh/melt");
eh = curl_easy_init ();
GNUNET_assert (NULL != (rmh->json_enc =
json_dumps (melt_obj,
@ -1449,7 +1324,6 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshRevealHandle *rrh,
struct TALER_CoinSpendPrivateKeyP *coin_privs,
struct TALER_DenominationSignature *sigs)
{
unsigned int i;
json_t *jsona;
struct GNUNET_JSON_Specification outer_spec[] = {
GNUNET_JSON_spec_json ("ev_sigs", &jsona),
@ -1478,7 +1352,7 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshRevealHandle *rrh,
GNUNET_JSON_parse_free (outer_spec);
return GNUNET_SYSERR;
}
for (i=0;i<rrh->md->num_fresh_coins;i++)
for (unsigned int i=0;i<rrh->md->num_fresh_coins;i++)
{
const struct TALER_PlanchetSecretsP *fc;
struct TALER_DenominationPublicKey *pk;
@ -1559,7 +1433,6 @@ handle_refresh_reveal_finished (void *cls,
{
struct TALER_CoinSpendPrivateKeyP coin_privs[rrh->md->num_fresh_coins];
struct TALER_DenominationSignature sigs[rrh->md->num_fresh_coins];
unsigned int i;
int ret;
memset (sigs, 0, sizeof (sigs));
@ -1582,7 +1455,7 @@ handle_refresh_reveal_finished (void *cls,
json);
rrh->reveal_cb = NULL;
}
for (i=0;i<rrh->md->num_fresh_coins;i++)
for (unsigned int i=0;i<rrh->md->num_fresh_coins;i++)
if (NULL != sigs[i].rsa_signature)
GNUNET_CRYPTO_rsa_signature_free (sigs[i].rsa_signature);
}
@ -1647,17 +1520,19 @@ struct TALER_EXCHANGE_RefreshRevealHandle *
TALER_EXCHANGE_refresh_reveal (struct TALER_EXCHANGE_Handle *exchange,
size_t refresh_data_length,
const char *refresh_data,
uint16_t noreveal_index,
uint32_t noreveal_index,
TALER_EXCHANGE_RefreshRevealCallback reveal_cb,
void *reveal_cb_cls)
{
struct TALER_EXCHANGE_RefreshRevealHandle *rrh;
json_t *transfer_privs;
json_t *new_denoms_h;
json_t *coin_evs;
json_t *reveal_obj;
CURL *eh;
struct GNUNET_CURL_Context *ctx;
struct MeltData *md;
unsigned int j;
struct TALER_TransferPublicKeyP transfer_pub;
GNUNET_assert (GNUNET_YES ==
MAH_handle_is_ready (exchange));
@ -1678,9 +1553,45 @@ TALER_EXCHANGE_refresh_reveal (struct TALER_EXCHANGE_Handle *exchange,
return NULL;
}
/* now transfer_pub */
GNUNET_CRYPTO_ecdhe_key_get_public (&md->melted_coin.transfer_priv[noreveal_index].ecdhe_priv,
&transfer_pub.ecdhe_pub);
/* now new_denoms */
GNUNET_assert (NULL != (new_denoms_h = json_array ()));
GNUNET_assert (NULL != (coin_evs = json_array ()));
for (unsigned int i=0;i<md->num_fresh_coins;i++)
{
struct GNUNET_HashCode denom_hash;
struct TALER_PlanchetDetail pd;
GNUNET_CRYPTO_rsa_public_key_hash (md->fresh_pks[i].rsa_public_key,
&denom_hash);
GNUNET_assert (0 ==
json_array_append_new (new_denoms_h,
GNUNET_JSON_from_data_auto (&denom_hash)));
if (GNUNET_OK !=
TALER_planchet_prepare (&md->fresh_pks[i],
&md->fresh_coins[noreveal_index][i],
&pd))
{
/* This should have been noticed during the preparation stage. */
GNUNET_break (0);
json_decref (new_denoms_h);
json_decref (coin_evs);
return NULL;
}
GNUNET_assert (0 ==
json_array_append_new (coin_evs,
GNUNET_JSON_from_data (pd.coin_ev,
pd.coin_ev_size)));
GNUNET_free (pd.coin_ev);
}
/* build array of transfer private keys */
transfer_privs = json_array ();
for (j=0;j<TALER_CNC_KAPPA;j++)
GNUNET_assert (NULL != (transfer_privs = json_array ()));
for (unsigned int j=0;j<TALER_CNC_KAPPA;j++)
{
if (j == noreveal_index)
{
@ -1694,11 +1605,17 @@ TALER_EXCHANGE_refresh_reveal (struct TALER_EXCHANGE_Handle *exchange,
}
/* build main JSON request */
reveal_obj = json_pack ("{s:o, s:o}",
"session_hash",
GNUNET_JSON_from_data_auto (&md->melt_session_hash),
reveal_obj = json_pack ("{s:o, s:o, s:o, s:o, s:o}",
"rc",
GNUNET_JSON_from_data_auto (&md->rc),
"transfer_pub",
GNUNET_JSON_from_data_auto (&transfer_pub),
"transfer_privs",
transfer_privs);
transfer_privs,
"new_denoms_h",
new_denoms_h,
"coin_evs",
coin_evs);
if (NULL == reveal_obj)
{
GNUNET_break (0);

View File

@ -1199,7 +1199,7 @@ static void
melt_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
uint16_t noreveal_index,
uint32_t noreveal_index,
const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *full_response)
{
@ -1312,8 +1312,6 @@ link_cb (void *cls,
struct InterpreterState *is = cls;
struct Command *cmd = &is->commands[is->ip];
const struct Command *ref;
unsigned int i;
unsigned int j;
unsigned int found;
cmd->details.refresh_link.rlh = NULL;
@ -1341,16 +1339,16 @@ link_cb (void *cls,
return;
}
/* check that the coins match */
for (i=0;i<num_coins;i++)
for (j=i+1;j<num_coins;j++)
for (unsigned int i=0;i<num_coins;i++)
for (unsigned int j=i+1;j<num_coins;j++)
if (0 == memcmp (&coin_privs[i],
&coin_privs[j],
sizeof (struct TALER_CoinSpendPrivateKeyP)))
GNUNET_break (0);
/* Note: coins might be legitimately permutated in here... */
found = 0;
for (i=0;i<num_coins;i++)
for (j=0;j<num_coins;j++)
for (unsigned int i=0;i<num_coins;i++)
for (unsigned int j=0;j<num_coins;j++)
{
const struct FreshCoin *fc;

View File

@ -155,7 +155,7 @@ TEH_DB_calculate_transaction_list_totals (struct TALER_EXCHANGEDB_TransactionLis
if (GNUNET_OK !=
TALER_amount_add (&spent,
&spent,
&pos->details.melt->amount_with_fee))
&pos->details.melt->session.amount_with_fee))
{
GNUNET_break (0);
return GNUNET_SYSERR;

View File

@ -39,7 +39,7 @@
* release version, and the format is NOT the same that semantic
* versioning uses either.
*/
#define TALER_PROTOCOL_VERSION "1:0:1"
#define TALER_PROTOCOL_VERSION "2:0:0"
/**
@ -1662,15 +1662,37 @@ TEH_KS_denomination_key_lookup (const struct TEH_KS_StateHandle *key_state,
enum TEH_KS_DenominationKeyUse use)
{
struct GNUNET_HashCode hc;
GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
&hc);
return TEH_KS_denomination_key_lookup_by_hash (key_state,
&hc,
use);
}
/**
* Look up the issue for a denom public key. Note that the result
* is only valid while the @a key_state is not released!
*
* @param key_state state to look in
* @param denom_pub_hash hash of denomination public key
* @param use purpose for which the key is being located
* @return the denomination key issue,
* or NULL if denom_pub could not be found (or is not valid at this time for the given @a use)
*/
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *
TEH_KS_denomination_key_lookup_by_hash (const struct TEH_KS_StateHandle *key_state,
const struct GNUNET_HashCode *denom_pub_hash,
enum TEH_KS_DenominationKeyUse use)
{
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
struct GNUNET_TIME_Absolute now;
const struct GNUNET_CONTAINER_MultiHashMap *map;
GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
&hc);
map = (TEH_KS_DKU_PAYBACK == use) ? key_state->revoked_map : key_state->denomkey_map;
dki = GNUNET_CONTAINER_multihashmap_get (map,
&hc);
denom_pub_hash);
if (NULL == dki)
return NULL;
now = GNUNET_TIME_absolute_get ();
@ -1679,7 +1701,7 @@ TEH_KS_denomination_key_lookup (const struct TEH_KS_StateHandle *key_state,
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Not returning DKI for %s, as start time is in the future\n",
GNUNET_h2s (&hc));
GNUNET_h2s (denom_pub_hash));
return NULL;
}
now = GNUNET_TIME_absolute_get ();
@ -1691,7 +1713,7 @@ TEH_KS_denomination_key_lookup (const struct TEH_KS_StateHandle *key_state,
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Not returning DKI for %s, as time to create coins has passed\n",
GNUNET_h2s (&hc));
GNUNET_h2s (denom_pub_hash));
return NULL;
}
break;
@ -1701,7 +1723,7 @@ TEH_KS_denomination_key_lookup (const struct TEH_KS_StateHandle *key_state,
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Not returning DKI for %s, as time to spend coin has passed\n",
GNUNET_h2s (&hc));
GNUNET_h2s (denom_pub_hash));
return NULL;
}
break;
@ -1711,7 +1733,7 @@ TEH_KS_denomination_key_lookup (const struct TEH_KS_StateHandle *key_state,
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Not returning DKI for %s, as time to payback coin has passed\n",
GNUNET_h2s (&hc));
GNUNET_h2s (denom_pub_hash));
return NULL;
}
break;

View File

@ -120,6 +120,22 @@ TEH_KS_denomination_key_lookup (const struct TEH_KS_StateHandle *key_state,
enum TEH_KS_DenominationKeyUse use);
/**
* Look up the issue for a denom public key. Note that the result
* is only valid while the @a key_state is not released!
*
* @param key_state state to look in
* @param denom_pub_hash hash of denomination public key
* @param use purpose for which the key is being located
* @return the denomination key issue,
* or NULL if denom_pub could not be found (or is not valid at this time for the given @a use)
*/
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *
TEH_KS_denomination_key_lookup_by_hash (const struct TEH_KS_StateHandle *key_state,
const struct GNUNET_HashCode *denom_pub_hash,
enum TEH_KS_DenominationKeyUse use);
/**
* Read signals from a pipe in a loop, and reload keys from disk if
* SIGUSR1 is received, terminate if SIGTERM/SIGINT is received, and

View File

@ -31,24 +31,6 @@
#include "taler-exchange-httpd_keystate.h"
/**
* @brief Information for each session a coin was melted into.
*/
struct TEH_RESPONSE_LinkSessionInfo
{
/**
* Transfer public key of the coin.
*/
struct TALER_TransferPublicKeyP transfer_pub;
/**
* Linked data of coins being created in the session.
*/
struct TALER_EXCHANGEDB_LinkDataList *ldl;
};
/**
* Closure for #handle_transfer_data().
*/
@ -56,98 +38,20 @@ struct HTD_Context
{
/**
* Public key of the coin that we are tracing.
* Public key of the coin for which we are running /refresh/link.
*/
struct TALER_CoinSpendPublicKeyP coin_pub;
/**
* Session link data we collect.
* Json array with transfer data we collect.
*/
struct TEH_RESPONSE_LinkSessionInfo *sessions;
/**
* Database session. Nothing to do with @a sessions.
*/
struct TALER_EXCHANGEDB_Session *session;
/**
* MHD connection, for queueing replies.
*/
struct MHD_Connection *connection;
/**
* Number of sessions the coin was melted into.
*/
unsigned int num_sessions;
/**
* How are we expected to proceed. #GNUNET_SYSERR if we
* failed to return an error (should return #MHD_NO).
* #GNUNET_NO if we succeeded in queueing an MHD error
* (should return #MHD_YES from #TEH_execute_refresh_link),
* #GNUNET_OK if we should call #reply_refresh_link_success().
*/
int status;
};
/**
* Send a response for "/refresh/link".
*
* @param connection the connection to send the response to
* @param num_sessions number of sessions the coin was used in
* @param sessions array of @a num_session entries with
* information for each session
* @return a MHD result code
*/
static int
reply_refresh_link_success (struct MHD_Connection *connection,
unsigned int num_sessions,
const struct TEH_RESPONSE_LinkSessionInfo *sessions)
{
json_t *mlist;
int res;
mlist = json_array ();
for (unsigned int i=0;i<num_sessions;i++)
{
json_t *list = json_array ();
json_t *root;
for (const struct TALER_EXCHANGEDB_LinkDataList *pos = sessions[i].ldl;
NULL != pos;
pos = pos->next)
{
json_t *obj;
obj = json_object ();
json_object_set_new (obj,
"denom_pub",
GNUNET_JSON_from_rsa_public_key (pos->denom_pub.rsa_public_key));
json_object_set_new (obj,
"ev_sig",
GNUNET_JSON_from_rsa_signature (pos->ev_sig.rsa_signature));
GNUNET_assert (0 ==
json_array_append_new (list,
obj));
}
root = json_object ();
json_object_set_new (root,
"new_coins",
list);
json_object_set_new (root,
"transfer_pub",
GNUNET_JSON_from_data_auto (&sessions[i].transfer_pub));
GNUNET_assert (0 ==
json_array_append_new (mlist,
root));
}
res = TEH_RESPONSE_reply_json (connection,
mlist,
MHD_HTTP_OK);
json_decref (mlist);
return res;
}
/**
* Taler error code.
*/
enum TALER_ErrorCode ec;
};
/**
@ -157,58 +61,59 @@ reply_refresh_link_success (struct MHD_Connection *connection,
*
*
* @param cls closure, a `struct HTD_Context`
* @param session_hash a session the coin was melted in
* @param transfer_pub public transfer key for the session
* @param ldl link data related to @a transfer_pub
*/
static void
handle_transfer_data (void *cls,
const struct GNUNET_HashCode *session_hash,
const struct TALER_TransferPublicKeyP *transfer_pub)
handle_link_data (void *cls,
const struct TALER_TransferPublicKeyP *transfer_pub,
const struct TALER_EXCHANGEDB_LinkDataList *ldl)
{
struct HTD_Context *ctx = cls;
struct TALER_EXCHANGEDB_LinkDataList *ldl;
struct TEH_RESPONSE_LinkSessionInfo *lsi;
enum GNUNET_DB_QueryStatus qs;
json_t *list;
json_t *root;
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != ctx->status)
if (NULL == ctx->mlist)
return;
ldl = NULL;
qs = TEH_plugin->get_link_data_list (TEH_plugin->cls,
ctx->session,
session_hash,
&ldl);
if (qs <= 0)
if (NULL == (list = json_array ()))
goto fail;
for (const struct TALER_EXCHANGEDB_LinkDataList *pos = ldl;
NULL != pos;
pos = pos->next)
{
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
ctx->status = GNUNET_DB_STATUS_HARD_ERROR;
else
ctx->status = qs;
return;
json_t *obj;
if (NULL == (obj = json_object ()))
goto fail;
json_object_set_new (obj,
"denom_pub",
GNUNET_JSON_from_rsa_public_key (pos->denom_pub.rsa_public_key));
json_object_set_new (obj,
"ev_sig",
GNUNET_JSON_from_rsa_signature (pos->ev_sig.rsa_signature));
if (0 !=
json_array_append_new (list,
obj))
goto fail;
}
GNUNET_assert (NULL != ldl);
GNUNET_array_grow (ctx->sessions,
ctx->num_sessions,
ctx->num_sessions + 1);
lsi = &ctx->sessions[ctx->num_sessions - 1];
lsi->transfer_pub = *transfer_pub;
lsi->ldl = ldl;
}
/**
* Free session data kept in @a ctx
*
* @param ctx context to clean up
*/
static void
purge_context (struct HTD_Context *ctx)
{
for (unsigned int i=0;i<ctx->num_sessions;i++)
TEH_plugin->free_link_data_list (TEH_plugin->cls,
ctx->sessions[i].ldl);
GNUNET_free_non_null (ctx->sessions);
ctx->sessions = NULL;
ctx->num_sessions = 0;
if (NULL == (root = json_object ()))
goto fail;
json_object_set_new (root,
"new_coins",
list);
json_object_set_new (root,
"transfer_pub",
GNUNET_JSON_from_data_auto (transfer_pub));
if (0 !=
json_array_append_new (ctx->mlist,
root))
goto fail;
return;
fail:
ctx->ec = TALER_EC_JSON_ALLOCATION_FAILURE;
json_decref (ctx->mlist);
ctx->mlist = NULL;
}
@ -239,14 +144,18 @@ refresh_link_transaction (void *cls,
struct HTD_Context *ctx = cls;
enum GNUNET_DB_QueryStatus qs;
ctx->session = session;
ctx->status = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
qs = TEH_plugin->get_transfer (TEH_plugin->cls,
qs = TEH_plugin->get_link_data (TEH_plugin->cls,
session,
&ctx->coin_pub,
&handle_transfer_data,
&handle_link_data,
ctx);
ctx->session = NULL;
if (NULL == ctx->mlist)
{
*mhd_ret = TEH_RESPONSE_reply_internal_error (connection,
ctx->ec,
"coin_pub");
return GNUNET_DB_STATUS_HARD_ERROR;
}
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
{
*mhd_ret = TEH_RESPONSE_reply_arg_unknown (connection,
@ -254,21 +163,6 @@ refresh_link_transaction (void *cls,
"coin_pub");
return GNUNET_DB_STATUS_HARD_ERROR;
}
if (0 < qs)
{
qs = ctx->status;
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
{
*mhd_ret = TEH_RESPONSE_reply_json_pack (ctx->connection,
MHD_HTTP_NOT_FOUND,
"{s:s}",
"error",
"link data not found (link)");
return GNUNET_DB_STATUS_HARD_ERROR;
}
return qs;
}
purge_context (ctx);
return qs;
}
@ -306,19 +200,21 @@ TEH_REFRESH_handler_refresh_link (struct TEH_RequestHandler *rh,
return MHD_NO;
if (GNUNET_OK != res)
return MHD_YES;
ctx.mlist = json_array ();
if (GNUNET_OK !=
TEH_DB_run_transaction (connection,
&mhd_ret,
&refresh_link_transaction,
&ctx))
{
purge_context (&ctx);
if (NULL != ctx.mlist)
json_decref (ctx.mlist);
return mhd_ret;
}
mhd_ret = reply_refresh_link_success (connection,
ctx.num_sessions,
ctx.sessions);
purge_context (&ctx);
mhd_ret = TEH_RESPONSE_reply_json (connection,
ctx.mlist,
MHD_HTTP_OK);
json_decref (ctx.mlist);
return mhd_ret;
}

View File

@ -31,38 +31,6 @@
#include "taler-exchange-httpd_keystate.h"
/**
* @brief Details about a melt operation of an individual coin.
*/
struct TEH_DB_MeltDetails
{
/**
* Information about the coin being melted.
*/
struct TALER_CoinPublicInfo coin_info;
/**
* Signature allowing the melt (using
* a `struct TALER_EXCHANGEDB_RefreshMeltConfirmSignRequestBody`) to sign over.
*/
struct TALER_CoinSpendSignatureP melt_sig;
/**
* How much of the coin's value did the client allow to be melted?
* This amount includes the fees, so the final amount contributed
* to the melt is this value minus the fee for melting the coin.
*/
struct TALER_Amount melt_amount_with_fee;
/**
* What fee is earned by the exchange? Set delayed during
* #verify_coin_public_info().
*/
struct TALER_Amount melt_fee;
};
/**
* Send a response for a failed "/refresh/melt" request. The
* transaction history of the given coin demonstrates that the
@ -116,14 +84,14 @@ reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection,
* Send a response to a "/refresh/melt" request.
*
* @param connection the connection to send the response to
* @param session_hash hash of the refresh session
* @param rc value the client commited to
* @param noreveal_index which index will the client not have to reveal
* @return a MHD status code
*/
static int
reply_refresh_melt_success (struct MHD_Connection *connection,
const struct GNUNET_HashCode *session_hash,
uint16_t noreveal_index)
const struct TALER_RefreshCommitmentP *rc,
uint32_t noreveal_index)
{
struct TALER_RefreshMeltConfirmationPS body;
struct TALER_ExchangePublicKeyP pub;
@ -132,9 +100,8 @@ reply_refresh_melt_success (struct MHD_Connection *connection,
body.purpose.size = htonl (sizeof (struct TALER_RefreshMeltConfirmationPS));
body.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT);
body.session_hash = *session_hash;
body.noreveal_index = htons (noreveal_index);
body.reserved = htons (0);
body.rc = *rc;
body.noreveal_index = htonl (noreveal_index);
if (GNUNET_OK !=
TEH_KS_sign (&body.purpose,
&pub,
@ -162,63 +129,22 @@ struct RefreshMeltContext
{
/**
* Key state that can be used to lookup keys.
*/
struct TEH_KS_StateHandle *key_state;
/**
* Information about the denomination key of the coin being
* melted.
*/
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
/**
* Array of denominations of the fresh coins.
*/
struct TALER_DenominationPublicKey *denom_pubs;
/**
* Number of new coins to be generated in the melt.
* Size of the @e denom_pubs array.
*/
unsigned int num_newcoins;
/**
* Details about the coin to be melted.
*/
struct TEH_DB_MeltDetails coin_melt_details;
/**
* Set to the session hash once the @e hash_context has finished.
*/
struct GNUNET_HashCode session_hash;
/**
* Hash operation used to calculate the session hash.
*/
struct GNUNET_HashContext *hash_context;
/**
* Committments to the blinded envelopes for the fresh coins.
*/
struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin[TALER_CNC_KAPPA];
/**
* Commmittments to the transfer public keys.
*/
struct TALER_TransferPublicKeyP transfer_pub[TALER_CNC_KAPPA];
/**
* Initialized during #refresh_melt_transaction().
* noreveal_index is only initialized during
* #refresh_melt_transaction().
*/
struct TALER_EXCHANGEDB_RefreshSession refresh_session;
/**
* Information about the @e coin's denomination.
*/
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
};
/**
* Parse coin melt requests from a JSON object and write them to
* the database.
* Check that the coin has sufficient funds left for the selected
* melt operation.
*
* @param connection the connection to send errors to
* @param session the database connection
@ -233,20 +159,19 @@ refresh_check_melt (struct MHD_Connection *connection,
int *mhd_ret)
{
struct TALER_EXCHANGEDB_TransactionList *tl;
struct TALER_EXCHANGEDB_RefreshMelt *meltp = &rmc->refresh_session.melt;
struct TALER_Amount coin_value;
struct TALER_Amount coin_residual;
struct TALER_Amount spent;
enum GNUNET_DB_QueryStatus qs;
TALER_amount_ntoh (&coin_value,
&rmc->dki->issue.properties.value);
/* fee for THIS transaction; the melt amount includes the fee! */
spent = rmc->coin_melt_details.melt_amount_with_fee;
/* Start with cost of this melt transaction */
spent = rmc->refresh_session.amount_with_fee;
/* add historic transaction costs of this coin */
qs = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
session,
&rmc->coin_melt_details.coin_info.coin_pub,
&rmc->refresh_session.coin.coin_pub,
&tl);
if (0 > qs)
{
@ -267,33 +192,32 @@ refresh_check_melt (struct MHD_Connection *connection,
TALER_EC_REFRESH_MELT_COIN_HISTORY_COMPUTATION_FAILED);
return GNUNET_DB_STATUS_HARD_ERROR;
}
/* Refuse to refresh when the coin's value is insufficient
for the cost of all transactions. */
if (TALER_amount_cmp (&coin_value,
&spent) < 0)
{
struct TALER_Amount coin_residual;
GNUNET_assert (GNUNET_SYSERR !=
TALER_amount_subtract (&coin_residual,
&spent,
&rmc->coin_melt_details.melt_amount_with_fee));
&rmc->refresh_session.amount_with_fee));
*mhd_ret = reply_refresh_melt_insufficient_funds (connection,
&rmc->coin_melt_details.coin_info.coin_pub,
&rmc->refresh_session.coin.coin_pub,
coin_value,
tl,
&rmc->coin_melt_details.melt_amount_with_fee,
&rmc->refresh_session.amount_with_fee,
&coin_residual);
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl);
return GNUNET_DB_STATUS_HARD_ERROR;
}
/* we're good, coin has sufficient funds to be melted */
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl);
meltp->coin = rmc->coin_melt_details.coin_info;
meltp->coin_sig = rmc->coin_melt_details.melt_sig;
meltp->session_hash = rmc->session_hash;
meltp->amount_with_fee = rmc->coin_melt_details.melt_amount_with_fee;
meltp->melt_fee = rmc->coin_melt_details.melt_fee;
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
}
@ -325,17 +249,19 @@ refresh_melt_transaction (void *cls,
int *mhd_ret)
{
struct RefreshMeltContext *rmc = cls;
struct TALER_EXCHANGEDB_RefreshMelt rm;
enum GNUNET_DB_QueryStatus qs;
qs = TEH_plugin->get_refresh_session (TEH_plugin->cls,
/* Check if we already created such a session */
qs = TEH_plugin->get_melt (TEH_plugin->cls,
session,
&rmc->session_hash,
&rmc->refresh_session);
&rmc->refresh_session.rc,
&rm);
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
{
*mhd_ret = reply_refresh_melt_success (connection,
&rmc->session_hash,
rmc->refresh_session.noreveal_index);
&rmc->refresh_session.rc,
rm.session.noreveal_index);
return GNUNET_DB_STATUS_HARD_ERROR;
}
if (0 > qs)
@ -346,12 +272,7 @@ refresh_melt_transaction (void *cls,
return qs;
}
/* store 'global' session data */
rmc->refresh_session.num_newcoins = rmc->num_newcoins;
rmc->refresh_session.noreveal_index
= GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
TALER_CNC_KAPPA);
/* check coin has enough funds remaining on it to cover melt cost */
qs = refresh_check_melt (connection,
session,
rmc,
@ -359,28 +280,15 @@ refresh_melt_transaction (void *cls,
if (0 > qs)
return qs;
if ( (0 >=
(qs = TEH_plugin->create_refresh_session (TEH_plugin->cls,
/* pick challenge and persist it */
rmc->refresh_session.noreveal_index
= GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
TALER_CNC_KAPPA);
if (0 >=
(qs = TEH_plugin->insert_melt (TEH_plugin->cls,
session,
&rmc->session_hash,
&rmc->refresh_session))) ||
(0 >=
(qs = TEH_plugin->insert_refresh_order (TEH_plugin->cls,
session,
&rmc->session_hash,
rmc->num_newcoins,
rmc->denom_pubs))) ||
(0 >=
(qs = TEH_plugin->insert_refresh_commit_coins (TEH_plugin->cls,
session,
&rmc->session_hash,
rmc->num_newcoins,
rmc->commit_coin[rmc->refresh_session.noreveal_index]))) ||
(0 >=
(qs = TEH_plugin->insert_refresh_transfer_public_key (TEH_plugin->cls,
session,
&rmc->session_hash,
&rmc->transfer_pub[rmc->refresh_session.noreveal_index]))) )
&rmc->refresh_session)))
{
if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
{
@ -394,233 +302,6 @@ refresh_melt_transaction (void *cls,
}
/**
* Handle a "/refresh/melt" request after the main JSON parsing has
* happened. We now need to validate the coins being melted and the
* session signature and then hand things of to execute the melt
* operation.
*
* @param connection the MHD connection to handle
* @param[out] mhd_ret set on failure to return value for MHD
* @param rmc information about the melt to process
* @return MHD result code
*/
static int
refresh_melt_prepare (struct MHD_Connection *connection,
int *mhd_ret,
struct RefreshMeltContext *rmc)
{
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dk;
struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki;
struct TALER_Amount cost;
struct TALER_Amount total_cost;
struct TALER_Amount value;
struct TALER_Amount fee_withdraw;
struct TALER_Amount fee_melt;
struct TALER_Amount total_melt;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"/refresh/melt request for session %s\n",
GNUNET_h2s (&rmc->session_hash));
GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (TEH_exchange_currency_string,
&total_cost));
for (unsigned int i=0;i<rmc->num_newcoins;i++)
{
dk = TEH_KS_denomination_key_lookup (rmc->key_state,
&rmc->denom_pubs[i],
TEH_KS_DKU_WITHDRAW);
if (NULL == dk)
{
GNUNET_break_op (0);
*mhd_ret = TEH_RESPONSE_reply_arg_invalid (connection,
TALER_EC_REFRESH_MELT_FRESH_DENOMINATION_KEY_NOT_FOUND,
"new_denoms");
return GNUNET_SYSERR;
}
dki = &dk->issue;
TALER_amount_ntoh (&value,
&dki->properties.value);
TALER_amount_ntoh (&fee_withdraw,
&dki->properties.fee_withdraw);
if ( (GNUNET_OK !=
TALER_amount_add (&cost,
&value,
&fee_withdraw)) ||
(GNUNET_OK !=
TALER_amount_add (&total_cost,
&cost,
&total_cost)) )
{
GNUNET_break_op (0);
*mhd_ret = TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_REFRESH_MELT_COST_CALCULATION_OVERFLOW,
"cost calculation failure");
return GNUNET_SYSERR;
}
}
dki = &rmc->dki->issue;
TALER_amount_ntoh (&fee_melt,
&dki->properties.fee_refresh);
if (GNUNET_OK !=
TALER_amount_subtract (&total_melt,
&rmc->coin_melt_details.melt_amount_with_fee,
&fee_melt))
{
GNUNET_break_op (0);
*mhd_ret = TEH_RESPONSE_reply_external_error (connection,
TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION,
"Melt contribution below melting fee");
return GNUNET_SYSERR;
}
if (0 !=
TALER_amount_cmp (&total_cost,
&total_melt))
{
GNUNET_break_op (0);
/* We require total value of coins being melted and
total value of coins being generated to match! */
*mhd_ret = TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:I}",
"error", "value mismatch",
"code", (json_int_t) TALER_EC_REFRESH_MELT_FEES_MISSMATCH);
return GNUNET_SYSERR;
}
return TEH_DB_run_transaction (connection,
mhd_ret,
&refresh_melt_transaction,
rmc);
}
/**
* Extract public coin information from a JSON object.
*
* @param connection the connection to send error responses to
* @param coin_info the JSON object to extract the coin info from
* @param[out] r_melt_detail set to details about the coin's melting permission (if valid)
* @return #GNUNET_YES if coin public info in JSON was valid
* #GNUNET_NO JSON was invalid, response was generated
* #GNUNET_SYSERR on internal error
*/
static int
get_coin_public_info (struct MHD_Connection *connection,
const json_t *coin_info,
struct TEH_DB_MeltDetails *r_melt_detail)
{
int ret;
struct TALER_CoinSpendSignatureP melt_sig;
struct TALER_DenominationSignature sig;
struct TALER_DenominationPublicKey pk;
struct TALER_Amount amount;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("coin_pub", &r_melt_detail->coin_info.coin_pub),
TALER_JSON_spec_denomination_signature ("denom_sig", &sig),
TALER_JSON_spec_denomination_public_key ("denom_pub", &pk),
GNUNET_JSON_spec_fixed_auto ("confirm_sig", &melt_sig),
TALER_JSON_spec_amount ("value_with_fee", &amount),
GNUNET_JSON_spec_end ()
};
ret = TEH_PARSE_json_data (connection,
coin_info,
spec);
if (GNUNET_OK != ret)
{
GNUNET_break_op (0);
return ret;
}
/* check exchange signature on the coin */
r_melt_detail->coin_info.denom_sig = sig;
r_melt_detail->coin_info.denom_pub = pk;
if (GNUNET_OK !=
TALER_test_coin_valid (&r_melt_detail->coin_info))
{
GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
r_melt_detail->coin_info.denom_sig.rsa_signature = NULL;
r_melt_detail->coin_info.denom_pub.rsa_public_key = NULL;
return (MHD_YES ==
TEH_RESPONSE_reply_signature_invalid (connection,
TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID,
"denom_sig"))
? GNUNET_NO : GNUNET_SYSERR;
}
r_melt_detail->melt_sig = melt_sig;
r_melt_detail->melt_amount_with_fee = amount;
return GNUNET_OK;
}
/**
* Release memory from the @a commit_coin array.
*
* @param commit_coin array to release
* @param kappa size of 1st dimension
* @param num_new_coins size of 2nd dimension
*/
static void
free_commit_coins (struct TALER_EXCHANGEDB_RefreshCommitCoin **commit_coin,
unsigned int kappa,
unsigned int num_new_coins)
{
for (unsigned int i=0;i<kappa;i++)
{
if (NULL == commit_coin[i])
break;
for (unsigned int j=0;j<num_new_coins;j++)
GNUNET_free_non_null (commit_coin[i][j].coin_ev);
GNUNET_free (commit_coin[i]);
commit_coin[i] = NULL;
}
}
/**
* Cleanup state kept in the @a rmc.
*
* @param rmc state to clean up; does not free @a rmc itself
*/
static void
cleanup_rmc (struct RefreshMeltContext *rmc)
{
free_commit_coins (rmc->commit_coin,
TALER_CNC_KAPPA,
rmc->num_newcoins);
if (NULL != rmc->coin_melt_details.coin_info.denom_pub.rsa_public_key)
{
GNUNET_CRYPTO_rsa_public_key_free (rmc->coin_melt_details.coin_info.denom_pub.rsa_public_key);
rmc->coin_melt_details.coin_info.denom_pub.rsa_public_key = NULL;
}
if (NULL != rmc->coin_melt_details.coin_info.denom_sig.rsa_signature)
{
GNUNET_CRYPTO_rsa_signature_free (rmc->coin_melt_details.coin_info.denom_sig.rsa_signature);
rmc->coin_melt_details.coin_info.denom_sig.rsa_signature = NULL;
}
if (NULL != rmc->denom_pubs)
{
for (unsigned int j=0;j<rmc->num_newcoins;j++)
if (NULL != rmc->denom_pubs[j].rsa_public_key)
GNUNET_CRYPTO_rsa_public_key_free (rmc->denom_pubs[j].rsa_public_key);
GNUNET_free (rmc->denom_pubs);
rmc->denom_pubs = NULL;
}
if (NULL != rmc->hash_context)
{
GNUNET_CRYPTO_hash_context_abort (rmc->hash_context);
rmc->hash_context = NULL;
}
if (NULL != rmc->key_state)
{
TEH_KS_release (rmc->key_state);
rmc->key_state = NULL;
}
}
/**
* Handle a "/refresh/melt" request after the first parsing has
* happened. We now need to validate the coins being melted and the
@ -629,223 +310,70 @@ cleanup_rmc (struct RefreshMeltContext *rmc)
* processing on to #handle_refresh_melt_binary().
*
* @param connection the MHD connection to handle
* @param new_denoms array of denomination keys
* @param melt_coin coin to melt
* @param transfer_pubs #TALER_CNC_KAPPA-dimensional array of transfer keys
* @param coin_evs #TALER_CNC_KAPPA-dimensional array of envelopes to sign
* @param[in,out] rmc details about the melt request
* @return MHD result code
*/
static int
handle_refresh_melt_json (struct MHD_Connection *connection,
const json_t *new_denoms,
const json_t *melt_coin,
const json_t *transfer_pubs,
const json_t *coin_evs)
handle_refresh_melt (struct MHD_Connection *connection,
struct RefreshMeltContext *rmc)
{
int res;
int mhd_ret;
struct RefreshMeltContext rmc;
memset (&rmc,
0,
sizeof (rmc));
/* For the signature check, we hash most of the inputs together
(except for the signatures on the coins). */
rmc.hash_context = GNUNET_CRYPTO_hash_context_start ();
for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)
/* sanity-check that "total melt amount > melt fee" */
{
struct GNUNET_JSON_Specification trans_spec[] = {
GNUNET_JSON_spec_fixed_auto (NULL, &rmc.transfer_pub[i]),
GNUNET_JSON_spec_end ()
};
struct TALER_Amount fee_refresh;
res = TEH_PARSE_json_array (connection,
transfer_pubs,
trans_spec,
i, -1);
if (GNUNET_OK != res)
TALER_amount_ntoh (&fee_refresh,
&rmc->dki->issue.properties.fee_refresh);
if (TALER_amount_cmp (&fee_refresh,
&rmc->refresh_session.amount_with_fee) > 0)
{
GNUNET_break_op (0);
mhd_ret = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
cleanup_rmc (&rmc);
return mhd_ret;
return TEH_RESPONSE_reply_external_error (connection,
TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION,
"melt amount smaller than melting fee");
}
GNUNET_CRYPTO_hash_context_read (rmc.hash_context,
&rmc.transfer_pub[i],
sizeof (struct TALER_TransferPublicKeyP));
}
rmc.num_newcoins = json_array_size (new_denoms);
rmc.denom_pubs = GNUNET_new_array (rmc.num_newcoins,
struct TALER_DenominationPublicKey);
for (unsigned int i=0;i<rmc.num_newcoins;i++)
{
char *buf;
size_t buf_size;
struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_denomination_public_key (NULL,
&rmc.denom_pubs[i]),
GNUNET_JSON_spec_end ()
};
res = TEH_PARSE_json_array (connection,
new_denoms,
spec,
i,
-1);
if (GNUNET_OK != res)
{
mhd_ret = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
cleanup_rmc (&rmc);
return mhd_ret;
}
buf_size = GNUNET_CRYPTO_rsa_public_key_encode (rmc.denom_pubs[i].rsa_public_key,
&buf);
GNUNET_CRYPTO_hash_context_read (rmc.hash_context,
buf,
buf_size);
GNUNET_free (buf);
}
/* decode JSON data on coin to melt and check that this is a
valid coin */
{
struct TALER_AmountNBO melt_amount;
res = get_coin_public_info (connection,
melt_coin,
&rmc.coin_melt_details);
if (GNUNET_OK != res)
{
GNUNET_break_op (0);
mhd_ret = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
cleanup_rmc (&rmc);
return mhd_ret;
}
TALER_amount_hton (&melt_amount,
&rmc.coin_melt_details.melt_amount_with_fee);
GNUNET_CRYPTO_hash_context_read (rmc.hash_context,
&rmc.coin_melt_details.coin_info.coin_pub,
sizeof (struct TALER_CoinSpendPublicKeyP));
GNUNET_CRYPTO_hash_context_read (rmc.hash_context,
&melt_amount,
sizeof (struct TALER_AmountNBO));
}
/* parse JSON arrays into binary arrays and hash everything
together for the signature check */
for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)
{
rmc.commit_coin[i] = GNUNET_new_array (rmc.num_newcoins,
struct TALER_EXCHANGEDB_RefreshCommitCoin);
for (unsigned int j = 0; j < rmc.num_newcoins; j++)
{
struct TALER_EXCHANGEDB_RefreshCommitCoin *rcc = &rmc.commit_coin[i][j];
struct GNUNET_JSON_Specification coin_spec[] = {
GNUNET_JSON_spec_varsize (NULL,
(void **) &rcc->coin_ev,
&rcc->coin_ev_size),
GNUNET_JSON_spec_end ()
};
res = TEH_PARSE_json_array (connection,
coin_evs,
coin_spec,
i,
j,
-1);
if (GNUNET_OK != res)
{
GNUNET_break_op (0);
mhd_ret = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
cleanup_rmc (&rmc);
return mhd_ret;
}
GNUNET_CRYPTO_hash_context_read (rmc.hash_context,
rcc->coin_ev,
rcc->coin_ev_size);
}
}
GNUNET_CRYPTO_hash_context_finish (rmc.hash_context,
&rmc.session_hash);
rmc.hash_context = NULL;
rmc.key_state = TEH_KS_acquire ();
if (NULL == rmc.key_state)
{
TALER_LOG_ERROR ("Lacking keys to operate\n");
return TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_EXCHANGE_BAD_CONFIGURATION,
"no keys");
}
rmc.dki = TEH_KS_denomination_key_lookup (rmc.key_state,
&rmc.coin_melt_details.coin_info.denom_pub,
TEH_KS_DKU_DEPOSIT);
if (NULL == rmc.dki)
{
TEH_KS_release (rmc.key_state);
TALER_LOG_WARNING ("Unknown denomination key in /refresh/melt request\n");
return TEH_RESPONSE_reply_arg_unknown (connection,
TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND,
"denom_pub");
}
/* verify signature of coin for melt operation */
{
struct TALER_RefreshMeltCoinAffirmationPS body;
struct TALER_Amount fee_refresh;
TALER_amount_ntoh (&fee_refresh,
&rmc.dki->issue.properties.fee_refresh);
rmc.coin_melt_details.melt_fee = fee_refresh;
body.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
body.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT);
body.session_hash = rmc.session_hash;
body.rc = rmc->refresh_session.rc;
TALER_amount_hton (&body.amount_with_fee,
&rmc.coin_melt_details.melt_amount_with_fee);
TALER_amount_hton (&body.melt_fee,
&fee_refresh);
body.coin_pub = rmc.coin_melt_details.coin_info.coin_pub;
if (TALER_amount_cmp (&fee_refresh,
&rmc.coin_melt_details.melt_amount_with_fee) > 0)
{
GNUNET_break_op (0);
cleanup_rmc (&rmc);
return TEH_RESPONSE_reply_external_error (connection,
TALER_EC_REFRESH_MELT_AMOUNT_INSUFFICIENT,
"melt amount smaller than melting fee");
}
&rmc->refresh_session.amount_with_fee);
body.melt_fee = rmc->dki->issue.properties.fee_refresh;
body.coin_pub = rmc->refresh_session.coin.coin_pub;
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
&body.purpose,
&rmc.coin_melt_details.melt_sig.eddsa_signature,
&rmc.coin_melt_details.coin_info.coin_pub.eddsa_pub))
&rmc->refresh_session.coin_sig.eddsa_signature,
&rmc->refresh_session.coin.coin_pub.eddsa_pub))
{
GNUNET_break_op (0);
cleanup_rmc (&rmc);
return TEH_RESPONSE_reply_signature_invalid (connection,
TALER_EC_REFRESH_MELT_COIN_SIGNATURE_INVALID,
"confirm_sig");
}
}
/* prepare commit */
if (GNUNET_OK !=
refresh_melt_prepare (connection,
&mhd_ret,
&rmc))
/* run transaction */
{
cleanup_rmc (&rmc);
int mhd_ret;
if (GNUNET_OK !=
TEH_DB_run_transaction (connection,
&mhd_ret,
&refresh_melt_transaction,
rmc))
return mhd_ret;
}
mhd_ret = reply_refresh_melt_success (connection,
&rmc.session_hash,
rmc.refresh_session.noreveal_index);
cleanup_rmc (&rmc);
return mhd_ret;
/* generate ordinary response */
return reply_refresh_melt_success (connection,
&rmc->refresh_session.rc,
rmc->refresh_session.noreveal_index);
}
@ -870,16 +398,22 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh,
size_t *upload_data_size)
{
json_t *root;
json_t *new_denoms;
json_t *melt_coin;
json_t *coin_evs;
json_t *transfer_pubs;
struct RefreshMeltContext rmc;
int res;
struct TEH_KS_StateHandle *key_state;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_json ("new_denoms", &new_denoms),
GNUNET_JSON_spec_json ("melt_coin", &melt_coin),
GNUNET_JSON_spec_json ("coin_evs", &coin_evs),
GNUNET_JSON_spec_json ("transfer_pubs", &transfer_pubs),
GNUNET_JSON_spec_fixed_auto ("coin_pub",
&rmc.refresh_session.coin.coin_pub),
TALER_JSON_spec_denomination_signature ("denom_sig",
&rmc.refresh_session.coin.denom_sig),
TALER_JSON_spec_denomination_public_key ("denom_pub",
&rmc.refresh_session.coin.denom_pub),
GNUNET_JSON_spec_fixed_auto ("confirm_sig",
&rmc.refresh_session.coin_sig),
TALER_JSON_spec_amount ("value_with_fee",
&rmc.refresh_session.amount_with_fee),
GNUNET_JSON_spec_fixed_auto ("rc",
&rmc.refresh_session.rc),
GNUNET_JSON_spec_end ()
};
@ -894,6 +428,9 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh,
(NULL == root) )
return MHD_YES;
memset (&rmc,
0,
sizeof (rmc));
res = TEH_PARSE_json_data (connection,
root,
spec);
@ -901,29 +438,60 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh,
if (GNUNET_OK != res)
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
/* Determine dimensionality of the request (kappa, #old and #new coins) */
if (TALER_CNC_KAPPA != json_array_size (coin_evs))
if (GNUNET_OK !=
TALER_test_coin_valid (&rmc.refresh_session.coin))
{
GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_invalid (connection,
TALER_EC_REFRESH_MELT_CNC_COIN_ARRAY_SIZE_INVALID,
"coin_evs");
return TEH_RESPONSE_reply_signature_invalid (connection,
TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID,
"denom_sig");
}
if (TALER_CNC_KAPPA != json_array_size (transfer_pubs))
/* run actual logic, now that the request was parsed */
key_state = TEH_KS_acquire ();
if (NULL == key_state)
{
GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_invalid (connection,
TALER_EC_REFRESH_MELT_CNC_TRANSFER_ARRAY_SIZE_INVALID,
"transfer_pubs");
TALER_LOG_ERROR ("Lacking keys to operate\n");
res = TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_EXCHANGE_BAD_CONFIGURATION,
"no keys");
goto cleanup;
}
rmc.dki = TEH_KS_denomination_key_lookup (key_state,
&rmc.refresh_session.coin.denom_pub,
TEH_KS_DKU_DEPOSIT);
if (NULL == rmc.dki)
{
TALER_LOG_WARNING ("Unknown denomination key in /refresh/melt request\n");
res = TEH_RESPONSE_reply_arg_unknown (connection,
TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND,
"denom_pub");
goto cleanup;
}
res = handle_refresh_melt (connection,
&rmc);
cleanup:
if (NULL != key_state)
{
TEH_KS_release (key_state);
key_state = NULL;
}
if (NULL != rmc.refresh_session.coin.denom_pub.rsa_public_key)
{
GNUNET_CRYPTO_rsa_public_key_free (rmc.refresh_session.coin.denom_pub.rsa_public_key);
rmc.refresh_session.coin.denom_pub.rsa_public_key = NULL;
}
if (NULL != rmc.refresh_session.coin.denom_sig.rsa_signature)
{
GNUNET_CRYPTO_rsa_signature_free (rmc.refresh_session.coin.denom_sig.rsa_signature);
rmc.refresh_session.coin.denom_sig.rsa_signature = NULL;
}
res = handle_refresh_melt_json (connection,
new_denoms,
melt_coin,
transfer_pubs,
coin_evs);
GNUNET_JSON_parse_free (spec);
return res;
}

File diff suppressed because it is too large Load Diff

View File

@ -541,18 +541,18 @@ TEH_RESPONSE_compile_transaction_history (const struct TALER_EXCHANGEDB_Transact
ms.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT);
ms.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
ms.session_hash = melt->session_hash;
ms.rc = melt->session.rc;
TALER_amount_hton (&ms.amount_with_fee,
&melt->amount_with_fee);
&melt->session.amount_with_fee);
TALER_amount_hton (&ms.melt_fee,
&melt->melt_fee);
ms.coin_pub = melt->coin.coin_pub;
ms.coin_pub = melt->session.coin.coin_pub;
/* internal sanity check before we hand out a bogus sig... */
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
&ms.purpose,
&melt->coin_sig.eddsa_signature,
&melt->coin.coin_pub.eddsa_pub))
&melt->session.coin_sig.eddsa_signature,
&melt->session.coin.coin_pub.eddsa_pub))
{
GNUNET_break (0);
json_decref (history);
@ -563,10 +563,10 @@ TEH_RESPONSE_compile_transaction_history (const struct TALER_EXCHANGEDB_Transact
json_array_append_new (history,
json_pack ("{s:s, s:o, s:o, s:o, s:o}",
"type", "MELT",
"amount", TALER_JSON_from_amount (&melt->amount_with_fee),
"amount", TALER_JSON_from_amount (&melt->session.amount_with_fee),
"melt_fee", TALER_JSON_from_amount (&melt->melt_fee),
"session_hash", GNUNET_JSON_from_data_auto (&melt->session_hash),
"coin_sig", GNUNET_JSON_from_data_auto (&melt->coin_sig))));
"rc", GNUNET_JSON_from_data_auto (&melt->session.rc),
"coin_sig", GNUNET_JSON_from_data_auto (&melt->session.coin_sig))));
}
break;
case TALER_EXCHANGEDB_TT_REFUND:

View File

@ -131,7 +131,17 @@ main (int argc, char ** argv)
PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("05 - refresh session init loop",
NB_REFRESH_INIT),
PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""),
PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_REFRESH_SESSION ("05 - refresh session"),
PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("05 - denomination load",
"05 - refresh session init loop",
"01 - save denomination"),
PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("05 - reserve load",
"05 - refresh session init loop",
"02 - save reserve"),
PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_WITHDRAW ("05 - withdraw",
"05 - denomination load",
"05 - reserve load"),
PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_REFRESH_SESSION ("05 - refresh session",
"05 - withdraw"),
PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("05 - session array",
"05 - refresh session init loop",
"05 - refresh session",
@ -330,7 +340,21 @@ main (int argc, char ** argv)
PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("29 - insert refresh session",
NB_REFRESH_SAVE),
PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""),
PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_REFRESH_SESSION (""),
PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("29 - denomination load",
"29 - insert refresh session",
"01 - save denomination"),
PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("29 - reserve load",
"29 - insert refresh session",
"02 - save reserve"),
PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_WITHDRAW ("29 - withdraw",
"29 - denomination load",
"29 - reserve load"),
PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_REFRESH_SESSION ("29 - refresh session",
"29 - withdraw"),
PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("29 - session array",
"29 - insert refresh session",
"29 - refresh session",
NB_RESERVE_SAVE),
PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""),
PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("",
"29 - insert refresh session"),

View File

@ -434,57 +434,15 @@ PERF_TALER_EXCHANGEDB_coin_free (struct PERF_TALER_EXCHANGEDB_Coin *coin)
}
/**
* @return a randomly generated refresh session
*/
struct TALER_EXCHANGEDB_RefreshSession *
PERF_TALER_EXCHANGEDB_refresh_session_init ()
{
struct TALER_EXCHANGEDB_RefreshSession *refresh_session;
GNUNET_assert (NULL !=
(refresh_session = GNUNET_new (struct TALER_EXCHANGEDB_RefreshSession)));
refresh_session->noreveal_index = 1;
refresh_session->num_newcoins = 1;
return refresh_session;
}
/**
* @return #GNUNET_OK if the copy was successful, #GNUNET_SYSERR if it wasn't
*/
int
PERF_TALER_EXCHANGEDB_refresh_session_copy (struct TALER_EXCHANGEDB_RefreshSession *session,
struct TALER_EXCHANGEDB_RefreshSession *copy)
{
*copy = *session;
return GNUNET_OK;
}
/**
* Free a refresh session
*/
int
PERF_TALER_EXCHANGEDB_refresh_session_free (struct TALER_EXCHANGEDB_RefreshSession *refresh_session)
{
if (NULL == refresh_session)
return GNUNET_OK;
GNUNET_free (refresh_session);
return GNUNET_OK;
}
/**
* Create a melt operation
*
* @param session the refresh session
* @param rc the commitment of the refresh session
* @param dki the denomination the melted coin uses
* @return a pointer to a #TALER_EXCHANGEDB_RefreshMelt
*/
struct TALER_EXCHANGEDB_RefreshMelt *
PERF_TALER_EXCHANGEDB_refresh_melt_init (struct GNUNET_HashCode *session,
PERF_TALER_EXCHANGEDB_refresh_melt_init (struct TALER_RefreshCommitmentP *rc,
struct PERF_TALER_EXCHANGEDB_Coin *coin)
{
struct TALER_EXCHANGEDB_RefreshMelt *melt;
@ -496,12 +454,12 @@ PERF_TALER_EXCHANGEDB_refresh_melt_init (struct GNUNET_HashCode *session,
struct
{
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct GNUNET_HashCode session;
struct TALER_RefreshCommitmentP rc;
} to_sign;
to_sign.purpose.purpose = GNUNET_SIGNATURE_PURPOSE_TEST;
to_sign.purpose.size = htonl (sizeof (to_sign));
to_sign.session = *session;
to_sign.rc = *rc;
GNUNET_CRYPTO_eddsa_sign (&coin->priv,
&to_sign.purpose,
&coin_sig.eddsa_signature);
@ -513,16 +471,16 @@ PERF_TALER_EXCHANGEDB_refresh_melt_init (struct GNUNET_HashCode *session,
TALER_string_to_amount (CURRENCY ":0.1",
&amount_with_fee));
melt = GNUNET_new (struct TALER_EXCHANGEDB_RefreshMelt);
melt->coin.coin_pub = coin->public_info.coin_pub;
melt->coin.denom_sig.rsa_signature =
melt->session.coin.coin_pub = coin->public_info.coin_pub;
melt->session.coin.denom_sig.rsa_signature =
GNUNET_CRYPTO_rsa_signature_dup (coin->public_info.denom_sig.rsa_signature);
melt->coin.denom_pub.rsa_public_key =
melt->session.coin.denom_pub.rsa_public_key =
GNUNET_CRYPTO_rsa_public_key_dup (coin->public_info.denom_pub.rsa_public_key);
GNUNET_assert (NULL != melt->coin.denom_pub.rsa_public_key);
GNUNET_assert (NULL != melt->coin.denom_sig.rsa_signature);
melt->coin_sig = coin_sig;
melt->session_hash = *session;
melt->amount_with_fee = amount;
GNUNET_assert (NULL != melt->session.coin.denom_pub.rsa_public_key);
GNUNET_assert (NULL != melt->session.coin.denom_sig.rsa_signature);
melt->session.coin_sig = coin_sig;
melt->session.rc = *rc;
melt->session.amount_with_fee = amount;
melt->melt_fee = amount_with_fee;
return melt;
}
@ -541,9 +499,9 @@ PERF_TALER_EXCHANGEDB_refresh_melt_copy (const struct TALER_EXCHANGEDB_RefreshMe
copy = GNUNET_new (struct TALER_EXCHANGEDB_RefreshMelt);
*copy = *melt;
copy->coin.denom_sig.rsa_signature =
GNUNET_CRYPTO_rsa_signature_dup (melt->coin.denom_sig.rsa_signature);
GNUNET_assert (NULL != copy->coin.denom_sig.rsa_signature);
copy->session.coin.denom_sig.rsa_signature =
GNUNET_CRYPTO_rsa_signature_dup (melt->session.coin.denom_sig.rsa_signature);
GNUNET_assert (NULL != copy->session.coin.denom_sig.rsa_signature);
return copy;
}
@ -558,51 +516,7 @@ PERF_TALER_EXCHANGEDB_refresh_melt_copy (const struct TALER_EXCHANGEDB_RefreshMe
int
PERF_TALER_EXCHANGEDB_refresh_melt_free (struct TALER_EXCHANGEDB_RefreshMelt *melt)
{
GNUNET_CRYPTO_rsa_signature_free (melt->coin.denom_sig.rsa_signature);
GNUNET_CRYPTO_rsa_signature_free (melt->session.coin.denom_sig.rsa_signature);
GNUNET_free (melt);
return GNUNET_OK;
}
/**
* Create a #TALER_EXCHANGEDB_RefreshCommitCoin
*/
struct TALER_EXCHANGEDB_RefreshCommitCoin *
PERF_TALER_EXCHANGEDB_refresh_commit_coin_init ()
{
struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin;
commit_coin = GNUNET_new (struct TALER_EXCHANGEDB_RefreshCommitCoin);
commit_coin->coin_ev = "coin_ev";
commit_coin->coin_ev_size = 8;
return commit_coin;
}
/**
* Copies a #TALER_EXCHANGEDB_RefreshCommitCoin
*
* @param commit_coin the commit to copy
* @return a copy of @a commit_coin
*/
struct TALER_EXCHANGEDB_RefreshCommitCoin *
PERF_TALER_EXCHANGEDB_refresh_commit_coin_copy (struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin)
{
struct TALER_EXCHANGEDB_RefreshCommitCoin *copy;
copy = GNUNET_new (struct TALER_EXCHANGEDB_RefreshCommitCoin);
*copy = *commit_coin;
return copy;
}
/**
* Free a #TALER_EXCHANGEDB_RefreshCommitCoin
*
* @param commit_coin the coin to free
*/
void
PERF_TALER_EXCHANGEDB_refresh_commit_coin_free (struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin)
{
GNUNET_free (commit_coin);
}

View File

@ -168,37 +168,15 @@ int
PERF_TALER_EXCHANGEDB_coin_free (struct PERF_TALER_EXCHANGEDB_Coin *coin);
/**
* @return a randomly generated refresh session
*/
struct TALER_EXCHANGEDB_RefreshSession *
PERF_TALER_EXCHANGEDB_refresh_session_init (void);
/**
* @return #GNUNET_OK if the copy was successful, #GNUNET_SYSERR if it wasn't
*/
int
PERF_TALER_EXCHANGEDB_refresh_session_copy (struct TALER_EXCHANGEDB_RefreshSession *session,
struct TALER_EXCHANGEDB_RefreshSession *copy);
/**
* Frees memory of a refresh_session
*/
int
PERF_TALER_EXCHANGEDB_refresh_session_free (struct TALER_EXCHANGEDB_RefreshSession *refresh_session);
/**
* Create a melt operation
*
* @param session the refresh session
* @param rc the commitment of the refresh session
* @param dki the denomination the melted coin uses
* @return a pointer to a #TALER_EXCHANGEDB_RefreshMelt
*/
struct TALER_EXCHANGEDB_RefreshMelt *
PERF_TALER_EXCHANGEDB_refresh_melt_init (struct GNUNET_HashCode *session,
PERF_TALER_EXCHANGEDB_refresh_melt_init (struct TALER_RefreshCommitmentP *rc,
struct PERF_TALER_EXCHANGEDB_Coin *coin);
@ -221,30 +199,4 @@ PERF_TALER_EXCHANGEDB_refresh_melt_copy (const struct TALER_EXCHANGEDB_RefreshMe
int
PERF_TALER_EXCHANGEDB_refresh_melt_free (struct TALER_EXCHANGEDB_RefreshMelt *melt);
/**
* Create a #TALER_EXCHANGEDB_RefreshCommitCoin
*/
struct TALER_EXCHANGEDB_RefreshCommitCoin *
PERF_TALER_EXCHANGEDB_refresh_commit_coin_init (void);
/**
* Copies a #TALER_EXCHANGEDB_RefreshCommitCoin
*
* @param commit_coin the commit to copy
* @return a copy of @a commit_coin
*/
struct TALER_EXCHANGEDB_RefreshCommitCoin *
PERF_TALER_EXCHANGEDB_refresh_commit_coin_copy (struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin);
/**
* Free a #TALER_EXCHANGEDB_RefreshCommitCoin
*
* @param commit_coin the coin to free
*/
void
PERF_TALER_EXCHANGEDB_refresh_commit_coin_free (struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin);
#endif

View File

@ -65,42 +65,32 @@ data_free (struct PERF_TALER_EXCHANGEDB_Data *data)
GNUNET_free (data->data.time);
data->data.time = NULL;
break;
case PERF_TALER_EXCHANGEDB_DEPOSIT:
if (NULL == data->data.deposit)
break;
PERF_TALER_EXCHANGEDB_deposit_free (data->data.deposit);
data->data.deposit = NULL;
break;
case PERF_TALER_EXCHANGEDB_COIN:
if (NULL == data->data.coin)
break;
PERF_TALER_EXCHANGEDB_coin_free (data->data.coin);
GNUNET_free (data->data.coin);
data->data.coin = NULL;
break;
case PERF_TALER_EXCHANGEDB_RESERVE:
if (NULL == data->data.reserve)
break;
PERF_TALER_EXCHANGEDB_reserve_free (data->data.reserve);
data->data.reserve = NULL;
break;
case PERF_TALER_EXCHANGEDB_DENOMINATION_INFO:
if (NULL == data->data.dki)
break;
PERF_TALER_EXCHANGEDB_denomination_free (data->data.dki);
data->data.dki = NULL;
break;
case PERF_TALER_EXCHANGEDB_REFRESH_HASH:
if (NULL == data->data.session_hash)
break;
GNUNET_free (data->data.session_hash);
data->data.session_hash = NULL;
break;
case PERF_TALER_EXCHANGEDB_NONE:
break;
}
@ -124,33 +114,25 @@ data_copy (const struct PERF_TALER_EXCHANGEDB_Data *data,
copy->data.time = GNUNET_new (struct GNUNET_TIME_Absolute);
*copy->data.time = *data->data.time;
return;
case PERF_TALER_EXCHANGEDB_DEPOSIT:
copy->data.deposit
= PERF_TALER_EXCHANGEDB_deposit_copy (data->data.deposit);
return;
case PERF_TALER_EXCHANGEDB_COIN:
copy->data.coin
= PERF_TALER_EXCHANGEDB_coin_copy (data->data.coin);
return;
case PERF_TALER_EXCHANGEDB_RESERVE:
copy->data.reserve
= PERF_TALER_EXCHANGEDB_reserve_copy (data->data.reserve);
return;
case PERF_TALER_EXCHANGEDB_DENOMINATION_INFO:
copy->data.dki
= PERF_TALER_EXCHANGEDB_denomination_copy (data->data.dki);
return;
case PERF_TALER_EXCHANGEDB_REFRESH_HASH:
copy-> data.session_hash = GNUNET_new (struct GNUNET_HashCode);
*copy->data.session_hash
= *data->data.session_hash;
copy->data.rc = data->data.rc;
break;
case PERF_TALER_EXCHANGEDB_NONE:
break;
}
@ -210,9 +192,10 @@ cmd_init (struct PERF_TALER_EXCHANGEDB_Cmd cmd[])
if (PERF_TALER_EXCHANGEDB_CMD_LOOP != cmd[ret].command)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s\n",
"%d:Wrong type reference to %s at %s\n",
i,
cmd[i].details.end_loop.label_loop);
cmd[i].details.end_loop.label_loop,
cmd[i].label);
return GNUNET_SYSERR;
}
cmd[i].details.end_loop.index_loop = ret;
@ -228,17 +211,19 @@ cmd_init (struct PERF_TALER_EXCHANGEDB_Cmd cmd[])
if (GNUNET_SYSERR == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Undefined reference to %s\n",
"%d:Undefined reference to %s at %s\n",
i,
cmd[i].details.save_array.label_save);
cmd[i].details.save_array.label_save,
cmd[i].label);
return GNUNET_SYSERR;
}
if (PERF_TALER_EXCHANGEDB_NONE == cmd[ret].exposed.type)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s\n",
"%d:Wrong type reference to %s at %s\n",
i,
cmd[i].details.save_array.label_save);
cmd[i].details.save_array.label_save,
cmd[i].label);
return GNUNET_SYSERR;
}
cmd[i].details.save_array.index_save = ret;
@ -248,17 +233,19 @@ cmd_init (struct PERF_TALER_EXCHANGEDB_Cmd cmd[])
if (GNUNET_SYSERR == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Undefined reference to %s\n",
"%d:Undefined reference to %s at %s\n",
i,
cmd[i].details.save_array.label_loop);
cmd[i].details.save_array.label_loop,
cmd[i].label);
return GNUNET_SYSERR;
}
if (PERF_TALER_EXCHANGEDB_CMD_LOOP != cmd[ret].command)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s\n",
"%d:Wrong type reference to %s at %s\n",
i,
cmd[i].details.save_array.label_loop);
cmd[i].details.save_array.label_loop,
cmd[i].label);
return GNUNET_SYSERR;
}
cmd[i].details.save_array.index_loop = ret;
@ -281,17 +268,19 @@ cmd_init (struct PERF_TALER_EXCHANGEDB_Cmd cmd[])
if (GNUNET_SYSERR == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Undefined reference to %s\n",
"%d:Undefined reference to %s at %s\n",
i,
cmd[i].details.load_array.label_save);
cmd[i].details.load_array.label_save,
cmd[i].label);
return GNUNET_SYSERR;
}
if (PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY != cmd[ret].command)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s\n",
"%d:Wrong type reference to %s at %s\n",
i,
cmd[i].details.load_array.label_save);
cmd[i].details.load_array.label_save,
cmd[i].label);
return GNUNET_SYSERR;
}
cmd[i].details.load_array.index_save = ret;
@ -732,6 +721,34 @@ cmd_init (struct PERF_TALER_EXCHANGEDB_Cmd cmd[])
}
break;
case PERF_TALER_EXCHANGEDB_CMD_CREATE_REFRESH_SESSION:
{
int ret;
ret = cmd_find (cmd,
cmd[i].details.create_refresh_session.label_coin);
if (GNUNET_SYSERR == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Undefined reference to %s at %s\n",
i,
cmd[i].details.create_refresh_session.label_coin,
cmd[i].label);
return GNUNET_SYSERR;
}
if (PERF_TALER_EXCHANGEDB_COIN != cmd[ret].exposed.type)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s at %s\n",
i,
cmd[i].details.create_refresh_session.label_coin,
cmd[i].label);
return GNUNET_SYSERR;
}
cmd[i].details.create_refresh_session.index_coin = ret;
}
break;
case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_SESSION:
{
int ret;
@ -741,34 +758,36 @@ cmd_init (struct PERF_TALER_EXCHANGEDB_Cmd cmd[])
if (GNUNET_SYSERR == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Undefined reference to %s\n",
"%d:Undefined reference to %s at %s\n",
i,
cmd[i].details.get_refresh_session.label_hash);
cmd[i].details.get_refresh_session.label_hash,
cmd[i].label);
return GNUNET_SYSERR;
}
if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s\n",
"%d:Wrong type reference to %s at %s\n",
i,
cmd[i].details.get_refresh_session.label_hash);
cmd[i].details.get_refresh_session.label_hash,
cmd[i].label);
return GNUNET_SYSERR;
}
cmd[i].details.get_refresh_session.index_hash = ret;
}
break;
case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_ORDER:
case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_REVEAL:
{
int ret;
ret = cmd_find (cmd,
cmd[i].details.insert_refresh_order.label_hash);
cmd[i].details.insert_refresh_reveal.label_hash);
if (GNUNET_SYSERR == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Undefined reference to %s\n",
i,
cmd[i].details.insert_refresh_order.label_hash);
cmd[i].details.insert_refresh_reveal.label_hash);
return GNUNET_SYSERR;
}
if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
@ -776,19 +795,19 @@ cmd_init (struct PERF_TALER_EXCHANGEDB_Cmd cmd[])
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s\n",
i,
cmd[i].details.insert_refresh_order.label_hash);
cmd[i].details.insert_refresh_reveal.label_hash);
return GNUNET_SYSERR;
}
cmd[i].details.insert_refresh_order.index_hash = ret;
cmd[i].details.insert_refresh_reveal.index_hash = ret;
ret = cmd_find (cmd,
cmd[i].details.insert_refresh_order.label_denom);
cmd[i].details.insert_refresh_reveal.label_denom);
if (GNUNET_SYSERR == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Undefined reference to %s\n",
i,
cmd[i].details.insert_refresh_order.label_denom);
cmd[i].details.insert_refresh_reveal.label_denom);
return GNUNET_SYSERR;
}
if (PERF_TALER_EXCHANGEDB_DENOMINATION_INFO != cmd[ret].exposed.type)
@ -796,24 +815,24 @@ cmd_init (struct PERF_TALER_EXCHANGEDB_Cmd cmd[])
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s\n",
i,
cmd[i].details.insert_refresh_order.label_denom);
cmd[i].details.insert_refresh_reveal.label_denom);
return GNUNET_SYSERR;
}
cmd[i].details.insert_refresh_order.index_denom = ret;
cmd[i].details.insert_refresh_reveal.index_denom = ret;
}
break;
case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_ORDER:
case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_REVEAL:
{
int ret;
ret = cmd_find (cmd,
cmd[i].details.get_refresh_order.label_hash);
cmd[i].details.get_refresh_reveal.label_hash);
if (GNUNET_SYSERR == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Undefined reference to %s\n",
i,
cmd[i].details.get_refresh_order.label_hash);
cmd[i].details.get_refresh_reveal.label_hash);
return GNUNET_SYSERR;
}
if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
@ -821,164 +840,14 @@ cmd_init (struct PERF_TALER_EXCHANGEDB_Cmd cmd[])
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s\n",
i,
cmd[i].details.get_refresh_order.label_hash);
cmd[i].details.get_refresh_reveal.label_hash);
return GNUNET_SYSERR;
}
cmd[i].details.get_refresh_order.index_hash = ret;
cmd[i].details.get_refresh_reveal.index_hash = ret;
}
break;
case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_COIN:
{
int ret;
ret = cmd_find (cmd,
cmd[i].details.insert_refresh_commit_coin.label_hash);
if (GNUNET_SYSERR == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Undefined reference to %s\n",
i,
cmd[i].details.insert_refresh_commit_coin.label_hash);
return GNUNET_SYSERR;
}
if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s\n",
i,
cmd[i].details.insert_refresh_commit_coin.label_hash);
return GNUNET_SYSERR;
}
cmd[i].details.insert_refresh_commit_coin.index_hash = ret;
}
break;
case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_COIN:
{
int ret;
ret = cmd_find (cmd,
cmd[i].details.get_refresh_commit_coin.label_hash);
if (GNUNET_SYSERR == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Undefined reference to %s\n",
i,
cmd[i].details.get_refresh_commit_coin.label_hash);
return GNUNET_SYSERR;
}
if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s\n",
i,
cmd[i].details.get_refresh_commit_coin.label_hash);
return GNUNET_SYSERR;
}
cmd[i].details.get_refresh_commit_coin.index_hash = ret;
}
break;
case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_LINK:
{
int ret;
ret = cmd_find (cmd,
cmd[i].details.insert_refresh_commit_link.label_hash);
if (GNUNET_SYSERR == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Undefined reference to %s\n",
i,
cmd[i].details.insert_refresh_commit_link.label_hash);
return GNUNET_SYSERR;
}
if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s\n",
i,
cmd[i].details.insert_refresh_commit_link.label_hash);
return GNUNET_SYSERR;
}
cmd[i].details.insert_refresh_commit_link.index_hash = ret;
}
break;
case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_LINK:
{
int ret;
ret = cmd_find (cmd,
cmd[i].details.get_refresh_commit_link.label_hash);
if (GNUNET_SYSERR == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Undefined reference to %s\n",
i,
cmd[i].details.get_refresh_commit_link.label_hash);
return GNUNET_SYSERR;
}
if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s\n",
i,
cmd[i].details.get_refresh_commit_link.label_hash);
return GNUNET_SYSERR;
}
cmd[i].details.get_refresh_commit_link.index_hash = ret;
}
break;
case PERF_TALER_EXCHANGEDB_CMD_GET_MELT_COMMITMENT:
{
int ret;
ret = cmd_find (cmd,
cmd[i].details.get_melt_commitment.label_hash);
if (GNUNET_SYSERR == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Undefined reference to %s\n",
i,
cmd[i].details.get_melt_commitment.label_hash);
return GNUNET_SYSERR;
}
if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s\n",
i,
cmd[i].details.get_melt_commitment.label_hash);
return GNUNET_SYSERR;
}
cmd[i].details.get_melt_commitment.index_hash = ret;
}
break;
case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_OUT:
{
int ret;
ret = cmd_find (cmd,
cmd[i].details.insert_refresh_out.label_hash);
if (GNUNET_SYSERR == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Undefined reference to %s\n",
i,
cmd[i].details.insert_refresh_out.label_hash);
return GNUNET_SYSERR;
}
if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s\n",
i,
cmd[i].details.insert_refresh_out.label_hash);
return GNUNET_SYSERR;
}
cmd[i].details.insert_refresh_out.index_hash = ret;
}
break;
case PERF_TALER_EXCHANGEDB_CMD_GET_LINK_DATA_LIST:
case PERF_TALER_EXCHANGEDB_CMD_GET_LINK_DATA:
{
int ret;
ret = cmd_find (cmd,
@ -1003,31 +872,6 @@ cmd_init (struct PERF_TALER_EXCHANGEDB_Cmd cmd[])
}
break;
case PERF_TALER_EXCHANGEDB_CMD_GET_TRANSFER:
{
int ret;
ret = cmd_find (cmd,
cmd[i].details.get_transfer.label_hash);
if (GNUNET_SYSERR == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Undefined reference to %s\n",
i,
cmd[i].details.get_transfer.label_hash);
return GNUNET_SYSERR;
}
if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%d:Wrong type reference to %s\n",
i,
cmd[i].details.get_transfer.label_hash);
return GNUNET_SYSERR;
}
cmd[i].details.get_transfer.index_hash = ret;
}
break;
case PERF_TALER_EXCHANGEDB_CMD_END:
case PERF_TALER_EXCHANGEDB_CMD_DEBUG:
case PERF_TALER_EXCHANGEDB_CMD_LOOP:
@ -1038,7 +882,6 @@ cmd_init (struct PERF_TALER_EXCHANGEDB_Cmd cmd[])
case PERF_TALER_EXCHANGEDB_CMD_GET_TIME:
case PERF_TALER_EXCHANGEDB_CMD_CREATE_DENOMINATION:
case PERF_TALER_EXCHANGEDB_CMD_CREATE_RESERVE:
case PERF_TALER_EXCHANGEDB_CMD_CREATE_REFRESH_SESSION:
break;
}
}
@ -1092,12 +935,11 @@ cmd_clean (struct PERF_TALER_EXCHANGEDB_Cmd cmd[])
static void
interpret_end_loop (struct PERF_TALER_EXCHANGEDB_interpreter_state *state)
{
unsigned int i;
int jump;
jump = state->cmd[state->i].details.end_loop.index_loop;
// Cleaning up the memory in the loop
for (i = jump; i < state->i; i++)
for (unsigned int i = jump; i < state->i; i++)
data_free (&state->cmd[i].exposed);
state->cmd[jump].details.loop.curr_iteration++;
@ -1229,6 +1071,29 @@ interprete_load_random (struct PERF_TALER_EXCHANGEDB_interpreter_state *state)
}
/**
* Function called with information about a refresh order.
*
* @param cls closure
* @param rowid unique serial ID for the row in our database
* @param num_newcoins size of the @a rrcs array
* @param rrcs array of @a num_newcoins information about coins to be created
* @param num_tprivs number of entries in @a tprivs, should be #TALER_CNC_KAPPA - 1
* @param tprivs array of @e num_tprivs transfer private keys
* @param tp transfer public key information
*/
static void
refresh_reveal_cb (void *cls,
uint32_t num_newcoins,
const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs,
unsigned int num_tprivs,
const struct TALER_TransferPrivateKeyP *tprivs,
const struct TALER_TransferPublicKeyP *tp)
{
/* intentionally empty */
}
/**
* Iterate over the commands, acting accordingly at each step
*
@ -1343,7 +1208,8 @@ interpret (struct PERF_TALER_EXCHANGEDB_interpreter_state *state)
state->session,
deposit);
GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
state->cmd[state->i].exposed.data.deposit = deposit;
state->cmd[state->i].exposed.data.deposit
= PERF_TALER_EXCHANGEDB_deposit_copy (deposit);
}
break;
@ -1546,143 +1412,100 @@ interpret (struct PERF_TALER_EXCHANGEDB_interpreter_state *state)
case PERF_TALER_EXCHANGEDB_CMD_CREATE_REFRESH_SESSION:
{
struct GNUNET_HashCode *hash;
struct TALER_EXCHANGEDB_RefreshSession *refresh_session;
struct TALER_EXCHANGEDB_RefreshSession refresh_session;
unsigned int coin_index;
struct PERF_TALER_EXCHANGEDB_Coin *coin;
hash = GNUNET_new (struct GNUNET_HashCode);
refresh_session = PERF_TALER_EXCHANGEDB_refresh_session_init ();
coin_index = state->cmd[state->i].details.create_refresh_session.index_coin;
coin = state->cmd[coin_index].exposed.data.coin;
refresh_session.coin = coin->public_info;
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&refresh_session.coin_sig,
sizeof (refresh_session.coin_sig));
GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
hash);
&refresh_session.rc.session_hash);
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":1.1",
&refresh_session.amount_with_fee));
refresh_session.noreveal_index = 1;
GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
state->plugin->create_refresh_session (state->session,
state->plugin->insert_melt (state->session,
state->session,
hash,
refresh_session));
state->cmd[state->i].exposed.data.session_hash = hash;
PERF_TALER_EXCHANGEDB_refresh_session_free (refresh_session);
GNUNET_free (refresh_session);
&refresh_session));
state->cmd[state->i].exposed.data.rc = refresh_session.rc;
}
break;
case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_SESSION:
{
unsigned int hash_index;
struct GNUNET_HashCode *hash;
struct TALER_EXCHANGEDB_RefreshSession refresh;
const struct TALER_RefreshCommitmentP *rc;
struct TALER_EXCHANGEDB_RefreshMelt refresh;
hash_index = state->cmd[state->i].details.get_refresh_session.index_hash;
hash = state->cmd[hash_index].exposed.data.session_hash;
state->plugin->get_refresh_session (state->session,
rc = &state->cmd[hash_index].exposed.data.rc;
state->plugin->get_melt (state->session,
state->session,
hash,
rc,
&refresh);
}
break;
case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_ORDER:
case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_REVEAL:
{
unsigned int hash_index;
unsigned int denom_index;
struct GNUNET_HashCode *session_hash;
const struct TALER_RefreshCommitmentP *rc;
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *denom;
struct TALER_TransferPublicKeyP tpub;
struct TALER_TransferPrivateKeyP tprivs[2];
struct TALER_EXCHANGEDB_RefreshRevealedCoin rrc;
hash_index = state->cmd[state->i].details.insert_refresh_order.index_hash;
denom_index = state->cmd[state->i].details.insert_refresh_order.index_denom;
session_hash = state->cmd[hash_index].exposed.data.session_hash;
hash_index = state->cmd[state->i].details.insert_refresh_reveal.index_hash;
denom_index = state->cmd[state->i].details.insert_refresh_reveal.index_denom;
rc = &state->cmd[hash_index].exposed.data.rc;
denom = state->cmd[denom_index].exposed.data.dki;
rrc.denom_pub = denom->denom_pub;
rrc.coin_ev = "coin_ev";
rrc.coin_ev_size = strlen (rrc.coin_ev) + 1;
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&rrc.coin_sig,
sizeof (struct TALER_CoinSpendSignatureP));
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
tprivs,
sizeof (struct TALER_TransferPrivateKeyP) * 2);
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&tpub,
sizeof (struct TALER_TransferPublicKeyP));
GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
state->plugin->insert_refresh_order (state->plugin->cls,
state->plugin->insert_refresh_reveal (state->plugin->cls,
state->session,
session_hash,
rc,
1,
&denom->denom_pub));
&rrc,
2,
tprivs,
&tpub));
}
break;
case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_ORDER:
case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_REVEAL:
{
int hash_index;
struct GNUNET_HashCode *hash;
struct TALER_DenominationPublicKey denom_pub;
const struct TALER_RefreshCommitmentP *rc;
hash_index = state->cmd[state->i].details.get_refresh_order.index_hash;
hash = state->cmd[hash_index].exposed.data.session_hash;
state->plugin->get_refresh_order (state->plugin->cls,
hash_index = state->cmd[state->i].details.get_refresh_reveal.index_hash;
rc = &state->cmd[hash_index].exposed.data.rc;
state->plugin->get_refresh_reveal (state->plugin->cls,
state->session,
hash,
1,
&denom_pub);
rc,
&refresh_reveal_cb,
state);
}
break;
case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_COIN:
{
enum GNUNET_DB_QueryStatus qs;
unsigned int hash_index;
struct TALER_EXCHANGEDB_RefreshCommitCoin *refresh_commit;
hash_index = state->cmd[state->i].details.insert_refresh_commit_coin.index_hash;
refresh_commit = PERF_TALER_EXCHANGEDB_refresh_commit_coin_init ();
qs = state->plugin->insert_refresh_commit_coins (state->plugin->cls,
state->session,
state->cmd[hash_index].exposed.data.session_hash,
1,
refresh_commit);
GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
}
break;
case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_COIN:
{
unsigned int hash_index;
struct TALER_EXCHANGEDB_RefreshCommitCoin refresh_commit;
hash_index = state->cmd[state->i].details.insert_refresh_commit_coin.index_hash;
state->plugin->get_refresh_commit_coins (state->plugin->cls,
state->session,
state->cmd[hash_index].exposed.data.session_hash,
1,
&refresh_commit);
}
break;
case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_LINK:
{
// unsigned int hash_index;
//
// hash_index = state->cmd[state->i].details.insert_refresh_commit_link.index_hash;
}
break;
case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_LINK:
{
int ret;
unsigned int hash_index;
struct TALER_EXCHANGEDB_RefreshCommitCoin commit_coin;
// FIXME: this should go after the public key!
hash_index = state->cmd[state->i].details.get_refresh_commit_link.index_hash;
ret = state->plugin->get_refresh_commit_coins(state->plugin->cls,
state->session,
state->cmd[hash_index].exposed.data.session_hash,
1,
&commit_coin);
GNUNET_assert (GNUNET_SYSERR != ret);
}
break;
case PERF_TALER_EXCHANGEDB_CMD_GET_MELT_COMMITMENT:
break;
case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_OUT:
break;
case PERF_TALER_EXCHANGEDB_CMD_GET_LINK_DATA_LIST:
break;
case PERF_TALER_EXCHANGEDB_CMD_GET_TRANSFER:
case PERF_TALER_EXCHANGEDB_CMD_GET_LINK_DATA:
break;
}

View File

@ -331,7 +331,7 @@
}
/**
* Inserts informations about a withdrawal in the database
* Inserts information about a withdrawal into the database
*
* @exposes #PERF_TALER_EXCHANGEDB_COIN
*
@ -452,16 +452,18 @@
_label_coin), \
PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DEPOSIT (_label "insert", \
_label "deposit")
/**
* Insert informations about a refresh session
* melts one coin into another
*
* @param _label the label of the command
*/
#define PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_REFRESH_SESSION(_label) \
#define PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_REFRESH_SESSION(_label, _label_coin) \
{ \
.command = PERF_TALER_EXCHANGEDB_CMD_CREATE_REFRESH_SESSION, \
.label = _label, \
.details.create_refresh_session.label_coin = _label_coin, \
.exposed.type = PERF_TALER_EXCHANGEDB_REFRESH_HASH \
}
@ -519,7 +521,7 @@ struct PERF_TALER_EXCHANGEDB_Data
/** #PERF_TALER_EXCHANGEDB_DENOMINATION_INFO */
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
/** #PERF_TALER_EXCHANGEDB_REFRESH_HASH */
struct GNUNET_HashCode *session_hash;
struct TALER_RefreshCommitmentP rc;
} data;
};
@ -679,54 +681,19 @@ enum PERF_TALER_EXCHANGEDB_CMD_Name
PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_SESSION,
/**
* Insert a melt refresh order
* Insert a melt refresh reveal data
*/
PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_ORDER,
PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_REVEAL,
/**
* Get informations about a refresh order
* Get informations about a refresh reveal data
*/
PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_ORDER,
/**
* Insert refresh commit coin
*/
PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_COIN,
/**
* Get refresh commit coin
*/
PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_COIN,
/**
* Insert refresh commit link
*/
PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_LINK,
/**
* Get refresh commit link
*/
PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_LINK,
/**
* Get information avout the melt commit
*/
PERF_TALER_EXCHANGEDB_CMD_GET_MELT_COMMITMENT,
/**
* Insert a new coin into the database after a melt operation
*/
PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_OUT,
PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_REVEAL,
/**
* Get the link data list of a coin
*/
PERF_TALER_EXCHANGEDB_CMD_GET_LINK_DATA_LIST,
/**
* Get the shared secret and the transfere public key
*/
PERF_TALER_EXCHANGEDB_CMD_GET_TRANSFER
PERF_TALER_EXCHANGEDB_CMD_GET_LINK_DATA
};
@ -1028,6 +995,18 @@ union PERF_TALER_EXCHANGEDB_CMD_Details
unsigned int index_deposit;
} get_deposit;
/**
* Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_CREATE_REFRESH_SESSION command
*/
struct PERF_TALER_EXCHANGEDB_CMD_createRefreshSessionDetails
{
/**
* label of the source of the hash of the session
*/
const char *label_coin;
unsigned int index_coin;
} create_refresh_session;
/**
* Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_SESSION command
*/
@ -1041,9 +1020,9 @@ union PERF_TALER_EXCHANGEDB_CMD_Details
} get_refresh_session;
/**
* Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_ORDER command
* Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_REVEAL command
*/
struct PERF_TALER_EXCHANGEDB_CMD_insertRefreshOrderDetails
struct PERF_TALER_EXCHANGEDB_CMD_insertRefreshRevealDetails
{
/**
* The refresh session hash
@ -1056,12 +1035,12 @@ union PERF_TALER_EXCHANGEDB_CMD_Details
*/
const char *label_denom;
unsigned int index_denom;
} insert_refresh_order;
} insert_refresh_reveal;
/**
* Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_ORDER command
* Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_REVEAL command
*/
struct PERF_TALER_EXCHANGEDB_CMD_getRefreshOrderDetails
struct PERF_TALER_EXCHANGEDB_CMD_getRefreshRevealDetails
{
/**
* The session hash
@ -1069,82 +1048,7 @@ union PERF_TALER_EXCHANGEDB_CMD_Details
const char *label_hash;
unsigned int index_hash;
} get_refresh_order;
/**
* Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_COIN command
*/
struct PERF_TALER_EXCHANGEDB_CMD_insertRefreshCommitCoinDetails
{
/**
* The refresh session hash
*/
const char *label_hash;
unsigned int index_hash;
} insert_refresh_commit_coin;
/**
* Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_COIN command
*/
struct PERF_TALER_EXCHANGEDB_CMD_getRefreshCommitCoinDetails
{
/**
* The refresh session hash
*/
const char *label_hash;
unsigned int index_hash;
} get_refresh_commit_coin;
/**
* Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_LINK command
*/
struct PERF_TALER_EXCHANGEDB_CMD_insertRefreshCommitLinkDetails
{
/**
* The refresh session hash
*/
const char *label_hash;
unsigned int index_hash;
} insert_refresh_commit_link;
/**
* Data requiered by the #PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_LINK command
*/
struct PERF_TALER_EXCHANGEDB_CMD_getRefreshCommitLinkDetails
{
/**
* The refresh session hash
*/
const char *label_hash;
unsigned int index_hash;
} get_refresh_commit_link;
/**
* Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_MELT_COMMITMENT command
*/
struct PERF_TALER_EXCHANGEDB_CMD_getMeltCommitmentDaetails
{
/**
* The refresh session hash
*/
const char *label_hash;
unsigned int index_hash;
} get_melt_commitment;
/**
* Data requiered by the #PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_OUT command
*/
struct PERF_TALER_EXCHANGEDB_CMD_insertRefreshOutDetails
{
/**
* The refresh session hash
*/
const char *label_hash;
unsigned int index_hash;
} insert_refresh_out;
} get_refresh_reveal;
/**
* Data requiered by the #PERF_TALER_EXCHANGEDB_CMD_GET_LINK_DATA_LIST command
@ -1158,17 +1062,6 @@ union PERF_TALER_EXCHANGEDB_CMD_Details
unsigned int index_hash;
} get_link_data_list;
/**
* Data requiered by the #PERF_TALER_EXCHANGEDB_CMD_GET_TRANSFER command
*/
struct PERF_TALER_EXCHANGEDB_CMD_getTransferDetails
{
/**
* The refresh session hash
*/
const char *label_hash;
unsigned int index_hash;
} get_transfer;
};

View File

@ -73,31 +73,6 @@ common_free_reserve_history (void *cls,
}
/**
* Free memory of the link data list.
*
* @param cls the @e cls of this struct with the plugin-specific state (unused)
* @param ldl link data list to release
*/
static void
common_free_link_data_list (void *cls,
struct TALER_EXCHANGEDB_LinkDataList *ldl)
{
struct TALER_EXCHANGEDB_LinkDataList *next;
while (NULL != ldl)
{
next = ldl->next;
if (NULL != ldl->denom_pub.rsa_public_key)
GNUNET_CRYPTO_rsa_public_key_free (ldl->denom_pub.rsa_public_key);
if (NULL != ldl->ev_sig.rsa_signature)
GNUNET_CRYPTO_rsa_signature_free (ldl->ev_sig.rsa_signature);
GNUNET_free (ldl);
ldl = next;
}
}
/**
* Free linked list of transactions.
*
@ -125,10 +100,10 @@ common_free_coin_transaction_list (void *cls,
GNUNET_free (list->details.deposit);
break;
case TALER_EXCHANGEDB_TT_REFRESH_MELT:
if (NULL != list->details.melt->coin.denom_pub.rsa_public_key)
GNUNET_CRYPTO_rsa_public_key_free (list->details.melt->coin.denom_pub.rsa_public_key);
if (NULL != list->details.melt->coin.denom_sig.rsa_signature)
GNUNET_CRYPTO_rsa_signature_free (list->details.melt->coin.denom_sig.rsa_signature);
if (NULL != list->details.melt->session.coin.denom_pub.rsa_public_key)
GNUNET_CRYPTO_rsa_public_key_free (list->details.melt->session.coin.denom_pub.rsa_public_key);
if (NULL != list->details.melt->session.coin.denom_sig.rsa_signature)
GNUNET_CRYPTO_rsa_signature_free (list->details.melt->session.coin.denom_sig.rsa_signature);
GNUNET_free (list->details.melt);
break;
case TALER_EXCHANGEDB_TT_REFUND:

File diff suppressed because it is too large Load Diff

View File

@ -308,162 +308,85 @@ static struct TALER_Amount amount_with_fee;
*/
#define MELT_NOREVEAL_INDEX 1
static struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins;
/**
* Test APIs related to the "insert_refresh_commit_coins" function.
*
* @param session database sesison to use
* @param refresh_session details about the refresh session to use
* @param session_hash refresh melt session hash to use
* @return #GNUNET_OK on success
* How big do we make the coin envelopes?
*/
static int
test_refresh_commit_coins (struct TALER_EXCHANGEDB_Session *session,
const struct TALER_EXCHANGEDB_RefreshSession *refresh_session,
const struct GNUNET_HashCode *session_hash)
{
struct TALER_EXCHANGEDB_RefreshCommitCoin *ret_commit_coins;
struct TALER_EXCHANGEDB_RefreshCommitCoin *a_ccoin;
struct TALER_EXCHANGEDB_RefreshCommitCoin *b_ccoin;
unsigned int cnt;
int ret;
#define COIN_ENC_MAX_SIZE 512
ret = GNUNET_SYSERR;
ret_commit_coins = NULL;
commit_coins
= GNUNET_new_array (MELT_NEW_COINS,
struct TALER_EXCHANGEDB_RefreshCommitCoin);
for (cnt=0; cnt < MELT_NEW_COINS; cnt++)
{
struct TALER_EXCHANGEDB_RefreshCommitCoin *ccoin;
ccoin = &commit_coins[cnt];
ccoin->coin_ev_size = GNUNET_CRYPTO_random_u64
(GNUNET_CRYPTO_QUALITY_WEAK, COIN_ENC_MAX_SIZE);
ccoin->coin_ev = GNUNET_malloc (ccoin->coin_ev_size);
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
ccoin->coin_ev,
ccoin->coin_ev_size);
}
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_refresh_commit_coins (plugin->cls,
session,
session_hash,
MELT_NEW_COINS,
commit_coins));
ret_commit_coins = GNUNET_new_array (MELT_NEW_COINS,
struct TALER_EXCHANGEDB_RefreshCommitCoin);
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_refresh_commit_coins (plugin->cls,
session,
session_hash,
MELT_NEW_COINS,
ret_commit_coins));
/* compare the refresh commit coin arrays */
for (cnt = 0; cnt < MELT_NEW_COINS; cnt++)
{
a_ccoin = &commit_coins[cnt];
b_ccoin = &ret_commit_coins[cnt];
FAILIF (a_ccoin->coin_ev_size != b_ccoin->coin_ev_size);
FAILIF (0 != memcmp (a_ccoin->coin_ev,
a_ccoin->coin_ev,
a_ccoin->coin_ev_size));
GNUNET_free (ret_commit_coins[cnt].coin_ev);
}
GNUNET_free (ret_commit_coins);
ret_commit_coins = NULL;
ret = GNUNET_OK;
drop:
if (NULL != ret_commit_coins)
{
plugin->free_refresh_commit_coins (plugin->cls,
MELT_NEW_COINS,
ret_commit_coins);
GNUNET_free (ret_commit_coins);
}
return ret;
}
static struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coins;
static struct TALER_TransferPrivateKeyP tprivs[TALER_CNC_KAPPA];
static struct TALER_TransferPublicKeyP rctp[TALER_CNC_KAPPA];
static struct TALER_TransferPublicKeyP tpub;
/**
* Test APIs related to the "insert_refresh_commit_coins" function.
*
* @param session database sesison to use
* @param refresh_session details about the refresh session to use
* @param session_hash refresh melt session hash to use
* @return #GNUNET_OK on success
*/
static int
test_refresh_commit_links (struct TALER_EXCHANGEDB_Session *session,
const struct TALER_EXCHANGEDB_RefreshSession *refresh_session,
const struct GNUNET_HashCode *session_hash)
{
int ret;
struct TALER_TransferPublicKeyP tp;
unsigned int i;
ret = GNUNET_SYSERR;
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
plugin->get_refresh_transfer_public_key (plugin->cls,
session,
session_hash,
&tp));
for (i=0;i<TALER_CNC_KAPPA;i++)
RND_BLK (&rctp[i]);
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_refresh_transfer_public_key (plugin->cls,
session,
session_hash,
&rctp[MELT_NOREVEAL_INDEX]));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_refresh_transfer_public_key (plugin->cls,
session,
session_hash,
&tp));
FAILIF (0 !=
memcmp (&rctp[MELT_NOREVEAL_INDEX],
&tp,
sizeof (struct TALER_TransferPublicKeyP)));
ret = GNUNET_OK;
drop:
return ret;
}
static struct GNUNET_HashCode session_hash;
/**
* Function called with the session hashes and transfer secret
* information for a given coin. Checks if they are as expected.
* Function called with information about a refresh order. This
* one should not be called in a successful test.
*
* @param cls closure
* @param sh a session the coin was melted in
* @param transfer_pub public transfer key for the session
* @param rowid unique serial ID for the row in our database
* @param num_newcoins size of the @a rrcs array
* @param rrcs array of @a num_newcoins information about coins to be created
* @param num_tprivs number of entries in @a tprivs, should be #TALER_CNC_KAPPA - 1
* @param tprivs array of @e num_tprivs transfer private keys
* @param tp transfer public key information
*/
static void
check_transfer_data (void *cls,
const struct GNUNET_HashCode *sh,
const struct TALER_TransferPublicKeyP *transfer_pub)
never_called_cb (void *cls,
uint32_t num_newcoins,
const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs,
unsigned int num_tprivs,
const struct TALER_TransferPrivateKeyP *tprivs,
const struct TALER_TransferPublicKeyP *tp)
{
int *ok = cls;
GNUNET_assert (0); /* should never be called! */
}
FAILIF (0 != memcmp (&rctp[MELT_NOREVEAL_INDEX],
transfer_pub,
sizeof (struct TALER_TransferPublicKeyP)));
FAILIF (0 != memcmp (&session_hash,
sh,
sizeof (struct GNUNET_HashCode)));
*ok = GNUNET_OK;
return;
drop:
*ok = GNUNET_SYSERR;
/**
* Function called with information about a refresh order.
* Checks that the response matches what we expect to see.
*
* @param cls closure
* @param rowid unique serial ID for the row in our database
* @param num_newcoins size of the @a rrcs array
* @param rrcs array of @a num_newcoins information about coins to be created
* @param num_tprivs number of entries in @a tprivs, should be #TALER_CNC_KAPPA - 1
* @param tprivsr array of @e num_tprivs transfer private keys
* @param tpr transfer public key information
*/
static void
check_refresh_reveal_cb (void *cls,
uint32_t num_newcoins,
const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs,
unsigned int num_tprivs,
const struct TALER_TransferPrivateKeyP *tprivsr,
const struct TALER_TransferPublicKeyP *tpr)
{
/* compare the refresh commit coin arrays */
for (unsigned int cnt = 0; cnt < num_newcoins; cnt++)
{
const struct TALER_EXCHANGEDB_RefreshRevealedCoin *acoin = &revealed_coins[cnt];
const struct TALER_EXCHANGEDB_RefreshRevealedCoin *bcoin = &rrcs[cnt];
GNUNET_assert (acoin->coin_ev_size == bcoin->coin_ev_size);
GNUNET_assert (0 ==
memcmp (acoin->coin_ev,
bcoin->coin_ev,
acoin->coin_ev_size));
GNUNET_assert (0 ==
GNUNET_CRYPTO_rsa_public_key_cmp (acoin->denom_pub.rsa_public_key,
bcoin->denom_pub.rsa_public_key));
}
GNUNET_assert (0 ==
memcmp (&tpub,
tpr,
sizeof (tpub)));
GNUNET_assert (0 ==
memcmp (tprivs,
tprivsr,
sizeof (struct TALER_TransferPrivateKeyP) * (TALER_CNC_KAPPA - 1)));
}
@ -487,7 +410,7 @@ static unsigned int auditor_row_cnt;
* @param amount_with_fee amount that was deposited including fee
* @param num_newcoins how many coins were issued
* @param noreveal_index which index was picked by the exchange in cut-and-choose
* @param session_hash what is the session hash
* @param rc what is the session hash
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
static int
@ -497,15 +420,59 @@ audit_refresh_session_cb (void *cls,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_CoinSpendSignatureP *coin_sig,
const struct TALER_Amount *amount_with_fee,
uint16_t num_newcoins,
uint16_t noreveal_index,
const struct GNUNET_HashCode *session_hash)
uint32_t noreveal_index,
const struct TALER_RefreshCommitmentP *rc)
{
auditor_row_cnt++;
return GNUNET_OK;
}
/**
* Denomination keys used for fresh coins in melt test.
*/
static struct DenomKeyPair **new_dkp;
/**
* Function called with the session hashes and transfer secret
* information for a given coin.
*
* @param cls closure
* @param transfer_pub public transfer key for the session
* @param ldl link data for @a transfer_pub
*/
static void
handle_link_data_cb (void *cls,
const struct TALER_TransferPublicKeyP *transfer_pub,
const struct TALER_EXCHANGEDB_LinkDataList *ldl)
{
for (const struct TALER_EXCHANGEDB_LinkDataList *ldlp = ldl;
NULL != ldlp;
ldlp = ldlp->next)
{
int found;
found = GNUNET_NO;
for (unsigned int cnt=0;cnt < MELT_NEW_COINS;cnt++)
{
GNUNET_assert (NULL != ldlp->ev_sig.rsa_signature);
if ( (0 ==
GNUNET_CRYPTO_rsa_public_key_cmp (ldlp->denom_pub.rsa_public_key,
new_dkp[cnt]->pub.rsa_public_key)) &&
(0 ==
GNUNET_CRYPTO_rsa_signature_cmp (ldlp->ev_sig.rsa_signature,
revealed_coins[cnt].coin_sig.rsa_signature)) )
{
found = GNUNET_YES;
break;
}
}
GNUNET_assert (GNUNET_NO != found);
}
}
/**
* Function to test melting of coins as part of a refresh session
*
@ -517,30 +484,20 @@ static int
test_melting (struct TALER_EXCHANGEDB_Session *session)
{
struct TALER_EXCHANGEDB_RefreshSession refresh_session;
struct TALER_EXCHANGEDB_RefreshSession ret_refresh_session;
struct TALER_EXCHANGEDB_RefreshMelt ret_refresh_session;
struct DenomKeyPair *dkp;
struct DenomKeyPair **new_dkp;
/* struct TALER_CoinPublicInfo *coins; */
struct TALER_EXCHANGEDB_RefreshMelt *meltp;
struct TALER_DenominationPublicKey *new_denom_pubs;
struct TALER_DenominationPublicKey *ret_denom_pubs;
struct TALER_EXCHANGEDB_LinkDataList *ldl;
struct TALER_EXCHANGEDB_LinkDataList *ldlp;
struct TALER_DenominationSignature ev_sigs[MELT_NEW_COINS];
unsigned int cnt;
int ret;
enum GNUNET_DB_QueryStatus qs;
ret = GNUNET_SYSERR;
memset (ev_sigs, 0, sizeof (ev_sigs));
RND_BLK (&refresh_session);
RND_BLK (&session_hash);
dkp = NULL;
new_dkp = NULL;
new_denom_pubs = NULL;
ret_denom_pubs = NULL;
/* create and test a refresh session */
refresh_session.num_newcoins = MELT_NEW_COINS;
refresh_session.noreveal_index = MELT_NOREVEAL_INDEX;
/* create a denomination (value: 1; fraction: 100) */
dkp = create_denom_key_pair (512,
@ -556,33 +513,62 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
{
struct GNUNET_HashCode hc;
meltp = &refresh_session.melt;
RND_BLK (&meltp->coin.coin_pub);
GNUNET_CRYPTO_hash (&meltp->coin.coin_pub,
sizeof (meltp->coin.coin_pub),
RND_BLK (&refresh_session.coin.coin_pub);
GNUNET_CRYPTO_hash (&refresh_session.coin.coin_pub,
sizeof (refresh_session.coin.coin_pub),
&hc);
meltp->coin.denom_sig.rsa_signature =
refresh_session.coin.denom_sig.rsa_signature =
GNUNET_CRYPTO_rsa_sign_fdh (dkp->priv.rsa_private_key,
&hc);
GNUNET_assert (NULL != meltp->coin.denom_sig.rsa_signature);
meltp->coin.denom_pub = dkp->pub;
RND_BLK (&meltp->coin_sig);
meltp->session_hash = session_hash;
meltp->amount_with_fee = amount_with_fee;
meltp->melt_fee = fee_refresh;
GNUNET_assert (NULL != refresh_session.coin.denom_sig.rsa_signature);
refresh_session.coin.denom_pub = dkp->pub;
refresh_session.amount_with_fee = amount_with_fee;
}
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->create_refresh_session (plugin->cls,
/* test insert_melt & get_melt */
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
plugin->get_melt (plugin->cls,
session,
&refresh_session.rc,
&ret_refresh_session));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_melt (plugin->cls,
session,
&session_hash,
&refresh_session));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_refresh_session (plugin->cls,
plugin->get_melt (plugin->cls,
session,
&session_hash,
&refresh_session.rc,
&ret_refresh_session));
FAILIF (refresh_session.noreveal_index !=
ret_refresh_session.session.noreveal_index);
FAILIF (0 !=
TALER_amount_cmp (&refresh_session.amount_with_fee,
&ret_refresh_session.session.amount_with_fee));
FAILIF (0 !=
TALER_amount_cmp (&fee_refresh,
&ret_refresh_session.melt_fee));
FAILIF (0 !=
memcmp (&refresh_session.rc,
&ret_refresh_session.session.rc,
sizeof (struct TALER_RefreshCommitmentP)));
FAILIF (0 !=
memcmp (&refresh_session.coin_sig,
&ret_refresh_session.session.coin_sig,
sizeof (struct TALER_CoinSpendSignatureP)));
FAILIF (0 !=
GNUNET_CRYPTO_rsa_signature_cmp (refresh_session.coin.denom_sig.rsa_signature,
ret_refresh_session.session.coin.denom_sig.rsa_signature));
FAILIF (0 != memcmp (&refresh_session.coin.coin_pub,
&ret_refresh_session.session.coin.coin_pub,
sizeof (refresh_session.coin.coin_pub)));
FAILIF (0 !=
GNUNET_CRYPTO_rsa_public_key_cmp (refresh_session.coin.denom_pub.rsa_public_key,
ret_refresh_session.session.coin.denom_pub.rsa_public_key));
GNUNET_CRYPTO_rsa_signature_free (ret_refresh_session.session.coin.denom_sig.rsa_signature);
GNUNET_CRYPTO_rsa_public_key_free (ret_refresh_session.session.coin.denom_pub.rsa_public_key);
/* test 'select_refreshs_above_serial_id' */
auditor_row_cnt = 0;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->select_refreshs_above_serial_id (plugin->cls,
@ -591,41 +577,19 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
&audit_refresh_session_cb,
NULL));
FAILIF (1 != auditor_row_cnt);
FAILIF (ret_refresh_session.num_newcoins != refresh_session.num_newcoins);
FAILIF (ret_refresh_session.noreveal_index != refresh_session.noreveal_index);
/* check refresh session melt data */
{
struct TALER_EXCHANGEDB_RefreshMelt *ret_melt;
ret_melt = &ret_refresh_session.melt;
FAILIF (0 != GNUNET_CRYPTO_rsa_signature_cmp
(ret_melt->coin.denom_sig.rsa_signature,
meltp->coin.denom_sig.rsa_signature));
FAILIF (0 != memcmp (&ret_melt->coin.coin_pub,
&meltp->coin.coin_pub,
sizeof (ret_melt->coin.coin_pub)));
FAILIF (0 != GNUNET_CRYPTO_rsa_public_key_cmp
(ret_melt->coin.denom_pub.rsa_public_key,
meltp->coin.denom_pub.rsa_public_key));
FAILIF (0 != memcmp (&ret_melt->coin_sig,
&meltp->coin_sig,
sizeof (ret_melt->coin_sig)));
FAILIF (0 != memcmp (&ret_melt->session_hash,
&meltp->session_hash,
sizeof (ret_melt->session_hash)));
FAILIF (0 != TALER_amount_cmp (&ret_melt->amount_with_fee,
&meltp->amount_with_fee));
FAILIF (0 != TALER_amount_cmp (&ret_melt->melt_fee,
&meltp->melt_fee));
GNUNET_CRYPTO_rsa_signature_free (ret_melt->coin.denom_sig.rsa_signature);
GNUNET_CRYPTO_rsa_public_key_free (ret_melt->coin.denom_pub.rsa_public_key);
}
new_dkp = GNUNET_new_array (MELT_NEW_COINS, struct DenomKeyPair *);
new_dkp = GNUNET_new_array (MELT_NEW_COINS,
struct DenomKeyPair *);
new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS,
struct TALER_DenominationPublicKey);
for (cnt=0; cnt < MELT_NEW_COINS; cnt++)
revealed_coins
= GNUNET_new_array (MELT_NEW_COINS,
struct TALER_EXCHANGEDB_RefreshRevealedCoin);
for (unsigned int cnt=0; cnt < MELT_NEW_COINS; cnt++)
{
struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin;
struct GNUNET_HashCode hc;
new_dkp[cnt] = create_denom_key_pair (1024,
session,
GNUNET_TIME_absolute_get (),
@ -636,100 +600,50 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
&fee_refund);
GNUNET_assert (NULL != new_dkp[cnt]);
new_denom_pubs[cnt] = new_dkp[cnt]->pub;
}
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_refresh_order (plugin->cls,
session,
&session_hash,
MELT_NEW_COINS,
new_denom_pubs));
ret_denom_pubs = GNUNET_new_array (MELT_NEW_COINS,
struct TALER_DenominationPublicKey);
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_refresh_order (plugin->cls,
session,
&session_hash,
MELT_NEW_COINS,
ret_denom_pubs));
for (cnt=0; cnt < MELT_NEW_COINS; cnt++)
{
FAILIF (0 != GNUNET_CRYPTO_rsa_public_key_cmp
(ret_denom_pubs[cnt].rsa_public_key,
new_denom_pubs[cnt].rsa_public_key));
}
FAILIF (GNUNET_OK !=
test_refresh_commit_coins (session,
&refresh_session,
&session_hash));
FAILIF (GNUNET_OK !=
test_refresh_commit_links (session,
&refresh_session,
&session_hash));
for (cnt=0; cnt < MELT_NEW_COINS; cnt++)
{
struct GNUNET_HashCode hc;
struct TALER_DenominationSignature test_sig;
ccoin = &revealed_coins[cnt];
ccoin->coin_ev_size = (size_t) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
COIN_ENC_MAX_SIZE);
ccoin->coin_ev = GNUNET_malloc (ccoin->coin_ev_size);
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
ccoin->coin_ev,
ccoin->coin_ev_size);
RND_BLK (&hc);
ev_sigs[cnt].rsa_signature
ccoin->denom_pub = new_dkp[cnt]->pub;
ccoin->coin_sig.rsa_signature
= GNUNET_CRYPTO_rsa_sign_fdh (new_dkp[cnt]->priv.rsa_private_key,
&hc);
GNUNET_assert (NULL != ev_sigs[cnt].rsa_signature);
}
RND_BLK (&tprivs);
RND_BLK (&tpub);
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
plugin->get_refresh_out (plugin->cls,
plugin->get_refresh_reveal (plugin->cls,
session,
&session_hash,
cnt,
&test_sig));
&refresh_session.rc,
&never_called_cb,
NULL));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_refresh_out (plugin->cls,
plugin->insert_refresh_reveal (plugin->cls,
session,
&session_hash,
cnt,
&ev_sigs[cnt]));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_refresh_out (plugin->cls,
&refresh_session.rc,
MELT_NEW_COINS,
revealed_coins,
TALER_CNC_KAPPA - 1,
tprivs,
&tpub));
FAILIF (0 >=
plugin->get_refresh_reveal (plugin->cls,
session,
&session_hash,
cnt,
&test_sig));
FAILIF (0 !=
GNUNET_CRYPTO_rsa_signature_cmp (test_sig.rsa_signature,
ev_sigs[cnt].rsa_signature));
GNUNET_CRYPTO_rsa_signature_free (test_sig.rsa_signature);
}
&refresh_session.rc,
&check_refresh_reveal_cb,
NULL));
qs = plugin->get_link_data_list (plugin->cls,
qs = plugin->get_link_data (plugin->cls,
session,
&session_hash,
&ldl);
&refresh_session.coin.coin_pub,
&handle_link_data_cb,
NULL);
FAILIF (0 >= qs);
FAILIF (NULL == ldl);
for (ldlp = ldl; NULL != ldlp; ldlp = ldlp->next)
{
int found;
found = GNUNET_NO;
for (cnt=0;cnt < MELT_NEW_COINS;cnt++)
{
FAILIF (NULL == ldlp->ev_sig.rsa_signature);
if ( (0 ==
GNUNET_CRYPTO_rsa_public_key_cmp (ldlp->denom_pub.rsa_public_key,
new_dkp[cnt]->pub.rsa_public_key)) &&
(0 ==
GNUNET_CRYPTO_rsa_signature_cmp (ldlp->ev_sig.rsa_signature,
ev_sigs[cnt].rsa_signature)) )
{
found = GNUNET_YES;
break;
}
}
FAILIF (GNUNET_NO == found);
}
plugin->free_link_data_list (plugin->cls,
ldl);
{
/* Just to test fetching a coin with melt history */
struct TALER_EXCHANGEDB_TransactionList *tl;
@ -737,7 +651,7 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
qs = plugin->get_coin_transactions (plugin->cls,
session,
&meltp->coin.coin_pub,
&refresh_session.coin.coin_pub,
&tl);
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
plugin->free_coin_transaction_list (plugin->cls,
@ -745,42 +659,29 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
}
{
int ok;
ok = GNUNET_NO;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_transfer (plugin->cls,
session,
&meltp->coin.coin_pub,
&check_transfer_data,
&ok));
FAILIF (GNUNET_OK != ok);
}
ret = GNUNET_OK;
drop:
for (cnt=0; cnt < MELT_NEW_COINS; cnt++)
if (NULL != ev_sigs[cnt].rsa_signature)
GNUNET_CRYPTO_rsa_signature_free (ev_sigs[cnt].rsa_signature);
if (NULL != commit_coins)
if (NULL != revealed_coins)
{
plugin->free_refresh_commit_coins (plugin->cls,
MELT_NEW_COINS,
commit_coins);
GNUNET_free (commit_coins);
commit_coins = NULL;
for (unsigned int cnt=0; cnt < MELT_NEW_COINS; cnt++)
{
if (NULL != revealed_coins[cnt].coin_sig.rsa_signature)
GNUNET_CRYPTO_rsa_signature_free (revealed_coins[cnt].coin_sig.rsa_signature);
GNUNET_free (revealed_coins[cnt].coin_ev);
}
GNUNET_free (revealed_coins);
revealed_coins = NULL;
}
destroy_denom_key_pair (dkp);
GNUNET_CRYPTO_rsa_signature_free (meltp->coin.denom_sig.rsa_signature);
for (cnt = 0;
GNUNET_CRYPTO_rsa_signature_free (refresh_session.coin.denom_sig.rsa_signature);
for (unsigned int cnt = 0;
(NULL != ret_denom_pubs) && (cnt < MELT_NEW_COINS)
&& (NULL != ret_denom_pubs[cnt].rsa_public_key);
cnt++)
GNUNET_CRYPTO_rsa_public_key_free (ret_denom_pubs[cnt].rsa_public_key);
GNUNET_free_non_null (ret_denom_pubs);
GNUNET_free_non_null (new_denom_pubs);
for (cnt = 0;
for (unsigned int cnt = 0;
(NULL != new_dkp) && (cnt < MELT_NEW_COINS) && (NULL != new_dkp[cnt]);
cnt++)
destroy_denom_key_pair (new_dkp[cnt]);
@ -1439,7 +1340,7 @@ wire_missing_cb (void *cls,
/* bool? */ int tiny,
/* bool? */ int done)
{
struct TALER_EXCHANGEDB_Deposit *deposit = cls;
const struct TALER_EXCHANGEDB_Deposit *deposit = cls;
struct GNUNET_HashCode h_wire;
if (NULL != wire)
@ -1615,6 +1516,7 @@ run (void *cls)
session,
&rr,
&rr_size));
GNUNET_free (rr);
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_latest_reserve_in_reference (plugin->cls,
session,

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014, 2015 GNUnet e.V.
Copyright (C) 2014, 2015, 2016, 2017 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
@ -289,6 +289,19 @@ struct TALER_DenominationBlindingKeyP
};
/**
* Commitment value for the refresh protocol.
* See #TALER_refresh_get_commitment().
*/
struct TALER_RefreshCommitmentP
{
/**
* The commitment is a hash code.
*/
struct GNUNET_HashCode session_hash;
};
GNUNET_NETWORK_STRUCT_END
@ -557,12 +570,12 @@ GNUNET_NETWORK_STRUCT_END
*
* @param secret_seed seed to use for KDF to derive coin keys
* @param coin_num_salt number of the coin to include in KDF
* @param[out] fc value to initialize
* @param[out] ps value to initialize
*/
void
TALER_planchet_setup_refresh (const struct TALER_TransferSecretP *secret_seed,
unsigned int coin_num_salt,
struct TALER_PlanchetSecretsP *fc);
uint32_t coin_num_salt,
struct TALER_PlanchetSecretsP *ps);
/**
@ -656,4 +669,65 @@ TALER_link_recover_transfer_secret (const struct TALER_TransferPublicKeyP *trans
struct TALER_TransferSecretP *transfer_secret);
/**
* Information about a coin to be created during a refresh operation.
*/
struct TALER_RefreshCoinData
{
/**
* The denomination's public key.
*/
const struct TALER_DenominationPublicKey *dk;
/**
* The envelope with the blinded coin.
*/
char *coin_ev;
/**
* Number of bytes in @a coin_ev
*/
size_t coin_ev_size;
};
/**
* One of the #TALER_CNC_KAPPA commitments.
*/
struct TALER_RefreshCommitmentEntry
{
/**
* Transfer public key of this commitment.
*/
struct TALER_TransferPublicKeyP transfer_pub;
/**
* Array of @e num_new_coins new coins to be created.
*/
struct TALER_RefreshCoinData *new_coins;
};
/**
* Compute the commitment for a /refresh/melt operation from
* the respective public inputs.
*
* @param[out] rc set to the value the wallet must commit to
* @param kappa number of transfer public keys involved (must be #TALER_CNC_KAPPA)
* @param num_new_coins number of new coins to be created
* @param commitments array of @a kappa commitments
* @param coin_pub public key of the coin to be melted
* @param amount_with_fee amount to be melted, including fee
*/
void
TALER_refresh_get_commitment (struct TALER_RefreshCommitmentP *rc,
uint32_t kappa,
uint32_t num_new_coins,
const struct TALER_RefreshCommitmentEntry *rcs,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_Amount *amount_with_fee);
#endif

View File

@ -68,6 +68,11 @@ enum TALER_ErrorCode
*/
TALER_EC_TIMEOUT = 6,
/**
* Exchange failed to allocate memory for building JSON reply.
*/
TALER_EC_JSON_ALLOCATION_FAILURE = 7,
/* ********** generic error codes ************* */
/**
@ -428,6 +433,7 @@ enum TALER_ErrorCode
*/
TALER_EC_DEPOSIT_INVALID_TIMESTAMP = 1218,
/**
* The respective coin did not have sufficient residual value
* for the /refresh/melt operation. The "history" in this
@ -468,86 +474,26 @@ enum TALER_ErrorCode
*/
TALER_EC_REFRESH_MELT_DB_STORE_SESSION_ERROR = 1304,
/**
* The exchange failed to store commit data in the
* database.
* This response is provided with HTTP status code
* MHD_HTTP_INTERNAL_ERROR.
*/
TALER_EC_REFRESH_MELT_DB_STORE_COMMIT_ERROR = 1306,
/**
* The exchange is unaware of the denomination key that was
* requested for one of the fresh coins. This response is provided
* with HTTP status code MHD_HTTP_BAD_REQUEST.
*/
TALER_EC_REFRESH_MELT_FRESH_DENOMINATION_KEY_NOT_FOUND = 1308,
/**
* The exchange encountered a numeric overflow totaling up
* the cost for the refresh operation. This response is provided
* with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
*/
TALER_EC_REFRESH_MELT_COST_CALCULATION_OVERFLOW = 1309,
/**
* During the transaction phase, the exchange could suddenly
* no longer find the denomination key that was
* used to sign the melted coin. This response is provided
* with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
*/
TALER_EC_REFRESH_MELT_DB_DENOMINATION_KEY_NOT_FOUND = 1310,
/**
* The exchange encountered melt fees exceeding the melted
* coin's contribution. This response is provided
* with HTTP status code MHD_HTTP_BAD_REQUEST.
*/
TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION = 1311,
/**
* The exchange's cost calculation does not add up to the
* melt fees specified in the request. This response is provided
* with HTTP status code MHD_HTTP_BAD_REQUEST.
*/
TALER_EC_REFRESH_MELT_FEES_MISSMATCH = 1312,
TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION = 1305,
/**
* The denomination key signature on the melted coin is invalid.
* This response is provided with HTTP status code
* MHD_HTTP_BAD_REQUEST.
*/
TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID = 1313,
/**
* The exchange's cost calculation shows that the melt amount
* is below the costs of the transaction. This response is provided
* with HTTP status code MHD_HTTP_BAD_REQUEST.
*/
TALER_EC_REFRESH_MELT_AMOUNT_INSUFFICIENT = 1314,
TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID = 1306,
/**
* The signature made with the coin to be melted is invalid.
* This response is provided with HTTP status code
* MHD_HTTP_BAD_REQUEST.
*/
TALER_EC_REFRESH_MELT_COIN_SIGNATURE_INVALID = 1315,
/**
* The size of the cut-and-choose dimension of the
* blinded coins request does not match #TALER_CNC_KAPPA.
* This response is provided with HTTP status code
* MHD_HTTP_BAD_REQUEST.
*/
TALER_EC_REFRESH_MELT_CNC_COIN_ARRAY_SIZE_INVALID = 1316,
/**
* The size of the cut-and-choose dimension of the
* transfer keys request does not match #TALER_CNC_KAPPA.
* This response is provided with HTTP status code
* MHD_HTTP_BAD_REQUEST.
*/
TALER_EC_REFRESH_MELT_CNC_TRANSFER_ARRAY_SIZE_INVALID = 1317,
TALER_EC_REFRESH_MELT_COIN_SIGNATURE_INVALID = 1307,
/**
* The exchange failed to obtain the transaction history of the
@ -556,7 +502,8 @@ enum TALER_ErrorCode
* This response is provided with HTTP status code
* MHD_HTTP_INTERNAL_SERVER_ERROR.
*/
TALER_EC_REFRESH_MELT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1318,
TALER_EC_REFRESH_MELT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1308,
/**
* The provided transfer keys do not match up with the
@ -566,21 +513,13 @@ enum TALER_ErrorCode
*/
TALER_EC_REFRESH_REVEAL_COMMITMENT_VIOLATION = 1350,
/**
* Failed to blind the envelope to reconstruct the blinded
* coins for revealation checks.
* This response is provided with HTTP status code
* MHD_HTTP_INTERNAL_ERROR.
*/
TALER_EC_REFRESH_REVEAL_BLINDING_ERROR = 1351,
/**
* Failed to produce the blinded signatures over the coins
* to be returned.
* This response is provided with HTTP status code
* MHD_HTTP_INTERNAL_ERROR.
*/
TALER_EC_REFRESH_REVEAL_SIGNING_ERROR = 1352,
TALER_EC_REFRESH_REVEAL_SIGNING_ERROR = 1351,
/**
* The exchange is unaware of the refresh sessino specified in
@ -588,7 +527,7 @@ enum TALER_ErrorCode
* This response is provided with HTTP status code
* MHD_HTTP_BAD_REQUEST.
*/
TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN = 1353,
TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN = 1352,
/**
* The exchange failed to retrieve valid session data from the
@ -596,23 +535,14 @@ enum TALER_ErrorCode
* This response is provided with HTTP status code
* MHD_HTTP_INTERNAL_ERROR.
*/
TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR = 1354,
TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR = 1353,
/**
* The exchange failed to retrieve order data from the
* database.
* This response is provided with HTTP status code
* The exchange failed to retrieve previously revealed data from the
* database. This response is provided with HTTP status code
* MHD_HTTP_INTERNAL_ERROR.
*/
TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR = 1355,
/**
* The exchange failed to retrieve transfer keys from the
* database.
* This response is provided with HTTP status code
* MHD_HTTP_INTERNAL_ERROR.
*/
TALER_EC_REFRESH_REVEAL_DB_FETCH_TRANSFER_ERROR = 1356,
TALER_EC_REFRESH_REVEAL_DB_FETCH_REVEAL_ERROR = 1354,
/**
* The exchange failed to retrieve commitment data from the
@ -620,7 +550,7 @@ enum TALER_ErrorCode
* This response is provided with HTTP status code
* MHD_HTTP_INTERNAL_ERROR.
*/
TALER_EC_REFRESH_REVEAL_DB_FETCH_COMMIT_ERROR = 1357,
TALER_EC_REFRESH_REVEAL_DB_COMMIT_ERROR = 1355,
/**
* The size of the cut-and-choose dimension of the
@ -628,7 +558,45 @@ enum TALER_ErrorCode
* This response is provided with HTTP status code
* MHD_HTTP_BAD_REQUEST.
*/
TALER_EC_REFRESH_REVEAL_CNC_TRANSFER_ARRAY_SIZE_INVALID = 1358,
TALER_EC_REFRESH_REVEAL_CNC_TRANSFER_ARRAY_SIZE_INVALID = 1356,
/**
* The number of coins to be created in refresh exceeds the limits
* of the exchange.
* private transfer keys request does not match #TALER_CNC_KAPPA - 1.
* This response is provided with HTTP status code
* MHD_HTTP_BAD_REQUEST.
*/
TALER_EC_REFRESH_REVEAL_NEW_DENOMS_ARRAY_SIZE_EXCESSIVE = 1357,
/**
* The number of envelopes given does not match the number
* of denomination keys given.
* This response is provided with HTTP status code
* MHD_HTTP_BAD_REQUEST.
*/
TALER_EC_REFRESH_REVEAL_NEW_DENOMS_ARRAY_SIZE_MISSMATCH = 1358,
/**
* The exchange encountered a numeric overflow totaling up
* the cost for the refresh operation. This response is provided
* with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
*/
TALER_EC_REFRESH_REVEAL_COST_CALCULATION_OVERFLOW = 1359,
/**
* The exchange's cost calculation shows that the melt amount
* is below the costs of the transaction. This response is provided
* with HTTP status code MHD_HTTP_BAD_REQUEST.
*/
TALER_EC_REFRESH_REVEAL_AMOUNT_INSUFFICIENT = 1360,
/**
* The exchange is unaware of the denomination key that was
* requested for one of the fresh coins. This response is provided
* with HTTP status code MHD_HTTP_BAD_REQUEST.
*/
TALER_EC_REFRESH_REVEAL_FRESH_DENOMINATION_KEY_NOT_FOUND = 1361,
/**

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014-2017 GNUnet e.V.
Copyright (C) 2014-2017 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@ -1110,7 +1110,7 @@ struct TALER_EXCHANGE_RefreshMeltHandle;
* 0 if the exchange's reply is bogus (fails to follow the protocol)
* @param ec taler-specific error code, #TALER_EC_NONE on success
* @param noreveal_index choice by the exchange in the cut-and-choose protocol,
* UINT16_MAX on error
* UINT32_MAX on error
* @param sign_key exchange key used to sign @a full_response, or NULL
* @param full_response full response from the exchange (for logging, in case of errors)
*/
@ -1118,7 +1118,7 @@ typedef void
(*TALER_EXCHANGE_RefreshMeltCallback) (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
uint16_t noreveal_index,
uint32_t noreveal_index,
const struct TALER_ExchangePublicKeyP *sign_key,
const json_t *full_response);
@ -1223,7 +1223,7 @@ struct TALER_EXCHANGE_RefreshRevealHandle *
TALER_EXCHANGE_refresh_reveal (struct TALER_EXCHANGE_Handle *exchange,
size_t refresh_data_length,
const char *refresh_data,
uint16_t noreveal_index,
uint32_t noreveal_index,
TALER_EXCHANGE_RefreshRevealCallback reveal_cb,
void *reveal_cb_cls);

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014-2017 GNUnet e.V.
Copyright (C) 2014-2017 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
@ -465,7 +465,7 @@ struct TALER_EXCHANGEDB_Refund
/**
* @brief Specification for coin in a /refresh/melt operation.
*/
struct TALER_EXCHANGEDB_RefreshMelt
struct TALER_EXCHANGEDB_RefreshSession
{
/**
* Information about the coin that is being melted.
@ -478,9 +478,9 @@ struct TALER_EXCHANGEDB_RefreshMelt
struct TALER_CoinSpendSignatureP coin_sig;
/**
* Hash of the refresh session this coin is melted into.
* Refresh commitment this coin is melted into.
*/
struct GNUNET_HashCode session_hash;
struct TALER_RefreshCommitmentP rc;
/**
* How much value is being melted? This amount includes the fees,
@ -492,65 +492,30 @@ struct TALER_EXCHANGEDB_RefreshMelt
*/
struct TALER_Amount amount_with_fee;
/**
* Melting fee charged by the exchange. This must match the Exchange's
* denomination key's melting fee. If the client puts in an invalid
* melting fee (too high or too low) that does not match the Exchange's
* denomination key, the melting operation is invalid and will be
* rejected by the exchange. The @e amount_with_fee minus the @e
* melt_fee is the amount that will be credited to the melting
* session.
*/
struct TALER_Amount melt_fee;
};
/**
* @brief Global information for a refreshing session. Includes
* dimensions of the operation, security parameters and
* client signatures from "/refresh/melt" and "/refresh/commit".
*/
struct TALER_EXCHANGEDB_RefreshSession
{
/**
* Melt operation details.
*/
struct TALER_EXCHANGEDB_RefreshMelt melt;
/**
* Number of new coins we are creating.
*/
uint16_t num_newcoins;
/**
* Index (smaller #TALER_CNC_KAPPA) which the exchange has chosen to not
* have revealed during cut and choose.
*/
uint16_t noreveal_index;
uint32_t noreveal_index;
};
/**
* @brief We have as many `struct TALER_EXCHANGEDB_RefreshCommitCoin` as there are new
* coins being created by the refresh (for each of the #TALER_CNC_KAPPA
* sets). These are the coins we ask the exchange to sign if the
* respective set is selected.
* Information about a /refresh/melt operation in the transaction history.
*/
struct TALER_EXCHANGEDB_RefreshCommitCoin
struct TALER_EXCHANGEDB_RefreshMelt
{
/**
* Blinded message to be signed (in envelope), with @e coin_env_size bytes.
* Overall session data.
*/
char *coin_ev;
struct TALER_EXCHANGEDB_RefreshSession session;
/**
* Number of bytes in @e coin_ev.
* Melt fee the exchange charged.
*/
size_t coin_ev_size;
struct TALER_Amount melt_fee;
};
@ -752,9 +717,8 @@ typedef int
* @param coin_pub public key of the coin
* @param coin_sig signature from the coin
* @param amount_with_fee amount that was deposited including fee
* @param num_newcoins how many coins were issued
* @param noreveal_index which index was picked by the exchange in cut-and-choose
* @param session_hash what is the session hash
* @param rc what is the commitment
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
typedef int
@ -764,9 +728,56 @@ typedef int
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_CoinSpendSignatureP *coin_sig,
const struct TALER_Amount *amount_with_fee,
uint16_t num_newcoins,
uint16_t noreveal_index,
const struct GNUNET_HashCode *session_hash);
uint32_t noreveal_index,
const struct TALER_RefreshCommitmentP *rc);
/**
* Information about a coin that was revealed to the exchange
* during /refresh/reveal.
*/
struct TALER_EXCHANGEDB_RefreshRevealedCoin
{
/**
* Public denomination key of the coin.
*/
struct TALER_DenominationPublicKey denom_pub;
/**
* Blinded message to be signed (in envelope), with @e coin_env_size bytes.
*/
char *coin_ev;
/**
* Number of bytes in @e coin_ev.
*/
size_t coin_ev_size;
/**
* Signature generated by the exchange over the coin (in blinded format).
*/
struct TALER_DenominationSignature coin_sig;
};
/**
* Function called with information about a refresh order.
*
* @param cls closure
* @param rowid unique serial ID for the row in our database
* @param num_newcoins size of the @a rrcs array
* @param rrcs array of @a num_newcoins information about coins to be created
* @param num_tprivs number of entries in @a tprivs, should be #TALER_CNC_KAPPA - 1
* @param tprivs array of @e num_tprivs transfer private keys
* @param tp transfer public key information
*/
typedef void
(*TALER_EXCHANGEDB_RefreshCallback)(void *cls,
uint32_t num_newcoins,
const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs,
unsigned int num_tprivs,
const struct TALER_TransferPrivateKeyP *tprivs,
const struct TALER_TransferPublicKeyP *tp);
/**
@ -851,14 +862,13 @@ typedef int
* information for a given coin.
*
* @param cls closure
* @param session_hash a session the coin was melted in
* @param transfer_pub public transfer key for the session
* @param shared_secret_enc set to shared secret for the session
* @param ldl link data for @a transfer_pub
*/
typedef void
(*TALER_EXCHANGEDB_TransferDataCallback)(void *cls,
const struct GNUNET_HashCode *session_hash,
const struct TALER_TransferPublicKeyP *transfer_pub);
(*TALER_EXCHANGEDB_LinkDataCallback)(void *cls,
const struct TALER_TransferPublicKeyP *transfer_pub,
const struct TALER_EXCHANGEDB_LinkDataList *ldl);
/**
@ -1454,225 +1464,79 @@ struct TALER_EXCHANGEDB_Plugin
/**
* Lookup refresh session data under the given @a session_hash.
* Store new refresh melt commitment data.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param session database handle to use
* @param session_hash hash over the melt to use for the lookup
* @param[out] refresh_session where to store the result
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
(*get_refresh_session) (void *cls,
struct TALER_EXCHANGEDB_Session *session,
const struct GNUNET_HashCode *session_hash,
struct TALER_EXCHANGEDB_RefreshSession *refresh_session);
/**
* Store new refresh session data under the given @a session_hash.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param session database handle to use
* @param session_hash hash over the melt to use to locate the session
* @param refresh_session session data to store
* @param refresh_session operational data to store
* @return query status for the transaction
*/
enum GNUNET_DB_QueryStatus
(*create_refresh_session) (void *cls,
(*insert_melt) (void *cls,
struct TALER_EXCHANGEDB_Session *session,
const struct GNUNET_HashCode *session_hash,
const struct TALER_EXCHANGEDB_RefreshSession *refresh_session);
/**
* Store in the database which coin(s) we want to create
* in a given refresh operation.
* Lookup refresh metl commitment data under the given @a rc.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param session database connection
* @param session_hash hash to identify refresh session
* @param num_newcoins number of coins to generate, size of the @a denom_pubs array
* @param denom_pubs array denominations of the coins to create
* @return query status for the transaction
*/
enum GNUNET_DB_QueryStatus
(*insert_refresh_order) (void *cls,
struct TALER_EXCHANGEDB_Session *session,
const struct GNUNET_HashCode *session_hash,
uint16_t num_newcoins,
const struct TALER_DenominationPublicKey *denom_pubs);
/**
* Lookup in the database for the @a num_newcoins coins that we want to
* create in the given refresh operation.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param session database connection
* @param session_hash hash to identify refresh session
* @param num_newcoins size of the @a denom_pubs array
* @param[out] denom_pubs where to write @a num_newcoins denomination keys
* @param session database handle to use
* @param rc commitment to use for the lookup
* @param[out] refresh_melt where to store the result
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
(*get_refresh_order) (void *cls,
(*get_melt) (void *cls,
struct TALER_EXCHANGEDB_Session *session,
const struct GNUNET_HashCode *session_hash,
uint16_t num_newcoins,
struct TALER_DenominationPublicKey *denom_pubs);
const struct TALER_RefreshCommitmentP *rc,
struct TALER_EXCHANGEDB_RefreshMelt *refresh_melt);
/**
* Store information about the commitments of the given index @a i
* for the given refresh session in the database.
* Store in the database which coin(s) the wallet wanted to create
* in a given refresh operation and all of the other information
* we learned or created in the /refresh/reveal step.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param session database connection to use
* @param session_hash hash to identify refresh session
* @param num_newcoins coin index size of the @a commit_coins array
* @param commit_coin array of coin commitments to store
* @return query status for the transaction
*/
enum GNUNET_DB_QueryStatus
(*insert_refresh_commit_coins) (void *cls,
struct TALER_EXCHANGEDB_Session *session,
const struct GNUNET_HashCode *session_hash,
uint16_t num_newcoins,
const struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins);
/**
* Obtain information about the commitment of the
* given coin of the given refresh session from the database.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param session database connection to use
* @param session_hash hash to identify refresh session
* @param num_coins size of the @a commit_coins array
* @param[out] commit_coins array of coin commitments to return
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
(*get_refresh_commit_coins) (void *cls,
struct TALER_EXCHANGEDB_Session *session,
const struct GNUNET_HashCode *session_hash,
uint16_t num_coins,
struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins);
/**
* Free refresh @a commit_coins data obtained via @e get_refresh_commit_coins.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param num_coins size of the @a commit_coins array
* @param commit_coins array of coin commitments to free
*/
void
(*free_refresh_commit_coins) (void *cls,
unsigned int num_coins,
struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins);
/**
* Store the commitment to the given (encrypted) refresh link data
* for the given refresh session.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param session database connection to use
* @param session_hash hash to identify refresh session
* @param session database connection
* @param rc identify commitment and thus refresh operation
* @param num_rrcs_newcoins number of coins to generate, size of the
* @a rrcs array
* @param rrcs information about the new coins
* @param num_tprivs number of entries in @a tprivs, should be #TALER_CNC_KAPPA - 1
* @param tprivs transfer private keys to store
* @param tp public key to store
* @return query status for the transaction
*/
enum GNUNET_DB_QueryStatus
(*insert_refresh_transfer_public_key) (void *cls,
(*insert_refresh_reveal) (void *cls,
struct TALER_EXCHANGEDB_Session *session,
const struct GNUNET_HashCode *session_hash,
const struct TALER_RefreshCommitmentP *rc,
uint32_t num_rrcs,
const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs,
unsigned int num_tprivs,
const struct TALER_TransferPrivateKeyP *tprivs,
const struct TALER_TransferPublicKeyP *tp);
/**
* Obtain the commited (encrypted) refresh link data
* for the given refresh session.
* Lookup in the database for the @a num_newcoins coins that we
* created in the given refresh operation.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param session database connection to use
* @param session_hash hash to identify refresh session
* @param[out] tp information to return
* @param session database connection
* @param rc identify commitment and thus refresh operation
* @param cb function to call with the results
* @param cb_cls closure for @a cb
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
(*get_refresh_transfer_public_key) (void *cls,
(*get_refresh_reveal) (void *cls,
struct TALER_EXCHANGEDB_Session *session,
const struct GNUNET_HashCode *session_hash,
struct TALER_TransferPublicKeyP *tp);
/**
* Get signature of a new coin generated during refresh into
* the database indexed by the refresh session and the index
* of the coin.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param session database connection
* @param session_hash hash to identify refresh session
* @param newcoin_index coin index
* @param[out] ev_sig coin signature
* @return transaction result status
*/
enum GNUNET_DB_QueryStatus
(*get_refresh_out) (void *cls,
struct TALER_EXCHANGEDB_Session *session,
const struct GNUNET_HashCode *session_hash,
uint16_t newcoin_index,
struct TALER_DenominationSignature *ev_sig);
/**
* Insert signature of a new coin generated during refresh into
* the database indexed by the refresh session and the index
* of the coin. This data is later used should an old coin
* be used to try to obtain the private keys during "/refresh/link".
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param session database connection
* @param session_hash hash to identify refresh session
* @param newcoin_index coin index
* @param ev_sig coin signature
* @return transaction result status
*/
enum GNUNET_DB_QueryStatus
(*insert_refresh_out) (void *cls,
struct TALER_EXCHANGEDB_Session *session,
const struct GNUNET_HashCode *session_hash,
uint16_t newcoin_index,
const struct TALER_DenominationSignature *ev_sig);
/**
* Obtain the link data of a coin, that is the encrypted link
* information, the denomination keys and the signatures.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param session database connection
* @param session_hash session to get linkage data for
* @param[out] ldldp set to all known link data for the session
* @return status of the transaction
*/
enum GNUNET_DB_QueryStatus
(*get_link_data_list) (void *cls,
struct TALER_EXCHANGEDB_Session *session,
const struct GNUNET_HashCode *session_hash,
struct TALER_EXCHANGEDB_LinkDataList **ldlp);
/**
* Free memory of the link data list.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param ldl link data list to release
*/
void
(*free_link_data_list) (void *cls,
struct TALER_EXCHANGEDB_LinkDataList *ldl);
const struct TALER_RefreshCommitmentP *rc,
TALER_EXCHANGEDB_RefreshCallback cb,
void *cb_cls);
/**
@ -1684,15 +1548,15 @@ struct TALER_EXCHANGEDB_Plugin
* @param cls the @e cls of this struct with the plugin-specific state
* @param session database connection
* @param coin_pub public key of the coin
* @param tdc function to call for each session the coin was melted into
* @param tdc_cls closure for @a tdc
* @param ldc function to call for each session the coin was melted into
* @param ldc_cls closure for @a tdc
* @return statement execution status
*/
enum GNUNET_DB_QueryStatus
(*get_transfer) (void *cls,
(*get_link_data) (void *cls,
struct TALER_EXCHANGEDB_Session *session,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
TALER_EXCHANGEDB_TransferDataCallback tdc,
TALER_EXCHANGEDB_LinkDataCallback ldc,
void *tdc_cls);

View File

@ -532,9 +532,9 @@ struct TALER_RefreshMeltCoinAffirmationPS
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
* Which melting session should the coin become a part of.
* Which melt commitment is made by the wallet.
*/
struct GNUNET_HashCode session_hash GNUNET_PACKED;
struct TALER_RefreshCommitmentP rc GNUNET_PACKED;
/**
* How much of the value of the coin should be melted? This amount
@ -581,20 +581,16 @@ struct TALER_RefreshMeltConfirmationPS
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
* Hash of the refresh session.
* Commitment made in the /refresh/melt.
*/
struct GNUNET_HashCode session_hash GNUNET_PACKED;
struct TALER_RefreshCommitmentP rc GNUNET_PACKED;
/**
* Index that the client will not have to reveal, in NBO.
* Must be smaller than #TALER_CNC_KAPPA.
*/
uint16_t noreveal_index GNUNET_PACKED;
uint32_t noreveal_index GNUNET_PACKED;
/**
* Zero.
*/
uint16_t reserved GNUNET_PACKED;
};

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014, 2015 GNUnet e.V.
Copyright (C) 2014-2017 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
@ -206,7 +206,7 @@ patch_private_key (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
*/
void
TALER_planchet_setup_refresh (const struct TALER_TransferSecretP *secret_seed,
unsigned int coin_num_salt,
uint32_t coin_num_salt,
struct TALER_PlanchetSecretsP *ps)
{
uint32_t be_salt = htonl (coin_num_salt);
@ -314,4 +314,87 @@ TALER_planchet_to_coin (const struct TALER_DenominationPublicKey *dk,
return GNUNET_OK;
}
/**
* Compute the commitment for a /refresh/melt operation from
* the respective public inputs.
*
* @param[out] rc set to the value the wallet must commit to
* @param kappa number of transfer public keys involved (must be #TALER_CNC_KAPPA)
* @param num_new_coins number of new coins to be created
* @param commitments array of @a kappa commitments
* @param coin_pub public key of the coin to be melted
* @param amount_with_fee amount to be melted, including fee
*/
void
TALER_refresh_get_commitment (struct TALER_RefreshCommitmentP *rc,
uint32_t kappa,
uint32_t num_new_coins,
const struct TALER_RefreshCommitmentEntry *rcs,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_Amount *amount_with_fee)
{
struct GNUNET_HashContext *hash_context;
hash_context = GNUNET_CRYPTO_hash_context_start ();
/* first, iterate over transfer public keys for hash_context */
for (unsigned int i=0;i<kappa;i++)
{
GNUNET_CRYPTO_hash_context_read (hash_context,
&rcs[i].transfer_pub,
sizeof (struct TALER_TransferPublicKeyP));
}
/* next, add all of the hashes from the denomination keys to the
hash_context */
for (unsigned int i=0;i<num_new_coins;i++)
{
char *buf;
size_t buf_size;
/* The denomination keys should / must all be identical regardless
of what offset we use, so we use [0]. */
GNUNET_assert (kappa > 0); /* sanity check */
buf_size = GNUNET_CRYPTO_rsa_public_key_encode (rcs[0].new_coins[i].dk->rsa_public_key,
&buf);
GNUNET_CRYPTO_hash_context_read (hash_context,
buf,
buf_size);
GNUNET_free (buf);
}
/* next, add public key of coin and amount being refreshed */
{
struct TALER_AmountNBO melt_amountn;
GNUNET_CRYPTO_hash_context_read (hash_context,
coin_pub,
sizeof (struct TALER_CoinSpendPublicKeyP));
TALER_amount_hton (&melt_amountn,
amount_with_fee);
GNUNET_CRYPTO_hash_context_read (hash_context,
&melt_amountn,
sizeof (struct TALER_AmountNBO));
}
/* finally, add all the envelopes */
for (unsigned int i=0;i<kappa;i++)
{
const struct TALER_RefreshCommitmentEntry *rce = &rcs[i];
for (unsigned int j=0;j<num_new_coins;j++)
{
const struct TALER_RefreshCoinData *rcd = &rce->new_coins[j];
GNUNET_CRYPTO_hash_context_read (hash_context,
rcd->coin_ev,
rcd->coin_ev_size);
}
}
/* Conclude */
GNUNET_CRYPTO_hash_context_finish (hash_context,
&rc->session_hash);
}
/* end of crypto.c */