gnunet-svn
[Top][All Lists]
Advanced

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

[taler-exchange] branch master updated: add batch logic to taler-exchang


From: gnunet
Subject: [taler-exchange] branch master updated: add batch logic to taler-exchange-secmod-cs
Date: Sun, 13 Nov 2022 19:03:59 +0100

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

grothoff pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new 18aba0ab add batch logic to taler-exchange-secmod-cs
18aba0ab is described below

commit 18aba0abbb427a2e0e76ae88f95fef493e74032d
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sun Nov 13 19:03:52 2022 +0100

    add batch logic to taler-exchange-secmod-cs
---
 src/include/taler_crypto_lib.h       |  52 +-
 src/util/crypto_helper_cs.c          |   2 +-
 src/util/taler-exchange-secmod-cs.c  | 913 ++++++++++++++++++++++++++++++-----
 src/util/taler-exchange-secmod-cs.h  |  11 +-
 src/util/taler-exchange-secmod-rsa.c |   4 +-
 5 files changed, 842 insertions(+), 140 deletions(-)

diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index 2f12a47b..8027181f 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -2484,8 +2484,7 @@ struct TALER_CRYPTO_CsSignRequest
 
 
 /**
- * Request helper @a dh to sign @a msg using the public key corresponding to
- * @a h_denom_pub.
+ * Request helper @a dh to sign @a req.
  *
  * This operation will block until the signature has been obtained.  Should
  * this process receive a signal (that is not ignored) while the operation is
@@ -2506,8 +2505,30 @@ TALER_CRYPTO_helper_cs_sign_melt (
 
 
 /**
- * Request helper @a dh to sign @a msg using the public key corresponding to
- * @a h_denom_pub.
+ * Request helper @a dh to batch sign batch @a reqs.
+ *
+ * This operation will block until the signature has been obtained.  Should
+ * this process receive a signal (that is not ignored) while the operation is
+ * pending, the operation will fail.  Note that the helper may still believe
+ * that it created the signature. Thus, signals may result in a small
+ * differences in the signature counters.  Retrying in this case may work.
+ *
+ * @param dh helper process connection
+ * @param reqs array with information about the keys to sign with and the 
values to sign
+ * @param reqs_length length of the @a reqs array
+ * @param[out] bss array set to the blind signatures, must be of length @a 
reqs_length!
+ * @return #TALER_EC_NONE on success
+ */
+enum TALER_ErrorCode
+TALER_CRYPTO_helper_cs_batch_sign_melt (
+  struct TALER_CRYPTO_CsDenominationHelper *dh,
+  const struct TALER_CRYPTO_CsSignRequest *reqs,
+  unsigned int reqs_length,
+  struct TALER_BlindedDenominationSignature *bss);
+
+
+/**
+ * Request helper @a dh to sign @a req.
  *
  * This operation will block until the signature has been obtained.  Should
  * this process receive a signal (that is not ignored) while the operation is
@@ -2527,6 +2548,29 @@ TALER_CRYPTO_helper_cs_sign_withdraw (
   struct TALER_BlindedDenominationSignature *bs);
 
 
+/**
+ * Request helper @a dh to sign batch of @a reqs requests.
+ *
+ * This operation will block until the signature has been obtained.  Should
+ * this process receive a signal (that is not ignored) while the operation is
+ * pending, the operation will fail.  Note that the helper may still believe
+ * that it created the signature. Thus, signals may result in a small
+ * differences in the signature counters.  Retrying in this case may work.
+ *
+ * @param dh helper process connection
+ * @param reqs information about the keys to sign with and the values to sign
+ * @param reqs_length length of the @a reqs array
+ * @param[out] bs array set to the blind signatures, must be of length @a 
reqs_length!
+ * @return #TALER_EC_NONE on success
+ */
+enum TALER_ErrorCode
+TALER_CRYPTO_helper_cs_batch_sign_withdraw (
+  struct TALER_CRYPTO_CsDenominationHelper *dh,
+  const struct TALER_CRYPTO_CsSignRequest *reqs,
+  unsigned int reqs_length,
+  struct TALER_BlindedDenominationSignature *bss);
+
+
 /**
  * Ask the helper to revoke the public key associated with @a h_cs.
  * Will cause the helper to tell all clients that the key is now unavailable,
diff --git a/src/util/crypto_helper_cs.c b/src/util/crypto_helper_cs.c
index 8b7602c0..66ecb26a 100644
--- a/src/util/crypto_helper_cs.c
+++ b/src/util/crypto_helper_cs.c
@@ -493,7 +493,7 @@ more:
       switch (ntohs (hdr->type))
       {
       case TALER_HELPER_CS_MT_RES_SIGNATURE:
-        if (msize < sizeof (struct TALER_CRYPTO_SignResponse))
+        if (msize != sizeof (struct TALER_CRYPTO_SignResponse))
         {
           GNUNET_break_op (0);
           do_disconnect (dh);
diff --git a/src/util/taler-exchange-secmod-cs.c 
b/src/util/taler-exchange-secmod-cs.c
index 176214e3..01f12e14 100644
--- a/src/util/taler-exchange-secmod-cs.c
+++ b/src/util/taler-exchange-secmod-cs.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2021 Taler Systems SA
+  Copyright (C) 2014-2022 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -160,6 +160,164 @@ struct Denomination
 };
 
 
+/**
+ * A semaphore.
+ */
+struct Semaphore
+{
+  /**
+   * Mutex for the semaphore.
+   */
+  pthread_mutex_t mutex;
+
+  /**
+   * Condition variable for the semaphore.
+   */
+  pthread_cond_t cv;
+
+  /**
+   * Counter of the semaphore.
+   */
+  unsigned int ctr;
+};
+
+
+/**
+ * Job in a batch sign request.
+ */
+struct BatchJob;
+
+/**
+ * Handle for a thread that does work in batch signing.
+ */
+struct Worker
+{
+  /**
+   * Kept in a DLL.
+   */
+  struct Worker *prev;
+
+  /**
+   * Kept in a DLL.
+   */
+  struct Worker *next;
+
+  /**
+   * Job this worker should do next.
+   */
+  struct BatchJob *job;
+
+  /**
+   * Semaphore to signal the worker that a job is available.
+   */
+  struct Semaphore sem;
+
+  /**
+   * Handle for this thread.
+   */
+  pthread_t pt;
+
+  /**
+   * Set to true if the worker should terminate.
+   */
+  bool do_shutdown;
+};
+
+
+/**
+ * Job in a batch sign request.
+ */
+struct BatchJob
+{
+
+  /**
+   * Thread doing the work.
+   */
+  struct Worker *worker;
+
+  /**
+   * Semaphore to signal that the job is finished.
+   */
+  struct Semaphore sem;
+
+  /**
+   * Computation status.
+   */
+  enum TALER_ErrorCode ec;
+
+  /**
+   * Which type of request is this?
+   */
+  enum { TYPE_SIGN, TYPE_RDERIVE } type;
+
+  /**
+   * Details depending on @e type.
+   */
+  union
+  {
+
+    /**
+     * Details if @e type is TYPE_SIGN.
+     */
+    struct
+    {
+      /**
+       * Request we are working on.
+       */
+      const struct TALER_CRYPTO_CsSignRequestMessage *sr;
+
+      /**
+       * Result with the signature.
+       */
+      struct TALER_BlindedDenominationCsSignAnswer cs_answer;
+    } sign;
+
+    /**
+     * Details if type is TYPE_RDERIVE.
+     */
+    struct
+    {
+      /**
+       * Request we are answering.
+       */
+      const struct TALER_CRYPTO_CsRDeriveRequest *rdr;
+
+      /**
+       * Pair of points to return.
+       */
+      struct TALER_DenominationCSPublicRPairP rpairp;
+
+    } rderive;
+
+  } details;
+
+};
+
+/**
+ * Head of DLL of workers ready for more work.
+ */
+static struct Worker *worker_head;
+
+/**
+ * Tail of DLL of workers ready for more work.
+ */
+static struct Worker *worker_tail;
+
+/**
+ * Lock for manipulating the worker DLL.
+ */
+static pthread_mutex_t worker_lock;
+
+/**
+ * Total number of workers that were started.
+ */
+static unsigned int workers;
+
+/**
+ * Semaphore used to grab a worker.
+ */
+static struct Semaphore worker_sem;
+
 /**
  * Return value from main().
  */
@@ -225,6 +383,12 @@ static pthread_mutex_t keys_lock;
  */
 static uint64_t key_gen;
 
+/**
+ * Number of workers to launch. Note that connections to
+ * exchanges are NOT workers.
+ */
+static unsigned int max_workers = 16;
+
 
 /**
  * Generate the announcement message for @a dk.
@@ -266,6 +430,110 @@ generate_response (struct DenominationKey *dk)
 }
 
 
+/**
+ * Do the actual signing work.
+ *
+ * @param h_cs key to sign with
+ * @param planchet message to sign
+ * @param for_melt true if for melting
+ * @param[out] cs_sigp set to the CS signature
+ * @return #TALER_EC_NONE on success
+ */
+static enum TALER_ErrorCode
+do_sign (const struct TALER_CsPubHashP *h_cs,
+         const struct TALER_BlindedCsPlanchet *planchet,
+         bool for_melt,
+         struct TALER_BlindedDenominationCsSignAnswer *cs_sigp)
+{
+  struct GNUNET_CRYPTO_CsRSecret r[2];
+  struct DenominationKey *dk;
+
+  GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
+  dk = GNUNET_CONTAINER_multihashmap_get (keys,
+                                          &h_cs->hash);
+  if (NULL == dk)
+  {
+    GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Signing request failed, denomination key %s unknown\n",
+                GNUNET_h2s (&h_cs->hash));
+    return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
+  }
+  if (GNUNET_TIME_absolute_is_future (dk->anchor.abs_time))
+  {
+    GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Signing request failed, denomination key %s is not yet 
valid\n",
+                GNUNET_h2s (&h_cs->hash));
+    return TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Received request to sign over bytes with key %s\n",
+              GNUNET_h2s (&h_cs->hash));
+  GNUNET_assert (dk->rc < UINT_MAX);
+  dk->rc++;
+  GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
+  GNUNET_CRYPTO_cs_r_derive (&planchet->nonce.nonce,
+                             for_melt ? "rm" : "rw",
+                             &dk->denom_priv,
+                             r);
+  cs_sigp->b = GNUNET_CRYPTO_cs_sign_derive (&dk->denom_priv,
+                                             r,
+                                             planchet->c,
+                                             &planchet->nonce.nonce,
+                                             &cs_sigp->s_scalar);
+  GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
+  GNUNET_assert (dk->rc > 0);
+  dk->rc--;
+  GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
+  return TALER_EC_NONE;
+}
+
+
+/**
+ * Generate error response that signing failed.
+ *
+ * @param client client to send response to
+ * @param ec error code to include
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+fail_sign (struct TES_Client *client,
+           enum TALER_ErrorCode ec)
+{
+  struct TALER_CRYPTO_SignFailure sf = {
+    .header.size = htons (sizeof (sf)),
+    .header.type = htons (TALER_HELPER_CS_MT_RES_SIGN_FAILURE),
+    .ec = htonl (ec)
+  };
+
+  return TES_transmit (client->csock,
+                       &sf.header);
+}
+
+
+/**
+ * Generate signature response.
+ *
+ * @param client client to send response to
+ * @param cs_answer signature to send
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+send_signature (struct TES_Client *client,
+                const struct TALER_BlindedDenominationCsSignAnswer *cs_answer)
+{
+  struct TALER_CRYPTO_SignResponse sres;
+
+  sres.header.size = htons (sizeof (sres));
+  sres.header.type = htons (TALER_HELPER_CS_MT_RES_SIGNATURE);
+  sres.reserved = htonl (0);
+  sres.cs_answer = *cs_answer;
+  return TES_transmit (client->csock,
+                       &sres.header);
+}
+
+
 /**
  * Handle @a client request @a sr to create signature. Create the
  * signature using the respective key and return the result to
@@ -279,92 +547,496 @@ static enum GNUNET_GenericReturnValue
 handle_sign_request (struct TES_Client *client,
                      const struct TALER_CRYPTO_CsSignRequestMessage *sr)
 {
-  struct DenominationKey *dk;
-  struct GNUNET_CRYPTO_CsRSecret r[2];
   struct TALER_BlindedDenominationCsSignAnswer cs_answer;
   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
-  bool for_melt;
+  enum TALER_ErrorCode ec;
+  enum GNUNET_GenericReturnValue ret;
+
+  ec = do_sign (&sr->h_cs,
+                &sr->planchet,
+                (0 != ntohl (sr->for_melt)),
+                &cs_answer);
+  if (TALER_EC_NONE != ec)
+  {
+    return fail_sign (client,
+                      ec);
+  }
+  ret = send_signature (client,
+                        &cs_answer);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Sent CS signature after %s\n",
+              GNUNET_TIME_relative2s (
+                GNUNET_TIME_absolute_get_duration (now),
+                GNUNET_YES));
+  return ret;
+}
+
+
+/**
+ * Do the actual deriving work.
+ *
+ * @param h_cs key to sign with
+ * @param nonce nonce to derive from
+ * @param for_melt true if for melting
+ * @param[out] rpairp set to the derived values
+ * @return #TALER_EC_NONE on success
+ */
+static enum TALER_ErrorCode
+do_derive (const struct TALER_CsPubHashP *h_cs,
+           const struct TALER_CsNonce *nonce,
+           bool for_melt,
+           struct TALER_DenominationCSPublicRPairP *rpairp)
+{
+  struct DenominationKey *dk;
+  struct TALER_DenominationCSPrivateRPairP r_priv;
 
   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
   dk = GNUNET_CONTAINER_multihashmap_get (keys,
-                                          &sr->h_cs.hash);
+                                          &h_cs->hash);
   if (NULL == dk)
   {
-    struct TALER_CRYPTO_SignFailure sf = {
-      .header.size = htons (sizeof (sr)),
-      .header.type = htons (TALER_HELPER_CS_MT_RES_SIGN_FAILURE),
-      .ec = htonl (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN)
-    };
-
     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Signing request failed, denomination key %s unknown\n",
-                GNUNET_h2s (&sr->h_cs.hash));
-    return TES_transmit (client->csock,
-                         &sf.header);
+                "R Derive request failed, denomination key %s unknown\n",
+                GNUNET_h2s (&h_cs->hash));
+    return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
   }
   if (GNUNET_TIME_absolute_is_future (dk->anchor.abs_time))
   {
-    /* it is too early */
-    struct TALER_CRYPTO_SignFailure sf = {
-      .header.size = htons (sizeof (sr)),
-      .header.type = htons (TALER_HELPER_CS_MT_RES_SIGN_FAILURE),
-      .ec = htonl (TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY)
-    };
-
     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Signing request failed, denomination key %s is not yet 
valid\n",
-                GNUNET_h2s (&sr->h_cs.hash));
-    return TES_transmit (client->csock,
-                         &sf.header);
+                "R Derive request failed, denomination key %s is not yet 
valid\n",
+                GNUNET_h2s (&h_cs->hash));
+    return TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY;
   }
-  for_melt = (0 != ntohl (sr->for_melt));
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Received request to sign over bytes with key %s\n",
-              GNUNET_h2s (&sr->h_cs.hash));
+              "Received request to derive R with key %s\n",
+              GNUNET_h2s (&h_cs->hash));
   GNUNET_assert (dk->rc < UINT_MAX);
   dk->rc++;
   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
-  GNUNET_CRYPTO_cs_r_derive (&sr->planchet.nonce.nonce,
+  GNUNET_CRYPTO_cs_r_derive (&nonce->nonce,
                              for_melt ? "rm" : "rw",
                              &dk->denom_priv,
-                             r);
-  cs_answer.b = GNUNET_CRYPTO_cs_sign_derive (&dk->denom_priv,
-                                              r,
-                                              sr->planchet.c,
-                                              &sr->planchet.nonce.nonce,
-                                              &cs_answer.s_scalar);
-
+                             r_priv.r);
   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
   GNUNET_assert (dk->rc > 0);
   dk->rc--;
   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
+  GNUNET_CRYPTO_cs_r_get_public (&r_priv.r[0],
+                                 &rpairp->r_pub[0]);
+  GNUNET_CRYPTO_cs_r_get_public (&r_priv.r[1],
+                                 &rpairp->r_pub[1]);
+  return TALER_EC_NONE;
+}
+
+
+/**
+ * Generate derivation response.
+ *
+ * @param client client to send response to
+ * @param r_pub public point value pair to send
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+send_derivation (struct TES_Client *client,
+                 const struct TALER_DenominationCSPublicRPairP *r_pub)
+{
+  struct TALER_CRYPTO_RDeriveResponse rdr = {
+    .header.size = htons (sizeof (struct TALER_CRYPTO_RDeriveResponse)),
+    .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE),
+    .r_pub = *r_pub
+  };
+
+  return TES_transmit (client->csock,
+                       &rdr.header);
+}
+
+
+/**
+ * Initialize a semaphore @a sem with a value of @a val.
+ *
+ * @param[out] sem semaphore to initialize
+ * @param val initial value of the semaphore
+ */
+static void
+sem_init (struct Semaphore *sem,
+          unsigned int val)
+{
+  GNUNET_assert (0 ==
+                 pthread_mutex_init (&sem->mutex,
+                                     NULL));
+  GNUNET_assert (0 ==
+                 pthread_cond_init (&sem->cv,
+                                    NULL));
+  sem->ctr = val;
+}
+
+
+/**
+ * Decrement semaphore, blocks until this is possible.
+ *
+ * @param[in,out] sem semaphore to decrement
+ */
+static void
+sem_down (struct Semaphore *sem)
+{
+  GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex));
+  while (0 == sem->ctr)
   {
-    struct TALER_CRYPTO_SignResponse *sr;
-    size_t tsize;
-    enum GNUNET_GenericReturnValue ret;
+    pthread_cond_wait (&sem->cv,
+                       &sem->mutex);
+  }
+  sem->ctr--;
+  GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex));
+}
 
-    tsize = sizeof (*sr) + sizeof(cs_answer);
-    GNUNET_assert (tsize < UINT16_MAX);
-    sr = GNUNET_malloc (tsize);
-    sr->header.size = htons (tsize);
-    sr->header.type = htons (TALER_HELPER_CS_MT_RES_SIGNATURE);
-    sr->cs_answer = cs_answer;
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Sending CS signature after %s\n",
-                GNUNET_TIME_relative2s (
-                  GNUNET_TIME_absolute_get_duration (now),
-                  GNUNET_YES));
-    ret = TES_transmit (client->csock,
-                        &sr->header);
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Sent CS signature after %s\n",
-                GNUNET_TIME_relative2s (
-                  GNUNET_TIME_absolute_get_duration (now),
-                  GNUNET_YES));
-    GNUNET_free (sr);
-    return ret;
+
+/**
+ * Increment semaphore, blocks until this is possible.
+ *
+ * @param[in,out] sem semaphore to decrement
+ */
+static void
+sem_up (struct Semaphore *sem)
+{
+  GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex));
+  sem->ctr++;
+  GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex));
+  pthread_cond_signal (&sem->cv);
+}
+
+
+/**
+ * Release resources used by @a sem.
+ *
+ * @param[in] sem semaphore to release (except the memory itself)
+ */
+static void
+sem_done (struct Semaphore *sem)
+{
+  GNUNET_break (0 == pthread_cond_destroy (&sem->cv));
+  GNUNET_break (0 == pthread_mutex_destroy (&sem->mutex));
+}
+
+
+/**
+ * Main logic of a worker thread. Grabs work, does it,
+ * grabs more work.
+ *
+ * @param cls a `struct Worker *`
+ * @returns cls
+ */
+static void *
+worker (void *cls)
+{
+  struct Worker *w = cls;
+
+  while (true)
+  {
+    GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
+    GNUNET_CONTAINER_DLL_insert (worker_head,
+                                 worker_tail,
+                                 w);
+    GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
+    sem_up (&worker_sem);
+    sem_down (&w->sem);
+    if (w->do_shutdown)
+      break;
+    {
+      struct BatchJob *bj = w->job;
+
+      switch (bj->type)
+      {
+      case TYPE_SIGN:
+        {
+          const struct TALER_CRYPTO_CsSignRequestMessage *sr
+            = bj->details.sign.sr;
+
+          bj->ec = do_sign (&sr->h_cs,
+                            &sr->planchet,
+                            (0 != ntohl (sr->for_melt)),
+                            &bj->details.sign.cs_answer);
+          break;
+        }
+      case TYPE_RDERIVE:
+        {
+          const struct TALER_CRYPTO_CsRDeriveRequest *rdr
+            = bj->details.rderive.rdr;
+          bj->ec = do_derive (&rdr->h_cs,
+                              &rdr->nonce,
+                              (0 != ntohl (rdr->for_melt)),
+                              &bj->details.rderive.rpairp);
+          break;
+        }
+      }
+      sem_up (&bj->sem);
+      w->job = NULL;
+    }
+  }
+  return w;
+}
+
+
+/**
+ * Start batch job @a bj to sign @a sr.
+ *
+ * @param sr signature request to answer
+ * @param[out] bj job data structure
+ */
+static void
+start_sign_job (const struct TALER_CRYPTO_CsSignRequestMessage *sr,
+                struct BatchJob *bj)
+{
+  sem_init (&bj->sem,
+            0);
+  bj->type = TYPE_SIGN;
+  bj->details.sign.sr = sr;
+  sem_down (&worker_sem);
+  GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
+  bj->worker = worker_head;
+  GNUNET_CONTAINER_DLL_remove (worker_head,
+                               worker_tail,
+                               bj->worker);
+  GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
+  bj->worker->job = bj;
+  sem_up (&bj->worker->sem);
+}
+
+
+/**
+ * Start batch job @a bj to derive @a rdr.
+ *
+ * @param rdr derivation request to answer
+ * @param[out] bj job data structure
+ */
+static void
+start_derive_job (const struct TALER_CRYPTO_CsRDeriveRequest *rdr,
+                  struct BatchJob *bj)
+{
+  sem_init (&bj->sem,
+            0);
+  bj->type = TYPE_RDERIVE;
+  bj->details.rderive.rdr = rdr;
+  sem_down (&worker_sem);
+  GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
+  bj->worker = worker_head;
+  GNUNET_CONTAINER_DLL_remove (worker_head,
+                               worker_tail,
+                               bj->worker);
+  GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
+  bj->worker->job = bj;
+  sem_up (&bj->worker->sem);
+}
+
+
+/**
+ * Finish a job @a bj for a @a client.
+ *
+ * @param client who made the request
+ * @param[in,out] bj job to finish
+ */
+static void
+finish_job (struct TES_Client *client,
+            struct BatchJob *bj)
+{
+  sem_down (&bj->sem);
+  sem_done (&bj->sem);
+  if (TALER_EC_NONE != bj->ec)
+  {
+    fail_sign (client,
+               bj->ec);
+    return;
+  }
+  switch (bj->type)
+  {
+  case TYPE_SIGN:
+    send_signature (client,
+                    &bj->details.sign.cs_answer);
+    break;
+  case TYPE_RDERIVE:
+    send_derivation (client,
+                     &bj->details.rderive.rpairp);
+    break;
+  }
+}
+
+
+/**
+ * Handle @a client request @a sr to create a batch of signature. Creates the
+ * signatures using the respective key and return the results to the client.
+ *
+ * @param client the client making the request
+ * @param bsr the request details
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+handle_batch_sign_request (struct TES_Client *client,
+                           const struct TALER_CRYPTO_BatchSignRequest *bsr)
+{
+  uint32_t bs = ntohl (bsr->batch_size);
+  uint16_t size = ntohs (bsr->header.size) - sizeof (*bsr);
+  const void *off = (const void *) &bsr[1];
+  unsigned int idx = 0;
+  struct BatchJob jobs[bs];
+  bool failure = false;
+
+  if (bs > TALER_MAX_FRESH_COINS)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  while ( (bs > 0) &&
+          (size > sizeof (struct TALER_CRYPTO_CsSignRequestMessage)) )
+  {
+    const struct TALER_CRYPTO_CsSignRequestMessage *sr = off;
+    uint16_t s = ntohs (sr->header.size);
+
+    if (s > size)
+    {
+      failure = true;
+      bs = idx;
+      break;
+    }
+    start_sign_job (sr,
+                    &jobs[idx++]);
+    off += s;
+    size -= s;
+  }
+  for (unsigned int i = 0; i<bs; i++)
+    finish_job (client,
+                &jobs[i]);
+  if (failure)
+  {
+    struct TALER_CRYPTO_SignFailure sf = {
+      .header.size = htons (sizeof (sf)),
+      .header.type = htons (TALER_HELPER_CS_MT_RES_BATCH_SIGN_FAILURE),
+      .ec = htonl (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE)
+    };
+
+    GNUNET_break (0);
+    return TES_transmit (client->csock,
+                         &sf.header);
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle @a client request @a sr to create a batch of derivations. Creates the
+ * derivations using the respective key and return the results to the client.
+ *
+ * @param client the client making the request
+ * @param bdr the request details
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+handle_batch_derive_request (struct TES_Client *client,
+                             const struct TALER_CRYPTO_BatchDeriveRequest *bdr)
+{
+  uint32_t bs = ntohl (bdr->batch_size);
+  uint16_t size = ntohs (bdr->header.size) - sizeof (*bdr);
+  const void *off = (const void *) &bdr[1];
+  unsigned int idx = 0;
+  struct BatchJob jobs[bs];
+  bool failure = false;
+
+  if (bs > TALER_MAX_FRESH_COINS)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  while ( (bs > 0) &&
+          (size > sizeof (struct TALER_CRYPTO_CsRDeriveRequest)) )
+  {
+    const struct TALER_CRYPTO_CsRDeriveRequest *rdr = off;
+    uint16_t s = ntohs (rdr->header.size);
+
+    if ( (s > size) ||
+         (s != sizeof (*rdr)) )
+    {
+      failure = true;
+      bs = idx;
+      break;
+    }
+    start_derive_job (rdr,
+                      &jobs[idx++]);
+    off += s;
+    size -= s;
+  }
+  for (unsigned int i = 0; i<bs; i++)
+    finish_job (client,
+                &jobs[i]);
+  if (failure)
+  {
+    struct TALER_CRYPTO_SignFailure sf = {
+      .header.size = htons (sizeof (sf)),
+      .header.type = htons (TALER_HELPER_CS_MT_RES_BATCH_RDERIVE_FAILURE),
+      .ec = htonl (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE)
+    };
+
+    GNUNET_break (0);
+    return TES_transmit (client->csock,
+                         &sf.header);
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Start worker thread for batch processing.
+ *
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+start_worker (void)
+{
+  struct Worker *w;
+
+  w = GNUNET_new (struct Worker);
+  sem_init (&w->sem,
+            0);
+  if (0 != pthread_create (&w->pt,
+                           NULL,
+                           &worker,
+                           w))
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+                         "pthread_create");
+    GNUNET_free (w);
+    return GNUNET_SYSERR;
+  }
+  workers++;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Stop all worker threads.
+ */
+static void
+stop_workers (void)
+{
+  while (workers > 0)
+  {
+    struct Worker *w;
+    void *result;
+
+    sem_down (&worker_sem);
+    GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
+    w = worker_head;
+    GNUNET_CONTAINER_DLL_remove (worker_head,
+                                 worker_tail,
+                                 w);
+    GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
+    w->do_shutdown = true;
+    sem_up (&w->sem);
+    pthread_join (w->pt,
+                  &result);
+    GNUNET_assert (result == w);
+    sem_done (&w->sem);
+    GNUNET_free (w);
+    workers--;
   }
 }
 
@@ -536,88 +1208,35 @@ static enum GNUNET_GenericReturnValue
 handle_r_derive_request (struct TES_Client *client,
                          const struct TALER_CRYPTO_CsRDeriveRequest *rdr)
 {
-  struct DenominationKey *dk;
-  struct TALER_DenominationCSPrivateRPairP r_priv;
   struct TALER_DenominationCSPublicRPairP r_pub;
   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
-  bool for_melt;
+  enum TALER_ErrorCode ec;
+  enum GNUNET_GenericReturnValue ret;
 
-  GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
-  dk = GNUNET_CONTAINER_multihashmap_get (keys,
-                                          &rdr->h_cs.hash);
-  if (NULL == dk)
+  ec = do_derive (&rdr->h_cs,
+                  &rdr->nonce,
+                  (0 != ntohl (rdr->for_melt)),
+                  &r_pub);
+  if (TALER_EC_NONE != ec)
   {
     struct TALER_CRYPTO_RDeriveFailure rdf = {
-      .header.size = htons (sizeof (rdr)),
+      .header.size = htons (sizeof (rdf)),
       .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE),
-      .ec = htonl (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN)
+      .ec = htonl (ec)
     };
 
-    GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "R Derive request failed, denomination key %s unknown\n",
-                GNUNET_h2s (&rdr->h_cs.hash));
     return TES_transmit (client->csock,
                          &rdf.header);
   }
-  if (GNUNET_TIME_absolute_is_future (dk->anchor.abs_time))
-  {
-    /* it is too early */
-    struct TALER_CRYPTO_RDeriveFailure rdf = {
-      .header.size = htons (sizeof (rdr)),
-      .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE),
-      .ec = htonl (TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY)
-    };
 
-    GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "R Derive request failed, denomination key %s is not yet 
valid\n",
-                GNUNET_h2s (&rdr->h_cs.hash));
-    return TES_transmit (client->csock,
-                         &rdf.header);
-  }
-  for_melt = (0 != ntohl (rdr->for_melt));
+  ret = send_derivation (client,
+                         &r_pub);
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Received request to derive R with key %s\n",
-              GNUNET_h2s (&rdr->h_cs.hash));
-  GNUNET_assert (dk->rc < UINT_MAX);
-  dk->rc++;
-  GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
-  GNUNET_CRYPTO_cs_r_derive (&rdr->nonce.nonce,
-                             for_melt ? "rm" : "rw",
-                             &dk->denom_priv,
-                             r_priv.r);
-  GNUNET_CRYPTO_cs_r_get_public (&r_priv.r[0],
-                                 &r_pub.r_pub[0]);
-  GNUNET_CRYPTO_cs_r_get_public (&r_priv.r[1],
-                                 &r_pub.r_pub[1]);
-  GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
-  GNUNET_assert (dk->rc > 0);
-  dk->rc--;
-  GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
-
-  {
-    struct TALER_CRYPTO_RDeriveResponse rdr = {
-      .header.size = htons (sizeof (struct TALER_CRYPTO_RDeriveResponse)),
-      .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE),
-      .r_pub = r_pub
-    };
-    enum GNUNET_GenericReturnValue ret;
-
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Sending CS Derived R after %s\n",
-                GNUNET_TIME_relative2s (
-                  GNUNET_TIME_absolute_get_duration (now),
-                  GNUNET_YES));
-    ret = TES_transmit (client->csock,
-                        &rdr.header);
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Sent CS Derived R after %s\n",
-                GNUNET_TIME_relative2s (
-                  GNUNET_TIME_absolute_get_duration (now),
-                  GNUNET_YES));
-    return ret;
-  }
+              "Sent CS Derived R after %s\n",
+              GNUNET_TIME_relative2s (
+                GNUNET_TIME_absolute_get_duration (now),
+                GNUNET_YES));
+  return ret;
 }
 
 
@@ -654,6 +1273,24 @@ cs_work_dispatch (struct TES_Client *client,
     return handle_revoke_request (
       client,
       (const struct TALER_CRYPTO_CsRevokeRequest *) hdr);
+  case TALER_HELPER_CS_MT_REQ_BATCH_SIGN:
+    if (msize <= sizeof (struct TALER_CRYPTO_BatchSignRequest))
+    {
+      GNUNET_break_op (0);
+      return GNUNET_SYSERR;
+    }
+    return handle_batch_sign_request (
+      client,
+      (const struct TALER_CRYPTO_BatchSignRequest *) hdr);
+  case TALER_HELPER_CS_MT_REQ_BATCH_RDERIVE:
+    if (msize <= sizeof (struct TALER_CRYPTO_BatchDeriveRequest))
+    {
+      GNUNET_break_op (0);
+      return GNUNET_SYSERR;
+    }
+    return handle_batch_derive_request (
+      client,
+      (const struct TALER_CRYPTO_BatchDeriveRequest *) hdr);
   case TALER_HELPER_CS_MT_REQ_RDERIVE:
     if (msize != sizeof (struct TALER_CRYPTO_CsRDeriveRequest))
     {
@@ -1467,6 +2104,8 @@ do_shutdown (void *cls)
     GNUNET_SCHEDULER_cancel (keygen_task);
     keygen_task = NULL;
   }
+  stop_workers ();
+  sem_done (&worker_sem);
 }
 
 
@@ -1526,8 +2165,19 @@ run (void *cls,
                                  &cb);
   if (0 != global_ret)
     return;
+  sem_init (&worker_sem,
+            0);
   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
                                  NULL);
+  if (0 == max_workers)
+    max_workers = 1; /* FIXME-#7272: or determine from CPU? */
+  for (unsigned int i = 0; i<max_workers; i++)
+    if (GNUNET_OK !=
+        start_worker ())
+    {
+      GNUNET_SCHEDULER_shutdown ();
+      return;
+    }
   /* Load denominations */
   keys = GNUNET_CONTAINER_multihashmap_create (65536,
                                                GNUNET_YES);
@@ -1585,6 +2235,11 @@ main (int argc,
                                     "TIMESTAMP",
                                     "pretend it is a different time for the 
update",
                                     &now_tmp),
+    GNUNET_GETOPT_option_uint ('w',
+                               "workers",
+                               "COUNT",
+                               "use COUNT workers for parallel processing of 
batch requests",
+                               &max_workers),
     GNUNET_GETOPT_OPTION_END
   };
   enum GNUNET_GenericReturnValue ret;
diff --git a/src/util/taler-exchange-secmod-cs.h 
b/src/util/taler-exchange-secmod-cs.h
index 21b1ef4c..0ccb71da 100644
--- a/src/util/taler-exchange-secmod-cs.h
+++ b/src/util/taler-exchange-secmod-cs.h
@@ -35,10 +35,12 @@
 
 #define TALER_HELPER_CS_MT_RES_SIGNATURE 9
 #define TALER_HELPER_CS_MT_RES_SIGN_FAILURE 10
-#define TALER_HELPER_CS_MT_RES_RDERIVE 11
-#define TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE 12
+#define TALER_HELPER_CS_MT_RES_BATCH_SIGN_FAILURE 11
+#define TALER_HELPER_CS_MT_RES_RDERIVE 12
+#define TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE 13
+#define TALER_HELPER_CS_MT_RES_BATCH_RDERIVE_FAILURE 14
 
-#define TALER_HELPER_CS_SYNCED 13
+#define TALER_HELPER_CS_SYNCED 15
 
 GNUNET_NETWORK_STRUCT_BEGIN
 
@@ -134,8 +136,7 @@ struct TALER_CRYPTO_CsSignRequestMessage
   struct TALER_CsPubHashP h_cs;
 
   /**
-   * Planchet containing message to sign
-   * and nonce to derive R from
+   * Planchet containing message to sign and nonce to derive R from
    */
   struct TALER_BlindedCsPlanchet planchet;
 
diff --git a/src/util/taler-exchange-secmod-rsa.c 
b/src/util/taler-exchange-secmod-rsa.c
index 9cfc14a4..1cee02ab 100644
--- a/src/util/taler-exchange-secmod-rsa.c
+++ b/src/util/taler-exchange-secmod-rsa.c
@@ -1568,7 +1568,9 @@ parse_key (struct Denomination *denom,
          NULL != pos;
          pos = pos->next)
     {
-      if (GNUNET_TIME_timestamp_cmp (pos->anchor, >, anchor))
+      if (GNUNET_TIME_timestamp_cmp (pos->anchor,
+                                     >,
+                                     anchor))
         break;
       before = pos;
     }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

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