make API actually workable, sketch out melt

This commit is contained in:
Christian Grothoff 2022-02-04 23:58:41 +01:00
parent cfc6c3fcd0
commit b30765c7d0
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
4 changed files with 221 additions and 50 deletions

View File

@ -1063,9 +1063,10 @@ struct TALER_EXCHANGE_CsRResponse
struct struct
{ {
/** /**
* Signature over the coin. * Values contributed by the exchange for the
* respective coin's withdraw operation.
*/ */
struct TALER_DenominationCsPublicR r_pubs; const struct TALER_ExchangeWithdrawValues *alg_values;
} success; } success;
/** /**
@ -1092,12 +1093,29 @@ typedef void
const struct TALER_EXCHANGE_CsRResponse *csrr); const struct TALER_EXCHANGE_CsRResponse *csrr);
/**
* Information we pass per coin to a /csr request.
*/
struct TALER_EXCHANGE_NonceKey
{
/**
* Which denomination key is the /csr request for?
*/
const struct TALER_EXCHANGE_DenomPublicKey *pk;
/**
* What is the client nonce for the request?
*/
struct TALER_CsNonce nonce;
};
/** /**
* Get a CS R using a /csr request. * Get a CS R using a /csr request.
* *
* @param exchange the exchange handle; the exchange must be ready to operate * @param exchange the exchange handle; the exchange must be ready to operate
* @param pk denomination of coin the R's will be used for * @param nks_len length of the @a nks array
* @param nonce public nonce for CS R request * @param nks array of denominations and nonces
* @param res_cb the callback to call when the final result for this request is available * @param res_cb the callback to call when the final result for this request is available
* @param res_cb_cls closure for the above callback * @param res_cb_cls closure for the above callback
* @return handle for the operation on success, NULL on error, i.e. * @return handle for the operation on success, NULL on error, i.e.
@ -1106,8 +1124,8 @@ typedef void
*/ */
struct TALER_EXCHANGE_CsRHandle * struct TALER_EXCHANGE_CsRHandle *
TALER_EXCHANGE_csr (struct TALER_EXCHANGE_Handle *exchange, TALER_EXCHANGE_csr (struct TALER_EXCHANGE_Handle *exchange,
const struct TALER_EXCHANGE_DenomPublicKey *pk, unsigned int nks_len,
const struct TALER_CsNonce *nonce, struct TALER_EXCHANGE_NonceKey *nks,
TALER_EXCHANGE_CsRCallback res_cb, TALER_EXCHANGE_CsRCallback res_cb,
void *res_cb_cls); void *res_cb_cls);

View File

@ -73,7 +73,23 @@ struct TALER_EXCHANGE_MeltHandle
/** /**
* Actual information about the melt operation. * Actual information about the melt operation.
*/ */
struct MeltData *md; struct MeltData md;
/**
* The secret the entire melt operation is seeded from.
*/
const struct TALER_PlanchetSecretsP *ps;
/**
* Details about the characteristics of the requested melt operation.
*/
const struct TALER_EXCHANGE_RefreshData *rd;
/**
* Array of `num_fresh_coins` contributory values of
* the exchange to the melt operation.
*/
struct TALER_ExchangeWithdrawValues *alg_values;
/** /**
* Public key of the coin being melted. * Public key of the coin being melted.
@ -106,9 +122,12 @@ verify_melt_signature_ok (struct TALER_EXCHANGE_MeltHandle *mh,
struct TALER_ExchangeSignatureP exchange_sig; struct TALER_ExchangeSignatureP exchange_sig;
const struct TALER_EXCHANGE_Keys *key_state; const struct TALER_EXCHANGE_Keys *key_state;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig), GNUNET_JSON_spec_fixed_auto ("exchange_sig",
GNUNET_JSON_spec_fixed_auto ("exchange_pub", exchange_pub), &exchange_sig),
GNUNET_JSON_spec_uint32 ("noreveal_index", noreveal_index), GNUNET_JSON_spec_fixed_auto ("exchange_pub",
exchange_pub),
GNUNET_JSON_spec_uint32 ("noreveal_index",
noreveal_index),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
struct TALER_RefreshMeltConfirmationPS confirm; struct TALER_RefreshMeltConfirmationPS confirm;
@ -338,6 +357,12 @@ handle_melt_finished (void *cls,
{ {
mh->melt_cb (mh->melt_cb_cls, mh->melt_cb (mh->melt_cb_cls,
&hr, &hr,
(0 == hr.http_status)
? 0
: mh->rd->fresh_pks_len,
(0 == hr.http_status)
? NULL
: mh->alg_values,
noreveal_index, noreveal_index,
(0 == hr.http_status) (0 == hr.http_status)
? NULL ? NULL
@ -419,42 +444,37 @@ handle_melt_finished (void *cls,
if (NULL != mh->melt_cb) if (NULL != mh->melt_cb)
mh->melt_cb (mh->melt_cb_cls, mh->melt_cb (mh->melt_cb_cls,
&hr, &hr,
0,
NULL,
UINT32_MAX, UINT32_MAX,
NULL); NULL);
TALER_EXCHANGE_melt_cancel (mh); TALER_EXCHANGE_melt_cancel (mh);
} }
struct TALER_EXCHANGE_MeltHandle * static enum GNUNET_GenericReturnValue
TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange, start_melt (struct TALER_EXCHANGE_MeltHandle *mh)
const struct TALER_PlanchetSecretsP *ps,
const struct TALER_EXCHANGE_RefreshData *rd,
TALER_EXCHANGE_MeltCallback melt_cb,
void *melt_cb_cls)
{ {
const struct TALER_EXCHANGE_Keys *key_state; const struct TALER_EXCHANGE_Keys *key_state;
const struct TALER_EXCHANGE_DenomPublicKey *dki; const struct TALER_EXCHANGE_DenomPublicKey *dki;
json_t *melt_obj; json_t *melt_obj;
struct TALER_EXCHANGE_MeltHandle *mh;
CURL *eh; CURL *eh;
struct GNUNET_CURL_Context *ctx; struct GNUNET_CURL_Context *ctx;
struct MeltData *md;
struct TALER_CoinSpendSignatureP confirm_sig; struct TALER_CoinSpendSignatureP confirm_sig;
char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32]; char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32];
struct TALER_DenominationHash h_denom_pub; struct TALER_DenominationHash h_denom_pub;
struct TALER_CoinSpendPublicKeyP coin_pub; struct TALER_CoinSpendPublicKeyP coin_pub;
GNUNET_assert (GNUNET_YES ==
TEAH_handle_is_ready (exchange));
if (GNUNET_OK != if (GNUNET_OK !=
TALER_EXCHANGE_get_melt_data (ps, TALER_EXCHANGE_get_melt_data_ (mh->ps,
rd, mh->rd,
&md)) mh->alg_values,
&mh->md))
{ {
GNUNET_break (0); GNUNET_break (0);
return NULL; return GNUNET_SYSERR;
} }
TALER_denom_pub_hash (&md->melted_coin.pub_key, TALER_denom_pub_hash (&mh->md.melted_coin.pub_key,
&h_denom_pub); &h_denom_pub);
TALER_wallet_melt_sign (&md->melted_coin.melt_amount_with_fee, TALER_wallet_melt_sign (&md->melted_coin.melt_amount_with_fee,
&md->melted_coin.fee_melt, &md->melted_coin.fee_melt,
@ -491,30 +511,19 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
pub_str); pub_str);
} }
key_state = TALER_EXCHANGE_get_keys (exchange); ctx = TEAH_handle_to_context (mh->exchange);
key_state = TALER_EXCHANGE_get_keys (mh->exchange);
dki = TALER_EXCHANGE_get_denomination_key (key_state, dki = TALER_EXCHANGE_get_denomination_key (key_state,
&md->melted_coin.pub_key); &mh->md.melted_coin.pub_key);
/* and now we can at last begin the actual request handling */ /* and now we can at last begin the actual request handling */
mh = GNUNET_new (struct TALER_EXCHANGE_MeltHandle);
mh->exchange = exchange; mh->url = TEAH_path_to_url (mh->exchange,
mh->coin_pub = coin_pub;
mh->dki = *dki;
memset (&mh->dki.key,
0,
sizeof (mh->dki.key)); /* lifetime not warranted, so better
not copy the pointers */
mh->melt_cb = melt_cb;
mh->melt_cb_cls = melt_cb_cls;
mh->md = md;
mh->url = TEAH_path_to_url (exchange,
arg_str); arg_str);
if (NULL == mh->url) if (NULL == mh->url)
{ {
json_decref (melt_obj); json_decref (melt_obj);
TALER_EXCHANGE_free_melt_data_ (&md); return GNUNET_SYSERR;
GNUNET_free (mh);
return NULL;
} }
eh = TALER_EXCHANGE_curl_easy_get_ (mh->url); eh = TALER_EXCHANGE_curl_easy_get_ (mh->url);
if ( (NULL == eh) || if ( (NULL == eh) ||
@ -526,19 +535,155 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
GNUNET_break (0); GNUNET_break (0);
if (NULL != eh) if (NULL != eh)
curl_easy_cleanup (eh); curl_easy_cleanup (eh);
TALER_EXCHANGE_free_melt_data_ (&md);
json_decref (melt_obj); json_decref (melt_obj);
GNUNET_free (mh->url); return GNUNET_SYSERR;
GNUNET_free (mh);
return NULL;
} }
json_decref (melt_obj); json_decref (melt_obj);
ctx = TEAH_handle_to_context (exchange);
mh->job = GNUNET_CURL_job_add2 (ctx, mh->job = GNUNET_CURL_job_add2 (ctx,
eh, eh,
mh->ctx.headers, mh->ctx.headers,
&handle_melt_finished, &handle_melt_finished,
mh); mh);
return GNUNET_OK;
}
static void
fail_mh (struct TALER_EXCHANGE_MeltHandle *mh)
{
// FIXME: do return more than NULLs if
// the /csr failed!
mh->melt_cb (mh->melt_cb_cls,
NULL,
0,
NULL,
UINT32_MAX,
NULL);
TALER_EXCHANGE_melt_cancel (mh);
}
/**
* Callbacks of this type are used to serve the result of submitting a
* CS R request to a exchange.
*
* @param cls closure with our `struct TALER_EXCHANGE_MeltHandle *`
* @param csrr response details
*/
static void
csr_cb (void *cls,
const struct TALER_EXCHANGE_CsRResponse *csrr)
{
struct TALER_EXCHANGE_MeltHandle *mh = cls;
unsigned int nks_off = 0;
for (unsigned int i = 0; i<rd->fresh_pks_len; i++)
{
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk = &rd->fresh_pks[i];
struct TALER_ExchangeWithdrawValues *wv = &mh->alg_values[i];
switch (fresh_pk->cipher)
{
case TALER_DENOMINATION_INVALID:
GNUNET_break (0);
fail_mh (mh).
return;
case TALER_DENOMINATION_RSA:
GNUNET_assert (TALER_DENOMINATION_RSA == wv->cipher);
break;
case TALER_DENOMINATION_CS:
GNUNET_assert (TALER_DENOMINATION_CS == wv->cipher);
*wv = csrr->details.success.alg_values[nks_off];
nks_off++;
break;
}
}
if (GNUNET_OK !=
start_melt (mh))
{
GNUNET_break (0);
fail_mh (mh);
return;
}
}
struct TALER_EXCHANGE_MeltHandle *
TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
const struct TALER_PlanchetSecretsP *ps,
const struct TALER_EXCHANGE_RefreshData *rd,
TALER_EXCHANGE_MeltCallback melt_cb,
void *melt_cb_cls)
s
{
const struct TALER_EXCHANGE_NonceKey *nks[GNUNET_NZL (rd->refresh_pks_len)];
unsigned int nks_off = 0;
if (0 == rd->refresh_pks_len)
{
GNUNET_break (0);
return NULL;
}
GNUNET_assert (GNUNET_YES ==
TEAH_handle_is_ready (exchange));
mh = GNUNET_new (struct TALER_EXCHANGE_MeltHandle);
mh->exchange = exchange;
mh->rd = rd;
mh->ps = ps;
mh->melt_cb = melt_cb;
mh->melt_cb_cls = melt_cb_cls;
mh->alg_values = GNUNET_new_array (struct TALER_ExchangeWithdrawValues,
rd->fresh_pks_len);
for (unsigned int i = 0; i<rd->fresh_pks_len; i++)
{
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk = &rd->fresh_pks[i];
struct TALER_ExchangeWithdrawValues *wv = &mh->alg_values[i];
switch (fresh_pk->cipher)
{
case TALER_DENOMINATION_INVALID:
GNUNET_break (0);
GNUNET_free (mh->alg_values);
GNUNET_free (mh);
return NULL;
case TALER_DENOMINATION_RSA:
wv->cipher = TALER_DENOMINATION_RSA;
break;
case TALER_DENOMINATION_CS:
wv->cipher = TALER_DENOMINATION_CS;
nks[nks_off].pk = fresh_pk;
// derive nonce for refresh by index and ps;
// FIXME: include fresh_pk or not?
TALER_CRYPTO_XXX (ps,
fresh_pk,
i,
&nks[nks_off].nonce);
nks_off++;
break;
}
}
if (0 != nks_off)
{
mh->csr = TALER_EXCHANGE_csr (exchange,
nks_off,
nks,
&csr_cb,
mh);
if (NULL == mh->csr)
{
GNUNET_break (0);
TALER_EXCHANGE_melt_cancel (mh->csr);
return NULL;
}
return mh;
}
if (GNUNET_OK !=
start_melt (mh))
{
GNUNET_break (0);
TALER_EXCHANGE_melt_cancel (mh->csr);
return NULL;
}
return mh; return mh;
} }
@ -551,8 +696,7 @@ TALER_EXCHANGE_melt_cancel (struct TALER_EXCHANGE_MeltHandle *mh)
GNUNET_CURL_job_cancel (mh->job); GNUNET_CURL_job_cancel (mh->job);
mh->job = NULL; mh->job = NULL;
} }
TALER_EXCHANGE_free_melt_data_ (mh->md); /* does not free 'md' itself */ TALER_EXCHANGE_free_melt_data_ (&mh->md); /* does not free 'md' itself */
GNUNET_free (mh->md);
GNUNET_free (mh->url); GNUNET_free (mh->url);
TALER_curl_easy_post_finished (&mh->ctx); TALER_curl_easy_post_finished (&mh->ctx);
GNUNET_free (mh); GNUNET_free (mh);

View File

@ -46,6 +46,7 @@ enum GNUNET_GenericReturnValue
TALER_EXCHANGE_get_melt_data_ ( TALER_EXCHANGE_get_melt_data_ (
const struct TALER_PlanchetSecretsP *ps, const struct TALER_PlanchetSecretsP *ps,
const struct struct TALER_EXCHANGE_RefreshData *rd, const struct struct TALER_EXCHANGE_RefreshData *rd,
const struct TALER_ExchangeWithdrawValues *alg_values,
struct MeltData *md) struct MeltData *md)
{ {
struct MeltData md; struct MeltData md;

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2015-2020 Taler Systems SA Copyright (C) 2015-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software
@ -102,6 +102,12 @@ struct MeltData
*/ */
struct TALER_DenominationPublicKey *fresh_pks; struct TALER_DenominationPublicKey *fresh_pks;
/**
* Array of @e num_fresh_coins with exchange contributions
* made during the refresh.
*/
struct TALER_ExchangeWithdrawValues *exchange_vals;
/** /**
* Arrays of @e num_fresh_coins with information about the fresh * Arrays of @e num_fresh_coins with information about the fresh
* coins to be created, for each cut-and-choose dimension. * coins to be created, for each cut-and-choose dimension.
@ -115,12 +121,14 @@ struct MeltData
* *
* @param ps secret internals of the refresh-reveal operation * @param ps secret internals of the refresh-reveal operation
* @param rd refresh data with the characteristics of the operation * @param rd refresh data with the characteristics of the operation
* @param alg_values contributions from the exchange into the melt
* @param[out] rd where to write the derived melt data * @param[out] rd where to write the derived melt data
*/ */
enum GNUNET_GenericReturnValue enum GNUNET_GenericReturnValue
TALER_EXCHANGE_get_melt_data_ ( TALER_EXCHANGE_get_melt_data_ (
const struct TALER_PlanchetSecretsP *ps, const struct TALER_PlanchetSecretsP *ps,
const struct struct TALER_EXCHANGE_RefreshData *rd, const struct struct TALER_EXCHANGE_RefreshData *rd,
const struct TALER_ExchangeWithdrawValues *alg_values,
struct MeltData *md); struct MeltData *md);