gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [taler-exchange] branch master updated (a946dc3 -> 2f2930f)


From: gnunet
Subject: [GNUnet-SVN] [taler-exchange] branch master updated (a946dc3 -> 2f2930f)
Date: Tue, 31 Oct 2017 14:02:59 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a change to branch master
in repository exchange.

    from a946dc3  start template for generating nicely formatted auditor reports
     new a491a47  rename: TALER_FreshCoinP -> TALER_PlanchetSecretsP, and 
TALER_setup_fresh_coin -> TALER_setup_planchet
     new ec8146d  rename: TALER_setup_planchet -> TALER_planchet_setup_refresh
     new 2f2930f  major API refactoring, adding planchet generation and coin 
extraction APIs to the Taler crypto library, thereby simplifying code in 
withdraw, refresh, tipping, payback and testcases; slight API incompatibilities 
to previous versions are introduced

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 ChangeLog                                          |   6 +
 src/benchmark/taler-exchange-benchmark.c           |   6 +-
 src/exchange-lib/exchange_api_payback.c            |  14 +-
 src/exchange-lib/exchange_api_refresh.c            | 149 +++++++----------
 src/exchange-lib/exchange_api_refresh_link.c       |   4 +-
 src/exchange-lib/exchange_api_reserve.c            |  82 ++++------
 src/exchange-lib/test_exchange_api.c               |  46 ++----
 src/exchange/taler-exchange-httpd_refresh_reveal.c |   4 +-
 src/include/taler_crypto_lib.h                     | 178 ++++++++++++++++-----
 src/include/taler_exchange_service.h               |  13 +-
 src/include/taler_util.h                           |   2 -
 src/util/crypto.c                                  | 139 +++++++++++++---
 src/util/test_crypto.c                             |  61 +++++--
 13 files changed, 441 insertions(+), 263 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index ab96d8a..2f12309 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Tue Oct 31 13:43:55 CET 2017
+       Extended crypto API to provide planchet generation functions
+       explicitly (to be used on withdraw, refresh and tipping).
+       Renamed a few API calls to better reflect their functions.
+       Changed a few function signatures to use new structs. -CG
+
 Wed Oct 18 15:20:29 CEST 2017
        Releasing Taler v0.4.0. -CG
 
diff --git a/src/benchmark/taler-exchange-benchmark.c 
b/src/benchmark/taler-exchange-benchmark.c
index 93afb68..a90773b 100644
--- a/src/benchmark/taler-exchange-benchmark.c
+++ b/src/benchmark/taler-exchange-benchmark.c
@@ -981,6 +981,7 @@ withdraw_coin (struct Coin *coin)
   struct TALER_Amount left;
   const struct TALER_EXCHANGE_Keys *keys;
   struct Reserve *r;
+  struct TALER_PlanchetSecretsP ps;
 
   keys = TALER_EXCHANGE_get_keys (exchange);
   r = &reserves[coin->reserve_index];
@@ -996,12 +997,13 @@ withdraw_coin (struct Coin *coin)
   GNUNET_assert (NULL != (coin->pk = find_pk (keys, &amount)));
   if (warm >= WARM_THRESHOLD)
     num_withdraw++;
+  ps.coin_priv = coin->coin_priv;
+  ps.blinding_key = blinding_key;
   coin->wsh =
     TALER_EXCHANGE_reserve_withdraw (exchange,
                                     coin->pk,
                                     &r->reserve_priv,
-                                    &coin->coin_priv,
-                                    &blinding_key,
+                                    &ps,
                                     &reserve_withdraw_cb,
                                     coin);
   GNUNET_assert (GNUNET_SYSERR !=
diff --git a/src/exchange-lib/exchange_api_payback.c 
b/src/exchange-lib/exchange_api_payback.c
index 40b7138..ec0cda1 100644
--- a/src/exchange-lib/exchange_api_payback.c
+++ b/src/exchange-lib/exchange_api_payback.c
@@ -260,8 +260,7 @@ handle_payback_finished (void *cls,
  * @param exchange the exchange handle; the exchange must be ready to operate
  * @param pk kind of coin to pay back
  * @param denom_sig signature over the coin by the exchange using @a pk
- * @param coin_priv the coin's private key,
- * @param blinding_key where to fetch the coin's blinding key
+ * @param ps secret internals of the original planchet
  * @param payback_cb the callback to call when the final result for this 
request is available
  * @param payback_cb_cls closure for @a payback_cb
  * @return NULL
@@ -272,8 +271,7 @@ struct TALER_EXCHANGE_PaybackHandle *
 TALER_EXCHANGE_payback (struct TALER_EXCHANGE_Handle *exchange,
                         const struct TALER_EXCHANGE_DenomPublicKey *pk,
                         const struct TALER_DenominationSignature *denom_sig,
-                        const struct TALER_CoinSpendPrivateKeyP *coin_priv,
-                        const struct TALER_DenominationBlindingKeyP 
*blinding_key,
+                        const struct TALER_PlanchetSecretsP *ps,
                         TALER_EXCHANGE_PaybackResultCallback payback_cb,
                         void *payback_cb_cls)
 {
@@ -288,12 +286,12 @@ TALER_EXCHANGE_payback (struct TALER_EXCHANGE_Handle 
*exchange,
                 MAH_handle_is_ready (exchange));
   pr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_PAYBACK);
   pr.purpose.size = htonl (sizeof (struct TALER_PaybackRequestPS));
-  GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
+  GNUNET_CRYPTO_eddsa_key_get_public (&ps->coin_priv.eddsa_priv,
                                       &pr.coin_pub.eddsa_pub);
   pr.h_denom_pub = pk->h_key;
-  pr.coin_blind = *blinding_key;
+  pr.coin_blind = ps->blinding_key;
   GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv,
+                 GNUNET_CRYPTO_eddsa_sign (&ps->coin_priv.eddsa_priv,
                                            &pr.purpose,
                                            &coin_sig.eddsa_signature));
 
@@ -304,7 +302,7 @@ TALER_EXCHANGE_payback (struct TALER_EXCHANGE_Handle 
*exchange,
                            "denom_sig", GNUNET_JSON_from_rsa_signature 
(denom_sig->rsa_signature),
                            "coin_pub", GNUNET_JSON_from_data_auto 
(&pr.coin_pub),
                            "coin_sig", GNUNET_JSON_from_data_auto (&coin_sig),
-                           "coin_blind_key_secret", GNUNET_JSON_from_data_auto 
(blinding_key)
+                           "coin_blind_key_secret", GNUNET_JSON_from_data_auto 
(&ps->blinding_key)
                          );
   if (NULL == payback_obj)
   {
diff --git a/src/exchange-lib/exchange_api_refresh.c 
b/src/exchange-lib/exchange_api_refresh.c
index 79381f3..305747f 100644
--- a/src/exchange-lib/exchange_api_refresh.c
+++ b/src/exchange-lib/exchange_api_refresh.c
@@ -117,7 +117,7 @@ struct MeltDataP
      1) struct MeltedCoinP melted_coins[num_melted_coins];
      2) struct TALER_EXCHANGE_DenomPublicKey fresh_pks[num_fresh_coins];
      3) TALER_CNC_KAPPA times:
-        3a) struct TALER_FreshCoinP fresh_coins[num_fresh_coins];
+        3a) struct TALER_PlanchetSecretsP fresh_coins[num_fresh_coins];
   */
 };
 
@@ -204,7 +204,7 @@ struct MeltData
    * Arrays of @e num_fresh_coins with information about the fresh
    * coins to be created, for each cut-and-choose dimension.
    */
-  struct TALER_FreshCoinP *fresh_coins[TALER_CNC_KAPPA];
+  struct TALER_PlanchetSecretsP *fresh_coins[TALER_CNC_KAPPA];
 };
 
 
@@ -236,18 +236,16 @@ free_melted_coin (struct MeltedCoin *mc)
 static void
 free_melt_data (struct MeltData *md)
 {
-  unsigned int i;
-
   free_melted_coin (&md->melted_coin);
   if (NULL != md->fresh_pks)
   {
-    for (i=0;i<md->num_fresh_coins;i++)
+    for (unsigned int i=0;i<md->num_fresh_coins;i++)
       if (NULL != md->fresh_pks[i].rsa_public_key)
         GNUNET_CRYPTO_rsa_public_key_free (md->fresh_pks[i].rsa_public_key);
     GNUNET_free (md->fresh_pks);
   }
 
-  for (i=0;i<TALER_CNC_KAPPA;i++)
+  for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
     GNUNET_free (md->fresh_coins[i]);
   /* Finally, clean up a bit...
      (NOTE: compilers might optimize this away, so this is
@@ -490,15 +488,15 @@ deserialize_denomination_key (struct 
TALER_DenominationPublicKey *dk,
  *        @a buf is NULL, number of bytes required
  */
 static size_t
-serialize_fresh_coin (const struct TALER_FreshCoinP *fc,
+serialize_fresh_coin (const struct TALER_PlanchetSecretsP *fc,
                       char *buf,
                       size_t off)
 {
   if (NULL != buf)
     memcpy (&buf[off],
            fc,
-           sizeof (struct TALER_FreshCoinP));
-  return sizeof (struct TALER_FreshCoinP);
+           sizeof (struct TALER_PlanchetSecretsP));
+  return sizeof (struct TALER_PlanchetSecretsP);
 }
 
 
@@ -512,12 +510,12 @@ serialize_fresh_coin (const struct TALER_FreshCoinP *fc,
  * @return number of bytes read from @a buf, 0 on error
  */
 static size_t
-deserialize_fresh_coin (struct TALER_FreshCoinP *fc,
+deserialize_fresh_coin (struct TALER_PlanchetSecretsP *fc,
                         const char *buf,
                         size_t size,
                         int *ok)
 {
-  if (size < sizeof (struct TALER_FreshCoinP))
+  if (size < sizeof (struct TALER_PlanchetSecretsP))
   {
     GNUNET_break (0);
     *ok = GNUNET_NO;
@@ -525,8 +523,8 @@ deserialize_fresh_coin (struct TALER_FreshCoinP *fc,
   }
   memcpy (fc,
           buf,
-          sizeof (struct TALER_FreshCoinP));
-  return sizeof (struct TALER_FreshCoinP);
+          sizeof (struct TALER_PlanchetSecretsP));
+  return sizeof (struct TALER_PlanchetSecretsP);
 }
 
 
@@ -600,8 +598,6 @@ deserialize_melt_data (const char *buf,
 {
   struct MeltData *md;
   struct MeltDataP mdp;
-  unsigned int i;
-  unsigned int j;
   size_t off;
   int ok;
 
@@ -615,23 +611,23 @@ deserialize_melt_data (const char *buf,
   md->num_fresh_coins = ntohs (mdp.num_fresh_coins);
   md->fresh_pks = GNUNET_new_array (md->num_fresh_coins,
                                     struct TALER_DenominationPublicKey);
-  for (i=0;i<TALER_CNC_KAPPA;i++)
+  for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
     md->fresh_coins[i] = GNUNET_new_array (md->num_fresh_coins,
-                                           struct TALER_FreshCoinP);
+                                           struct TALER_PlanchetSecretsP);
   off = sizeof (struct MeltDataP);
   ok = GNUNET_YES;
   off += deserialize_melted_coin (&md->melted_coin,
                                   &buf[off],
                                   buf_size - off,
                                   &ok);
-  for (i=0;(i<md->num_fresh_coins)&&(GNUNET_YES == ok);i++)
+  for (unsigned int i=0;(i<md->num_fresh_coins)&&(GNUNET_YES == ok);i++)
     off += deserialize_denomination_key (&md->fresh_pks[i],
                                          &buf[off],
                                          buf_size - off,
                                          &ok);
 
-  for (i=0;i<TALER_CNC_KAPPA;i++)
-    for(j=0;(j<md->num_fresh_coins)&&(GNUNET_YES == ok);j++)
+  for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
+    for (unsigned int j=0;(j<md->num_fresh_coins)&&(GNUNET_YES == ok);j++)
       off += deserialize_fresh_coin (&md->fresh_coins[i][j],
                                      &buf[off],
                                      buf_size - off,
@@ -704,8 +700,6 @@ TALER_EXCHANGE_refresh_prepare (const struct 
TALER_CoinSpendPrivateKeyP *melt_pr
 {
   struct MeltData md;
   char *buf;
-  unsigned int i;
-  unsigned int j;
   struct GNUNET_HashContext *hash_context;
   struct TALER_Amount total;
   struct TALER_CoinSpendPublicKeyP coin_pub;
@@ -715,7 +709,7 @@ TALER_EXCHANGE_refresh_prepare (const struct 
TALER_CoinSpendPrivateKeyP *melt_pr
                                       &coin_pub.eddsa_pub);
   hash_context = GNUNET_CRYPTO_hash_context_start ();
   /* build up melt data structure */
-  for (i=0;i<TALER_CNC_KAPPA;i++)
+  for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
   {
     struct GNUNET_CRYPTO_EcdhePrivateKey *tpk;
     struct TALER_TransferPublicKeyP tp;
@@ -747,18 +741,18 @@ TALER_EXCHANGE_refresh_prepare (const struct 
TALER_CoinSpendPrivateKeyP *melt_pr
     = GNUNET_CRYPTO_rsa_signature_dup (melt_sig->rsa_signature);
   md.fresh_pks = GNUNET_new_array (fresh_pks_len,
                                    struct TALER_DenominationPublicKey);
-  for (i=0;i<fresh_pks_len;i++)
+  for (unsigned int i=0;i<fresh_pks_len;i++)
     md.fresh_pks[i].rsa_public_key
       = GNUNET_CRYPTO_rsa_public_key_dup (fresh_pks[i].key.rsa_public_key);
-  for (i=0;i<TALER_CNC_KAPPA;i++)
+  for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
   {
     md.fresh_coins[i] = GNUNET_new_array (fresh_pks_len,
-                                          struct TALER_FreshCoinP);
-    for (j=0;j<fresh_pks_len;j++)
+                                          struct TALER_PlanchetSecretsP);
+    for (unsigned int j=0;j<fresh_pks_len;j++)
     {
-      TALER_setup_fresh_coin (&trans_sec[i],
-                              j,
-                              &md.fresh_coins[i][j]);
+      TALER_planchet_setup_refresh (&trans_sec[i],
+                                    j,
+                                    &md.fresh_coins[i][j]);
     }
   }
 
@@ -766,7 +760,7 @@ TALER_EXCHANGE_refresh_prepare (const struct 
TALER_CoinSpendPrivateKeyP *melt_pr
   GNUNET_assert (GNUNET_OK ==
                 TALER_amount_get_zero (melt_amount->currency,
                                        &total));
-  for (j=0;j<fresh_pks_len;j++)
+  for (unsigned int j=0;j<fresh_pks_len;j++)
   {
     if ( (GNUNET_OK !=
          TALER_amount_add (&total,
@@ -795,7 +789,7 @@ TALER_EXCHANGE_refresh_prepare (const struct 
TALER_CoinSpendPrivateKeyP *melt_pr
 
   /* next, add all of the hashes from the denomination keys to the
      hash_context */
-  for (i=0;i<fresh_pks_len;i++)
+  for (unsigned int i=0;i<fresh_pks_len;i++)
   {
     char *buf;
     size_t buf_size;
@@ -820,28 +814,18 @@ TALER_EXCHANGE_refresh_prepare (const struct 
TALER_CoinSpendPrivateKeyP *melt_pr
                                      sizeof (struct TALER_AmountNBO));
 
   }
-  for (i = 0; i < TALER_CNC_KAPPA; i++)
+  for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)
   {
-    for (j = 0; j < fresh_pks_len; j++)
+    for (unsigned int j = 0; j < fresh_pks_len; j++)
     {
-      const struct TALER_FreshCoinP *fc; /* coin this is about */
-      struct TALER_CoinSpendPublicKeyP coin_pub;
-      struct GNUNET_HashCode coin_hash;
-      char *coin_ev; /* blinded message to be signed (in envelope) for each 
coin */
-      size_t coin_ev_size;
+      const struct TALER_PlanchetSecretsP *fc; /* coin this is about */
+      struct TALER_PlanchetDetail pd;
 
       fc = &md.fresh_coins[i][j];
-      GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
-                                          &coin_pub.eddsa_pub);
-      GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub,
-                          sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
-                          &coin_hash);
-      if (GNUNET_YES !=
-          GNUNET_CRYPTO_rsa_blind (&coin_hash,
-                                   &fc->blinding_key.bks,
-                                   md.fresh_pks[j].rsa_public_key,
-                                   &coin_ev,
-                                   &coin_ev_size))
+      if (GNUNET_OK !=
+          TALER_planchet_prepare (&md.fresh_pks[j],
+                                  fc,
+                                  &pd))
       {
         GNUNET_break_op (0);
         GNUNET_CRYPTO_hash_context_abort (hash_context);
@@ -849,9 +833,9 @@ TALER_EXCHANGE_refresh_prepare (const struct 
TALER_CoinSpendPrivateKeyP *melt_pr
         return NULL;
       }
       GNUNET_CRYPTO_hash_context_read (hash_context,
-                                       coin_ev,
-                                       coin_ev_size);
-      GNUNET_free (coin_ev);
+                                       pd.coin_ev,
+                                       pd.coin_ev_size);
+      GNUNET_free (pd.coin_ev);
     }
   }
   GNUNET_CRYPTO_hash_context_finish (hash_context,
@@ -1293,23 +1277,13 @@ TALER_EXCHANGE_refresh_melt (struct 
TALER_EXCHANGE_Handle *exchange,
     tmp = json_array ();
     for (i=0;i<md->num_fresh_coins;i++)
     {
-      const struct TALER_FreshCoinP *fc = &md->fresh_coins[j][i];
-      struct TALER_CoinSpendPublicKeyP coin_pub;
-      struct GNUNET_HashCode coin_hash;
-      char *coin_ev; /* blinded message to be signed (in envelope) for each 
coin */
-      size_t coin_ev_size;
-
-      GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
-                                          &coin_pub.eddsa_pub);
-      GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub,
-                          sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
-                          &coin_hash);
-      if (GNUNET_YES !=
-          GNUNET_CRYPTO_rsa_blind (&coin_hash,
-                                   &fc->blinding_key.bks,
-                                   md->fresh_pks[i].rsa_public_key,
-                                   &coin_ev,
-                                   &coin_ev_size))
+      const struct TALER_PlanchetSecretsP *fc = &md->fresh_coins[j][i];
+      struct TALER_PlanchetDetail pd;
+
+      if (GNUNET_OK !=
+          TALER_planchet_prepare (&md->fresh_pks[i],
+                                  fc,
+                                  &pd))
       {
         /* This should have been noticed during the preparation stage. */
         GNUNET_break (0);
@@ -1322,9 +1296,9 @@ TALER_EXCHANGE_refresh_melt (struct TALER_EXCHANGE_Handle 
*exchange,
       }
       GNUNET_assert (0 ==
                      json_array_append_new (tmp,
-                                            GNUNET_JSON_from_data (coin_ev,
-                                                                   
coin_ev_size)));
-      GNUNET_free (coin_ev);
+                                            GNUNET_JSON_from_data (pd.coin_ev,
+                                                                   
pd.coin_ev_size)));
+      GNUNET_free (pd.coin_ev);
     }
     GNUNET_assert (0 ==
                    json_array_append_new (coin_evs,
@@ -1506,17 +1480,17 @@ refresh_reveal_ok (struct 
TALER_EXCHANGE_RefreshRevealHandle *rrh,
   }
   for (i=0;i<rrh->md->num_fresh_coins;i++)
   {
-    const struct TALER_FreshCoinP *fc;
+    const struct TALER_PlanchetSecretsP *fc;
     struct TALER_DenominationPublicKey *pk;
     json_t *jsonai;
     struct GNUNET_CRYPTO_RsaSignature *blind_sig;
-    struct GNUNET_CRYPTO_RsaSignature *sig;
     struct TALER_CoinSpendPublicKeyP coin_pub;
     struct GNUNET_HashCode coin_hash;
     struct GNUNET_JSON_Specification spec[] = {
       GNUNET_JSON_spec_rsa_signature ("ev_sig", &blind_sig),
       GNUNET_JSON_spec_end()
     };
+    struct TALER_FreshCoin coin;
 
     fc = &rrh->md->fresh_coins[rrh->noreveal_index][i];
     pk = &rrh->md->fresh_pks[i];
@@ -1533,31 +1507,28 @@ refresh_reveal_ok (struct 
TALER_EXCHANGE_RefreshRevealHandle *rrh,
       return GNUNET_SYSERR;
     }
 
-    /* unblind the signature */
-    sig = GNUNET_CRYPTO_rsa_unblind (blind_sig,
-                                    &fc->blinding_key.bks,
-                                     pk->rsa_public_key);
-    GNUNET_CRYPTO_rsa_signature_free (blind_sig);
-
-    /* verify the signature */
+    /* needed to verify the signature, and we didn't store it earlier,
+       hence recomputing it here... */
     GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
                                         &coin_pub.eddsa_pub);
     GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub,
                         sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
                         &coin_hash);
-
     if (GNUNET_OK !=
-        GNUNET_CRYPTO_rsa_verify (&coin_hash,
-                                  sig,
-                                  pk->rsa_public_key))
+        TALER_planchet_to_coin (pk,
+                                blind_sig,
+                                fc,
+                                &coin_hash,
+                                &coin))
     {
       GNUNET_break_op (0);
-      GNUNET_CRYPTO_rsa_signature_free (sig);
+      GNUNET_CRYPTO_rsa_signature_free (blind_sig);
       GNUNET_JSON_parse_free (outer_spec);
       return GNUNET_SYSERR;
     }
-    coin_privs[i] = fc->coin_priv;
-    sigs[i].rsa_signature = sig;
+    GNUNET_CRYPTO_rsa_signature_free (blind_sig);
+    coin_privs[i] = coin.coin_priv;
+    sigs[i] = coin.sig;
   }
   GNUNET_JSON_parse_free (outer_spec);
   return GNUNET_OK;
diff --git a/src/exchange-lib/exchange_api_refresh_link.c 
b/src/exchange-lib/exchange_api_refresh_link.c
index 5b7f686..4cefec5 100644
--- a/src/exchange-lib/exchange_api_refresh_link.c
+++ b/src/exchange-lib/exchange_api_refresh_link.c
@@ -99,7 +99,7 @@ parse_refresh_link_coin (const struct 
TALER_EXCHANGE_RefreshLinkHandle *rlh,
     GNUNET_JSON_spec_end()
   };
   struct TALER_TransferSecretP secret;
-  struct TALER_FreshCoinP fc;
+  struct TALER_PlanchetSecretsP fc;
 
   /* parse reply */
   if (GNUNET_OK !=
@@ -114,7 +114,7 @@ parse_refresh_link_coin (const struct 
TALER_EXCHANGE_RefreshLinkHandle *rlh,
   TALER_link_recover_transfer_secret (trans_pub,
                                       &rlh->coin_priv,
                                       &secret);
-  TALER_setup_fresh_coin (&secret,
+  TALER_planchet_setup_refresh (&secret,
                           coin_num,
                           &fc);
 
diff --git a/src/exchange-lib/exchange_api_reserve.c 
b/src/exchange-lib/exchange_api_reserve.c
index 22e0e3d..ef505d8 100644
--- a/src/exchange-lib/exchange_api_reserve.c
+++ b/src/exchange-lib/exchange_api_reserve.c
@@ -693,9 +693,9 @@ struct TALER_EXCHANGE_ReserveWithdrawHandle
   TALER_EXCHANGE_ReserveWithdrawResultCallback cb;
 
   /**
-   * Key used to blind the value.
+   * Secrets of the planchet.
    */
-  struct TALER_DenominationBlindingKeyP blinding_key;
+  struct TALER_PlanchetSecretsP ps;
 
   /**
    * Denomination key we are withdrawing.
@@ -739,8 +739,7 @@ reserve_withdraw_ok (struct 
TALER_EXCHANGE_ReserveWithdrawHandle *wsh,
                      const json_t *json)
 {
   struct GNUNET_CRYPTO_RsaSignature *blind_sig;
-  struct GNUNET_CRYPTO_RsaSignature *sig;
-  struct TALER_DenominationSignature dsig;
+  struct TALER_FreshCoin fc;
   struct GNUNET_JSON_Specification spec[] = {
     GNUNET_JSON_spec_rsa_signature ("ev_sig", &blind_sig),
     GNUNET_JSON_spec_end()
@@ -754,29 +753,28 @@ reserve_withdraw_ok (struct 
TALER_EXCHANGE_ReserveWithdrawHandle *wsh,
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
-  sig = GNUNET_CRYPTO_rsa_unblind (blind_sig,
-                                   &wsh->blinding_key.bks,
-                                   wsh->pk->key.rsa_public_key);
-  GNUNET_CRYPTO_rsa_signature_free (blind_sig);
   if (GNUNET_OK !=
-      GNUNET_CRYPTO_rsa_verify (&wsh->c_hash,
-                                sig,
-                                wsh->pk->key.rsa_public_key))
+      TALER_planchet_to_coin (&wsh->pk->key,
+                              blind_sig,
+                              &wsh->ps,
+                              &wsh->c_hash,
+                              &fc))
   {
     GNUNET_break_op (0);
-    GNUNET_CRYPTO_rsa_signature_free (sig);
+    GNUNET_JSON_parse_free (spec);
     return GNUNET_SYSERR;
   }
+  GNUNET_JSON_parse_free (spec);
+
   /* signature is valid, return it to the application */
-  dsig.rsa_signature = sig;
   wsh->cb (wsh->cb_cls,
            MHD_HTTP_OK,
           TALER_EC_NONE,
-           &dsig,
+           &fc.sig,
            json);
   /* make sure callback isn't called again after return */
   wsh->cb = NULL;
-  GNUNET_CRYPTO_rsa_signature_free (sig);
+  GNUNET_CRYPTO_rsa_signature_free (fc.sig.rsa_signature);
   return GNUNET_OK;
 }
 
@@ -978,9 +976,7 @@ handle_reserve_withdraw_finished (void *cls,
  * @param exchange the exchange handle; the exchange must be ready to operate
  * @param pk kind of coin to create
  * @param reserve_priv private key of the reserve to withdraw from
- * @param coin_priv where to fetch the coin's private key,
- *        caller must have committed this value to disk before the call (with 
@a pk)
- * @param blinding_key where to fetch the coin's blinding key
+ * @param ps secrets of the planchet
  *        caller must have committed this value to disk before the call (with 
@a pk)
  * @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
@@ -992,44 +988,33 @@ struct TALER_EXCHANGE_ReserveWithdrawHandle *
 TALER_EXCHANGE_reserve_withdraw (struct TALER_EXCHANGE_Handle *exchange,
                                  const struct TALER_EXCHANGE_DenomPublicKey 
*pk,
                                  const struct TALER_ReservePrivateKeyP 
*reserve_priv,
-                                 const struct TALER_CoinSpendPrivateKeyP 
*coin_priv,
-                                 const struct TALER_DenominationBlindingKeyP 
*blinding_key,
+                                 const struct TALER_PlanchetSecretsP *ps,
                                  TALER_EXCHANGE_ReserveWithdrawResultCallback 
res_cb,
                                  void *res_cb_cls)
 {
   struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh;
   struct TALER_WithdrawRequestPS req;
   struct TALER_ReserveSignatureP reserve_sig;
-  struct TALER_CoinSpendPublicKeyP coin_pub;
   struct GNUNET_CURL_Context *ctx;
   struct TALER_Amount amount_with_fee;
-  char *coin_ev;
-  size_t coin_ev_size;
   json_t *withdraw_obj;
   CURL *eh;
+  struct TALER_PlanchetDetail pd;
 
+  if (GNUNET_OK !=
+      TALER_planchet_prepare (&pk->key,
+                              ps,
+                              &pd))
+  {
+    GNUNET_break_op (0);
+    return NULL;
+  }
   wsh = GNUNET_new (struct TALER_EXCHANGE_ReserveWithdrawHandle);
   wsh->exchange = exchange;
   wsh->cb = res_cb;
   wsh->cb_cls = res_cb_cls;
   wsh->pk = pk;
-
-  GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
-                                      &coin_pub.eddsa_pub);
-  GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub,
-                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
-                      &wsh->c_hash);
-  if (GNUNET_YES !=
-      GNUNET_CRYPTO_rsa_blind (&wsh->c_hash,
-                               &blinding_key->bks,
-                               pk->key.rsa_public_key,
-                               &coin_ev,
-                               &coin_ev_size))
-  {
-    GNUNET_break_op (0);
-    GNUNET_free (wsh);
-    return NULL;
-  }
+  wsh->c_hash = pd.c_hash;
   GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
                                       &wsh->reserve_pub.eddsa_pub);
   req.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS));
@@ -1042,7 +1027,7 @@ TALER_EXCHANGE_reserve_withdraw (struct 
TALER_EXCHANGE_Handle *exchange,
   {
     /* exchange gave us denomination keys that overflow like this!? */
     GNUNET_break_op (0);
-    GNUNET_free (coin_ev);
+    GNUNET_free (pd.coin_ev);
     GNUNET_free (wsh);
     return NULL;
   }
@@ -1050,10 +1035,9 @@ TALER_EXCHANGE_reserve_withdraw (struct 
TALER_EXCHANGE_Handle *exchange,
                      &amount_with_fee);
   TALER_amount_hton (&req.withdraw_fee,
                      &pk->fee_withdraw);
-  GNUNET_CRYPTO_rsa_public_key_hash (pk->key.rsa_public_key,
-                                     &req.h_denomination_pub);
-  GNUNET_CRYPTO_hash (coin_ev,
-                      coin_ev_size,
+  req.h_denomination_pub = pd.denom_pub_hash;
+  GNUNET_CRYPTO_hash (pd.coin_ev,
+                      pd.coin_ev_size,
                       &req.h_coin_envelope);
   GNUNET_assert (GNUNET_OK ==
                  GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv,
@@ -1062,11 +1046,11 @@ TALER_EXCHANGE_reserve_withdraw (struct 
TALER_EXCHANGE_Handle *exchange,
   withdraw_obj = json_pack ("{s:o, s:o," /* denom_pub and coin_ev */
                             " s:o, s:o}",/* reserve_pub and reserve_sig */
                             "denom_pub", GNUNET_JSON_from_rsa_public_key 
(pk->key.rsa_public_key),
-                            "coin_ev", GNUNET_JSON_from_data (coin_ev,
-                                                              coin_ev_size),
+                            "coin_ev", GNUNET_JSON_from_data (pd.coin_ev,
+                                                              pd.coin_ev_size),
                             "reserve_pub", GNUNET_JSON_from_data_auto 
(&wsh->reserve_pub),
                             "reserve_sig", GNUNET_JSON_from_data_auto 
(&reserve_sig));
-  GNUNET_free (coin_ev);
+  GNUNET_free (pd.coin_ev);
   if (NULL == withdraw_obj)
   {
     GNUNET_break (0);
@@ -1074,7 +1058,7 @@ TALER_EXCHANGE_reserve_withdraw (struct 
TALER_EXCHANGE_Handle *exchange,
   }
 
 
-  wsh->blinding_key = *blinding_key;
+  wsh->ps = *ps;
   wsh->url = MAH_path_to_url (exchange, "/reserve/withdraw");
 
   eh = curl_easy_init ();
diff --git a/src/exchange-lib/test_exchange_api.c 
b/src/exchange-lib/test_exchange_api.c
index 70fb3ff..7c0dfa9 100644
--- a/src/exchange-lib/test_exchange_api.c
+++ b/src/exchange-lib/test_exchange_api.c
@@ -341,14 +341,9 @@ struct Command
       struct TALER_DenominationSignature sig;
 
       /**
-       * Set (by the interpreter) to the coin's private key.
+       * Private key material of the coin, set by the interpreter.
        */
-      struct TALER_CoinSpendPrivateKeyP coin_priv;
-
-      /**
-       * Blinding key used for the operation.
-       */
-      struct TALER_DenominationBlindingKeyP blinding_key;
+      struct TALER_PlanchetSecretsP ps;
 
       /**
        * Withdraw handle (while operation is running).
@@ -1984,7 +1979,7 @@ get_public_key_from_coin_command (const struct Command 
*coin,
   switch (coin->oc)
   {
   case OC_WITHDRAW_SIGN:
-    GNUNET_CRYPTO_eddsa_key_get_public 
(&coin->details.reserve_withdraw.coin_priv.eddsa_priv,
+    GNUNET_CRYPTO_eddsa_key_get_public 
(&coin->details.reserve_withdraw.ps.coin_priv.eddsa_priv,
                                         &coin_pub->eddsa_pub);
     break;
   case OC_REFRESH_REVEAL:
@@ -2016,7 +2011,6 @@ interpreter_run (void *cls)
   struct Command *cmd = &is->commands[is->ip];
   const struct Command *ref;
   struct TALER_ReservePublicKeyP reserve_pub;
-  struct TALER_CoinSpendPublicKeyP coin_pub;
   struct TALER_Amount amount;
   struct GNUNET_TIME_Absolute execution_date;
   json_t *sender_details;
@@ -2165,27 +2159,14 @@ interpreter_run (void *cls)
       return;
     }
 
-    /* create coin's private key */
-    {
-      struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
-
-      priv = GNUNET_CRYPTO_eddsa_key_create ();
-      cmd->details.reserve_withdraw.coin_priv.eddsa_priv = *priv;
-      GNUNET_free (priv);
-    }
-    GNUNET_CRYPTO_eddsa_key_get_public 
(&cmd->details.reserve_withdraw.coin_priv.eddsa_priv,
-                                        &coin_pub.eddsa_pub);
-    GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
-                               &cmd->details.reserve_withdraw.blinding_key,
-                               sizeof 
(cmd->details.reserve_withdraw.blinding_key));
+    TALER_planchet_setup_random (&cmd->details.reserve_withdraw.ps);
     cmd->details.reserve_withdraw.wsh
       = TALER_EXCHANGE_reserve_withdraw (exchange,
-                                     cmd->details.reserve_withdraw.pk,
-                                     
&ref->details.admin_add_incoming.reserve_priv,
-                                     &cmd->details.reserve_withdraw.coin_priv,
-                                     
&cmd->details.reserve_withdraw.blinding_key,
-                                     &reserve_withdraw_cb,
-                                     is);
+                                         cmd->details.reserve_withdraw.pk,
+                                         
&ref->details.admin_add_incoming.reserve_priv,
+                                         &cmd->details.reserve_withdraw.ps,
+                                         &reserve_withdraw_cb,
+                                         is);
     if (NULL == cmd->details.reserve_withdraw.wsh)
     {
       GNUNET_break (0);
@@ -2217,7 +2198,7 @@ interpreter_run (void *cls)
       switch (ref->oc)
       {
       case OC_WITHDRAW_SIGN:
-        coin_priv = &ref->details.reserve_withdraw.coin_priv;
+        coin_priv = &ref->details.reserve_withdraw.ps.coin_priv;
         coin_pk = ref->details.reserve_withdraw.pk;
         coin_pk_sig = &ref->details.reserve_withdraw.sig;
         break;
@@ -2376,7 +2357,7 @@ interpreter_run (void *cls)
         GNUNET_assert (NULL != ref);
         GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc);
 
-        melt_priv = ref->details.reserve_withdraw.coin_priv;
+        melt_priv = ref->details.reserve_withdraw.ps.coin_priv;
         if (GNUNET_OK !=
             TALER_string_to_amount (md->amount,
                                     &melt_amount))
@@ -2478,7 +2459,7 @@ interpreter_run (void *cls)
     /* finally, use private key from withdraw sign command */
     cmd->details.refresh_link.rlh
       = TALER_EXCHANGE_refresh_link (exchange,
-                                     &ref->details.reserve_withdraw.coin_priv,
+                                     
&ref->details.reserve_withdraw.ps.coin_priv,
                                      &link_cb,
                                      is);
     if (NULL == cmd->details.refresh_link.rlh)
@@ -2745,8 +2726,7 @@ interpreter_run (void *cls)
         = TALER_EXCHANGE_payback (exchange,
                                   ref->details.reserve_withdraw.pk,
                                   &ref->details.reserve_withdraw.sig,
-                                  &ref->details.reserve_withdraw.coin_priv,
-                                  &ref->details.reserve_withdraw.blinding_key,
+                                  &ref->details.reserve_withdraw.ps,
                                   &payback_cb,
                                   is);
       return;
diff --git a/src/exchange/taler-exchange-httpd_refresh_reveal.c 
b/src/exchange/taler-exchange-httpd_refresh_reveal.c
index 5d857fc..a64ec1c 100644
--- a/src/exchange/taler-exchange-httpd_refresh_reveal.c
+++ b/src/exchange/taler-exchange-httpd_refresh_reveal.c
@@ -171,13 +171,13 @@ check_commitment (struct MHD_Connection *connection,
   /* Check that the commitments for all new coins were correct */
   for (unsigned int j = 0; j < num_newcoins; j++)
   {
-    struct TALER_FreshCoinP fc;
+    struct TALER_PlanchetSecretsP fc;
     struct TALER_CoinSpendPublicKeyP coin_pub;
     struct GNUNET_HashCode h_msg;
     char *buf;
     size_t buf_len;
 
-    TALER_setup_fresh_coin (&transfer_secret,
+    TALER_planchet_setup_refresh (&transfer_secret,
                             j,
                             &fc);
     GNUNET_CRYPTO_eddsa_key_get_public (&fc.coin_priv.eddsa_priv,
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index 9e9352f..d5024e6 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -396,7 +396,83 @@ int
 TALER_test_coin_valid (const struct TALER_CoinPublicInfo *coin_public_info);
 
 
-/* ****************** Refresh crypto primitives ************* */
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Header for serializations of coin-specific information about the
+ * fresh coins we generate.  These are the secrets that arise during
+ * planchet generation, which is the first stage of creating a new
+ * coin.
+ */
+struct TALER_PlanchetSecretsP
+{
+
+  /**
+   * Private key of the coin.
+   */
+  struct TALER_CoinSpendPrivateKeyP coin_priv;
+
+  /**
+   * The blinding key.
+   */
+  struct TALER_DenominationBlindingKeyP blinding_key;
+
+};
+
+GNUNET_NETWORK_STRUCT_END
+
+
+/**
+ * Details about a planchet that the customer wants to obtain
+ * a withdrawal authorization.  This is the information that
+ * will need to be sent to the exchange to obtain the blind
+ * signature required to turn a planchet into a coin.
+ */
+struct TALER_PlanchetDetail
+{
+  /**
+   * Hash of the denomination public key.
+   */
+  struct GNUNET_HashCode denom_pub_hash;
+
+  /**
+   * Hash of the coin's public key.  Kept around so we do not need to
+   * compute it again.  Can be recomputed by hashing the public key
+   * of @a coin_priv if storage is at a premium.
+   */
+  struct GNUNET_HashCode c_hash;
+
+  /**
+   * Blinded coin (see GNUNET_CRYPTO_rsa_blind()).  Note: is malloc()'ed!
+   */
+  char *coin_ev;
+
+  /**
+   * Number of bytes in @a coin_ev.
+   */
+  size_t coin_ev_size;
+};
+
+
+/**
+ * Information about a (fresh) coin, returned from the API when we
+ * finished creating a coin.  Note that @e sig needs to be freed
+ * using the appropriate code.
+ */
+struct TALER_FreshCoin
+{
+
+  /**
+   * The exchange's signature over the coin's public key.
+   */
+  struct TALER_DenominationSignature sig;
+
+  /**
+   * The coin's private key.
+   */
+  struct TALER_CoinSpendPrivateKeyP coin_priv;
+
+};
 
 
 GNUNET_NETWORK_STRUCT_BEGIN
@@ -426,6 +502,7 @@ struct TALER_TransferSecretP
  */
 #define TALER_WIRE_TRANSFER_IDENTIFIER_LEN_STR "32"
 
+
 /**
  * Raw value of a wire transfer subjects, without the checksum.
  */
@@ -472,6 +549,68 @@ struct TALER_WireTransferIdentifierP
 
 GNUNET_NETWORK_STRUCT_END
 
+
+/**
+ * Setup information for a fresh coin, deriving the coin private key
+ * and the blinding factor from the @a secret_seed with a KDF salted
+ * by the @a coin_num_salt.
+ *
+ * @param secret_seed seed to use for KDF to derive coin keys
+ * @param coin_num_salt number of the coin to include in KDF
+ * @param[out] fc value to initialize
+ */
+void
+TALER_planchet_setup_refresh (const struct TALER_TransferSecretP *secret_seed,
+                              unsigned int coin_num_salt,
+                              struct TALER_PlanchetSecretsP *fc);
+
+
+/**
+ * Setup information for a fresh coin.
+ *
+ * @param[out] ps value to initialize
+ */
+void
+TALER_planchet_setup_random (struct TALER_PlanchetSecretsP *ps);
+
+
+/**
+ * Prepare a planchet for tipping.  Creates and blinds a coin.
+ *
+ * @param dk denomination key for the coin to be created
+ * @param ps secret planchet internals (for #TALER_planchet_to_coin)
+ * @param[out] pd set to the planchet detail for TALER_MERCHANT_tip_pickup() 
and
+ *               other withdraw operations
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_planchet_prepare (const struct TALER_DenominationPublicKey *dk,
+                        const struct TALER_PlanchetSecretsP *ps,
+                        struct TALER_PlanchetDetail *pd);
+
+
+/**
+ * Obtain a coin from the planchet's secrets and the blind signature
+ * of the exchange.
+ *
+ * @param dk denomination key, must match what was given to 
#TALER_planchet_prepare()
+ * @param blind_sig blind signature from the exchange
+ * @param ps secrets from #TALER_planchet_prepare()
+ * @param c_hash hash of the coin's public key for verification of the 
signature
+ * @param[out] coin set to the details of the fresh coin
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_planchet_to_coin (const struct TALER_DenominationPublicKey *dk,
+                        const struct GNUNET_CRYPTO_RsaSignature *blind_sig,
+                        const struct TALER_PlanchetSecretsP *ps,
+                        const struct GNUNET_HashCode *c_hash,
+                        struct TALER_FreshCoin *coin);
+
+
+/* ****************** Refresh crypto primitives ************* */
+
+
 /**
  * Given the coin and the transfer private keys, compute the
  * transfer secret.  (Technically, we only need one of the two
@@ -503,7 +642,6 @@ TALER_link_reveal_transfer_secret (const struct 
TALER_TransferPrivateKeyP *trans
                                    struct TALER_TransferSecretP 
*transfer_secret);
 
 
-
 /**
  * Decrypt the shared @a secret from the information in the
  * @a trans_priv and @a coin_pub.
@@ -518,40 +656,4 @@ TALER_link_recover_transfer_secret (const struct 
TALER_TransferPublicKeyP *trans
                                     struct TALER_TransferSecretP 
*transfer_secret);
 
 
-/**
- * Header for serializations of coin-specific information about the
- * fresh coins we generate during a melt.
- */
-struct TALER_FreshCoinP
-{
-
-  /**
-   * Private key of the coin.
-   */
-  struct TALER_CoinSpendPrivateKeyP coin_priv;
-
-  /**
-   * The blinding key.
-   */
-  struct TALER_DenominationBlindingKeyP blinding_key;
-
-};
-
-
-/**
- * Setup information for a fresh coin, deriving the coin private key
- * and the blinding factor from the @a secret_seed with a KDF salted
- * by the @a coin_num_salt.
- *
- * @param secret_seed seed to use for KDF to derive coin keys
- * @param coin_num_salt number of the coin to include in KDF
- * @param[out] fc value to initialize
- */
-void
-TALER_setup_fresh_coin (const struct TALER_TransferSecretP *secret_seed,
-                        unsigned int coin_num_salt,
-                        struct TALER_FreshCoinP *fc);
-
-
-
 #endif
diff --git a/src/include/taler_exchange_service.h 
b/src/include/taler_exchange_service.h
index 814078a..3b4562a 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -976,9 +976,7 @@ typedef void
  * @param exchange the exchange handle; the exchange must be ready to operate
  * @param pk kind of coin to create
  * @param reserve_priv private key of the reserve to withdraw from
- * @param coin_priv where to fetch the coin's private key,
- *        caller must have committed this value to disk before the call (with 
@a pk)
- * @param blinding_key where to fetch the coin's blinding key
+ * @param ps secrets of the planchet
  *        caller must have committed this value to disk before the call (with 
@a pk)
  * @param res_cb the callback to call when the final result for this request 
is available
  * @param res_cb_cls closure for @a res_cb
@@ -990,8 +988,7 @@ struct TALER_EXCHANGE_ReserveWithdrawHandle *
 TALER_EXCHANGE_reserve_withdraw (struct TALER_EXCHANGE_Handle *exchange,
                                  const struct TALER_EXCHANGE_DenomPublicKey 
*pk,
                                  const struct TALER_ReservePrivateKeyP 
*reserve_priv,
-                                 const struct TALER_CoinSpendPrivateKeyP 
*coin_priv,
-                                 const struct TALER_DenominationBlindingKeyP 
*blinding_key,
+                                 const struct TALER_PlanchetSecretsP *ps,
                                  TALER_EXCHANGE_ReserveWithdrawResultCallback 
res_cb,
                                  void *res_cb_cls);
 
@@ -1540,8 +1537,7 @@ typedef void
  * @param exchange the exchange handle; the exchange must be ready to operate
  * @param pk kind of coin to pay back
  * @param denom_sig signature over the coin by the exchange using @a pk
- * @param coin_priv the coin's private key,
- * @param blinding_key where to fetch the coin's blinding key
+ * @param ps secret internals of the original planchet
  * @param payback_cb the callback to call when the final result for this 
request is available
  * @param payback_cb_cls closure for @a payback_cb
  * @return NULL
@@ -1552,8 +1548,7 @@ struct TALER_EXCHANGE_PaybackHandle *
 TALER_EXCHANGE_payback (struct TALER_EXCHANGE_Handle *exchange,
                         const struct TALER_EXCHANGE_DenomPublicKey *pk,
                         const struct TALER_DenominationSignature *denom_sig,
-                        const struct TALER_CoinSpendPrivateKeyP *coin_priv,
-                        const struct TALER_DenominationBlindingKeyP 
*blinding_key,
+                        const struct TALER_PlanchetSecretsP *ps,
                         TALER_EXCHANGE_PaybackResultCallback payback_cb,
                         void *payback_cb_cls);
 
diff --git a/src/include/taler_util.h b/src/include/taler_util.h
index 34e07a3..84d4f5d 100644
--- a/src/include/taler_util.h
+++ b/src/include/taler_util.h
@@ -134,6 +134,4 @@ const struct GNUNET_OS_ProjectData *
 TALER_project_data_default (void);
 
 
-
-
 #endif
diff --git a/src/util/crypto.c b/src/util/crypto.c
index ce5bfac..efc7485 100644
--- a/src/util/crypto.c
+++ b/src/util/crypto.c
@@ -171,23 +171,49 @@ TALER_link_recover_transfer_secret (const struct 
TALER_TransferPublicKeyP *trans
 
 
 /**
+ * Set the bits in the private EdDSA key so that they match
+ * the specification.
+ *
+ * @param[in,out] pk private key to patch
+ */
+static void
+patch_private_key (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
+{
+  uint8_t *p = (uint8_t *) pk;
+
+  /* Taken from like 170-172 of libgcrypt/cipher/ecc.c
+   * We note that libgcrypt stores the private key in the reverse order
+   * from many Ed25519 implementatons. */
+  p[0] &= 0x7f;  /* Clear bit 255. */
+  p[0] |= 0x40;  /* Set bit 254.   */
+  p[31] &= 0xf8; /* Clear bits 2..0 so that d mod 8 == 0  */
+
+  /* FIXME: Run GNUNET_CRYPTO_ecdhe_key_create several times and inspect
+   * the output to verify that the same bits are set and cleared.
+   * Is it worth also adding a test case that runs gcry_pk_testkey on
+   * this key after first parsing it into libgcrypt's s-expression mess
+   * ala decode_private_eddsa_key from gnunet/src/util/crypto_ecc.c?
+   * It'd run check_secret_key but not test_keys from libgcrypt/cipher/ecc.c */
+}
+
+
+/**
  * Setup information for a fresh coin.
  *
  * @param secret_seed seed to use for KDF to derive coin keys
  * @param coin_num_salt number of the coin to include in KDF
- * @param[out] fc value to initialize
+ * @param[out] ps value to initialize
  */
 void
-TALER_setup_fresh_coin (const struct TALER_TransferSecretP *secret_seed,
-                        unsigned int coin_num_salt,
-                        struct TALER_FreshCoinP *fc)
+TALER_planchet_setup_refresh (const struct TALER_TransferSecretP *secret_seed,
+                              unsigned int coin_num_salt,
+                              struct TALER_PlanchetSecretsP *ps)
 {
   uint32_t be_salt = htonl (coin_num_salt);
-  uint8_t *p;
 
   GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CRYPTO_kdf (fc,
-                                    sizeof (*fc),
+                 GNUNET_CRYPTO_kdf (ps,
+                                    sizeof (*ps),
                                     &be_salt,
                                     sizeof (be_salt),
                                     secret_seed,
@@ -195,24 +221,97 @@ TALER_setup_fresh_coin (const struct 
TALER_TransferSecretP *secret_seed,
                                     "taler-coin-derivation",
                                     strlen ("taler-coin-derivation"),
                                     NULL, 0));
+  patch_private_key (&ps->coin_priv.eddsa_priv);
+}
 
-  /* Taken from like 170-172 of libgcrypt/cipher/ecc.c
-   * We note that libgcrypt stores the private key in the reverse order
-   * from many Ed25519 implementatons. */
-  p = (uint8_t *) &(fc->coin_priv);
-  p[0] &= 0x7f;  /* Clear bit 255. */
-  p[0] |= 0x40;  /* Set bit 254.   */
-  p[31] &= 0xf8; /* Clear bits 2..0 so that d mod 8 == 0  */
 
-  /* FIXME: Run GNUNET_CRYPTO_ecdhe_key_create several times and inspect
-   * the output to verify that the same bits are set and cleared.
-   * Is it worth also adding a test case that runs gcry_pk_testkey on
-   * this key after first parsing it into libgcrypt's s-expression mess
-   * ala decode_private_eddsa_key from gnunet/src/util/crypto_ecc.c?
-   * It'd run check_secret_key but not test_keys from libgcrypt/cipher/ecc.c */
+/**
+ * Setup information for a fresh coin.
+ *
+ * @param[out] ps value to initialize
+ */
+void
+TALER_planchet_setup_random (struct TALER_PlanchetSecretsP *ps)
+{
+  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
+                              ps,
+                              sizeof (*ps));
+  patch_private_key (&ps->coin_priv.eddsa_priv);
+}
+
+
+/**
+ * Prepare a planchet for tipping.  Creates and blinds a coin.
+ *
+ * @param dk denomination key for the coin to be created
+ * @param ps secret planchet internals (for #TALER_planchet_to_coin)
+ * @param[out] pd set to the planchet detail for TALER_MERCHANT_tip_pickup() 
and
+ *               other withdraw operations
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_planchet_prepare (const struct TALER_DenominationPublicKey *dk,
+                        const struct TALER_PlanchetSecretsP *ps,
+                        struct TALER_PlanchetDetail *pd)
+{
+  struct TALER_CoinSpendPublicKeyP coin_pub;
+
+  GNUNET_CRYPTO_eddsa_key_get_public (&ps->coin_priv.eddsa_priv,
+                                      &coin_pub.eddsa_pub);
+  GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub,
+                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
+                      &pd->c_hash);
+  if (GNUNET_YES !=
+      GNUNET_CRYPTO_rsa_blind (&pd->c_hash,
+                               &ps->blinding_key.bks,
+                               dk->rsa_public_key,
+                               &pd->coin_ev,
+                               &pd->coin_ev_size))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  GNUNET_CRYPTO_rsa_public_key_hash (dk->rsa_public_key,
+                                     &pd->denom_pub_hash);
+  return GNUNET_OK;
 }
 
 
+/**
+ * Obtain a coin from the planchet's secrets and the blind signature
+ * of the exchange.
+ *
+ * @param dk denomination key, must match what was given to 
#TALER_planchet_prepare()
+ * @param blind_sig blind signature from the exchange
+ * @param ps secrets from #TALER_planchet_prepare()
+ * @param c_hash hash of the coin's public key for verification of the 
signature
+ * @param[out] coin set to the details of the fresh coin
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_planchet_to_coin (const struct TALER_DenominationPublicKey *dk,
+                        const struct GNUNET_CRYPTO_RsaSignature *blind_sig,
+                        const struct TALER_PlanchetSecretsP *ps,
+                        const struct GNUNET_HashCode *c_hash,
+                        struct TALER_FreshCoin *coin)
+{
+  struct GNUNET_CRYPTO_RsaSignature *sig;
 
+  sig = GNUNET_CRYPTO_rsa_unblind (blind_sig,
+                                   &ps->blinding_key.bks,
+                                   dk->rsa_public_key);
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_rsa_verify (c_hash,
+                                sig,
+                                dk->rsa_public_key))
+  {
+    GNUNET_break_op (0);
+    GNUNET_CRYPTO_rsa_signature_free (sig);
+    return GNUNET_SYSERR;
+  }
+  coin->sig.rsa_signature = sig;
+  coin->coin_priv = ps->coin_priv;
+  return GNUNET_OK;
+}
 
 /* end of crypto.c */
diff --git a/src/util/test_crypto.c b/src/util/test_crypto.c
index f28ae80..4713b3a 100644
--- a/src/util/test_crypto.c
+++ b/src/util/test_crypto.c
@@ -40,8 +40,8 @@ test_high_level ()
   struct TALER_TransferPublicKeyP trans_pub;
   struct TALER_TransferSecretP secret;
   struct TALER_TransferSecretP secret2;
-  struct TALER_FreshCoinP fc1;
-  struct TALER_FreshCoinP fc2;
+  struct TALER_PlanchetSecretsP fc1;
+  struct TALER_PlanchetSecretsP fc2;
 
   pk = GNUNET_CRYPTO_eddsa_key_create ();
   coin_priv.eddsa_priv = *pk;
@@ -70,16 +70,57 @@ test_high_level ()
                 memcmp (&secret,
                         &secret2,
                         sizeof (secret)));
-  TALER_setup_fresh_coin (&secret,
-                          0,
-                          &fc1);
-  TALER_setup_fresh_coin (&secret,
-                          1,
-                          &fc2);
+  TALER_planchet_setup_refresh (&secret,
+                                0,
+                                &fc1);
+  TALER_planchet_setup_refresh (&secret,
+                                1,
+                                &fc2);
   GNUNET_assert (0 !=
                  memcmp (&fc1,
                          &fc2,
-                         sizeof (struct TALER_FreshCoinP)));
+                         sizeof (struct TALER_PlanchetSecretsP)));
+  return 0;
+}
+
+
+/**
+ * Test the basic planchet functionality of creating a fresh planchet
+ * and extracting the respective signature.
+ *
+ * @return 0 on success
+ */
+static int
+test_planchets ()
+{
+  struct TALER_PlanchetSecretsP ps;
+  struct TALER_DenominationPrivateKey dk_priv;
+  struct TALER_DenominationPublicKey dk_pub;
+  struct TALER_PlanchetDetail pd;
+  struct GNUNET_CRYPTO_RsaSignature *blind_sig;
+  struct TALER_FreshCoin coin;
+
+  dk_priv.rsa_private_key = GNUNET_CRYPTO_rsa_private_key_create (1024);
+  dk_pub.rsa_public_key = GNUNET_CRYPTO_rsa_private_key_get_public 
(dk_priv.rsa_private_key);
+  TALER_planchet_setup_random (&ps);
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_planchet_prepare (&dk_pub,
+                                         &ps,
+                                         &pd));
+  blind_sig = GNUNET_CRYPTO_rsa_sign_blinded (dk_priv.rsa_private_key,
+                                              pd.coin_ev,
+                                              pd.coin_ev_size);
+  GNUNET_assert (NULL != blind_sig);
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_planchet_to_coin (&dk_pub,
+                                         blind_sig,
+                                         &ps,
+                                         &pd.c_hash,
+                                         &coin));
+  GNUNET_CRYPTO_rsa_signature_free (blind_sig);
+  GNUNET_CRYPTO_rsa_signature_free (coin.sig.rsa_signature);
+  GNUNET_CRYPTO_rsa_private_key_free (dk_priv.rsa_private_key);
+  GNUNET_CRYPTO_rsa_public_key_free (dk_pub.rsa_public_key);
   return 0;
 }
 
@@ -90,6 +131,8 @@ main(int argc,
 {
   if (0 != test_high_level ())
     return 1;
+  if (0 != test_planchets ())
+    return 1;
   return 0;
 }
 

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]