gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-exchange] 03/03: major API refactoring, adding planc


From: gnunet
Subject: [GNUnet-SVN] [taler-exchange] 03/03: 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
Date: Tue, 31 Oct 2017 14:03:02 +0100

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

grothoff pushed a commit to branch master
in repository exchange.

commit 2f2930f1ba0f1708fc4455c66173fd61188a3369
Author: Christian Grothoff <address@hidden>
AuthorDate: Tue Oct 31 14:02:54 2017 +0100

    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
---
 ChangeLog                                |   6 ++
 src/benchmark/taler-exchange-benchmark.c |   6 +-
 src/exchange-lib/exchange_api_payback.c  |  14 ++-
 src/exchange-lib/exchange_api_refresh.c  | 119 ++++++++------------
 src/exchange-lib/exchange_api_reserve.c  |  82 ++++++--------
 src/exchange-lib/test_exchange_api.c     |  46 +++-----
 src/include/taler_crypto_lib.h           | 180 ++++++++++++++++++++++++-------
 src/include/taler_exchange_service.h     |  13 +--
 src/include/taler_util.h                 |   2 -
 src/util/crypto.c                        | 137 +++++++++++++++++++----
 src/util/test_crypto.c                   |  51 ++++++++-
 11 files changed, 416 insertions(+), 240 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 510b6e4..305747f 100644
--- a/src/exchange-lib/exchange_api_refresh.c
+++ b/src/exchange-lib/exchange_api_refresh.c
@@ -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
@@ -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,7 +611,7 @@ 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_PlanchetSecretsP);
   off = sizeof (struct MeltDataP);
@@ -624,14 +620,14 @@ deserialize_melt_data (const char *buf,
                                   &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_PlanchetSecretsP);
-    for (j=0;j<fresh_pks_len;j++)
+    for (unsigned int j=0;j<fresh_pks_len;j++)
     {
       TALER_planchet_setup_refresh (&trans_sec[i],
-                              j,
-                              &md.fresh_coins[i][j]);
+                                    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_PlanchetSecretsP *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;
+      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,
@@ -1294,22 +1278,12 @@ TALER_EXCHANGE_refresh_melt (struct 
TALER_EXCHANGE_Handle *exchange,
     for (i=0;i<md->num_fresh_coins;i++)
     {
       const struct TALER_PlanchetSecretsP *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))
+      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,
@@ -1510,13 +1484,13 @@ refresh_reveal_ok (struct 
TALER_EXCHANGE_RefreshRevealHandle *rrh,
     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_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/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index 39de34b..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
@@ -516,44 +655,5 @@ TALER_link_recover_transfer_secret (const struct 
TALER_TransferPublicKeyP *trans
                                     const struct TALER_CoinSpendPrivateKeyP 
*coin_priv,
                                     struct TALER_TransferSecretP 
*transfer_secret);
 
-GNUNET_NETWORK_STRUCT_BEGIN
-
-/**
- * Header for serializations of coin-specific information about the
- * fresh coins we generate during a melt.
- */
-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
-
-
-/**
- * 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);
-
-
 
 #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 378b73d..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_planchet_setup_refresh (const struct TALER_TransferSecretP *secret_seed,
-                        unsigned int coin_num_salt,
-                        struct TALER_PlanchetSecretsP *fc)
+                              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_planchet_setup_refresh (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 953ad94..4713b3a 100644
--- a/src/util/test_crypto.c
+++ b/src/util/test_crypto.c
@@ -71,11 +71,11 @@ test_high_level ()
                         &secret2,
                         sizeof (secret)));
   TALER_planchet_setup_refresh (&secret,
-                          0,
-                          &fc1);
+                                0,
+                                &fc1);
   TALER_planchet_setup_refresh (&secret,
-                          1,
-                          &fc2);
+                                1,
+                                &fc2);
   GNUNET_assert (0 !=
                  memcmp (&fc1,
                          &fc2,
@@ -84,12 +84,55 @@ test_high_level ()
 }
 
 
+/**
+ * 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;
+}
+
+
 int
 main(int argc,
      const char *const argv[])
 {
   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]