aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-03-10 16:15:14 +0100
committerChristian Grothoff <christian@grothoff.org>2015-03-10 16:15:14 +0100
commitc2c8646a83c07662e1246f768c23e71c687ddcb0 (patch)
tree3ea5a96e43fda20b9ecb10485bbc05b0749eff33
parent07f18f16601cc4757c0c2658ad501497b07cebee (diff)
downloadexchange-c2c8646a83c07662e1246f768c23e71c687ddcb0.tar.gz
exchange-c2c8646a83c07662e1246f768c23e71c687ddcb0.zip
combining /mint/melt and /mint/commit
-rw-r--r--src/include/taler_signatures.h65
-rw-r--r--src/mint/mint_db.c27
-rw-r--r--src/mint/mint_db.h27
-rw-r--r--src/mint/taler-mint-httpd.c6
-rw-r--r--src/mint/taler-mint-httpd_db.c209
-rw-r--r--src/mint/taler-mint-httpd_db.h49
-rw-r--r--src/mint/taler-mint-httpd_refresh.c381
-rw-r--r--src/mint/taler-mint-httpd_refresh.h24
-rw-r--r--src/mint/taler-mint-httpd_responses.c122
-rw-r--r--src/mint/taler-mint-httpd_responses.h45
10 files changed, 354 insertions, 601 deletions
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index bf39c0aba..9e3068a78 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -56,30 +56,25 @@
56#define TALER_SIGNATURE_WITHDRAW 4 56#define TALER_SIGNATURE_WITHDRAW 4
57 57
58/** 58/**
59 * Signature where the refresh session confirms 59 * Signature using a coin key confirming the melting of
60 * the list of melted coins and requested denominations. 60 * a coin.
61 */ 61 */
62#define TALER_SIGNATURE_REFRESH_MELT 5 62#define TALER_SIGNATURE_REFRESH_MELT_COIN 5
63 63
64/** 64/**
65 * Signature where the refresh session confirms 65 * Signature where the refresh session confirms
66 * the commits. 66 * the commits.
67 */ 67 */
68#define TALER_SIGNATURE_REFRESH_COMMIT 6 68#define TALER_SIGNATURE_REFRESH_MELT 6
69 69
70/** 70/**
71 * Signature where the mint (current signing key) 71 * Signature where the mint (current signing key)
72 * confirms the list of blind session keys. 72 * confirms the no-reveal index for cut-and-choose and
73 * the validity of the melted coins.
73 */ 74 */
74#define TALER_SIGNATURE_REFRESH_MELT_RESPONSE 7 75#define TALER_SIGNATURE_REFRESH_MELT_RESPONSE 7
75 76
76/** 77/**
77 * Signature where the mint (current signing key)
78 * confirms the no-reveal index for cut-and-choose.
79 */
80#define TALER_SIGNATURE_REFRESH_COMMIT_RESPONSE 8
81
82/**
83 * Signature where coins confirm that they want 78 * Signature where coins confirm that they want
84 * to be melted into a certain session. 79 * to be melted into a certain session.
85 */ 80 */
@@ -234,18 +229,22 @@ struct TALER_DepositConfirmation
234 229
235 230
236/** 231/**
237 * Format of the block signed by the Mint in response to 232 * Message signed by a coin to indicate that the coin should
238 * a successful "/refresh/melt" request. Hereby the mint 233 * be melted.
239 * affirms that all of the coins were successfully melted.
240 */ 234 */
241struct RefreshMeltResponseSignatureBody 235struct RefreshMeltSignatureBody
242{ 236{
243 /** 237 /**
244 * Purpose is #TALER_SIGNATURE_REFRESH_MELT_RESPONSE. 238 * Purpose is #TALER_SIGNATURE_REFRESH_MELT_COIN.
245 */ 239 */
246 struct GNUNET_CRYPTO_EccSignaturePurpose purpose; 240 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
247 241
248 /** 242 /**
243 * Which melting operation should the coin become a part of.
244 */
245 struct GNUNET_HashCode melt_hash;
246
247 /**
249 * Signature of the client over the melt request (thereby 248 * Signature of the client over the melt request (thereby
250 * indirectly including all of the information the client 249 * indirectly including all of the information the client
251 * sent). 250 * sent).
@@ -259,30 +258,6 @@ struct RefreshMeltResponseSignatureBody
259 struct GNUNET_CRYPTO_EddsaPublicKey session_key; 258 struct GNUNET_CRYPTO_EddsaPublicKey session_key;
260 259
261 /** 260 /**
262 * Security parameter requested for the commitments.
263 */
264 uint32_t kappa GNUNET_PACKED;
265
266};
267
268
269/**
270 * Message signed by a coin to indicate that the coin should
271 * be melted.
272 */
273struct RefreshMeltSignatureBody
274{
275 /**
276 * Purpose is #TALER_SIGNATURE_REFRESH_MELT.
277 */
278 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
279
280 /**
281 * Which melting operation should the coin become a part of.
282 */
283 struct GNUNET_HashCode melt_hash;
284
285 /**
286 * How much of the value of the coin should be melted? 261 * How much of the value of the coin should be melted?
287 * This amount includes the fees, so the final amount contributed 262 * This amount includes the fees, so the final amount contributed
288 * to the melt is this value minus the fee for melting the coin. 263 * to the melt is this value minus the fee for melting the coin.
@@ -298,7 +273,7 @@ struct RefreshMeltSignatureBody
298struct RefreshCommitSignatureBody 273struct RefreshCommitSignatureBody
299{ 274{
300 /** 275 /**
301 * Purpose is #TALER_SIGNATURE_REFRESH_COMMIT. 276 * Purpose is #TALER_SIGNATURE_REFRESH_MELT.
302 */ 277 */
303 struct GNUNET_CRYPTO_EccSignaturePurpose purpose; 278 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
304 279
@@ -310,10 +285,12 @@ struct RefreshCommitSignatureBody
310 285
311 286
312/** 287/**
313 * Message signed by the mint, committing it to a particular 288 * Format of the block signed by the Mint in response to a successful
314 * index to not be revealed during the refresh. 289 * "/refresh/melt" request. Hereby the mint affirms that all of the
290 * coins were successfully melted. This also commits the mint to a
291 * particular index to not be revealed during the refresh.
315 */ 292 */
316struct RefreshCommitResponseSignatureBody 293struct RefreshMeltResponseSignatureBody
317{ 294{
318 /** 295 /**
319 * Purpose is #TALER_SIGNATURE_REFRESH_MELT_RESPONSE. 296 * Purpose is #TALER_SIGNATURE_REFRESH_MELT_RESPONSE.
diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c
index 53d35b33d..848f9e045 100644
--- a/src/mint/mint_db.c
+++ b/src/mint/mint_db.c
@@ -1417,11 +1417,6 @@ TALER_MINT_DB_get_refresh_session (PGconn *db_conn,
1417 return GNUNET_SYSERR; 1417 return GNUNET_SYSERR;
1418 } 1418 }
1419 1419
1420 if (TALER_DB_field_isnull (result, 0, "session_commit_sig"))
1421 session->has_commit_sig = GNUNET_NO;
1422 else
1423 session->has_commit_sig = GNUNET_YES;
1424
1425 session->num_oldcoins = ntohs (session->num_oldcoins); 1420 session->num_oldcoins = ntohs (session->num_oldcoins);
1426 session->num_newcoins = ntohs (session->num_newcoins); 1421 session->num_newcoins = ntohs (session->num_newcoins);
1427 session->kappa = ntohs (session->kappa); 1422 session->kappa = ntohs (session->kappa);
@@ -1472,28 +1467,6 @@ TALER_MINT_DB_create_refresh_session (PGconn *db_conn,
1472 1467
1473 1468
1474/** 1469/**
1475 * Update new refresh session with the new state after the
1476 * /refresh/commit operation.
1477 *
1478 * @param db_conn database handle to use
1479 * @param refresh_session_pub public key to use to locate the session
1480 * @param noreveal_index index chosen for the client to not reveal
1481 * @param commit_client_sig signature of the client over its commitment
1482 * @return #GNUNET_YES on success,
1483 * #GNUNET_SYSERR on DB failure
1484 */
1485int
1486TALER_MINT_DB_update_refresh_session (PGconn *db_conn,
1487 const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
1488 uint16_t noreveal_index,
1489 const struct GNUNET_CRYPTO_EddsaSignature *commit_client_sig)
1490{
1491 // FIXME: implement!
1492 return GNUNET_SYSERR;
1493}
1494
1495
1496/**
1497 * Store the given /refresh/melt request in the database. 1470 * Store the given /refresh/melt request in the database.
1498 * 1471 *
1499 * @param db_conn database connection 1472 * @param db_conn database connection
diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h
index 403e1f394..9818172af 100644
--- a/src/mint/mint_db.h
+++ b/src/mint/mint_db.h
@@ -474,17 +474,10 @@ struct RefreshSession
474 474
475 /** 475 /**
476 * Index (smaller @e kappa) which the mint has chosen to not 476 * Index (smaller @e kappa) which the mint has chosen to not
477 * have revealed during cut and choose. Only valid if 477 * have revealed during cut and choose.
478 * @e has_commit_sig is set to #GNUNET_YES.
479 */ 478 */
480 uint16_t noreveal_index; 479 uint16_t noreveal_index;
481 480
482 /**
483 * #GNUNET_YES if we have accepted the /refresh/commit and
484 * thus the @e commit_sig is valid.
485 */
486 int has_commit_sig;
487
488}; 481};
489 482
490 483
@@ -520,24 +513,6 @@ TALER_MINT_DB_create_refresh_session (PGconn *db_conn,
520 513
521 514
522/** 515/**
523 * Update new refresh session with the new state after the
524 * /refresh/commit operation.
525 *
526 * @param db_conn database handle to use
527 * @param refresh_session_pub public key to use to locate the session
528 * @param noreveal_index index chosen for the client to not reveal
529 * @param commit_client_sig signature of the client over its commitment
530 * @return #GNUNET_YES on success,
531 * #GNUNET_SYSERR on DB failure
532 */
533int
534TALER_MINT_DB_update_refresh_session (PGconn *db_conn,
535 const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
536 uint16_t noreveal_index,
537 const struct GNUNET_CRYPTO_EddsaSignature *commit_client_sig);
538
539
540/**
541 * Specification for coin in a /refresh/melt operation. 516 * Specification for coin in a /refresh/melt operation.
542 */ 517 */
543struct RefreshMelt 518struct RefreshMelt
diff --git a/src/mint/taler-mint-httpd.c b/src/mint/taler-mint-httpd.c
index 281f58f1b..3b1512ff1 100644
--- a/src/mint/taler-mint-httpd.c
+++ b/src/mint/taler-mint-httpd.c
@@ -152,12 +152,6 @@ handle_mhd_request (void *cls,
152 { "/refresh/melt", NULL, "text/plain", 152 { "/refresh/melt", NULL, "text/plain",
153 "Only POST is allowed", 0, 153 "Only POST is allowed", 0,
154 &TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, 154 &TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
155 { "/refresh/commit", MHD_HTTP_METHOD_POST, "application/json",
156 NULL, 0,
157 &TALER_MINT_handler_refresh_commit, MHD_HTTP_OK },
158 { "/refresh/commit", NULL, "text/plain",
159 "Only POST is allowed", 0,
160 &TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
161 { "/refresh/reveal", MHD_HTTP_METHOD_POST, "application/json", 155 { "/refresh/reveal", MHD_HTTP_METHOD_POST, "application/json",
162 NULL, 0, 156 NULL, 0,
163 &TALER_MINT_handler_refresh_melt, MHD_HTTP_OK }, 157 &TALER_MINT_handler_refresh_melt, MHD_HTTP_OK },
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c
index d9a172a40..4423433b8 100644
--- a/src/mint/taler-mint-httpd_db.c
+++ b/src/mint/taler-mint-httpd_db.c
@@ -151,7 +151,7 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
151 if (0 < TALER_amount_cmp (spent, value)) 151 if (0 < TALER_amount_cmp (spent, value))
152 { 152 {
153 TALER_MINT_DB_rollback (db_conn); 153 TALER_MINT_DB_rollback (db_conn);
154 ret = TALER_MINT_reply_insufficient_funds (connection, 154 ret = TALER_MINT_reply_deposit_insufficient_funds (connection,
155 tl); 155 tl);
156 TALER_MINT_DB_free_coin_transaction_list (tl); 156 TALER_MINT_DB_free_coin_transaction_list (tl);
157 return ret; 157 return ret;
@@ -435,8 +435,10 @@ refresh_accept_melts (struct MHD_Connection *connection,
435{ 435{
436 struct TALER_MINT_DenomKeyIssue *dki; 436 struct TALER_MINT_DenomKeyIssue *dki;
437 struct TALER_MINT_DB_TransactionList *tl; 437 struct TALER_MINT_DB_TransactionList *tl;
438 struct TALER_Amount coin_gain; 438 struct TALER_Amount coin_value;
439 struct TALER_Amount coin_residual;
439 struct RefreshMelt melt; 440 struct RefreshMelt melt;
441 int res;
440 442
441 dki = &TALER_MINT_get_denom_key (key_state, 443 dki = &TALER_MINT_get_denom_key (key_state,
442 coin_public_info->denom_pub)->issue; 444 coin_public_info->denom_pub)->issue;
@@ -450,25 +452,30 @@ refresh_accept_melts (struct MHD_Connection *connection,
450 "denom not found")) 452 "denom not found"))
451 ? GNUNET_NO : GNUNET_SYSERR; 453 ? GNUNET_NO : GNUNET_SYSERR;
452 454
453 coin_gain = TALER_amount_ntoh (dki->value); 455 coin_value = TALER_amount_ntoh (dki->value);
454 tl = TALER_MINT_DB_get_coin_transactions (db_conn, 456 tl = TALER_MINT_DB_get_coin_transactions (db_conn,
455 &coin_public_info->coin_pub); 457 &coin_public_info->coin_pub);
456 /* FIXME: #3636: compute how much value is left with this coin and 458 /* FIXME: #3636: compute how much value is left with this coin and
457 compare to `expected_value`! (subtract from "coin_gain") */ 459 compare to `expected_value`! (subtract from "coin_value") */
458 TALER_MINT_DB_free_coin_transaction_list (tl); 460 coin_residual = coin_value;
459
460 /* Refuse to refresh when the coin does not have enough money left to 461 /* Refuse to refresh when the coin does not have enough money left to
461 * pay the refreshing fees of the coin. */ 462 * pay the refreshing fees of the coin. */
462 463
463 if (TALER_amount_cmp (coin_gain, 464 if (TALER_amount_cmp (coin_residual,
464 coin_details->melt_amount) < 0) 465 coin_details->melt_amount) < 0)
465 return (MHD_YES == 466 {
466 TALER_MINT_reply_json_pack (connection, 467 res = (MHD_YES ==
467 MHD_HTTP_NOT_FOUND, 468 TALER_MINT_reply_refresh_melt_insufficient_funds (connection,
468 "{s:s}", 469 &coin_public_info->coin_pub,
469 "error", "depleted")) ? GNUNET_NO : GNUNET_SYSERR; 470 coin_value,
470 471 tl,
471 472 coin_details->melt_amount,
473 coin_residual))
474 ? GNUNET_NO : GNUNET_SYSERR;
475 TALER_MINT_DB_free_coin_transaction_list (tl);
476 return res;
477 }
478 TALER_MINT_DB_free_coin_transaction_list (tl);
472 479
473 melt.coin = *coin_public_info; 480 melt.coin = *coin_public_info;
474 melt.coin_sig = coin_details->melt_sig; 481 melt.coin_sig = coin_details->melt_sig;
@@ -494,6 +501,8 @@ refresh_accept_melts (struct MHD_Connection *connection,
494 * required value left and if so, store that they have been 501 * required value left and if so, store that they have been
495 * melted and confirm the melting operation to the client. 502 * melted and confirm the melting operation to the client.
496 * 503 *
504 * FIXME: some arguments are redundant here...
505 *
497 * @param connection the MHD connection to handle 506 * @param connection the MHD connection to handle
498 * @param melt_hash hash code of the session the coins are melted into 507 * @param melt_hash hash code of the session the coins are melted into
499 * @param refresh_session_pub public key of the refresh session 508 * @param refresh_session_pub public key of the refresh session
@@ -504,6 +513,15 @@ refresh_accept_melts (struct MHD_Connection *connection,
504 * @param coin_count number of entries in @a coin_public_infos and @a coin_melt_details 513 * @param coin_count number of entries in @a coin_public_infos and @a coin_melt_details
505 * @param coin_public_infos information about the coins to melt 514 * @param coin_public_infos information about the coins to melt
506 * @param coin_melt_details signatures and (residual) value of the respective coin should be melted 515 * @param coin_melt_details signatures and (residual) value of the respective coin should be melted
516 * @param commit_client_sig signature of the client over this commitment
517 * @param kappa size of x-dimension of @commit_coin and @commit_link arrays
518 * @param num_oldcoins size of y-dimension of @commit_link array
519 * @param num_newcoins size of y-dimension of @commit_coin array
520 * @param commit_coin 2d array of coin commitments (what the mint is to sign
521 * once the "/refres/reveal" of cut and choose is done)
522 * @param commit_link 2d array of coin link commitments (what the mint is
523 * to return via "/refresh/link" to enable linkage in the
524 * future)
507 * @return MHD result code 525 * @return MHD result code
508 */ 526 */
509int 527int
@@ -515,13 +533,20 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
515 struct GNUNET_CRYPTO_rsa_PublicKey *const*denom_pubs, 533 struct GNUNET_CRYPTO_rsa_PublicKey *const*denom_pubs,
516 unsigned int coin_count, 534 unsigned int coin_count,
517 const struct TALER_CoinPublicInfo *coin_public_infos, 535 const struct TALER_CoinPublicInfo *coin_public_infos,
518 const struct MeltDetails *coin_melt_details) 536 const struct MeltDetails *coin_melt_details,
537 const struct GNUNET_CRYPTO_EddsaSignature *commit_client_sig,
538 unsigned int kappa,
539 unsigned int num_oldcoins,
540 unsigned int num_newcoins,
541 struct RefreshCommitCoin *const* commit_coin,
542 struct RefreshCommitLink *const* commit_link)
519{ 543{
520 struct MintKeyState *key_state; 544 struct MintKeyState *key_state;
521 struct RefreshSession session; 545 struct RefreshSession session;
522 PGconn *db_conn; 546 PGconn *db_conn;
523 int res; 547 int res;
524 unsigned int i; 548 unsigned int i;
549 unsigned int j;
525 550
526 if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO))) 551 if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO)))
527 { 552 {
@@ -540,10 +565,10 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
540 if (GNUNET_YES == res) 565 if (GNUNET_YES == res)
541 { 566 {
542 TALER_MINT_DB_rollback (db_conn); 567 TALER_MINT_DB_rollback (db_conn);
543 return TALER_MINT_reply_refresh_melt_success (connection, 568 res = TALER_MINT_reply_refresh_melt_success (connection,
544 &session.melt_sig, 569 &session.session_hash,
545 refresh_session_pub, 570 session.noreveal_index);
546 session.kappa); 571 return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
547 } 572 }
548 if (GNUNET_SYSERR == res) 573 if (GNUNET_SYSERR == res)
549 { 574 {
@@ -586,116 +611,6 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
586 } 611 }
587 } 612 }
588 613
589 /* store 'global' session data */
590 session.melt_sig = *client_signature;
591 session.session_hash = *melt_hash;
592 session.num_oldcoins = coin_count;
593 session.num_newcoins = num_new_denoms;
594 session.kappa = KAPPA;
595 session.noreveal_index = UINT16_MAX;
596 session.has_commit_sig = GNUNET_NO;
597 if (GNUNET_OK !=
598 (res = TALER_MINT_DB_create_refresh_session (db_conn,
599 refresh_session_pub,
600 &session)))
601 {
602 TALER_MINT_DB_rollback (db_conn);
603 return TALER_MINT_reply_internal_db_error (connection);
604 }
605
606 if (GNUNET_OK !=
607 TALER_MINT_DB_commit (db_conn))
608 {
609 LOG_WARNING ("/refresh/melt transaction commit failed\n");
610 return TALER_MINT_reply_commit_error (connection);
611 }
612 return TALER_MINT_reply_refresh_melt_success (connection,
613 client_signature,
614 refresh_session_pub,
615 session.kappa);
616}
617
618
619/**
620 * Execute a "/refresh/commit". The client is committing to @a kappa
621 * sets of transfer keys, and linkage information for a refresh
622 * operation. Confirm that the commit matches the melts of an
623 * existing @a refresh_session_pub, store the refresh session commit
624 * data and then return the client a challenge specifying which of the
625 * @a kappa sets of private transfer keys should not be revealed.
626 *
627 * @param connection the MHD connection to handle
628 * @param refresh_session public key of the session
629 * @param commit_client_sig signature of the client over this commitment
630 * @param kappa size of x-dimension of @commit_coin and @commit_link arrays
631 * @param num_oldcoins size of y-dimension of @commit_link array
632 * @param num_newcoins size of y-dimension of @commit_coin array
633 * @param commit_coin 2d array of coin commitments (what the mint is to sign
634 * once the "/refres/reveal" of cut and choose is done)
635 * @param commit_link 2d array of coin link commitments (what the mint is
636 * to return via "/refresh/link" to enable linkage in the
637 * future)
638 * @return MHD result code
639 */
640int
641TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection,
642 const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
643 const struct GNUNET_CRYPTO_EddsaSignature *commit_client_sig,
644 unsigned int kappa,
645 unsigned int num_oldcoins,
646 unsigned int num_newcoins,
647 struct RefreshCommitCoin *const*commit_coin,
648 struct RefreshCommitLink *const*commit_link)
649
650{
651 PGconn *db_conn;
652 struct RefreshSession refresh_session;
653 unsigned int i;
654 unsigned int j;
655 int res;
656
657 if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO)))
658 {
659 GNUNET_break (0);
660 return TALER_MINT_reply_internal_db_error (connection);
661 }
662
663 if (GNUNET_OK !=
664 TALER_MINT_DB_transaction (db_conn))
665 {
666 GNUNET_break (0);
667 return TALER_MINT_reply_internal_db_error (connection);
668 }
669 res = TALER_MINT_DB_get_refresh_session (db_conn,
670 refresh_session_pub,
671 &refresh_session);
672 if (GNUNET_SYSERR == res)
673 {
674 TALER_MINT_DB_rollback (db_conn);
675 return TALER_MINT_reply_internal_db_error (connection);
676 }
677 if (GNUNET_NO == res)
678 {
679 TALER_MINT_DB_rollback (db_conn);
680 return TALER_MINT_reply_arg_invalid (connection,
681 "session_pub");
682 }
683 if ( (refresh_session.kappa != kappa) ||
684 (refresh_session.num_newcoins != num_newcoins) ||
685 (refresh_session.num_oldcoins != num_oldcoins) )
686 {
687 TALER_MINT_DB_rollback (db_conn);
688 return TALER_MINT_reply_arg_invalid (connection,
689 "dimensions");
690 }
691 if (GNUNET_YES == refresh_session.has_commit_sig)
692 {
693 TALER_MINT_DB_rollback (db_conn);
694 res = TALER_MINT_reply_refresh_commit_success (connection,
695 &refresh_session.session_hash,
696 refresh_session.noreveal_index);
697 return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
698 }
699 for (i = 0; i < kappa; i++) 614 for (i = 0; i < kappa; i++)
700 { 615 {
701 for (j = 0; j < num_newcoins; j++) 616 for (j = 0; j < num_newcoins; j++)
@@ -729,31 +644,36 @@ TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection,
729 } 644 }
730 } 645 }
731 646
732 refresh_session.noreveal_index
733 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
734 refresh_session.kappa);
735 647
648 /* store 'global' session data */
649 session.melt_sig = *client_signature;
650 session.session_hash = *melt_hash;
651 session.num_oldcoins = coin_count;
652 session.num_newcoins = num_new_denoms;
653 session.kappa = KAPPA; // FIXME...
654 session.noreveal_index
655 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
656 session.kappa);
736 if (GNUNET_OK != 657 if (GNUNET_OK !=
737 (res = TALER_MINT_DB_update_refresh_session (db_conn, 658 (res = TALER_MINT_DB_create_refresh_session (db_conn,
738 refresh_session_pub, 659 refresh_session_pub,
739 refresh_session.noreveal_index, 660 &session)))
740 commit_client_sig)))
741 { 661 {
742 TALER_MINT_DB_rollback (db_conn); 662 TALER_MINT_DB_rollback (db_conn);
743 return TALER_MINT_reply_internal_db_error (connection); 663 return TALER_MINT_reply_internal_db_error (connection);
744 } 664 }
745 665
746 666
667
747 if (GNUNET_OK != 668 if (GNUNET_OK !=
748 TALER_MINT_DB_commit (db_conn)) 669 TALER_MINT_DB_commit (db_conn))
749 { 670 {
750 LOG_WARNING ("/refresh/commit transaction commit failed\n"); 671 LOG_WARNING ("/refresh/melt transaction commit failed\n");
751 return TALER_MINT_reply_commit_error (connection); 672 return TALER_MINT_reply_commit_error (connection);
752 } 673 }
753 674 return TALER_MINT_reply_refresh_melt_success (connection,
754 return TALER_MINT_reply_refresh_commit_success (connection, 675 &session.session_hash,
755 &refresh_session.session_hash, 676 session.noreveal_index);
756 refresh_session.noreveal_index);
757} 677}
758 678
759 679
@@ -1061,15 +981,6 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
1061 return TALER_MINT_reply_internal_db_error (connection); 981 return TALER_MINT_reply_internal_db_error (connection);
1062 } 982 }
1063 983
1064 if ( (refresh_session.noreveal_index >= refresh_session.kappa) ||
1065 (GNUNET_NO == refresh_session.has_commit_sig) )
1066 {
1067 GNUNET_break (UINT16_MAX == refresh_session.noreveal_index);
1068 GNUNET_break (GNUNET_NO == refresh_session.has_commit_sig);
1069 return TALER_MINT_reply_external_error (connection,
1070 "/refresh/commit must be executed first");
1071 }
1072
1073 melts = GNUNET_malloc (refresh_session.num_oldcoins * 984 melts = GNUNET_malloc (refresh_session.num_oldcoins *
1074 sizeof (struct RefreshMelt)); 985 sizeof (struct RefreshMelt));
1075 for (j=0;j<refresh_session.num_oldcoins;j++) 986 for (j=0;j<refresh_session.num_oldcoins;j++)
diff --git a/src/mint/taler-mint-httpd_db.h b/src/mint/taler-mint-httpd_db.h
index dcd5e6fa0..2a26de9b4 100644
--- a/src/mint/taler-mint-httpd_db.h
+++ b/src/mint/taler-mint-httpd_db.h
@@ -107,6 +107,8 @@ struct MeltDetails
107 * required value left and if so, store that they have been 107 * required value left and if so, store that they have been
108 * melted and confirm the melting operation to the client. 108 * melted and confirm the melting operation to the client.
109 * 109 *
110 * FIXME: some arguments are redundant here...
111 *
110 * @param connection the MHD connection to handle 112 * @param connection the MHD connection to handle
111 * @param melt_hash hash code of the session the coins are melted into 113 * @param melt_hash hash code of the session the coins are melted into
112 * @param refresh_session_pub public key of the refresh session 114 * @param refresh_session_pub public key of the refresh session
@@ -117,30 +119,6 @@ struct MeltDetails
117 * @param coin_count number of entries in @a coin_public_infos and @ a coin_melt_details 119 * @param coin_count number of entries in @a coin_public_infos and @ a coin_melt_details
118 * @param coin_public_infos information about the coins to melt 120 * @param coin_public_infos information about the coins to melt
119 * @param coin_melt_details signatures and (residual) value of the respective coin should be melted 121 * @param coin_melt_details signatures and (residual) value of the respective coin should be melted
120 * @return MHD result code
121 */
122int
123TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
124 const struct GNUNET_HashCode *melt_hash,
125 const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
126 const struct GNUNET_CRYPTO_EddsaSignature *client_signature,
127 unsigned int num_new_denoms,
128 struct GNUNET_CRYPTO_rsa_PublicKey *const*denom_pubs,
129 unsigned int coin_count,
130 const struct TALER_CoinPublicInfo *coin_public_infos,
131 const struct MeltDetails *coin_melt_details);
132
133
134/**
135 * Execute a "/refresh/commit". The client is committing to @a kappa
136 * sets of transfer keys, and linkage information for a refresh
137 * operation. Confirm that the commit matches the melts of an
138 * existing @a refresh_session_pub, store the refresh session commit
139 * data and then return the client a challenge specifying which of the
140 * @a kappa sets of private transfer keys should not be revealed.
141 *
142 * @param connection the MHD connection to handle
143 * @param refresh_session public key of the session
144 * @param commit_client_sig signature of the client over this commitment 122 * @param commit_client_sig signature of the client over this commitment
145 * @param kappa size of x-dimension of @commit_coin and @commit_link arrays 123 * @param kappa size of x-dimension of @commit_coin and @commit_link arrays
146 * @param num_oldcoins size of y-dimension of @commit_coin array 124 * @param num_oldcoins size of y-dimension of @commit_coin array
@@ -154,14 +132,21 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
154 */ 132 */
155// FIXME: see #3635. 133// FIXME: see #3635.
156int 134int
157TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection, 135TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
158 const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub, 136 const struct GNUNET_HashCode *melt_hash,
159 const struct GNUNET_CRYPTO_EddsaSignature *commit_client_sig, 137 const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
160 unsigned int kappa, 138 const struct GNUNET_CRYPTO_EddsaSignature *client_signature,
161 unsigned int num_oldcoins, 139 unsigned int num_new_denoms,
162 unsigned int num_newcoins, 140 struct GNUNET_CRYPTO_rsa_PublicKey *const*denom_pubs,
163 struct RefreshCommitCoin *const* commit_coin, 141 unsigned int coin_count,
164 struct RefreshCommitLink *const* commit_link); 142 const struct TALER_CoinPublicInfo *coin_public_infos,
143 const struct MeltDetails *coin_melt_details,
144 const struct GNUNET_CRYPTO_EddsaSignature *commit_client_sig,
145 unsigned int kappa,
146 unsigned int num_oldcoins,
147 unsigned int num_newcoins,
148 struct RefreshCommitCoin *const* commit_coin,
149 struct RefreshCommitLink *const* commit_link);
165 150
166 151
167/** 152/**
diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c
index cfb3ba0f5..d7b670749 100644
--- a/src/mint/taler-mint-httpd_refresh.c
+++ b/src/mint/taler-mint-httpd_refresh.c
@@ -151,6 +151,15 @@ request_json_check_signature (struct MHD_Connection *connection,
151 * @param coin_public_infos array with @a coin_count entries about the coins 151 * @param coin_public_infos array with @a coin_count entries about the coins
152 * @param coin_melt_details array with @a coin_count entries with melting details 152 * @param coin_melt_details array with @a coin_count entries with melting details
153 * @param melt_sig_json signature affirming the overall melt operation 153 * @param melt_sig_json signature affirming the overall melt operation
154 * @param commit_client_sig signature of the client over this commitment
155 * @param kappa size of x-dimension of @commit_coin and @commit_link arrays
156 * @param num_oldcoins size of y-dimension of @commit_coin array
157 * @param num_newcoins size of y-dimension of @commit_link array
158 * @param commit_coin 2d array of coin commitments (what the mint is to sign
159 * once the "/refres/reveal" of cut and choose is done)
160 * @param commit_link 2d array of coin link commitments (what the mint is
161 * to return via "/refresh/link" to enable linkage in the
162 * future)
154 * @return MHD result code 163 * @return MHD result code
155 */ 164 */
156static int 165static int
@@ -161,7 +170,14 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
161 unsigned int coin_count, 170 unsigned int coin_count,
162 struct TALER_CoinPublicInfo *coin_public_infos, 171 struct TALER_CoinPublicInfo *coin_public_infos,
163 const struct MeltDetails *coin_melt_details, 172 const struct MeltDetails *coin_melt_details,
164 const json_t *melt_sig_json) 173 const json_t *melt_sig_json,
174 const struct GNUNET_CRYPTO_EddsaSignature *commit_client_sig,
175 unsigned int kappa,
176 unsigned int num_oldcoins,
177 unsigned int num_newcoins,
178 struct RefreshCommitCoin *const* commit_coin,
179 struct RefreshCommitLink *const* commit_link)
180
165{ 181{
166 int res; 182 int res;
167 unsigned int i; 183 unsigned int i;
@@ -256,7 +272,13 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
256 denom_pubs, 272 denom_pubs,
257 coin_count, 273 coin_count,
258 coin_public_infos, 274 coin_public_infos,
259 coin_melt_details); 275 coin_melt_details,
276 NULL /* FIXME: 3635! */,
277 kappa,
278 num_oldcoins,
279 num_newcoins,
280 commit_coin,
281 commit_link);
260} 282}
261 283
262 284
@@ -364,6 +386,58 @@ get_and_verify_coin_public_info (struct MHD_Connection *connection,
364 386
365 387
366/** 388/**
389 * Release memory from the @a commit_coin array.
390 *
391 * @param commit_coin array to release
392 * @param kappa size of 1st dimension
393 * @param num_new_coins size of 2nd dimension
394 */
395static void
396free_commit_coins (struct RefreshCommitCoin **commit_coin,
397 unsigned int kappa,
398 unsigned int num_new_coins)
399{
400 unsigned int i;
401 unsigned int j;
402
403 for (i=0;i<kappa;i++)
404 {
405 if (NULL == commit_coin[i])
406 break;
407 for (j=0;j<num_new_coins;j++)
408 {
409 GNUNET_free_non_null (commit_coin[i][j].coin_ev);
410 GNUNET_free_non_null (commit_coin[i][j].refresh_link);
411 }
412 GNUNET_free (commit_coin[i]);
413 }
414}
415
416
417/**
418 * Release memory from the @a commit_link array.
419 *
420 * @param commit_coin array to release
421 * @param kappa size of 1st dimension
422 * @param num_old_coins size of 2nd dimension
423 */
424static void
425free_commit_links (struct RefreshCommitLink **commit_link,
426 unsigned int kappa,
427 unsigned int num_old_coins)
428{
429 unsigned int i;
430
431 for (i=0;i<kappa;i++)
432 {
433 if (NULL == commit_link[i])
434 break;
435 GNUNET_free (commit_link[i]);
436 }
437}
438
439
440/**
367 * Handle a "/refresh/melt" request after the first parsing has happened. 441 * Handle a "/refresh/melt" request after the first parsing has happened.
368 * We now need to validate the coins being melted and the session signature 442 * We now need to validate the coins being melted and the session signature
369 * and then hand things of to execute the melt operation. This function 443 * and then hand things of to execute the melt operation. This function
@@ -375,6 +449,14 @@ get_and_verify_coin_public_info (struct MHD_Connection *connection,
375 * @param new_denoms array of denomination keys 449 * @param new_denoms array of denomination keys
376 * @param melt_coins array of coins to melt 450 * @param melt_coins array of coins to melt
377 * @param melt_sig_json signature affirming the melt operation 451 * @param melt_sig_json signature affirming the melt operation
452 * @param commit_signature signature over the commit
453 * @param kappa security parameter for cut and choose
454 * @param num_oldcoins number of coins that are being melted
455 * @param transfer_pubs @a kappa-dimensional array of @a num_oldcoins transfer keys
456 * @param secret_encs @a kappa-dimensional array of @a num_oldcoins secrets
457 * @param num_newcoins number of coins that the refresh will generate
458 * @param coin_envs @a kappa-dimensional array of @a num_newcoins envelopes to sign
459 * @param link_encs @a kappa-dimensional array of @a num_newcoins encrypted links
378 * @return MHD result code 460 * @return MHD result code
379 */ 461 */
380static int 462static int
@@ -382,7 +464,16 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
382 const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub, 464 const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
383 const json_t *new_denoms, 465 const json_t *new_denoms,
384 const json_t *melt_coins, 466 const json_t *melt_coins,
385 const json_t *melt_sig_json) 467 const json_t *melt_sig_json,
468 const json_t *commit_signature,
469 unsigned int kappa,
470 unsigned int num_oldcoins,
471 const json_t *transfer_pubs,
472 const json_t *secret_encs,
473 unsigned int num_newcoins,
474 const json_t *coin_evs,
475 const json_t *link_encs)
476
386{ 477{
387 int res; 478 int res;
388 unsigned int i; 479 unsigned int i;
@@ -392,6 +483,11 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
392 struct TALER_CoinPublicInfo *coin_public_infos; 483 struct TALER_CoinPublicInfo *coin_public_infos;
393 struct MeltDetails *coin_melt_details; 484 struct MeltDetails *coin_melt_details;
394 unsigned int coin_count; 485 unsigned int coin_count;
486 struct GNUNET_HashCode commit_hash;
487 struct GNUNET_HashContext *hash_context;
488 struct RefreshCommitSignatureBody body;
489 struct RefreshCommitCoin *commit_coin[kappa];
490 struct RefreshCommitLink *commit_link[kappa];
395 491
396 num_new_denoms = json_array_size (new_denoms); 492 num_new_denoms = json_array_size (new_denoms);
397 denom_pubs = GNUNET_malloc (num_new_denoms * 493 denom_pubs = GNUNET_malloc (num_new_denoms *
@@ -441,180 +537,6 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
441 } 537 }
442 } 538 }
443 539
444 res = handle_refresh_melt_binary (connection,
445 refresh_session_pub,
446 num_new_denoms,
447 denom_pubs,
448 coin_count,
449 coin_public_infos,
450 coin_melt_details,
451 melt_sig_json);
452 for (j=0;j<coin_count;j++)
453 {
454 GNUNET_CRYPTO_rsa_public_key_free (coin_public_infos[j].denom_pub);
455 GNUNET_CRYPTO_rsa_signature_free (coin_public_infos[j].denom_sig);
456 }
457 GNUNET_free (coin_public_infos);
458 for (j=0;j<num_new_denoms;j++)
459 {
460 GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j]);
461 }
462 GNUNET_free (coin_melt_details);
463 GNUNET_free (denom_pubs);
464 return res;
465}
466
467
468/**
469 * Handle a "/refresh/melt" request. Parses the request into the JSON
470 * components and then hands things of to #handle_referesh_melt_json()
471 * to validate the melted coins, the signature and execute the melt
472 * using TALER_MINT_db_execute_refresh_melt().
473 *
474 * @param rh context of the handler
475 * @param connection the MHD connection to handle
476 * @param[IN|OUT] connection_cls the connection's closure (can be updated)
477 * @param upload_data upload data
478 * @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
479 * @return MHD result code
480 */
481int
482TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
483 struct MHD_Connection *connection,
484 void **connection_cls,
485 const char *upload_data,
486 size_t *upload_data_size)
487{
488 json_t *root;
489 json_t *new_denoms;
490 json_t *melt_coins;
491 json_t *melt_sig_json;
492 struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub;
493 int res;
494 struct GNUNET_MINT_ParseFieldSpec spec[] = {
495 TALER_MINT_PARSE_FIXED ("session_pub", &refresh_session_pub),
496 TALER_MINT_PARSE_ARRAY ("new_denoms", &new_denoms),
497 TALER_MINT_PARSE_ARRAY ("melt_coins", &melt_coins),
498 TALER_MINT_PARSE_ARRAY ("melt_signature", &melt_sig_json),
499 TALER_MINT_PARSE_END
500 };
501
502 res = TALER_MINT_parse_post_json (connection,
503 connection_cls,
504 upload_data,
505 upload_data_size,
506 &root);
507 if (GNUNET_SYSERR == res)
508 return MHD_NO;
509 if ( (GNUNET_NO == res) || (NULL == root) )
510 return MHD_YES;
511
512 res = TALER_MINT_parse_json_data (connection,
513 root,
514 spec);
515 json_decref (root);
516 if (GNUNET_OK != res)
517 return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
518 res = handle_refresh_melt_json (connection,
519 &refresh_session_pub,
520 new_denoms,
521 melt_coins,
522 melt_sig_json);
523 TALER_MINT_release_parsed_data (spec);
524 return res;
525}
526
527
528/**
529 * Release memory from the @a commit_coin array.
530 *
531 * @param commit_coin array to release
532 * @param kappa size of 1st dimension
533 * @param num_new_coins size of 2nd dimension
534 */
535static void
536free_commit_coins (struct RefreshCommitCoin **commit_coin,
537 unsigned int kappa,
538 unsigned int num_new_coins)
539{
540 unsigned int i;
541 unsigned int j;
542
543 for (i=0;i<kappa;i++)
544 {
545 if (NULL == commit_coin[i])
546 break;
547 for (j=0;j<num_new_coins;j++)
548 {
549 GNUNET_free_non_null (commit_coin[i][j].coin_ev);
550 GNUNET_free_non_null (commit_coin[i][j].refresh_link);
551 }
552 GNUNET_free (commit_coin[i]);
553 }
554}
555
556
557/**
558 * Release memory from the @a commit_link array.
559 *
560 * @param commit_coin array to release
561 * @param kappa size of 1st dimension
562 * @param num_old_coins size of 2nd dimension
563 */
564static void
565free_commit_links (struct RefreshCommitLink **commit_link,
566 unsigned int kappa,
567 unsigned int num_old_coins)
568{
569 unsigned int i;
570
571 for (i=0;i<kappa;i++)
572 {
573 if (NULL == commit_link[i])
574 break;
575 GNUNET_free (commit_link[i]);
576 }
577}
578
579
580
581/**
582 * Handle a "/refresh/commit" request. We have the individual JSON
583 * arrays, now we need to parse their contents and verify the
584 * commit signature. Then we can commit the data to the database.
585 *
586 * @param connection the MHD connection to handle
587 * @param refresh_session_pub public key of the refresh session
588 * @param commit_signature signature over the commit
589 * @param kappa security parameter for cut and choose
590 * @param num_oldcoins number of coins that are being melted
591 * @param transfer_pubs @a kappa-dimensional array of @a num_oldcoins transfer keys
592 * @param secret_encs @a kappa-dimensional array of @a num_oldcoins secrets
593 * @param num_newcoins number of coins that the refresh will generate
594 * @param coin_envs @a kappa-dimensional array of @a num_newcoins envelopes to sign
595 * @param link_encs @a kappa-dimensional array of @a num_newcoins encrypted links
596 * @return MHD result code
597 */
598static int
599handle_refresh_commit_json (struct MHD_Connection *connection,
600 const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
601 const json_t *commit_signature,
602 unsigned int kappa,
603 unsigned int num_oldcoins,
604 const json_t *transfer_pubs,
605 const json_t *secret_encs,
606 unsigned int num_newcoins,
607 const json_t *coin_evs,
608 const json_t *link_encs)
609{
610 struct GNUNET_HashCode commit_hash;
611 struct GNUNET_HashContext *hash_context;
612 struct RefreshCommitSignatureBody body;
613 struct RefreshCommitCoin *commit_coin[kappa];
614 struct RefreshCommitLink *commit_link[kappa];
615 unsigned int i;
616 unsigned int j;
617 int res;
618 540
619 /* parse JSON arrays into 2d binary arrays and hash everything 541 /* parse JSON arrays into 2d binary arrays and hash everything
620 together for the signature check */ 542 together for the signature check */
@@ -721,7 +643,7 @@ handle_refresh_commit_json (struct MHD_Connection *connection,
721 GNUNET_CRYPTO_hash_context_finish (hash_context, &commit_hash); 643 GNUNET_CRYPTO_hash_context_finish (hash_context, &commit_hash);
722 644
723 /* verify commit signature */ 645 /* verify commit signature */
724 body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_COMMIT); 646 body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT);
725 body.purpose.size = htonl (sizeof (struct RefreshCommitSignatureBody)); 647 body.purpose.size = htonl (sizeof (struct RefreshCommitSignatureBody));
726 body.commit_hash = commit_hash; 648 body.commit_hash = commit_hash;
727 649
@@ -738,29 +660,43 @@ handle_refresh_commit_json (struct MHD_Connection *connection,
738 660
739 /* execute commit */ 661 /* execute commit */
740 /* FIXME: we must also store the signature! (#3635) */ 662 /* FIXME: we must also store the signature! (#3635) */
741 res = TALER_MINT_db_execute_refresh_commit (connection, 663 res = handle_refresh_melt_binary (connection,
742 refresh_session_pub, 664 refresh_session_pub,
743 NULL /* FIXME: 3635! */, 665 num_new_denoms,
744 kappa, 666 denom_pubs,
745 num_oldcoins, 667 coin_count,
746 num_newcoins, 668 coin_public_infos,
747 commit_coin, 669 coin_melt_details,
748 commit_link); 670 melt_sig_json,
671 NULL /* FIXME: 3635! */,
672 kappa,
673 num_oldcoins,
674 num_newcoins,
675 commit_coin,
676 commit_link);
749 free_commit_coins (commit_coin, kappa, num_newcoins); 677 free_commit_coins (commit_coin, kappa, num_newcoins);
750 free_commit_links (commit_link, kappa, num_oldcoins); 678 free_commit_links (commit_link, kappa, num_oldcoins);
751 679 for (j=0;j<coin_count;j++)
680 {
681 GNUNET_CRYPTO_rsa_public_key_free (coin_public_infos[j].denom_pub);
682 GNUNET_CRYPTO_rsa_signature_free (coin_public_infos[j].denom_sig);
683 }
684 GNUNET_free (coin_public_infos);
685 for (j=0;j<num_new_denoms;j++)
686 {
687 GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j]);
688 }
689 GNUNET_free (coin_melt_details);
690 GNUNET_free (denom_pubs);
752 return res; 691 return res;
753} 692}
754 693
755 694
756/** 695/**
757 * Handle a "/refresh/commit" request. Parses the top-level JSON to 696 * Handle a "/refresh/melt" request. Parses the request into the JSON
758 * determine the dimensions of the problem and then handles handing 697 * components and then hands things of to #handle_referesh_melt_json()
759 * off to #handle_refresh_commit_json() to parse the details of the 698 * to validate the melted coins, the signature and execute the melt
760 * JSON arguments. Once the signature has been verified, the 699 * using TALER_MINT_db_execute_refresh_melt().
761 * commit data is written to the database via
762 * #TALER_MINT_db_execute_refresh_commit() and the reveal parameter
763 * is then returned to the client.
764 * 700 *
765 * @param rh context of the handler 701 * @param rh context of the handler
766 * @param connection the MHD connection to handle 702 * @param connection the MHD connection to handle
@@ -768,28 +704,34 @@ handle_refresh_commit_json (struct MHD_Connection *connection,
768 * @param upload_data upload data 704 * @param upload_data upload data
769 * @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data 705 * @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
770 * @return MHD result code 706 * @return MHD result code
771 */ 707 */
772int 708int
773TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, 709TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
774 struct MHD_Connection *connection, 710 struct MHD_Connection *connection,
775 void **connection_cls, 711 void **connection_cls,
776 const char *upload_data, 712 const char *upload_data,
777 size_t *upload_data_size) 713 size_t *upload_data_size)
778{ 714{
779 struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub;
780 int res;
781 unsigned int kappa;
782 unsigned int num_oldcoins;
783 unsigned int num_newcoins;
784 json_t *root; 715 json_t *root;
716 json_t *new_denoms;
717 json_t *melt_coins;
718 json_t *melt_sig_json;
785 json_t *coin_evs; 719 json_t *coin_evs;
786 json_t *link_encs; 720 json_t *link_encs;
787 json_t *transfer_pubs; 721 json_t *transfer_pubs;
788 json_t *secret_encs; 722 json_t *secret_encs;
789 json_t *coin_detail;
790 json_t *commit_sig_json; 723 json_t *commit_sig_json;
724 unsigned int kappa;
725 unsigned int num_oldcoins;
726 unsigned int num_newcoins;
727 json_t *coin_detail;
728 struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub;
729 int res;
791 struct GNUNET_MINT_ParseFieldSpec spec[] = { 730 struct GNUNET_MINT_ParseFieldSpec spec[] = {
792 TALER_MINT_PARSE_FIXED ("session_pub", &refresh_session_pub), 731 TALER_MINT_PARSE_FIXED ("session_pub", &refresh_session_pub),
732 TALER_MINT_PARSE_ARRAY ("new_denoms", &new_denoms),
733 TALER_MINT_PARSE_ARRAY ("melt_coins", &melt_coins),
734 TALER_MINT_PARSE_ARRAY ("melt_signature", &melt_sig_json),
793 TALER_MINT_PARSE_ARRAY ("coin_evs", &coin_evs), 735 TALER_MINT_PARSE_ARRAY ("coin_evs", &coin_evs),
794 TALER_MINT_PARSE_ARRAY ("link_encs", &link_encs), 736 TALER_MINT_PARSE_ARRAY ("link_encs", &link_encs),
795 TALER_MINT_PARSE_ARRAY ("transfer_pubs", &transfer_pubs), 737 TALER_MINT_PARSE_ARRAY ("transfer_pubs", &transfer_pubs),
@@ -852,16 +794,21 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh,
852 return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; 794 return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
853 } 795 }
854 num_oldcoins = json_array_size (coin_detail); 796 num_oldcoins = json_array_size (coin_detail);
855 res = handle_refresh_commit_json (connection, 797
856 &refresh_session_pub, 798 res = handle_refresh_melt_json (connection,
857 commit_sig_json, 799 &refresh_session_pub,
858 kappa, 800 new_denoms,
859 num_oldcoins, 801 melt_coins,
860 transfer_pubs, 802 melt_sig_json,
861 secret_encs, 803 commit_sig_json,
862 num_newcoins, 804 kappa,
863 coin_evs, 805 num_oldcoins,
864 link_encs); 806 transfer_pubs,
807 secret_encs,
808 num_newcoins,
809 coin_evs,
810 link_encs);
811
865 TALER_MINT_release_parsed_data (spec); 812 TALER_MINT_release_parsed_data (spec);
866 return res; 813 return res;
867} 814}
@@ -931,7 +878,7 @@ handle_refresh_reveal_json (struct MHD_Connection *connection,
931/** 878/**
932 * Handle a "/refresh/reveal" request. This time, the client reveals 879 * Handle a "/refresh/reveal" request. This time, the client reveals
933 * the private transfer keys except for the cut-and-choose value 880 * the private transfer keys except for the cut-and-choose value
934 * returned from "/refresh/commit". This function parses the revealed 881 * returned from "/refresh/melt". This function parses the revealed
935 * keys and secrets and ultimately passes everything to 882 * keys and secrets and ultimately passes everything to
936 * #TALER_MINT_db_execute_refresh_reveal() which will verify that the 883 * #TALER_MINT_db_execute_refresh_reveal() which will verify that the
937 * revealed information is valid then returns the signed refreshed 884 * revealed information is valid then returns the signed refreshed
diff --git a/src/mint/taler-mint-httpd_refresh.h b/src/mint/taler-mint-httpd_refresh.h
index 80bad6c5c..c1f69e1de 100644
--- a/src/mint/taler-mint-httpd_refresh.h
+++ b/src/mint/taler-mint-httpd_refresh.h
@@ -50,30 +50,6 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
50 50
51 51
52/** 52/**
53 * Handle a "/refresh/commit" request. Parses the top-level JSON to
54 * determine the dimensions of the problem and then handles handing
55 * off to #handle_refresh_commit_json() to parse the details of the
56 * JSON arguments. Once the signature has been verified, the
57 * commit data is written to the database via
58 * #TALER_MINT_db_execute_refresh_commit() and the cut-and-choose value
59 * is then returned to the client.
60 *
61 * @param rh context of the handler
62 * @param connection the MHD connection to handle
63 * @param[IN|OUT] connection_cls the connection's closure (can be updated)
64 * @param upload_data upload data
65 * @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
66 * @return MHD result code
67 */
68int
69TALER_MINT_handler_refresh_commit (struct RequestHandler *rh,
70 struct MHD_Connection *connection,
71 void **connection_cls,
72 const char *upload_data,
73 size_t *upload_data_size);
74
75
76/**
77 * Handle a "/refresh/reveal" request. This time, the client reveals 53 * Handle a "/refresh/reveal" request. This time, the client reveals
78 * the private transfer keys except for the cut-and-choose value 54 * the private transfer keys except for the cut-and-choose value
79 * returned from "/refresh/commit". This function parses the revealed 55 * returned from "/refresh/commit". This function parses the revealed
diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c
index 21e208115..83c81e800 100644
--- a/src/mint/taler-mint-httpd_responses.c
+++ b/src/mint/taler-mint-httpd_responses.c
@@ -315,27 +315,20 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
315 return ret; 315 return ret;
316} 316}
317 317
318
319/** 318/**
320 * Send proof that a /deposit, /refresh/melt or /lock request is 319 * Compile the transaction history of a coin into a JSON object.
321 * invalid to client. This function will create a message with all of
322 * the operations affecting the coin that demonstrate that the coin
323 * has insufficient value.
324 * 320 *
325 * @param connection connection to the client 321 * @param tl transaction history to JSON-ify
326 * @param tl transaction list to use to build reply 322 * @return json representation of the @a rh
327 * @return MHD result code
328 */ 323 */
329int 324static json_t *
330TALER_MINT_reply_insufficient_funds (struct MHD_Connection *connection, 325compile_transaction_history (const struct TALER_MINT_DB_TransactionList *tl)
331 const struct TALER_MINT_DB_TransactionList *tl)
332{ 326{
333 const struct TALER_MINT_DB_TransactionList *pos;
334 int ret;
335 json_t *history;
336 json_t *transaction; 327 json_t *transaction;
337 const char *type; 328 const char *type;
338 struct TALER_Amount value; 329 struct TALER_Amount value;
330 json_t *history;
331 const struct TALER_MINT_DB_TransactionList *pos;
339 332
340 history = json_array (); 333 history = json_array ();
341 for (pos = tl; NULL != pos; pos = pos->next) 334 for (pos = tl; NULL != pos; pos = pos->next)
@@ -392,13 +385,31 @@ TALER_MINT_reply_insufficient_funds (struct MHD_Connection *connection,
392 "amount", TALER_JSON_from_amount (value), 385 "amount", TALER_JSON_from_amount (value),
393 "signature", transaction)); 386 "signature", transaction));
394 } 387 }
388 return history;
389}
395 390
396 ret = TALER_MINT_reply_json_pack (connection, 391
397 MHD_HTTP_FORBIDDEN, 392/**
398 "{s:s, s:o}", 393 * Send proof that a /withdraw request is invalid to client. This
399 "error", "insufficient funds", 394 * function will create a message with all of the operations affecting
400 "history", history); 395 * the coin that demonstrate that the coin has insufficient value.
401 return ret; 396 *
397 * @param connection connection to the client
398 * @param tl transaction list to use to build reply
399 * @return MHD result code
400 */
401int
402TALER_MINT_reply_deposit_insufficient_funds (struct MHD_Connection *connection,
403 const struct TALER_MINT_DB_TransactionList *tl)
404{
405 json_t *history;
406
407 history = compile_transaction_history (tl);
408 return TALER_MINT_reply_json_pack (connection,
409 MHD_HTTP_FORBIDDEN,
410 "{s:s, s:o}",
411 "error", "insufficient funds",
412 "history", history);
402} 413}
403 414
404 415
@@ -589,47 +600,46 @@ TALER_MINT_reply_withdraw_sign_success (struct MHD_Connection *connection,
589 600
590 601
591/** 602/**
592 * Send a response for "/refresh/melt". Essentially we sign 603 * Send a response for a failed "/refresh/melt" request. The
593 * over the client's signature and public key, thereby 604 * transaction history of the given coin demonstrates that the
594 * demonstrating that we accepted all of the client's coins. 605 * @a residual value of the coin is below the @a requested
606 * contribution of the coin for the melt. Thus, the mint
607 * refuses the melt operation.
595 * 608 *
596 * @param connection the connection to send the response to 609 * @param connection the connection to send the response to
597 * @param signature the client's signature over the melt request 610 * @param coin_pub public key of the coin
598 * @param session_pub the refresh session public key. 611 * @param coin_value original value of the coin
599 * @param kappa security parameter to use for cut and choose 612 * @param tl transaction history for the coin
613 * @param requested how much this coin was supposed to contribute
614 * @param residual remaining value of the coin (after subtracting @a tl)
600 * @return a MHD result code 615 * @return a MHD result code
601 */ 616 */
602int 617int
603TALER_MINT_reply_refresh_melt_success (struct MHD_Connection *connection, 618TALER_MINT_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection,
604 const struct GNUNET_CRYPTO_EddsaSignature *signature, 619 const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
605 const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub, 620 struct TALER_Amount coin_value,
606 unsigned int kappa) 621 struct TALER_MINT_DB_TransactionList *tl,
622 struct TALER_Amount requested,
623 struct TALER_Amount residual)
607{ 624{
608 int ret; 625 json_t *history;
609 struct RefreshMeltResponseSignatureBody body;
610 struct GNUNET_CRYPTO_EddsaSignature sig;
611 json_t *sig_json;
612 626
613 body.purpose.size = htonl (sizeof (struct RefreshMeltResponseSignatureBody)); 627 history = compile_transaction_history (tl);
614 body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_RESPONSE); 628 return TALER_MINT_reply_json_pack (connection,
615 body.melt_client_signature = *signature; 629 MHD_HTTP_NOT_FOUND,
616 body.session_key = *session_pub; 630 "{s:s, s:o, s:o, s:o, s:o, s:o}",
617 body.kappa = htonl (kappa); 631 "error", "insufficient funds",
618 TALER_MINT_keys_sign (&body.purpose, 632 "coin-pub", TALER_JSON_from_data (coin_pub,
619 &sig); 633 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)),
620 sig_json = TALER_JSON_from_eddsa_sig (&body.purpose, &sig); 634 "original-value", TALER_JSON_from_amount (coin_value),
621 ret = TALER_MINT_reply_json_pack (connection, 635 "residual-value", TALER_JSON_from_amount (residual),
622 MHD_HTTP_OK, 636 "requested-value", TALER_JSON_from_amount (requested),
623 "{s:o, s:i}", 637 "history", history);
624 "signature", sig_json,
625 "kappa", (int) kappa);
626 json_decref (sig_json);
627 return ret;
628} 638}
629 639
630 640
631/** 641/**
632 * Send a response to a "/refresh/commit" request. 642 * Send a response to a "/refresh/melt" request.
633 * 643 *
634 * @param connection the connection to send the response to 644 * @param connection the connection to send the response to
635 * @param session_hash hash of the refresh session 645 * @param session_hash hash of the refresh session
@@ -637,17 +647,17 @@ TALER_MINT_reply_refresh_melt_success (struct MHD_Connection *connection,
637 * @return a MHD status code 647 * @return a MHD status code
638 */ 648 */
639int 649int
640TALER_MINT_reply_refresh_commit_success (struct MHD_Connection *connection, 650TALER_MINT_reply_refresh_melt_success (struct MHD_Connection *connection,
641 const struct GNUNET_HashCode *session_hash, 651 const struct GNUNET_HashCode *session_hash,
642 uint16_t noreveal_index) 652 uint16_t noreveal_index)
643{ 653{
644 struct RefreshCommitResponseSignatureBody body; 654 struct RefreshMeltResponseSignatureBody body;
645 struct GNUNET_CRYPTO_EddsaSignature sig; 655 struct GNUNET_CRYPTO_EddsaSignature sig;
646 json_t *sig_json; 656 json_t *sig_json;
647 int ret; 657 int ret;
648 658
649 body.purpose.size = htonl (sizeof (struct RefreshCommitResponseSignatureBody)); 659 body.purpose.size = htonl (sizeof (struct RefreshMeltResponseSignatureBody));
650 body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_COMMIT_RESPONSE); 660 body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_RESPONSE);
651 body.session_hash = *session_hash; 661 body.session_hash = *session_hash;
652 body.noreveal_index = htons (noreveal_index); 662 body.noreveal_index = htons (noreveal_index);
653 TALER_MINT_keys_sign (&body.purpose, 663 TALER_MINT_keys_sign (&body.purpose,
diff --git a/src/mint/taler-mint-httpd_responses.h b/src/mint/taler-mint-httpd_responses.h
index abfb4318c..7d0824c88 100644
--- a/src/mint/taler-mint-httpd_responses.h
+++ b/src/mint/taler-mint-httpd_responses.h
@@ -194,18 +194,17 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
194 194
195 195
196/** 196/**
197 * Send proof that a /deposit, /refresh/melt or /lock request is 197 * Send proof that a /deposit request is invalid to client. This
198 * invalid to client. This function will create a message with all of 198 * function will create a message with all of the operations affecting
199 * the operations affecting the coin that demonstrate that the coin 199 * the coin that demonstrate that the coin has insufficient value.
200 * has insufficient value.
201 * 200 *
202 * @param connection connection to the client 201 * @param connection connection to the client
203 * @param tl transaction list to use to build reply 202 * @param tl transaction list to use to build reply
204 * @return MHD result code 203 * @return MHD result code
205 */ 204 */
206int 205int
207TALER_MINT_reply_insufficient_funds (struct MHD_Connection *connection, 206TALER_MINT_reply_deposit_insufficient_funds (struct MHD_Connection *connection,
208 const struct TALER_MINT_DB_TransactionList *tl); 207 const struct TALER_MINT_DB_TransactionList *tl);
209 208
210 209
211/** 210/**
@@ -247,7 +246,7 @@ TALER_MINT_reply_withdraw_sign_success (struct MHD_Connection *connection,
247 246
248 247
249/** 248/**
250 * Send a response to a "/refresh/commit" request. 249 * Send a confirmation response to a "/refresh/melt" request.
251 * 250 *
252 * @param connection the connection to send the response to 251 * @param connection the connection to send the response to
253 * @param session_hash hash of the refresh session 252 * @param session_hash hash of the refresh session
@@ -255,27 +254,33 @@ TALER_MINT_reply_withdraw_sign_success (struct MHD_Connection *connection,
255 * @return a MHD status code 254 * @return a MHD status code
256 */ 255 */
257int 256int
258TALER_MINT_reply_refresh_commit_success (struct MHD_Connection *connection, 257TALER_MINT_reply_refresh_melt_success (struct MHD_Connection *connection,
259 const struct GNUNET_HashCode *session_hash, 258 const struct GNUNET_HashCode *session_hash,
260 uint16_t noreveal_index); 259 uint16_t noreveal_index);
261 260
262 261
263/** 262/**
264 * Send a response for "/refresh/melt". Essentially we sign 263 * Send a response for a failed "/refresh/melt" request. The
265 * over the client's signature and public key, thereby 264 * transaction history of the given coin demonstrates that the
266 * demonstrating that we accepted all of the client's coins. 265 * @a residual value of the coin is below the @a requested
266 * contribution of the coin for the melt. Thus, the mint
267 * refuses the melt operation.
267 * 268 *
268 * @param connection the connection to send the response to 269 * @param connection the connection to send the response to
269 * @param signature the client's signature over the melt request 270 * @param coin_pub public key of the coin
270 * @param session_pub the refresh session public key. 271 * @param coin_value original value of the coin
271 * @param kappa security parameter to use for cut and choose 272 * @param tl transaction history for the coin
273 * @param requested how much this coin was supposed to contribute
274 * @param residual remaining value of the coin (after subtracting @a tl)
272 * @return a MHD result code 275 * @return a MHD result code
273 */ 276 */
274int 277int
275TALER_MINT_reply_refresh_melt_success (struct MHD_Connection *connection, 278TALER_MINT_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection,
276 const struct GNUNET_CRYPTO_EddsaSignature *signature, 279 const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
277 const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub, 280 struct TALER_Amount coin_value,
278 unsigned int kappa); 281 struct TALER_MINT_DB_TransactionList *tl,
282 struct TALER_Amount requested,
283 struct TALER_Amount residual);
279 284
280 285
281/** 286/**