-fix recoup ugliness

This commit is contained in:
Christian Grothoff 2021-12-16 20:18:44 +01:00
parent 3b6a0dd599
commit 1acc851deb
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
13 changed files with 248 additions and 160 deletions

View File

@ -1983,20 +1983,12 @@ check_recoup (struct CoinContext *cc,
cc->qs = qs; cc->qs = qs;
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
{
struct TALER_RecoupRequestPS pr = {
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP),
.purpose.size = htonl (sizeof (pr)),
.coin_pub = coin->coin_pub,
.coin_blind = *coin_blind,
.h_denom_pub = coin->denom_pub_hash
};
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP, TALER_wallet_recoup_verify (&coin->denom_pub_hash,
&pr, coin_blind,
&coin_sig->eddsa_signature, amount,
&coin->coin_pub.eddsa_pub)) &coin->coin_pub,
coin_sig))
{ {
TALER_ARL_report (report_bad_sig_losses, TALER_ARL_report (report_bad_sig_losses,
GNUNET_JSON_PACK ( GNUNET_JSON_PACK (
@ -2015,7 +2007,6 @@ check_recoup (struct CoinContext *cc,
return GNUNET_SYSERR; return GNUNET_SYSERR;
return GNUNET_OK; return GNUNET_OK;
} }
}
ds = get_denomination_summary (cc, ds = get_denomination_summary (cc,
issue, issue,
&issue->denom_hash); &issue->denom_hash);

View File

@ -684,7 +684,7 @@ handle_reserve_out (void *cls,
* @param coin_blind blinding factor used to blind the coin * @param coin_blind blinding factor used to blind the coin
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/ */
static int static enum GNUNET_GenericReturnValue
handle_recoup_by_reserve ( handle_recoup_by_reserve (
void *cls, void *cls,
uint64_t rowid, uint64_t rowid,
@ -711,20 +711,12 @@ handle_recoup_by_reserve (
ppr.last_reserve_recoup_serial_id = rowid + 1; ppr.last_reserve_recoup_serial_id = rowid + 1;
/* We know that denom_pub matches denom_pub_hash because this /* We know that denom_pub matches denom_pub_hash because this
is how the SQL statement joined the tables. */ is how the SQL statement joined the tables. */
{
struct TALER_RecoupRequestPS pr = {
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP),
.purpose.size = htonl (sizeof (pr)),
.h_denom_pub = coin->denom_pub_hash,
.coin_pub = coin->coin_pub,
.coin_blind = *coin_blind
};
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP, TALER_wallet_recoup_verify (&coin->denom_pub_hash,
&pr, coin_blind,
&coin_sig->eddsa_signature, amount,
&coin->coin_pub.eddsa_pub)) &coin->coin_pub,
coin_sig))
{ {
TALER_ARL_report (report_bad_sig_losses, TALER_ARL_report (report_bad_sig_losses,
GNUNET_JSON_PACK ( GNUNET_JSON_PACK (
@ -740,7 +732,6 @@ handle_recoup_by_reserve (
&total_bad_sig_loss, &total_bad_sig_loss,
amount); amount);
} }
}
/* check that the coin was eligible for recoup!*/ /* check that the coin was eligible for recoup!*/
rev = GNUNET_CONTAINER_multihashmap_get (rc->revoked, rev = GNUNET_CONTAINER_multihashmap_get (rc->revoked,

View File

@ -87,6 +87,7 @@ struct RecoupContext
* Set by #recoup_transaction() to the amount that will be paid back * Set by #recoup_transaction() to the amount that will be paid back
*/ */
struct TALER_Amount amount; struct TALER_Amount amount;
const struct TALER_Amount *requested_amount;
/** /**
* Set by #recoup_transaction to the timestamp when the recoup * Set by #recoup_transaction to the timestamp when the recoup
@ -234,6 +235,15 @@ recoup_transaction (void *cls,
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl); tl);
pc->now = GNUNET_TIME_timestamp_get (); pc->now = GNUNET_TIME_timestamp_get ();
if (0 != TALER_amount_cmp (&pc->amount,
pc->requested_amount))
{
*mhd_ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_CONFLICT,
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
TALER_amount2s (&pc->amount));
return GNUNET_DB_STATUS_HARD_ERROR;
}
/* add coin to list of wire transfers for recoup */ /* add coin to list of wire transfers for recoup */
if (pc->refreshed) if (pc->refreshed)
@ -284,6 +294,7 @@ recoup_transaction (void *cls,
* @param coin information about the coin * @param coin information about the coin
* @param coin_bks blinding data of the coin (to be checked) * @param coin_bks blinding data of the coin (to be checked)
* @param coin_sig signature of the coin * @param coin_sig signature of the coin
* @param requested_amount requested amount to be recouped
* @param refreshed true if the coin was refreshed * @param refreshed true if the coin was refreshed
* @return MHD result code * @return MHD result code
*/ */
@ -293,6 +304,7 @@ verify_and_execute_recoup (
const struct TALER_CoinPublicInfo *coin, const struct TALER_CoinPublicInfo *coin,
const union TALER_DenominationBlindingKeyP *coin_bks, const union TALER_DenominationBlindingKeyP *coin_bks,
const struct TALER_CoinSpendSignatureP *coin_sig, const struct TALER_CoinSpendSignatureP *coin_sig,
const struct TALER_Amount *requested_amount,
bool refreshed) bool refreshed)
{ {
struct RecoupContext pc; struct RecoupContext pc;
@ -352,28 +364,19 @@ verify_and_execute_recoup (
} }
/* check recoup request signature */ /* check recoup request signature */
{
struct TALER_RecoupRequestPS pr = {
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP),
.purpose.size = htonl (sizeof (pr)),
.coin_pub = coin->coin_pub,
.h_denom_pub = coin->denom_pub_hash,
.coin_blind = *coin_bks
};
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP, TALER_wallet_recoup_verify (&coin->denom_pub_hash,
&pr, coin_bks,
&coin_sig->eddsa_signature, requested_amount,
&coin->coin_pub.eddsa_pub)) &coin->coin_pub,
coin_sig))
{ {
TALER_LOG_WARNING ("Invalid signature on recoup request\n"); GNUNET_break_op (0);
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_FORBIDDEN, MHD_HTTP_FORBIDDEN,
TALER_EC_EXCHANGE_RECOUP_SIGNATURE_INVALID, TALER_EC_EXCHANGE_RECOUP_SIGNATURE_INVALID,
NULL); NULL);
} }
}
{ {
void *coin_ev; void *coin_ev;
@ -404,6 +407,7 @@ verify_and_execute_recoup (
pc.coin_bks = coin_bks; pc.coin_bks = coin_bks;
pc.coin = coin; pc.coin = coin;
pc.refreshed = refreshed; pc.refreshed = refreshed;
pc.requested_amount = requested_amount;
{ {
MHD_RESULT mhd_ret = MHD_NO; MHD_RESULT mhd_ret = MHD_NO;
@ -552,6 +556,7 @@ TEH_handler_recoup (struct MHD_Connection *connection,
&coin, &coin,
&coin_bks, &coin_bks,
&coin_sig, &coin_sig,
&amount,
refreshed); refreshed);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return res; return res;

View File

@ -697,8 +697,6 @@ CREATE INDEX IF NOT EXISTS revolving_work_shards_index
-- Stored procedures -- Stored procedures
DROP FUNCTION IF EXISTS exchange_do_withdraw(bigint,integer,bytea,bytea,bytea,bytea,bytea,bigint,bigint) ;
CREATE OR REPLACE FUNCTION exchange_do_withdraw( CREATE OR REPLACE FUNCTION exchange_do_withdraw(
IN amount_val INT8, IN amount_val INT8,
IN amount_frac INT4, IN amount_frac INT4,
@ -857,9 +855,6 @@ COMMENT ON FUNCTION exchange_do_withdraw(INT8, INT4, BYTEA, BYTEA, BYTEA, BYTEA,
DROP FUNCTION IF EXISTS exchange_do_withdraw_limit_check(bigint,bigint,bigint,int) ;
CREATE OR REPLACE FUNCTION exchange_do_withdraw_limit_check( CREATE OR REPLACE FUNCTION exchange_do_withdraw_limit_check(
IN ruuid INT8, IN ruuid INT8,
IN start_time INT8, IN start_time INT8,

View File

@ -3246,8 +3246,8 @@ postgres_get_denomination_info (
rs); rs);
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
return qs; return qs;
issue->properties.purpose.size = htonl (sizeof (struct issue->properties.purpose.size
TALER_DenominationKeyValidityPS)); = htonl (sizeof (struct TALER_DenominationKeyValidityPS));
issue->properties.purpose.purpose = htonl ( issue->properties.purpose.purpose = htonl (
TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY); TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);
issue->properties.denom_hash = *denom_pub_hash; issue->properties.denom_hash = *denom_pub_hash;

View File

@ -238,18 +238,21 @@ create_denom_key_pair (unsigned int size,
sizeof (struct TALER_EXCHANGEDB_DenominationKey)); sizeof (struct TALER_EXCHANGEDB_DenominationKey));
dki.denom_pub = dkp->pub; dki.denom_pub = dkp->pub;
dki.issue.properties.start = GNUNET_TIME_timestamp_hton (now); dki.issue.properties.start = GNUNET_TIME_timestamp_hton (now);
dki.issue.properties.expire_withdraw = GNUNET_TIME_timestamp_hton dki.issue.properties.expire_withdraw
= GNUNET_TIME_timestamp_hton
(GNUNET_TIME_absolute_to_timestamp (GNUNET_TIME_absolute_to_timestamp
(GNUNET_TIME_absolute_add ( (GNUNET_TIME_absolute_add (
now.abs_time, now.abs_time,
GNUNET_TIME_UNIT_HOURS))); GNUNET_TIME_UNIT_HOURS)));
dki.issue.properties.expire_deposit = GNUNET_TIME_timestamp_hton ( dki.issue.properties.expire_deposit
= GNUNET_TIME_timestamp_hton (
GNUNET_TIME_absolute_to_timestamp GNUNET_TIME_absolute_to_timestamp
(GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_add
(now.abs_time, (now.abs_time,
GNUNET_TIME_relative_multiply ( GNUNET_TIME_relative_multiply (
GNUNET_TIME_UNIT_HOURS, 2)))); GNUNET_TIME_UNIT_HOURS, 2))));
dki.issue.properties.expire_legal = GNUNET_TIME_timestamp_hton ( dki.issue.properties.expire_legal
= GNUNET_TIME_timestamp_hton (
GNUNET_TIME_absolute_to_timestamp GNUNET_TIME_absolute_to_timestamp
(GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_add
(now.abs_time, (now.abs_time,
@ -276,6 +279,8 @@ create_denom_key_pair (unsigned int size,
destroy_denom_key_pair (dkp); destroy_denom_key_pair (dkp);
return NULL; return NULL;
} }
memset (&issue2, 0, sizeof (issue2));
plugin->commit (plugin->cls);
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_denomination_info (plugin->cls, plugin->get_denomination_info (plugin->cls,
&dki.issue.properties.denom_hash, &dki.issue.properties.denom_hash,

View File

@ -1738,6 +1738,63 @@ TALER_wallet_link_verify (
const struct TALER_CoinSpendPublicKeyP *old_coin_pub, const struct TALER_CoinSpendPublicKeyP *old_coin_pub,
const struct TALER_CoinSpendSignatureP *coin_sig); const struct TALER_CoinSpendSignatureP *coin_sig);
/**
* Sign link data.
*
* @param h_denom_pub hash of the denomiantion public key of the new coin
* @param transfer_pub transfer public key
* @param coin_ev coin envelope
* @param coin_ev_size number of bytes in @a coin_ev
* @param old_coin_priv private key to sign with
* @param[out] coin_sig resulting signature
*/
void
TALER_wallet_link_sign (const struct TALER_DenominationHash *h_denom_pub,
const struct TALER_TransferPublicKeyP *transfer_pub,
const void *coin_ev,
size_t coin_ev_size,
const struct TALER_CoinSpendPrivateKeyP *old_coin_priv,
struct TALER_CoinSpendSignatureP *coin_sig);
/**
* Verify recoup signature.
*
* @param h_denom_pub hash of the denomiantion public key of the coin
* @param coin_bks blinding factor used when withdrawing the coin
* @param requested_amount amount that is left to be recouped
* @param coin_pub coin key of the coin to be recouped
* @param coin_sig resulting signature
* @return #GNUNET_OK if the signature is valid
*/
enum GNUNET_GenericReturnValue
TALER_wallet_recoup_verify (
const struct TALER_DenominationHash *h_denom_pub,
const union TALER_DenominationBlindingKeyP *coin_bks,
const struct TALER_Amount *requested_amount,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_CoinSpendSignatureP *coin_sig);
/**
* Create recoup signature.
*
* @param h_denom_pub hash of the denomiantion public key of the coin
* @param coin_bks blinding factor used when withdrawing the coin
* @param requested_amount amount that is left to be recouped
* @param coin_priv coin key of the coin to be recouped
* @param coin_sig resulting signature
*/
void
TALER_wallet_recoup_sign (
const struct TALER_DenominationHash *h_denom_pub,
const union TALER_DenominationBlindingKeyP *coin_bks,
const struct TALER_Amount *requested_amount,
const struct TALER_CoinSpendPrivateKeyP *coin_priv,
struct TALER_CoinSpendSignatureP *coin_sig);
/* ********************* offline signing ************************** */ /* ********************* offline signing ************************** */

View File

@ -1496,11 +1496,6 @@ struct TALER_RecoupRequestPS
*/ */
struct GNUNET_CRYPTO_EccSignaturePurpose purpose; struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
* Public key of the coin to be refunded.
*/
struct TALER_CoinSpendPublicKeyP coin_pub;
/** /**
* Hash of the (revoked) denomination public key of the coin. * Hash of the (revoked) denomination public key of the coin.
*/ */
@ -1510,6 +1505,12 @@ struct TALER_RecoupRequestPS
* Blinding factor that was used to withdraw the coin. * Blinding factor that was used to withdraw the coin.
*/ */
union TALER_DenominationBlindingKeyP coin_blind; union TALER_DenominationBlindingKeyP coin_blind;
/**
* How much of the coin's value will be recouped?
*/
struct TALER_AmountNBO recoup_amount;
}; };

View File

@ -688,17 +688,16 @@ TALER_EXCHANGE_verify_coin_history (
.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP), .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP),
.coin_pub = *coin_pub .coin_pub = *coin_pub
}; };
struct TALER_RecoupRequestPS rr = { union TALER_DenominationBlindingKeyP coin_bks;
.purpose.size = htonl (sizeof (pc)), struct TALER_Amount recoup_amount;
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP),
.coin_pub = *coin_pub
};
struct TALER_ExchangePublicKeyP exchange_pub; struct TALER_ExchangePublicKeyP exchange_pub;
struct TALER_ExchangeSignatureP exchange_sig; struct TALER_ExchangeSignatureP exchange_sig;
struct TALER_CoinSpendSignatureP coin_sig; struct TALER_CoinSpendSignatureP coin_sig;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_amount_any_nbo ("amount", TALER_JSON_spec_amount_any_nbo ("amount",
&pc.recoup_amount), &pc.recoup_amount),
TALER_JSON_spec_amount_any ("amount",
&recoup_amount),
GNUNET_JSON_spec_fixed_auto ("exchange_sig", GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&exchange_sig), &exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub", GNUNET_JSON_spec_fixed_auto ("exchange_pub",
@ -708,9 +707,9 @@ TALER_EXCHANGE_verify_coin_history (
GNUNET_JSON_spec_fixed_auto ("coin_sig", GNUNET_JSON_spec_fixed_auto ("coin_sig",
&coin_sig), &coin_sig),
GNUNET_JSON_spec_fixed_auto ("coin_blind", GNUNET_JSON_spec_fixed_auto ("coin_blind",
&rr.coin_blind), &coin_bks),
GNUNET_JSON_spec_fixed_auto ("h_denom_pub", GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
&rr.h_denom_pub), h_denom_pub),
GNUNET_JSON_spec_timestamp_nbo ("timestamp", GNUNET_JSON_spec_timestamp_nbo ("timestamp",
&pc.timestamp), &pc.timestamp),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
@ -736,15 +735,15 @@ TALER_EXCHANGE_verify_coin_history (
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP, TALER_wallet_recoup_verify (h_denom_pub,
&rr, &coin_bks,
&coin_sig.eddsa_signature, &recoup_amount,
&coin_pub->eddsa_pub)) coin_pub,
&coin_sig))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
*h_denom_pub = rr.h_denom_pub;
add = GNUNET_YES; add = GNUNET_YES;
} }
else if (0 == strcasecmp (type, else if (0 == strcasecmp (type,
@ -758,17 +757,16 @@ TALER_EXCHANGE_verify_coin_history (
TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH), TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH),
.coin_pub = *coin_pub .coin_pub = *coin_pub
}; };
struct TALER_RecoupRequestPS rr = { union TALER_DenominationBlindingKeyP coin_bks;
.purpose.size = htonl (sizeof (pc)), struct TALER_Amount recoup_amount;
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP),
.coin_pub = *coin_pub
};
struct TALER_ExchangePublicKeyP exchange_pub; struct TALER_ExchangePublicKeyP exchange_pub;
struct TALER_ExchangeSignatureP exchange_sig; struct TALER_ExchangeSignatureP exchange_sig;
struct TALER_CoinSpendSignatureP coin_sig; struct TALER_CoinSpendSignatureP coin_sig;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_amount_any_nbo ("amount", TALER_JSON_spec_amount_any_nbo ("amount",
&pc.recoup_amount), &pc.recoup_amount),
TALER_JSON_spec_amount_any ("amount",
&recoup_amount),
GNUNET_JSON_spec_fixed_auto ("exchange_sig", GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&exchange_sig), &exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub", GNUNET_JSON_spec_fixed_auto ("exchange_pub",
@ -778,9 +776,9 @@ TALER_EXCHANGE_verify_coin_history (
GNUNET_JSON_spec_fixed_auto ("old_coin_pub", GNUNET_JSON_spec_fixed_auto ("old_coin_pub",
&pc.old_coin_pub), &pc.old_coin_pub),
GNUNET_JSON_spec_fixed_auto ("coin_blind", GNUNET_JSON_spec_fixed_auto ("coin_blind",
&rr.coin_blind), &coin_bks),
GNUNET_JSON_spec_fixed_auto ("h_denom_pub", GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
&rr.h_denom_pub), h_denom_pub),
GNUNET_JSON_spec_timestamp_nbo ("timestamp", GNUNET_JSON_spec_timestamp_nbo ("timestamp",
&pc.timestamp), &pc.timestamp),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
@ -807,15 +805,15 @@ TALER_EXCHANGE_verify_coin_history (
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP, TALER_wallet_recoup_verify (h_denom_pub,
&rr, &coin_bks,
&coin_sig.eddsa_signature, &recoup_amount,
&coin_pub->eddsa_pub)) coin_pub,
&coin_sig))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
*h_denom_pub = rr.h_denom_pub;
add = GNUNET_YES; add = GNUNET_YES;
} }
else if (0 == strcasecmp (type, else if (0 == strcasecmp (type,

View File

@ -95,7 +95,7 @@ struct TALER_EXCHANGE_RecoupHandle
* @return #GNUNET_OK if the signature is valid and we called the callback; * @return #GNUNET_OK if the signature is valid and we called the callback;
* #GNUNET_SYSERR if not (callback must still be called) * #GNUNET_SYSERR if not (callback must still be called)
*/ */
static int static enum GNUNET_GenericReturnValue
process_recoup_response (const struct TALER_EXCHANGE_RecoupHandle *ph, process_recoup_response (const struct TALER_EXCHANGE_RecoupHandle *ph,
const json_t *json) const json_t *json)
{ {
@ -312,8 +312,8 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
{ {
struct TALER_EXCHANGE_RecoupHandle *ph; struct TALER_EXCHANGE_RecoupHandle *ph;
struct GNUNET_CURL_Context *ctx; struct GNUNET_CURL_Context *ctx;
struct TALER_RecoupRequestPS pr;
struct TALER_CoinSpendSignatureP coin_sig; struct TALER_CoinSpendSignatureP coin_sig;
struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_DenominationHash h_denom_pub; struct TALER_DenominationHash h_denom_pub;
json_t *recoup_obj; json_t *recoup_obj;
CURL *eh; CURL *eh;
@ -321,17 +321,15 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
GNUNET_assert (GNUNET_YES == GNUNET_assert (GNUNET_YES ==
TEAH_handle_is_ready (exchange)); TEAH_handle_is_ready (exchange));
pr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP);
pr.purpose.size = htonl (sizeof (struct TALER_RecoupRequestPS));
GNUNET_CRYPTO_eddsa_key_get_public (&ps->coin_priv.eddsa_priv, GNUNET_CRYPTO_eddsa_key_get_public (&ps->coin_priv.eddsa_priv,
&pr.coin_pub.eddsa_pub); &coin_pub.eddsa_pub);
TALER_denom_pub_hash (&pk->key, TALER_denom_pub_hash (&pk->key,
&h_denom_pub); &h_denom_pub);
pr.h_denom_pub = pk->h_key; TALER_wallet_recoup_sign (&h_denom_pub,
pr.coin_blind = ps->blinding_key; &ps->blinding_key,
GNUNET_CRYPTO_eddsa_sign (&ps->coin_priv.eddsa_priv, amount,
&pr, &ps->coin_priv,
&coin_sig.eddsa_signature); &coin_sig);
recoup_obj = GNUNET_JSON_PACK ( recoup_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("denom_pub_hash", GNUNET_JSON_pack_data_auto ("denom_pub_hash",
&h_denom_pub), &h_denom_pub),
@ -349,9 +347,9 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2]; char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2];
char *end; char *end;
end = GNUNET_STRINGS_data_to_string (&pr.coin_pub, end = GNUNET_STRINGS_data_to_string (
sizeof (struct &coin_pub,
TALER_CoinSpendPublicKeyP), sizeof (struct TALER_CoinSpendPublicKeyP),
pub_str, pub_str,
sizeof (pub_str)); sizeof (pub_str));
*end = '\0'; *end = '\0';
@ -362,7 +360,7 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
} }
ph = GNUNET_new (struct TALER_EXCHANGE_RecoupHandle); ph = GNUNET_new (struct TALER_EXCHANGE_RecoupHandle);
ph->coin_pub = pr.coin_pub; ph->coin_pub = coin_pub;
ph->exchange = exchange; ph->exchange = exchange;
ph->pk = *pk; ph->pk = *pk;
memset (&ph->pk.key, memset (&ph->pk.key,

View File

@ -855,7 +855,7 @@ run (void *cls,
MHD_HTTP_OK, MHD_HTTP_OK,
"recoup-withdraw-coin-2a", "recoup-withdraw-coin-2a",
NULL, NULL,
NULL), "EUR:0.5"),
TALER_TESTING_cmd_deposit ("recoup-deposit-revoked", TALER_TESTING_cmd_deposit ("recoup-deposit-revoked",
"recoup-withdraw-coin-2b", "recoup-withdraw-coin-2b",
0, 0,

View File

@ -139,7 +139,7 @@ run (void *cls,
MHD_HTTP_GONE, MHD_HTTP_GONE,
"refresh-reveal-1#0", "refresh-reveal-1#0",
"refresh-melt-1", "refresh-melt-1",
NULL), "EUR:0.1"),
/* Make refreshed coin invalid */ /* Make refreshed coin invalid */
TALER_TESTING_cmd_revoke ("revoke-2-EUR:5", TALER_TESTING_cmd_revoke ("revoke-2-EUR:5",
MHD_HTTP_OK, MHD_HTTP_OK,
@ -155,44 +155,44 @@ run (void *cls,
MHD_HTTP_CONFLICT, MHD_HTTP_CONFLICT,
"withdraw-revocation-coin-2", "withdraw-revocation-coin-2",
NULL, NULL,
NULL), "EUR:0.1"),
/* Refund coin to original coin */ /* Refund coin to original coin */
TALER_TESTING_cmd_recoup ("recoup-1a", TALER_TESTING_cmd_recoup ("recoup-1a",
MHD_HTTP_OK, MHD_HTTP_OK,
"refresh-reveal-1#0", "refresh-reveal-1#0",
"refresh-melt-1", "refresh-melt-1",
NULL), "EUR:1"),
TALER_TESTING_cmd_recoup ("recoup-1b", TALER_TESTING_cmd_recoup ("recoup-1b",
MHD_HTTP_OK, MHD_HTTP_OK,
"refresh-reveal-1#1", "refresh-reveal-1#1",
"refresh-melt-1", "refresh-melt-1",
NULL), "EUR:1"),
TALER_TESTING_cmd_recoup ("recoup-1c", TALER_TESTING_cmd_recoup ("recoup-1c",
MHD_HTTP_OK, MHD_HTTP_OK,
"refresh-reveal-1#2", "refresh-reveal-1#2",
"refresh-melt-1", "refresh-melt-1",
NULL), "EUR:1"),
/* Repeat recoup to test idempotency */ /* Repeat recoup to test idempotency */
TALER_TESTING_cmd_recoup ("recoup-1c", TALER_TESTING_cmd_recoup ("recoup-1c",
MHD_HTTP_OK, MHD_HTTP_OK,
"refresh-reveal-1#2", "refresh-reveal-1#2",
"refresh-melt-1", "refresh-melt-1",
NULL), "EUR:1"),
TALER_TESTING_cmd_recoup ("recoup-1c", TALER_TESTING_cmd_recoup ("recoup-1c",
MHD_HTTP_OK, MHD_HTTP_OK,
"refresh-reveal-1#2", "refresh-reveal-1#2",
"refresh-melt-1", "refresh-melt-1",
NULL), "EUR:1"),
TALER_TESTING_cmd_recoup ("recoup-1c", TALER_TESTING_cmd_recoup ("recoup-1c",
MHD_HTTP_OK, MHD_HTTP_OK,
"refresh-reveal-1#2", "refresh-reveal-1#2",
"refresh-melt-1", "refresh-melt-1",
NULL), "EUR:1"),
TALER_TESTING_cmd_recoup ("recoup-1c", TALER_TESTING_cmd_recoup ("recoup-1c",
MHD_HTTP_OK, MHD_HTTP_OK,
"refresh-reveal-1#2", "refresh-reveal-1#2",
"refresh-melt-1", "refresh-melt-1",
NULL), "EUR:1"),
/* Now we have EUR:3.83 EUR back after 3x EUR:1 in recoups */ /* Now we have EUR:3.83 EUR back after 3x EUR:1 in recoups */
/* Melt original coin AGAIN, but only create one 0.1 EUR coin; /* Melt original coin AGAIN, but only create one 0.1 EUR coin;
This costs EUR:0.03 in refresh and EUR:01 in withdraw fees, This costs EUR:0.03 in refresh and EUR:01 in withdraw fees,
@ -223,7 +223,7 @@ run (void *cls,
MHD_HTTP_OK, MHD_HTTP_OK,
"refresh-reveal-2", "refresh-reveal-2",
"refresh-melt-2", "refresh-melt-2",
NULL), "EUR:0.1"),
/* Due to recoup, original coin is now at EUR:3.79 */ /* Due to recoup, original coin is now at EUR:3.79 */
/* Refund original (now zombie) coin to reserve */ /* Refund original (now zombie) coin to reserve */
TALER_TESTING_cmd_recoup ("recoup-3", TALER_TESTING_cmd_recoup ("recoup-3",

View File

@ -155,4 +155,51 @@ TALER_wallet_link_verify (
} }
enum GNUNET_GenericReturnValue
TALER_wallet_recoup_verify (
const struct TALER_DenominationHash *h_denom_pub,
const union TALER_DenominationBlindingKeyP *coin_bks,
const struct TALER_Amount *requested_amount,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_CoinSpendSignatureP *coin_sig)
{
struct TALER_RecoupRequestPS pr = {
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP),
.purpose.size = htonl (sizeof (pr)),
.h_denom_pub = *h_denom_pub,
.coin_blind = *coin_bks
};
TALER_amount_hton (&pr.recoup_amount,
requested_amount);
return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP,
&pr,
&coin_sig->eddsa_signature,
&coin_pub->eddsa_pub);
}
void
TALER_wallet_recoup_sign (
const struct TALER_DenominationHash *h_denom_pub,
const union TALER_DenominationBlindingKeyP *coin_bks,
const struct TALER_Amount *requested_amount,
const struct TALER_CoinSpendPrivateKeyP *coin_priv,
struct TALER_CoinSpendSignatureP *coin_sig)
{
struct TALER_RecoupRequestPS pr = {
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP),
.purpose.size = htonl (sizeof (struct TALER_RecoupRequestPS)),
.h_denom_pub = *h_denom_pub,
.coin_blind = *coin_bks
};
TALER_amount_hton (&pr.recoup_amount,
requested_amount);
GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv,
&pr,
&coin_sig->eddsa_signature);
}
/* end of wallet_signatures.c */ /* end of wallet_signatures.c */