gnunet-svn
[Top][All Lists]
Advanced

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

[taler-donau] 01/02: [secmod/helpers] Add helpers from Exchange and adap


From: gnunet
Subject: [taler-donau] 01/02: [secmod/helpers] Add helpers from Exchange and adapt to Donau
Date: Sun, 14 Jan 2024 22:56:53 +0100

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

pius-loosli pushed a commit to branch master
in repository donau.

commit ade143d8dcda67578aa3d8479b5ab45fd69303d7
Author: Pius Loosli <loosp2@bfh.ch>
AuthorDate: Sun Jan 14 22:41:57 2024 +0100

    [secmod/helpers] Add helpers from Exchange and adapt to Donau
---
 src/include/donau_crypto_lib.h  |  565 ++++++++++++++++-
 src/util/Makefile.am            |    5 +-
 src/util/crypto_helper_common.c |   51 ++
 src/util/crypto_helper_common.h |   41 ++
 src/util/crypto_helper_cs.c     | 1317 +++++++++++++++++++++++++++++++++++++++
 src/util/crypto_helper_esign.c  |  557 +++++++++++++++++
 src/util/crypto_helper_rsa.c    |  917 +++++++++++++++++++++++++++
 7 files changed, 3443 insertions(+), 10 deletions(-)

diff --git a/src/include/donau_crypto_lib.h b/src/include/donau_crypto_lib.h
index 2616a9e..ad7f950 100644
--- a/src/include/donau_crypto_lib.h
+++ b/src/include/donau_crypto_lib.h
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2023 Taler Systems SA
+  Copyright (C) 2023-2024 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
@@ -21,6 +21,7 @@
  * @author Christian Grothoff <christian@grothoff.org>
  * @author Özgür Kesim <oec-taler@kesim.org>
  * @author Lukas Matyja
+ * @author Pius Loosli
  */
 #if ! defined (__DONAU_UTIL_LIB_H_INSIDE__)
  #error "Only <donau_util.h> can be included directly."
@@ -126,8 +127,10 @@ struct DONAU_DonationUnitHashP
  * @return 0 if the keys are equal, otherwise -1 or 1
  */
 int
-DONAU_donation_unit_pub_cmp (const struct DONAU_DonationUnitPublicKey 
*donation_unit1,
-                     const struct DONAU_DonationUnitPublicKey *donation_unit2);
+DONAU_donation_unit_pub_cmp (const struct
+                             DONAU_DonationUnitPublicKey *donation_unit1,
+                             const struct
+                             DONAU_DonationUnitPublicKey *donation_unit2);
 
 /**
  * Make a (deep) copy of the given @a donation_unit_src to
@@ -137,8 +140,12 @@ DONAU_donation_unit_pub_cmp (const struct 
DONAU_DonationUnitPublicKey *donation_
  * @param donation_unit_src public key to copy
  */
 void
-DONAU_donation_unit_pub_deep_copy (struct DONAU_DonationUnitPublicKey 
*donation_unit_dst,
-                             const struct DONAU_DonationUnitPublicKey 
*donation_unit_src);
+DONAU_donation_unit_pub_deep_copy (struct
+                                   DONAU_DonationUnitPublicKey *
+                                   donation_unit_dst,
+                                   const struct
+                                   DONAU_DonationUnitPublicKey *
+                                   donation_unit_src);
 
 /**
  * Free internals of @a donation_unit_pub, but not @a donation_unit_pub itself.
@@ -146,7 +153,8 @@ DONAU_donation_unit_pub_deep_copy (struct 
DONAU_DonationUnitPublicKey *donation_
  * @param[in] donation_unit_pub key to free
  */
 void
-DONAU_donation_unit_pub_free (struct DONAU_DonationUnitPublicKey 
*donation_unit_pub);
+DONAU_donation_unit_pub_free (struct
+                              DONAU_DonationUnitPublicKey *donation_unit_pub);
 
 /**
  * Hash used to represent a Donation Receipt
@@ -174,9 +182,9 @@ struct DONAU_HashDonorTaxId
 struct DONAU_BlindedDonationUnitSignature
 {
   /**
-   * The blinded signature
+   * Donation Units use blind signatures.
    */
-  struct TALER_DenominationSignature b_sig;
+  struct GNUNET_CRYPTO_BlindedSignature *blinded_sig;
 
 };
 
@@ -324,9 +332,134 @@ DONAU_donation_statement_verify (
   const struct DONAU_DonauSignatureP *statement_sig);
 
 
-/* ********************* helper ************************** */
+///* ********************* donau blind signing ************************** */
 
 
+/**
+ * Free internals of @a donation_unit_sig, but not @a donation_unit_sig itself.
+ *
+ * @param[in] donation_unit_sig signature to free
+// */
+void
+DONAU_blinded_donation_unit_sig_free (
+  struct DONAU_BlindedDonationUnitSignature *donation_unit_sig);
+
+// FIXME: Copied from taler_crypto_lib.h, is anything of this necessary?
+///**
+// * Compute the hash of the given @a donation_unit_pub.
+// *
+// * @param donation_unit_pub public key to hash
+// * @param[out] donation_unit_hash resulting hash value
+// */
+// void
+// TALER_donation_unit_pub_hash (const struct DONAU_DonationUnitPublicKey 
*donation_unit_pub,
+//                      struct DONAU_DonationUnitHashP *donation_unit_hash);
+//
+//
+///**
+// * Make a (deep) copy of the given @a donation_unit_src to
+// * @a donation_unit_dst.
+// *
+// * @param[out] donation_unit_dst target to copy to
+// * @param donation_unit_src public key to copy
+// */
+// void
+// TALER_donation_unit_pub_deep_copy (struct DONAU_DonationUnitPublicKey 
*donation_unit_dst,
+//                           const struct DONAU_DonationUnitPublicKey 
*donation_unit_src);
+//
+//
+///**
+// * Make a (deep) copy of the given @a donation_unit_src to
+// * @a donation_unit_dst.
+// *
+// * @param[out] donation_unit_dst target to copy to
+// * @param donation_unit_src public key to copy
+// */
+// void
+// TALER_donation_unit_sig_deep_copy (struct DONAU_DonationUnitSignature 
*donation_unit_dst,
+//                           const struct DONAU_DonationUnitSignature 
*donation_unit_src);
+//
+//
+///**
+// * Make a (deep) copy of the given @a donation_unit_src to
+// * @a donation_unit_dst.
+// *
+// * @param[out] donation_unit_dst target to copy to
+// * @param donation_unit_src public key to copy
+// */
+// void
+// TALER_blinded_donation_unit_sig_deep_copy (
+//  struct DONAU_BlindedDonationUnitSignature *donation_unit_dst,
+//  const struct DONAU_BlindedDonationUnitSignature *donation_unit_src);
+//
+//
+///**
+// * Compare two donation unit public keys.
+// *
+// * @param donation_unit1 first key
+// * @param donation_unit2 second key
+// * @return 0 if the keys are equal, otherwise -1 or 1
+// */
+// int
+// TALER_donation_unit_pub_cmp (const struct DONAU_DonationUnitPublicKey 
*donation_unit1,
+//                     const struct DONAU_DonationUnitPublicKey 
*donation_unit2);
+//
+//
+///**
+// * Compare two donation unit signatures.
+// *
+// * @param sig1 first signature
+// * @param sig2 second signature
+// * @return 0 if the keys are equal, otherwise -1 or 1
+// */
+// int
+// TALER_donation_unit_sig_cmp (const struct DONAU_DonationUnitSignature *sig1,
+//                     const struct DONAU_DonationUnitSignature *sig2);
+//
+//
+///**
+// * Compare two blinded donation unit signatures.
+// *
+// * @param sig1 first signature
+// * @param sig2 second signature
+// * @return 0 if the keys are equal, otherwise -1 or 1
+// */
+// int
+// TALER_blinded_donation_unit_sig_cmp (
+//  const struct DONAU_BlindedDonationUnitSignature *sig1,
+//  const struct DONAU_BlindedDonationUnitSignature *sig2);
+//
+//
+///**
+// * Compare two blinded planchets.
+// *
+// * @param bp1 first blinded planchet
+// * @param bp2 second blinded planchet
+// * @return 0 if the keys are equal, otherwise -1 or 1
+// */
+// int
+// TALER_blinded_planchet_cmp (
+//  const struct DONAU_BlindedPlanchet *bp1,
+//  const struct DONAU_BlindedPlanchet *bp2);
+//
+//
+///**
+// * Verify signature made with a donation unit public key
+// * over a donation receipt.
+// *
+// * @param donation_unit_pub public donation unit key
+// * @param donation_unit_sig signature made with the private key
+// * @param c_hash hash over the coin
+// * @return #GNUNET_OK if the signature is valid
+// */
+// enum GNUNET_GenericReturnValue
+// TALER_donation_unit_pub_verify (const struct DONAU_DonationUnitPublicKey 
*donation_unit_pub,
+//                        const struct DONAU_DonationUnitSignature 
*donation_unit_sig,
+//                        const struct DONAU_ *c_hash);
+//
+
+
+/*********************** helpers 
************************************************/
 /**
  * Group of donation units. These are the common fields of an array of
  * donation units.
@@ -369,4 +502,418 @@ struct TALER_DonauBatchIssueValues
 };
 
 
+/* ********************* Helper-based RSA operations 
************************** */
+/**
+ * Function called with information about available keys for signing.  Usually
+ * only called once per key upon connect. Also called again in case a key is
+ * being revoked, in that case with an @a end_time of zero.
+ *
+ * @param cls closure
+ * @param section_name name of the donation unit type in the configuration;
+ *                 NULL if the key has been revoked or purged
+ * @param start_time when does the key become available for signing;
+ *                 zero if the key has been revoked or purged
+ * @param validity_duration how long does the key remain available for signing;
+ *                 zero if the key has been revoked or purged
+ * @param h_rsa hash of the RSA @a donation_unit_pub that is available (or was 
purged)
+ * @param bs_pub the public key itself, NULL if the key was revoked or purged
+ * @param sm_pub public key of the security module, NULL if the key was 
revoked or purged
+ * @param sm_sig signature from the security module, NULL if the key was 
revoked or purged
+ *               The signature was already verified against @a sm_pub.
+ */
+typedef void
+(*DONAU_CRYPTO_RsaDonationUnitKeyStatusCallback)(
+  void *cls,
+  const char *section_name,
+  struct GNUNET_TIME_Timestamp start_time,
+  struct GNUNET_TIME_Relative validity_duration,
+  const struct TALER_RsaPubHashP *h_rsa,
+  struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub,
+  const struct TALER_SecurityModulePublicKeyP *sm_pub,
+  const struct TALER_SecurityModuleSignatureP *sm_sig);
+
+/**
+ * Handle for talking to an Donation unit key signing helper.
+ */
+struct DONAU_CRYPTO_RsaDonationUnitHelper;
+
+
+/**
+ * Initiate connection to an donation unit key helper.
+ *
+ * @param cfg configuration to use
+ * @param section configuration section prefix to use, usually 'taler' or 
'donau'
+ * @param dkc function to call with key information
+ * @param dkc_cls closure for @a dkc
+ * @return NULL on error (such as bad @a cfg).
+ */
+struct DONAU_CRYPTO_RsaDonationUnitHelper *
+DONAU_CRYPTO_helper_rsa_connect (
+  const struct GNUNET_CONFIGURATION_Handle *cfg,
+  const char *section,
+  DONAU_CRYPTO_RsaDonationUnitKeyStatusCallback dkc,
+  void *dkc_cls);
+
+
+/**
+ * Function to call to 'poll' for updates to the available key material.
+ * Should be called whenever it is important that the key material status is
+ * current, like when handling a "/keys" request.  This function basically
+ * briefly checks if there are messages from the helper announcing changes to
+ * donation unit keys.
+ *
+ * @param dh helper process connection
+ */
+void
+DONAU_CRYPTO_helper_rsa_poll (struct DONAU_CRYPTO_RsaDonationUnitHelper *dh);
+
+/**
+ * Close connection to @a dh.
+ *
+ * @param[in] dh connection to close
+ */
+void
+DONAU_CRYPTO_helper_rsa_disconnect (
+  struct DONAU_CRYPTO_RsaDonationUnitHelper *dh);
+
+
+/* **************** Helper-based CS operations **************** */
+
+/**
+ * Handle for talking to an DonationUnit key signing helper.
+ */
+struct DONAU_CRYPTO_CsDonationUnitHelper;
+
+/**
+ * Function called with information about available keys for signing.  Usually
+ * only called once per key upon connect. Also called again in case a key is
+ * being revoked, in that case with an @a end_time of zero.
+ *
+ * @param cls closure
+ * @param section_name name of the donation unit type in the configuration;
+ *                 NULL if the key has been revoked or purged
+ * @param start_time when does the key become available for signing;
+ *                 zero if the key has been revoked or purged
+ * @param validity_duration how long does the key remain available for signing;
+ *                 zero if the key has been revoked or purged
+ * @param h_cs hash of the CS @a donation_unit_pub that is available (or was 
purged)
+ * @param bsign_pub the public key itself, NULL if the key was revoked or 
purged
+ * @param sm_pub public key of the security module, NULL if the key was 
revoked or purged
+ * @param sm_sig signature from the security module, NULL if the key was 
revoked or purged
+ *               The signature was already verified against @a sm_pub.
+ */
+typedef void
+(*DONAU_CRYPTO_CsDonationUnitKeyStatusCallback)(
+  void *cls,
+  const char *section_name,
+  struct GNUNET_TIME_Timestamp start_time,
+  struct GNUNET_TIME_Relative validity_duration,
+  const struct TALER_CsPubHashP *h_cs,
+  struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub,
+  const struct TALER_SecurityModulePublicKeyP *sm_pub,
+  const struct TALER_SecurityModuleSignatureP *sm_sig);
+
+
+/**
+ * Initiate connection to an donation unit key helper.
+ *
+ * @param cfg configuration to use
+ * @param section configuration section prefix to use, usually 'taler' or 
'donau'
+ * @param dkc function to call with key information
+ * @param dkc_cls closure for @a dkc
+ * @return NULL on error (such as bad @a cfg).
+ */
+struct DONAU_CRYPTO_CsDonationUnitHelper *
+DONAU_CRYPTO_helper_cs_connect (
+  const struct GNUNET_CONFIGURATION_Handle *cfg,
+  const char *section,
+  DONAU_CRYPTO_CsDonationUnitKeyStatusCallback dkc,
+  void *dkc_cls);
+
+
+/**
+ * Function to call to 'poll' for updates to the available key material.
+ * Should be called whenever it is important that the key material status is
+ * current, like when handling a "/keys" request.  This function basically
+ * briefly checks if there are messages from the helper announcing changes to
+ * donation unit keys.
+ *
+ * @param dh helper process connection
+ */
+void
+DONAU_CRYPTO_helper_cs_poll (struct DONAU_CRYPTO_CsDonationUnitHelper *dh);
+
+
+/**
+ * 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
+ * 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 req information about the key to sign with and the value to sign
+ * @param for_melt true if for melt operation
+ * @param[out] bs set to the blind signature
+ * @return #TALER_EC_NONE on success
+ */
+enum TALER_ErrorCode
+DONAU_CRYPTO_helper_cs_sign (
+  struct DONAU_CRYPTO_CsDonationUnitHelper *dh,
+  const struct TALER_CRYPTO_CsSignRequest *req,
+  bool for_melt,
+  struct DONAU_BlindedDonationUnitSignature *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 for_melt true if this is for a melt operation
+ * @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
+DONAU_CRYPTO_helper_cs_batch_sign (
+  struct DONAU_CRYPTO_CsDonationUnitHelper *dh,
+  unsigned int reqs_length,
+  const struct TALER_CRYPTO_CsSignRequest reqs[static reqs_length],
+  bool for_melt,
+  struct DONAU_BlindedDonationUnitSignature bss[static reqs_length]);
+
+
+/**
+ * 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,
+ * and to create a replacement key.
+ *
+ * This operation will block until the revocation request has been
+ * transmitted.  Should this process receive a signal (that is not ignored)
+ * while the operation is pending, the operation may fail. If the key is
+ * unknown, this function will also appear to have succeeded. To be sure that
+ * the revocation worked, clients must watch the donation unit key status
+ * callback.
+ *
+ * @param dh helper to process connection
+ * @param h_cs hash of the CS public key to revoke
+ */
+void
+DONAU_CRYPTO_helper_cs_revoke (
+  struct DONAU_CRYPTO_CsDonationUnitHelper *dh,
+  const struct TALER_CsPubHashP *h_cs);
+
+
+/**
+ * Ask the helper to derive R using the information
+ * from @a cdr.
+ *
+ * This operation will block until the R 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 to process connection
+ * @param cdr derivation input data
+ * @param for_melt true if this is for a melt operation
+ * @param[out] crp set to the pair of R values
+ * @return set to the error code (or #TALER_EC_NONE on success)
+ */
+enum TALER_ErrorCode
+DONAU_CRYPTO_helper_cs_r_derive (
+  struct DONAU_CRYPTO_CsDonationUnitHelper *dh,
+  const struct TALER_CRYPTO_CsDeriveRequest *cdr,
+  bool for_melt,
+  struct GNUNET_CRYPTO_CSPublicRPairP *crp);
+
+
+/**
+ * Ask the helper to derive R using the information from @a cdrs.
+ *
+ * This operation will block until the R 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 to process connection
+ * @param cdrs_length length of the @a cdrs array
+ * @param cdrs array with derivation input data
+ * @param for_melt true if this is for a melt operation
+ * @param[out] crps array set to the pair of R values, must be of length @a 
cdrs_length
+ * @return set to the error code (or #TALER_EC_NONE on success)
+ */
+enum TALER_ErrorCode
+DONAU_CRYPTO_helper_cs_r_batch_derive (
+  struct DONAU_CRYPTO_CsDonationUnitHelper *dh,
+  unsigned int cdrs_length,
+  const struct TALER_CRYPTO_CsDeriveRequest cdrs[static cdrs_length],
+  bool for_melt,
+  struct GNUNET_CRYPTO_CSPublicRPairP crps[static cdrs_length]);
+
+
+/**
+ * Close connection to @a dh.
+ *
+ * @param[in] dh connection to close
+ */
+void
+DONAU_CRYPTO_helper_cs_disconnect (
+  struct DONAU_CRYPTO_CsDonationUnitHelper *dh);
+
+
+/*********************** Helper-based EDDSA operations 
*****************************/
+
+/**
+ * Handle for talking to an online key signing helper.
+ */
+struct DONAU_CRYPTO_DonauSignHelper;
+
+/**
+ * Function called with information about available keys for signing.  Usually
+ * only called once per key upon connect. Also called again in case a key is
+ * being revoked, in that case with an @a end_time of zero.
+ *
+ * @param cls closure
+ * @param start_time when does the key become available for signing;
+ *                 zero if the key has been revoked or purged
+ * @param validity_duration how long does the key remain available for signing;
+ *                 zero if the key has been revoked or purged
+ * @param exchange_pub the public key itself, NULL if the key was revoked or 
purged
+ * @param sm_pub public key of the security module, NULL if the key was 
revoked or purged
+ * @param sm_sig signature from the security module, NULL if the key was 
revoked or purged
+ *               The signature was already verified against @a sm_pub.
+ */
+typedef void
+(*DONAU_CRYPTO_DonauKeyStatusCallback)(
+  void *cls,
+  struct GNUNET_TIME_Timestamp start_time,
+  struct GNUNET_TIME_Relative validity_duration,
+  const struct DONAU_DonauPublicKeyP *exchange_pub,
+  const struct TALER_SecurityModulePublicKeyP *sm_pub,
+  const struct TALER_SecurityModuleSignatureP *sm_sig);
+
+
+/**
+ * Initiate connection to an online signing key helper.
+ *
+ * @param cfg configuration to use
+ * @param section configuration section prefix to use, usually 'taler' or 
'donau'
+ * @param ekc function to call with key information
+ * @param ekc_cls closure for @a ekc
+ * @return NULL on error (such as bad @a cfg).
+ */
+struct DONAU_CRYPTO_DonauSignHelper *
+DONAU_CRYPTO_helper_esign_connect (
+  const struct GNUNET_CONFIGURATION_Handle *cfg,
+  const char *section,
+  DONAU_CRYPTO_DonauKeyStatusCallback ekc,
+  void *ekc_cls);
+
+
+/**
+ * Function to call to 'poll' for updates to the available key material.
+ * Should be called whenever it is important that the key material status is
+ * current, like when handling a "/keys" request.  This function basically
+ * briefly checks if there are messages from the helper announcing changes to
+ * donau online signing keys.
+ *
+ * @param esh helper process connection
+ */
+void
+DONAU_CRYPTO_helper_esign_poll (struct DONAU_CRYPTO_DonauSignHelper *esh);
+
+
+/**
+ * Request helper @a esh to sign @a msg using the current online
+ * signing key.
+ *
+ * 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 esh helper process connection
+ * @param purpose message to sign (must extend beyond the purpose)
+ * @param[out] donau_pub set to the public key used for the signature upon 
success
+ * @param[out] donau_sig set to the signature upon success
+ * @return the error code (or #TALER_EC_NONE on success)
+ */
+enum TALER_ErrorCode
+DONAU_CRYPTO_helper_esign_sign_ (
+  struct DONAU_CRYPTO_DonauSignHelper *esh,
+  const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+  struct DONAU_DonauPublicKeyP *donau_pub,
+  struct DONAU_DonauSignatureP *donau_sig);
+
+
+/**
+ * Request helper @a esh to sign @a msg using the current online
+ * signing key.
+ *
+ * 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 esh helper process connection
+ * @param ps message to sign (MUST begin with a purpose)
+ * @param[out] epub set to the public key used for the signature upon success
+ * @param[out] esig set to the signature upon success
+ * @return the error code (or #TALER_EC_NONE on success)
+ */
+#define DONAU_CRYPTO_helper_esign_sign(esh,ps,epub,esig) (         \
+    /* check size is set correctly */                              \
+    GNUNET_assert (ntohl ((ps)->purpose.size) == sizeof (*ps)),    \
+    /* check 'ps' begins with the purpose */                       \
+    GNUNET_static_assert (((void*) (ps)) ==                        \
+                          ((void*) &(ps)->purpose)),               \
+    DONAU_CRYPTO_helper_esign_sign_ (esh,                          \
+                                     &(ps)->purpose,               \
+                                     epub,                         \
+                                     esig) )
+
+
+/**
+ * Ask the helper to revoke the public key @a donau_pub .
+ * Will cause the helper to tell all clients that the key is now unavailable,
+ * and to create a replacement key.
+ *
+ * This operation will block until the revocation request has been
+ * transmitted.  Should this process receive a signal (that is not ignored)
+ * while the operation is pending, the operation may fail. If the key is
+ * unknown, this function will also appear to have succeeded. To be sure that
+ * the revocation worked, clients must watch the signing key status callback.
+ *
+ * @param esh helper to process connection
+ * @param donau_pub the public key to revoke
+ */
+void
+DONAU_CRYPTO_helper_esign_revoke (
+  struct DONAU_CRYPTO_DonauSignHelper *esh,
+  const struct DONAU_DonauPublicKeyP *donau_pub);
+
+
+/**
+ * Close connection to @a esh.
+ *
+ * @param[in] esh connection to close
+ */
+void
+DONAU_CRYPTO_helper_esign_disconnect (
+  struct DONAU_CRYPTO_DonauSignHelper *esh);
+
+
 #endif
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 92f00ac..889249e 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -15,7 +15,10 @@ lib_LTLIBRARIES = \
 libdonauutil_la_SOURCES = \
   charity_signatures.c \
   donau_signatures.c \
-  donau_os_installation.c 
+  donau_os_installation.c \
+  crypto_helper_cs.c \
+  crypto_helper_rsa.c \
+  crypto_helper_esign.c
 
 libdonauutil_la_LIBADD = \
   -ltalerutil \
diff --git a/src/util/crypto_helper_common.c b/src/util/crypto_helper_common.c
new file mode 100644
index 0000000..fccfe9b
--- /dev/null
+++ b/src/util/crypto_helper_common.c
@@ -0,0 +1,51 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2020, 2021 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
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file util/crypto_helper_common.c
+ * @brief Common functions for the exchange security modules
+ * @author Florian Dold <dold@taler.net>
+ */
+#include <taler/platform.h>
+#include <taler/taler_util.h>
+#include <taler/taler_signatures.h>
+
+
+enum GNUNET_GenericReturnValue
+TALER_crypto_helper_send_all (int sock,
+                              const void *buf,
+                              size_t buf_size)
+{
+  size_t off = 0;
+
+  while (off < buf_size)
+  {
+    ssize_t ret;
+
+    ret = send (sock,
+                buf + off,
+                buf_size - off,
+                0);
+    if (ret < 0)
+    {
+      if (EINTR == errno)
+        continue;
+      return GNUNET_SYSERR;
+    }
+    GNUNET_assert (ret > 0);
+    off += ret;
+  }
+  return GNUNET_OK;
+}
diff --git a/src/util/crypto_helper_common.h b/src/util/crypto_helper_common.h
new file mode 100644
index 0000000..cf8b281
--- /dev/null
+++ b/src/util/crypto_helper_common.h
@@ -0,0 +1,41 @@
+/*
+  This file is part of GNU Taler
+  Copyright (C) 2021 Taler Systems SA
+
+  GNU 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
+  Foundation; either version 3, or (at your option) any later version.
+
+  GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  TALER; see the file COPYING.  If not, see
+  <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file util/crypto_helper_common.h
+ * @brief Common functions for the exchange security modules
+ * @author Florian Dold <dold@taler.net>
+ */
+#ifndef CRYPTO_HELPER_COMMON_H
+#define CRYPTO_HELPER_COMMON_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_network_lib.h>
+
+/**
+ * Send all @a buf_size bytes from @a buf to @a sock.
+ *
+ * @param sock socket to send on
+ * @param buf data to send
+ * @param buf_size number of bytes in @a buf
+ * @return #GNUNET_OK on success
+ */
+enum GNUNET_GenericReturnValue
+TALER_crypto_helper_send_all (int sock,
+                              const void *buf,
+                              size_t buf_size);
+
+#endif
diff --git a/src/util/crypto_helper_cs.c b/src/util/crypto_helper_cs.c
new file mode 100644
index 0000000..fd04663
--- /dev/null
+++ b/src/util/crypto_helper_cs.c
@@ -0,0 +1,1317 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2020-2024 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
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file util/crypto_helper_cs.c
+ * @brief utility functions for running out-of-process private key operations
+ * @author Christian Grothoff
+ * @author Pius Loosli
+ */
+#include "taler/platform.h"
+#include "taler/taler_util.h"
+#include "taler/taler_signatures.h"
+#include "taler/taler-exchange-secmod-cs.h"
+#include <poll.h>
+#include "crypto_helper_common.h"
+#include "donau_util.h"
+
+struct DONAU_CRYPTO_CsDonationUnitHelper
+{
+  /**
+   * Function to call with updates to available key material.
+   */
+  DONAU_CRYPTO_CsDonationUnitKeyStatusCallback dkc;
+
+  /**
+   * Closure for @e dkc
+   */
+  void *dkc_cls;
+
+  /**
+   * Socket address of the donation unit helper process.
+   * Used to reconnect if the connection breaks.
+   */
+  struct sockaddr_un sa;
+
+  /**
+   * The UNIX domain socket, -1 if we are currently not connected.
+   */
+  int sock;
+
+  /**
+   * Have we ever been sync'ed?
+   */
+  bool synced;
+};
+
+
+/**
+ * Disconnect from the helper process.  Updates
+ * @e sock field in @a dh.
+ *
+ * @param[in,out] dh handle to tear down connection of
+ */
+static void
+do_disconnect (struct DONAU_CRYPTO_CsDonationUnitHelper *dh)
+{
+  GNUNET_break (0 == close (dh->sock));
+  dh->sock = -1;
+  dh->synced = false;
+}
+
+
+/**
+ * Try to connect to the helper process.  Updates
+ * @e sock field in @a dh.
+ *
+ * @param[in,out] dh handle to establish connection for
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+try_connect (struct DONAU_CRYPTO_CsDonationUnitHelper *dh)
+{
+  if (-1 != dh->sock)
+    return GNUNET_OK;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Establishing connection!\n");
+  dh->sock = socket (AF_UNIX,
+                     SOCK_STREAM,
+                     0);
+  if (-1 == dh->sock)
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                         "socket");
+    return GNUNET_SYSERR;
+  }
+  if (0 !=
+      connect (dh->sock,
+               (const struct sockaddr *) &dh->sa,
+               sizeof (dh->sa)))
+  {
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                              "connect",
+                              dh->sa.sun_path);
+    do_disconnect (dh);
+    return GNUNET_SYSERR;
+  }
+  DONAU_CRYPTO_helper_cs_poll (dh);
+  return GNUNET_OK;
+}
+
+
+struct DONAU_CRYPTO_CsDonationUnitHelper *
+DONAU_CRYPTO_helper_cs_connect (
+  const struct GNUNET_CONFIGURATION_Handle *cfg,
+  const char *section,
+  DONAU_CRYPTO_CsDonationUnitKeyStatusCallback dkc,
+  void *dkc_cls)
+{
+  struct DONAU_CRYPTO_CsDonationUnitHelper *dh;
+  char *unixpath;
+  char *secname;
+
+  GNUNET_asprintf (&secname,
+                   "%s-exchange-secmod-cs",
+                   section);
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (cfg,
+                                               secname,
+                                               "UNIXPATH",
+                                               &unixpath))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               secname,
+                               "UNIXPATH");
+    GNUNET_free (secname);
+    return NULL;
+  }
+  /* we use >= here because we want the sun_path to always
+     be 0-terminated */
+  if (strlen (unixpath) >= sizeof (dh->sa.sun_path))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+                               secname,
+                               "UNIXPATH",
+                               "path too long");
+    GNUNET_free (unixpath);
+    GNUNET_free (secname);
+    return NULL;
+  }
+  GNUNET_free (secname);
+  dh = GNUNET_new (struct DONAU_CRYPTO_CsDonationUnitHelper);
+  dh->dkc = dkc;
+  dh->dkc_cls = dkc_cls;
+  dh->sa.sun_family = AF_UNIX;
+  strncpy (dh->sa.sun_path,
+           unixpath,
+           sizeof (dh->sa.sun_path) - 1);
+  GNUNET_free (unixpath);
+  dh->sock = -1;
+  if (GNUNET_OK !=
+      try_connect (dh))
+  {
+    DONAU_CRYPTO_helper_cs_disconnect (dh);
+    return NULL;
+  }
+  return dh;
+}
+
+
+/**
+ * Handle a #DONAU_HELPER_CS_MT_AVAIL message from the helper.
+ *
+ * @param dh helper context
+ * @param hdr message that we received
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+handle_mt_avail (struct DONAU_CRYPTO_CsDonationUnitHelper *dh,
+                 const struct GNUNET_MessageHeader *hdr)
+{
+  const struct TALER_CRYPTO_CsKeyAvailableNotification *kan
+    = (const struct TALER_CRYPTO_CsKeyAvailableNotification *) hdr;
+  const char *buf = (const char *) &kan[1];
+  const char *section_name;
+  uint16_t snl;
+
+  if (sizeof (*kan) > ntohs (hdr->size))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  snl = ntohs (kan->section_name_len);
+  if (ntohs (hdr->size) != sizeof (*kan) + snl)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  if (0 == snl)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  section_name = buf;
+  if ('\0' != section_name[snl - 1])
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+
+  {
+    struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
+    struct TALER_CsPubHashP h_cs;
+
+    bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
+    bsign_pub->cipher = GNUNET_CRYPTO_BSA_CS;
+    bsign_pub->rc = 1;
+    bsign_pub->details.cs_public_key = kan->denom_pub;
+
+    GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key,
+                        sizeof (bsign_pub->details.cs_public_key),
+                        &bsign_pub->pub_key_hash);
+    h_cs.hash = bsign_pub->pub_key_hash;
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Received CS key %s (%s)\n",
+                GNUNET_h2s (&h_cs.hash),
+                section_name);
+    if (GNUNET_OK !=
+        TALER_exchange_secmod_cs_verify (
+          &h_cs,
+          section_name,
+          GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
+          GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
+          &kan->secm_pub,
+          &kan->secm_sig))
+    {
+      GNUNET_break_op (0);
+      GNUNET_CRYPTO_blind_sign_pub_decref (bsign_pub);
+      return GNUNET_SYSERR;
+    }
+    dh->dkc (dh->dkc_cls,
+             section_name,
+             GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
+             GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
+             &h_cs,
+             bsign_pub,
+             &kan->secm_pub,
+             &kan->secm_sig);
+    GNUNET_CRYPTO_blind_sign_pub_decref (bsign_pub);
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle a #DONAU_HELPER_CS_MT_PURGE message from the helper.
+ *
+ * @param dh helper context
+ * @param hdr message that we received
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+handle_mt_purge (struct DONAU_CRYPTO_CsDonationUnitHelper *dh,
+                 const struct GNUNET_MessageHeader *hdr)
+{
+  const struct TALER_CRYPTO_CsKeyPurgeNotification *pn
+    = (const struct TALER_CRYPTO_CsKeyPurgeNotification *) hdr;
+
+  if (sizeof (*pn) != ntohs (hdr->size))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Received revocation of donation unit key %s\n",
+              GNUNET_h2s (&pn->h_cs.hash));
+  dh->dkc (dh->dkc_cls,
+           NULL,
+           GNUNET_TIME_UNIT_ZERO_TS,
+           GNUNET_TIME_UNIT_ZERO,
+           &pn->h_cs,
+           NULL,
+           NULL,
+           NULL);
+  return GNUNET_OK;
+}
+
+
+void
+DONAU_CRYPTO_helper_cs_poll (struct DONAU_CRYPTO_CsDonationUnitHelper *dh)
+{
+  char buf[UINT16_MAX];
+  size_t off = 0;
+  unsigned int retry_limit = 3;
+  const struct GNUNET_MessageHeader *hdr
+    = (const struct GNUNET_MessageHeader *) buf;
+
+  if (GNUNET_OK !=
+      try_connect (dh))
+    return; /* give up */
+  while (1)
+  {
+    uint16_t msize;
+    ssize_t ret;
+
+    ret = recv (dh->sock,
+                buf + off,
+                sizeof (buf) - off,
+                (dh->synced && (0 == off))
+                ? MSG_DONTWAIT
+                : 0);
+    if (ret < 0)
+    {
+      if (EINTR == errno)
+        continue;
+      if (EAGAIN == errno)
+      {
+        GNUNET_assert (dh->synced);
+        GNUNET_assert (0 == off);
+        break;
+      }
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                           "recv");
+      do_disconnect (dh);
+      if (0 == retry_limit)
+        return; /* give up */
+      if (GNUNET_OK !=
+          try_connect (dh))
+        return; /* give up */
+      retry_limit--;
+      continue;
+    }
+    if (0 == ret)
+    {
+      GNUNET_break (0 == off);
+      return;
+    }
+    off += ret;
+more:
+    if (off < sizeof (struct GNUNET_MessageHeader))
+      continue;
+    msize = ntohs (hdr->size);
+    if (off < msize)
+      continue;
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Received message of type %u and length %u\n",
+                (unsigned int) ntohs (hdr->type),
+                (unsigned int) msize);
+    switch (ntohs (hdr->type))
+    {
+    case TALER_HELPER_CS_MT_AVAIL:
+      if (GNUNET_OK !=
+          handle_mt_avail (dh,
+                           hdr))
+      {
+        GNUNET_break_op (0);
+        do_disconnect (dh);
+        return;
+      }
+      break;
+    case TALER_HELPER_CS_MT_PURGE:
+      if (GNUNET_OK !=
+          handle_mt_purge (dh,
+                           hdr))
+      {
+        GNUNET_break_op (0);
+        do_disconnect (dh);
+        return;
+      }
+      break;
+    case TALER_HELPER_CS_SYNCED:
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  "Now synchronized with CS helper\n");
+      dh->synced = true;
+      break;
+    default:
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Received unexpected message of type %d (len: %u)\n",
+                  (unsigned int) ntohs (hdr->type),
+                  (unsigned int) msize);
+      GNUNET_break_op (0);
+      do_disconnect (dh);
+      return;
+    }
+    memmove (buf,
+             &buf[msize],
+             off - msize);
+    off -= msize;
+    goto more;
+  }
+}
+
+
+enum TALER_ErrorCode
+DONAU_CRYPTO_helper_cs_sign (
+  struct DONAU_CRYPTO_CsDonationUnitHelper *dh,
+  const struct TALER_CRYPTO_CsSignRequest *req,
+  bool for_melt,
+  struct DONAU_BlindedDonationUnitSignature *bs)
+{
+  enum TALER_ErrorCode ec = TALER_EC_INVALID;
+  const struct TALER_CsPubHashP *h_cs = req->h_cs;
+
+  memset (bs,
+          0,
+          sizeof (*bs));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Starting signature process\n");
+  if (GNUNET_OK !=
+      try_connect (dh))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Failed to connect to helper\n");
+    return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Requesting signature\n");
+  {
+    char buf[sizeof (struct TALER_CRYPTO_CsSignRequestMessage)];
+    struct TALER_CRYPTO_CsSignRequestMessage *sr
+      = (struct TALER_CRYPTO_CsSignRequestMessage *) buf;
+
+    sr->header.size = htons (sizeof (buf));
+    sr->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN);
+    sr->for_melt = htonl (for_melt ? 1 : 0);
+    sr->h_cs = *h_cs;
+    sr->message = *req->blinded_planchet;
+    if (GNUNET_OK !=
+        TALER_crypto_helper_send_all (dh->sock,
+                                      buf,
+                                      sizeof (buf)))
+    {
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                           "send");
+      do_disconnect (dh);
+      return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+    }
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Awaiting reply\n");
+  {
+    char buf[UINT16_MAX];
+    size_t off = 0;
+    const struct GNUNET_MessageHeader *hdr
+      = (const struct GNUNET_MessageHeader *) buf;
+    bool finished = false;
+
+    while (1)
+    {
+      uint16_t msize;
+      ssize_t ret;
+
+      ret = recv (dh->sock,
+                  &buf[off],
+                  sizeof (buf) - off,
+                  (finished && (0 == off))
+                  ? MSG_DONTWAIT
+                  : 0);
+      if (ret < 0)
+      {
+        if (EINTR == errno)
+          continue;
+        if (EAGAIN == errno)
+        {
+          GNUNET_assert (finished);
+          GNUNET_assert (0 == off);
+          return ec;
+        }
+        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                             "recv");
+        do_disconnect (dh);
+        ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+        break;
+      }
+      if (0 == ret)
+      {
+        GNUNET_break (0 == off);
+        if (! finished)
+          ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
+        return ec;
+      }
+      off += ret;
+more:
+      if (off < sizeof (struct GNUNET_MessageHeader))
+        continue;
+      msize = ntohs (hdr->size);
+      if (off < msize)
+        continue;
+      switch (ntohs (hdr->type))
+      {
+      case TALER_HELPER_CS_MT_RES_SIGNATURE:
+        if (msize != sizeof (struct TALER_CRYPTO_SignResponse))
+        {
+          GNUNET_break_op (0);
+          do_disconnect (dh);
+          ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          goto end;
+        }
+        if (finished)
+        {
+          GNUNET_break_op (0);
+          do_disconnect (dh);
+          ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          goto end;
+        }
+        {
+          const struct TALER_CRYPTO_SignResponse *sr =
+            (const struct TALER_CRYPTO_SignResponse *) buf;
+          struct GNUNET_CRYPTO_BlindedSignature *blinded_sig;
+
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Received signature\n");
+          ec = TALER_EC_NONE;
+          finished = true;
+          blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
+          blinded_sig->cipher = GNUNET_CRYPTO_BSA_CS;
+          blinded_sig->rc = 1;
+          blinded_sig->details.blinded_cs_answer.b = ntohl (sr->b);
+          blinded_sig->details.blinded_cs_answer.s_scalar = sr->cs_answer;
+          bs->blinded_sig = blinded_sig;
+          break;
+        }
+      case TALER_HELPER_CS_MT_RES_SIGN_FAILURE:
+        if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
+        {
+          GNUNET_break_op (0);
+          do_disconnect (dh);
+          ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          goto end;
+        }
+        {
+          const struct TALER_CRYPTO_SignFailure *sf =
+            (const struct TALER_CRYPTO_SignFailure *) buf;
+
+          ec = (enum TALER_ErrorCode) ntohl (sf->ec);
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Signing failed with status %d!\n",
+                      ec);
+          finished = true;
+          break;
+        }
+      case TALER_HELPER_CS_MT_AVAIL:
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Received new key!\n");
+        if (GNUNET_OK !=
+            handle_mt_avail (dh,
+                             hdr))
+        {
+          GNUNET_break_op (0);
+          do_disconnect (dh);
+          ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          goto end;
+        }
+        break; /* while(1) loop ensures we recvfrom() again */
+      case TALER_HELPER_CS_MT_PURGE:
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Received revocation!\n");
+        if (GNUNET_OK !=
+            handle_mt_purge (dh,
+                             hdr))
+        {
+          GNUNET_break_op (0);
+          do_disconnect (dh);
+          ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          goto end;
+        }
+        break; /* while(1) loop ensures we recvfrom() again */
+      case TALER_HELPER_CS_SYNCED:
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                    "Synchronized add odd time with CS helper!\n");
+        dh->synced = true;
+        break;
+      default:
+        GNUNET_break_op (0);
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                    "Received unexpected message of type %u\n",
+                    ntohs (hdr->type));
+        do_disconnect (dh);
+        ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+        goto end;
+      }
+      memmove (buf,
+               &buf[msize],
+               off - msize);
+      off -= msize;
+      goto more;
+    } /* while(1) */
+end:
+    if (finished)
+//      DONAU_blinded_donation_unit_sig_free (bs);
+      return ec;
+  }
+}
+
+
+void
+DONAU_CRYPTO_helper_cs_revoke (
+  struct DONAU_CRYPTO_CsDonationUnitHelper *dh,
+  const struct TALER_CsPubHashP *h_cs)
+{
+  struct TALER_CRYPTO_CsRevokeRequest rr = {
+    .header.size = htons (sizeof (rr)),
+    .header.type = htons (TALER_HELPER_CS_MT_REQ_REVOKE),
+    .h_cs = *h_cs
+  };
+
+  if (GNUNET_OK !=
+      try_connect (dh))
+    return; /* give up */
+  if (GNUNET_OK !=
+      TALER_crypto_helper_send_all (dh->sock,
+                                    &rr,
+                                    sizeof (rr)))
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                         "send");
+    do_disconnect (dh);
+    return;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Requested revocation of donation unit key %s\n",
+              GNUNET_h2s (&h_cs->hash));
+}
+
+
+enum TALER_ErrorCode
+DONAU_CRYPTO_helper_cs_r_derive (struct DONAU_CRYPTO_CsDonationUnitHelper *dh,
+                                 const struct TALER_CRYPTO_CsDeriveRequest 
*cdr,
+                                 bool for_melt,
+                                 struct GNUNET_CRYPTO_CSPublicRPairP *crp)
+{
+  enum TALER_ErrorCode ec = TALER_EC_INVALID;
+  const struct TALER_CsPubHashP *h_cs = cdr->h_cs;
+  const struct GNUNET_CRYPTO_CsSessionNonce *nonce = cdr->nonce;
+
+  memset (crp,
+          0,
+          sizeof (*crp));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Starting R derivation process\n");
+  if (GNUNET_OK !=
+      try_connect (dh))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Failed to connect to helper\n");
+    return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Requesting R\n");
+  {
+    struct TALER_CRYPTO_CsRDeriveRequest rdr = {
+      .header.size = htons (sizeof (rdr)),
+      .header.type = htons (TALER_HELPER_CS_MT_REQ_RDERIVE),
+      .for_melt = htonl (for_melt ? 1 : 0),
+      .h_cs = *h_cs,
+      .nonce = *nonce
+    };
+
+    if (GNUNET_OK !=
+        TALER_crypto_helper_send_all (dh->sock,
+                                      &rdr,
+                                      sizeof (rdr)))
+    {
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                           "send");
+      do_disconnect (dh);
+      return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+    }
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Awaiting reply\n");
+  {
+    char buf[UINT16_MAX];
+    size_t off = 0;
+    const struct GNUNET_MessageHeader *hdr
+      = (const struct GNUNET_MessageHeader *) buf;
+    bool finished = false;
+
+    while (1)
+    {
+      uint16_t msize;
+      ssize_t ret;
+
+      ret = recv (dh->sock,
+                  &buf[off],
+                  sizeof (buf) - off,
+                  (finished && (0 == off))
+                  ? MSG_DONTWAIT
+                  : 0);
+      if (ret < 0)
+      {
+        if (EINTR == errno)
+          continue;
+        if (EAGAIN == errno)
+        {
+          GNUNET_assert (finished);
+          GNUNET_assert (0 == off);
+          return ec;
+        }
+        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                             "recv");
+        do_disconnect (dh);
+        return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+      }
+      if (0 == ret)
+      {
+        GNUNET_break (0 == off);
+        if (! finished)
+          return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
+        return ec;
+      }
+      off += ret;
+more:
+      if (off < sizeof (struct GNUNET_MessageHeader))
+        continue;
+      msize = ntohs (hdr->size);
+      if (off < msize)
+        continue;
+      switch (ntohs (hdr->type))
+      {
+      case TALER_HELPER_CS_MT_RES_RDERIVE:
+        if (msize != sizeof (struct TALER_CRYPTO_RDeriveResponse))
+        {
+          GNUNET_break_op (0);
+          do_disconnect (dh);
+          return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+        }
+        if (finished)
+        {
+          GNUNET_break_op (0);
+          do_disconnect (dh);
+          return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+        }
+        {
+          const struct TALER_CRYPTO_RDeriveResponse *rdr =
+            (const struct TALER_CRYPTO_RDeriveResponse *) buf;
+
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Received R\n");
+          finished = true;
+          ec = TALER_EC_NONE;
+          *crp = rdr->r_pub;
+          break;
+        }
+      case TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE:
+        if (msize != sizeof (struct TALER_CRYPTO_RDeriveFailure))
+        {
+          GNUNET_break_op (0);
+          do_disconnect (dh);
+          return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+        }
+        {
+          const struct TALER_CRYPTO_RDeriveFailure *rdf =
+            (const struct TALER_CRYPTO_RDeriveFailure *) buf;
+
+          ec = (enum TALER_ErrorCode) ntohl (rdf->ec);
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "R derivation failed!\n");
+          finished = true;
+          break;
+        }
+      case TALER_HELPER_CS_MT_AVAIL:
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Received new key!\n");
+        if (GNUNET_OK !=
+            handle_mt_avail (dh,
+                             hdr))
+        {
+          GNUNET_break_op (0);
+          do_disconnect (dh);
+          return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+        }
+        break; /* while(1) loop ensures we recvfrom() again */
+      case TALER_HELPER_CS_MT_PURGE:
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Received revocation!\n");
+        if (GNUNET_OK !=
+            handle_mt_purge (dh,
+                             hdr))
+        {
+          GNUNET_break_op (0);
+          do_disconnect (dh);
+          return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+        }
+        break; /* while(1) loop ensures we recvfrom() again */
+      case TALER_HELPER_CS_SYNCED:
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                    "Synchronized add odd time with CS helper!\n");
+        dh->synced = true;
+        break;
+      default:
+        GNUNET_break_op (0);
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                    "Received unexpected message of type %u\n",
+                    ntohs (hdr->type));
+        do_disconnect (dh);
+        return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+      }
+      memmove (buf,
+               &buf[msize],
+               off - msize);
+      off -= msize;
+      goto more;
+    } /* while(1) */
+  }
+}
+
+
+enum TALER_ErrorCode
+DONAU_CRYPTO_helper_cs_batch_sign (
+  struct DONAU_CRYPTO_CsDonationUnitHelper *dh,
+  unsigned int reqs_length,
+  const struct TALER_CRYPTO_CsSignRequest reqs[static reqs_length],
+  bool for_melt,
+  struct DONAU_BlindedDonationUnitSignature bss[static reqs_length])
+{
+  enum TALER_ErrorCode ec = TALER_EC_INVALID;
+  unsigned int rpos;
+  unsigned int rend;
+  unsigned int wpos;
+
+  memset (bss,
+          0,
+          sizeof (*bss) * reqs_length);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Starting signature process\n");
+  if (GNUNET_OK !=
+      try_connect (dh))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Failed to connect to helper\n");
+    return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Requesting %u signatures\n",
+              reqs_length);
+  rpos = 0;
+  rend = 0;
+  wpos = 0;
+  while (rpos < reqs_length)
+  {
+    unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchSignRequest);
+
+    while ( (rend < reqs_length) &&
+            (mlen + sizeof (struct TALER_CRYPTO_CsSignRequestMessage)
+             < UINT16_MAX) )
+    {
+      mlen += sizeof (struct TALER_CRYPTO_CsSignRequestMessage);
+      rend++;
+    }
+    {
+      char obuf[mlen] GNUNET_ALIGN;
+      struct TALER_CRYPTO_BatchSignRequest *bsr
+        = (struct TALER_CRYPTO_BatchSignRequest *) obuf;
+      void *wbuf;
+
+      bsr->header.type = htons (TALER_HELPER_CS_MT_REQ_BATCH_SIGN);
+      bsr->header.size = htons (mlen);
+      bsr->batch_size = htonl (rend - rpos);
+      wbuf = &bsr[1];
+      for (unsigned int i = rpos; i<rend; i++)
+      {
+        struct TALER_CRYPTO_CsSignRequestMessage *csm = wbuf;
+        const struct TALER_CRYPTO_CsSignRequest *csr = &reqs[i];
+
+        csm->header.size = htons (sizeof (*csm));
+        csm->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN);
+        csm->for_melt = htonl (for_melt ? 1 : 0);
+        csm->h_cs = *csr->h_cs;
+        csm->message = *csr->blinded_planchet;
+        wbuf += sizeof (*csm);
+      }
+      GNUNET_assert (wbuf == &obuf[mlen]);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Sending batch request [%u-%u)\n",
+                  rpos,
+                  rend);
+      if (GNUNET_OK !=
+          TALER_crypto_helper_send_all (dh->sock,
+                                        obuf,
+                                        sizeof (obuf)))
+      {
+        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                             "send");
+        do_disconnect (dh);
+        return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+      }
+    } /* end of obuf scope */
+    rpos = rend;
+    {
+      char buf[UINT16_MAX];
+      size_t off = 0;
+      const struct GNUNET_MessageHeader *hdr
+        = (const struct GNUNET_MessageHeader *) buf;
+      bool finished = false;
+
+      while (1)
+      {
+        uint16_t msize;
+        ssize_t ret;
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Awaiting reply at %u (up to %u)\n",
+                    wpos,
+                    rend);
+        ret = recv (dh->sock,
+                    &buf[off],
+                    sizeof (buf) - off,
+                    (finished && (0 == off))
+                  ? MSG_DONTWAIT
+                  : 0);
+        if (ret < 0)
+        {
+          if (EINTR == errno)
+            continue;
+          if (EAGAIN == errno)
+          {
+            GNUNET_assert (finished);
+            GNUNET_assert (0 == off);
+            break;
+          }
+          GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                               "recv");
+          do_disconnect (dh);
+          return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+        }
+        if (0 == ret)
+        {
+          GNUNET_break (0 == off);
+          if (! finished)
+            return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
+          if (TALER_EC_NONE == ec)
+            break;
+          return ec;
+        }
+        off += ret;
+more:
+        if (off < sizeof (struct GNUNET_MessageHeader))
+          continue;
+        msize = ntohs (hdr->size);
+        if (off < msize)
+          continue;
+        switch (ntohs (hdr->type))
+        {
+        case TALER_HELPER_CS_MT_RES_SIGNATURE:
+          if (msize != sizeof (struct TALER_CRYPTO_SignResponse))
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          }
+          if (finished)
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          }
+          {
+            const struct TALER_CRYPTO_SignResponse *sr =
+              (const struct TALER_CRYPTO_SignResponse *) buf;
+            struct GNUNET_CRYPTO_BlindedSignature *blinded_sig;
+            GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                        "Received %u signature\n",
+                        wpos);
+            blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
+            blinded_sig->cipher = GNUNET_CRYPTO_BSA_CS;
+            blinded_sig->rc = 1;
+            blinded_sig->details.blinded_cs_answer.b = ntohl (sr->b);
+            blinded_sig->details.blinded_cs_answer.s_scalar = sr->cs_answer;
+
+            bss[wpos].blinded_sig = blinded_sig;
+            wpos++;
+            if (wpos == rend)
+            {
+              if (TALER_EC_INVALID == ec)
+                ec = TALER_EC_NONE;
+              finished = true;
+            }
+            break;
+          }
+
+        case TALER_HELPER_CS_MT_RES_SIGN_FAILURE:
+          if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          }
+          {
+            const struct TALER_CRYPTO_SignFailure *sf =
+              (const struct TALER_CRYPTO_SignFailure *) buf;
+
+            ec = (enum TALER_ErrorCode) ntohl (sf->ec);
+            GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                        "Signing %u failed with status %d!\n",
+                        wpos,
+                        ec);
+            wpos++;
+            if (wpos == rend)
+            {
+              finished = true;
+            }
+            break;
+          }
+        case TALER_HELPER_CS_MT_AVAIL:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Received new key!\n");
+          if (GNUNET_OK !=
+              handle_mt_avail (dh,
+                               hdr))
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          }
+          break; /* while(1) loop ensures we recvfrom() again */
+        case TALER_HELPER_CS_MT_PURGE:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Received revocation!\n");
+          if (GNUNET_OK !=
+              handle_mt_purge (dh,
+                               hdr))
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          }
+          break; /* while(1) loop ensures we recvfrom() again */
+        case TALER_HELPER_CS_SYNCED:
+          GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                      "Synchronized add odd time with CS helper!\n");
+          dh->synced = true;
+          break;
+        default:
+          GNUNET_break_op (0);
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                      "Received unexpected message of type %u\n",
+                      ntohs (hdr->type));
+          do_disconnect (dh);
+          return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+        }
+        memmove (buf,
+                 &buf[msize],
+                 off - msize);
+        off -= msize;
+        goto more;
+      } /* while(1) */
+    } /* scope */
+  } /* while (rpos < cdrs_length) */
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Existing with %u signatures and status %d\n",
+              wpos,
+              ec);
+  return ec;
+}
+
+
+enum TALER_ErrorCode
+DONAU_CRYPTO_helper_cs_r_batch_derive (
+  struct DONAU_CRYPTO_CsDonationUnitHelper *dh,
+  unsigned int cdrs_length,
+  const struct TALER_CRYPTO_CsDeriveRequest cdrs[static cdrs_length],
+  bool for_melt,
+  struct GNUNET_CRYPTO_CSPublicRPairP crps[static cdrs_length])
+{
+  enum TALER_ErrorCode ec = TALER_EC_INVALID;
+  unsigned int rpos;
+  unsigned int rend;
+  unsigned int wpos;
+
+  memset (crps,
+          0,
+          sizeof (*crps) * cdrs_length);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Starting R derivation process\n");
+  if (GNUNET_OK !=
+      try_connect (dh))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Failed to connect to helper\n");
+    return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Requesting %u R pairs\n",
+              cdrs_length);
+  rpos = 0;
+  rend = 0;
+  wpos = 0;
+  while (rpos < cdrs_length)
+  {
+    unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchDeriveRequest);
+
+    while ( (rend < cdrs_length) &&
+            (mlen + sizeof (struct TALER_CRYPTO_CsRDeriveRequest)
+             < UINT16_MAX) )
+    {
+      mlen += sizeof (struct TALER_CRYPTO_CsRDeriveRequest);
+      rend++;
+    }
+    {
+      char obuf[mlen] GNUNET_ALIGN;
+      struct TALER_CRYPTO_BatchDeriveRequest *bdr
+        = (struct TALER_CRYPTO_BatchDeriveRequest *) obuf;
+      void *wbuf;
+
+      bdr->header.type = htons (TALER_HELPER_CS_MT_REQ_BATCH_RDERIVE);
+      bdr->header.size = htons (mlen);
+      bdr->batch_size = htonl (rend - rpos);
+      wbuf = &bdr[1];
+      for (unsigned int i = rpos; i<rend; i++)
+      {
+        struct TALER_CRYPTO_CsRDeriveRequest *rdr = wbuf;
+        const struct TALER_CRYPTO_CsDeriveRequest *cdr = &cdrs[i];
+
+        rdr->header.size = htons (sizeof (*rdr));
+        rdr->header.type = htons (TALER_HELPER_CS_MT_REQ_RDERIVE);
+        rdr->for_melt = htonl (for_melt ? 1 : 0);
+        rdr->h_cs = *cdr->h_cs;
+        rdr->nonce = *cdr->nonce;
+        wbuf += sizeof (*rdr);
+      }
+      GNUNET_assert (wbuf == &obuf[mlen]);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Sending batch request [%u-%u)\n",
+                  rpos,
+                  rend);
+      if (GNUNET_OK !=
+          TALER_crypto_helper_send_all (dh->sock,
+                                        obuf,
+                                        sizeof (obuf)))
+      {
+        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                             "send");
+        do_disconnect (dh);
+        return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+      }
+    } /* end of obuf scope */
+    rpos = rend;
+    {
+      char buf[UINT16_MAX];
+      size_t off = 0;
+      const struct GNUNET_MessageHeader *hdr
+        = (const struct GNUNET_MessageHeader *) buf;
+      bool finished = false;
+
+      while (1)
+      {
+        uint16_t msize;
+        ssize_t ret;
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Awaiting reply at %u (up to %u)\n",
+                    wpos,
+                    rend);
+        ret = recv (dh->sock,
+                    &buf[off],
+                    sizeof (buf) - off,
+                    (finished && (0 == off))
+                  ? MSG_DONTWAIT
+                  : 0);
+        if (ret < 0)
+        {
+          if (EINTR == errno)
+            continue;
+          if (EAGAIN == errno)
+          {
+            GNUNET_assert (finished);
+            GNUNET_assert (0 == off);
+            break;
+          }
+          GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                               "recv");
+          do_disconnect (dh);
+          return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+        }
+        if (0 == ret)
+        {
+          GNUNET_break (0 == off);
+          if (! finished)
+            return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
+          if (TALER_EC_NONE == ec)
+            break;
+          return ec;
+        }
+        off += ret;
+more:
+        if (off < sizeof (struct GNUNET_MessageHeader))
+          continue;
+        msize = ntohs (hdr->size);
+        if (off < msize)
+          continue;
+        switch (ntohs (hdr->type))
+        {
+        case TALER_HELPER_CS_MT_RES_RDERIVE:
+          if (msize != sizeof (struct TALER_CRYPTO_RDeriveResponse))
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          }
+          if (finished)
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          }
+          {
+            const struct TALER_CRYPTO_RDeriveResponse *rdr =
+              (const struct TALER_CRYPTO_RDeriveResponse *) buf;
+
+            GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                        "Received %u R pair\n",
+                        wpos);
+            crps[wpos] = rdr->r_pub;
+            wpos++;
+            if (wpos == rend)
+            {
+              if (TALER_EC_INVALID == ec)
+                ec = TALER_EC_NONE;
+              finished = true;
+            }
+            break;
+          }
+        case TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE:
+          if (msize != sizeof (struct TALER_CRYPTO_RDeriveFailure))
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          }
+          {
+            const struct TALER_CRYPTO_RDeriveFailure *rdf =
+              (const struct TALER_CRYPTO_RDeriveFailure *) buf;
+
+            ec = (enum TALER_ErrorCode) ntohl (rdf->ec);
+            GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                        "R derivation %u failed with status %d!\n",
+                        wpos,
+                        ec);
+            wpos++;
+            if (wpos == rend)
+            {
+              finished = true;
+            }
+            break;
+          }
+        case TALER_HELPER_CS_MT_AVAIL:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Received new key!\n");
+          if (GNUNET_OK !=
+              handle_mt_avail (dh,
+                               hdr))
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          }
+          break; /* while(1) loop ensures we recvfrom() again */
+        case TALER_HELPER_CS_MT_PURGE:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Received revocation!\n");
+          if (GNUNET_OK !=
+              handle_mt_purge (dh,
+                               hdr))
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          }
+          break; /* while(1) loop ensures we recvfrom() again */
+        case TALER_HELPER_CS_SYNCED:
+          GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                      "Synchronized add odd time with CS helper!\n");
+          dh->synced = true;
+          break;
+        default:
+          GNUNET_break_op (0);
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                      "Received unexpected message of type %u\n",
+                      ntohs (hdr->type));
+          do_disconnect (dh);
+          return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+        }
+        memmove (buf,
+                 &buf[msize],
+                 off - msize);
+        off -= msize;
+        goto more;
+      } /* while(1) */
+    } /* scope */
+  } /* while (rpos < cdrs_length) */
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Existing with %u signatures and status %d\n",
+              wpos,
+              ec);
+  return ec;
+}
+
+
+void
+DONAU_CRYPTO_helper_cs_disconnect (
+  struct DONAU_CRYPTO_CsDonationUnitHelper *dh)
+{
+  if (-1 != dh->sock)
+    do_disconnect (dh);
+  GNUNET_free (dh);
+}
+
+
+/* end of crypto_helper_cs.c */
diff --git a/src/util/crypto_helper_esign.c b/src/util/crypto_helper_esign.c
new file mode 100644
index 0000000..a4a4a40
--- /dev/null
+++ b/src/util/crypto_helper_esign.c
@@ -0,0 +1,557 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2020-2024 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
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file util/crypto_helper_esign.c
+ * @brief utility functions for running out-of-process private key operations
+ * @author Christian Grothoff
+ * @author Pius Loosli
+ */
+#include <taler/platform.h>
+#include <taler/taler_util.h>
+#include <taler/taler_signatures.h>
+#include <taler/taler-exchange-secmod-eddsa.h>
+#include <poll.h>
+#include <crypto_helper_common.h>
+#include "donau_util.h"
+
+struct DONAU_CRYPTO_DonauSignHelper
+{
+  /**
+   * Function to call with updates to available key material.
+   */
+  DONAU_CRYPTO_DonauKeyStatusCallback dkc;
+
+  /**
+   * Closure for @e dkc
+   */
+  void *dkc_cls;
+
+  /**
+   * Socket address of the denomination helper process.
+   * Used to reconnect if the connection breaks.
+   */
+  struct sockaddr_un sa;
+
+  /**
+   * The UNIX domain socket, -1 if we are currently not connected.
+   */
+  int sock;
+
+  /**
+   * Have we reached the sync'ed state?
+   */
+  bool synced;
+
+};
+
+
+/**
+ * Disconnect from the helper process.  Updates
+ * @e sock field in @a dsh.
+ *
+ * @param[in,out] dsh handle to tear down connection of
+ */
+static void
+do_disconnect (struct DONAU_CRYPTO_DonauSignHelper *dsh)
+{
+  GNUNET_break (0 == close (dsh->sock));
+  dsh->sock = -1;
+  dsh->synced = false;
+}
+
+
+/**
+ * Try to connect to the helper process.  Updates
+ * @e sock field in @a dsh.
+ *
+ * @param[in,out] dsh handle to establish connection for
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+try_connect (struct DONAU_CRYPTO_DonauSignHelper *dsh)
+{
+  if (-1 != dsh->sock)
+    return GNUNET_OK;
+  dsh->sock = socket (AF_UNIX,
+                      SOCK_STREAM,
+                      0);
+  if (-1 == dsh->sock)
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                         "socket");
+    return GNUNET_SYSERR;
+  }
+  if (0 !=
+      connect (dsh->sock,
+               (const struct sockaddr *) &dsh->sa,
+               sizeof (dsh->sa)))
+  {
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                              "connect",
+                              dsh->sa.sun_path);
+    do_disconnect (dsh);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+struct DONAU_CRYPTO_DonauSignHelper *
+DONAU_CRYPTO_helper_esign_connect (
+  const struct GNUNET_CONFIGURATION_Handle *cfg,
+  const char *section,
+  DONAU_CRYPTO_DonauKeyStatusCallback dkc,
+  void *dkc_cls)
+{
+  struct DONAU_CRYPTO_DonauSignHelper *dsh;
+  char *unixpath;
+  char *secname;
+
+  GNUNET_asprintf (&secname,
+                   "%s-exchange-secmod-eddsa",
+                   section);
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (cfg,
+                                               secname,
+                                               "UNIXPATH",
+                                               &unixpath))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               secname,
+                               "UNIXPATH");
+    GNUNET_free (secname);
+    return NULL;
+  }
+  /* we use >= here because we want the sun_path to always
+     be 0-terminated */
+  if (strlen (unixpath) >= sizeof (dsh->sa.sun_path))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+                               secname,
+                               "UNIXPATH",
+                               "path too long");
+    GNUNET_free (unixpath);
+    GNUNET_free (secname);
+    return NULL;
+  }
+  GNUNET_free (secname);
+  dsh = GNUNET_new (struct DONAU_CRYPTO_DonauSignHelper);
+  dsh->dkc = dkc;
+  dsh->dkc_cls = dkc_cls;
+  dsh->sa.sun_family = AF_UNIX;
+  strncpy (dsh->sa.sun_path,
+           unixpath,
+           sizeof (dsh->sa.sun_path) - 1);
+  GNUNET_free (unixpath);
+  dsh->sock = -1;
+  if (GNUNET_OK !=
+      try_connect (dsh))
+  {
+    DONAU_CRYPTO_helper_esign_disconnect (dsh);
+    return NULL;
+  }
+
+//  DONAU_CRYPTO_helper_esign_poll (dsh);
+  return dsh;
+}
+
+
+/**
+ * Handle a #TALER_HELPER_EDDSA_MT_AVAIL message from the helper.
+ *
+ * @param dsh helper context
+ * @param hdr message that we received
+ * @return #GNUNET_OK on success
+ */
+// static enum GNUNET_GenericReturnValue
+// handle_mt_avail (struct DONAU_CRYPTO_DonauSignHelper *dsh,
+//                 const struct GNUNET_MessageHeader *hdr)
+// {
+//  const struct TALER_CRYPTO_EddsaKeyAvailableNotification *kan
+//    = (const struct TALER_CRYPTO_EddsaKeyAvailableNotification *) hdr;
+//
+//  if (sizeof (*kan) != ntohs (hdr->size))
+//  {
+//    GNUNET_break_op (0);
+//    return GNUNET_SYSERR;
+//  }
+//
+//  if (GNUNET_OK !=
+//      TALER_exchange_secmod_eddsa_verify (
+//        &kan->exchange_pub,
+//        GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
+//        GNUNET_TIME_relative_ntoh (kan->duration),
+//        &kan->secm_pub,
+//        &kan->secm_sig))
+//  {
+//    GNUNET_break_op (0);
+//    return GNUNET_SYSERR;
+//  }
+//  dsh->dkc (dsh->dkc_cls,
+//            GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
+//            GNUNET_TIME_relative_ntoh (kan->duration),
+//            &kan->donau_pub,
+//            &kan->secm_pub,
+//            &kan->secm_sig);
+//  return GNUNET_OK;
+// }
+
+
+/**
+ * Handle a #TALER_HELPER_EDDSA_MT_PURGE message from the helper.
+ *
+ * @param dsh helper context
+ * @param hdr message that we received
+ * @return #GNUNET_OK on success
+ */
+// static enum GNUNET_GenericReturnValue
+// handle_mt_purge (struct DONAU_CRYPTO_DonauSignHelper *dsh,
+//                 const struct GNUNET_MessageHeader *hdr)
+// {
+//  const struct TALER_CRYPTO_EddsaKeyPurgeNotification *pn
+//    = (const struct TALER_CRYPTO_EddsaKeyPurgeNotification *) hdr;
+//
+//  if (sizeof (*pn) != ntohs (hdr->size))
+//  {
+//    GNUNET_break_op (0);
+//    return GNUNET_SYSERR;
+//  }
+//  dsh->dkc (dsh->dkc_cls,
+//            GNUNET_TIME_UNIT_ZERO_TS,
+//            GNUNET_TIME_UNIT_ZERO,
+//            &pn->exchange_pub,
+//            NULL,
+//            NULL);
+//  return GNUNET_OK;
+// }
+
+
+// void
+// DONAU_CRYPTO_helper_esign_poll (struct DONAU_CRYPTO_DonauSignHelper *dsh)
+// {
+//  char buf[UINT16_MAX];
+//  size_t off = 0;
+//  unsigned int retry_limit = 3;
+//  const struct GNUNET_MessageHeader *hdr
+//    = (const struct GNUNET_MessageHeader *) buf;
+//
+//  if (GNUNET_OK !=
+//      try_connect (dsh))
+//    return; /* give up */
+//  while (1)
+//  {
+//    uint16_t msize;
+//    ssize_t ret;
+//
+//    ret = recv (dsh->sock,
+//                buf + off,
+//                sizeof (buf) - off,
+//                (dsh->synced && (0 == off))
+//                ? MSG_DONTWAIT
+//                : 0);
+//    if (ret < 0)
+//    {
+//      if (EINTR == errno)
+//        continue;
+//      if (EAGAIN == errno)
+//      {
+//        GNUNET_assert (dsh->synced);
+//        GNUNET_assert (0 == off);
+//        break;
+//      }
+//      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+//                           "recv");
+//      do_disconnect (dsh);
+//      if (0 == retry_limit)
+//        return; /* give up */
+//      if (GNUNET_OK !=
+//          try_connect (dsh))
+//        return; /* give up */
+//      retry_limit--;
+//      continue;
+//    }
+//    if (0 == ret)
+//    {
+//      GNUNET_break (0 == off);
+//      return;
+//    }
+//    off += ret;
+// more:
+//    if (off < sizeof (struct GNUNET_MessageHeader))
+//      continue;
+//    msize = ntohs (hdr->size);
+//    if (off < msize)
+//      continue;
+//    switch (ntohs (hdr->type))
+//    {
+//    case TALER_HELPER_EDDSA_MT_AVAIL:
+//      if (GNUNET_OK !=
+//          handle_mt_avail (dsh,
+//                           hdr))
+//      {
+//        GNUNET_break_op (0);
+//        do_disconnect (dsh);
+//        return;
+//      }
+//      break;
+//    case TALER_HELPER_EDDSA_MT_PURGE:
+//      if (GNUNET_OK !=
+//          handle_mt_purge (dsh,
+//                           hdr))
+//      {
+//        GNUNET_break_op (0);
+//        do_disconnect (dsh);
+//        return;
+//      }
+//      break;
+//    case TALER_HELPER_EDDSA_SYNCED:
+//      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+//                  "Now synchronized with EdDSA helper\n");
+//      dsh->synced = true;
+//      break;
+//    default:
+//      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+//                  "Received unexpected message of type %d (len: %u)\n",
+//                  (unsigned int) ntohs (hdr->type),
+//                  (unsigned int) msize);
+//      GNUNET_break_op (0);
+//      do_disconnect (dsh);
+//      return;
+//    }
+//    memmove (buf,
+//             &buf[msize],
+//             off - msize);
+//    off -= msize;
+//    goto more;
+//  }
+// }
+
+
+// enum TALER_ErrorCode
+// DONAU_CRYPTO_helper_esign_sign_ (
+//  struct DONAU_CRYPTO_DonauSignHelper *dsh,
+//  const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+//  struct DONAU_DonauPublicKeyP *exchange_pub,
+//  struct DONAU_DonauSignatureP *exchange_sig)
+// {
+//  uint32_t purpose_size = ntohl (purpose->size);
+//
+//  if (GNUNET_OK !=
+//      try_connect (dsh))
+//  {
+//    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+//                "Failed to connect to helper\n");
+//    return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE;
+//  }
+//  GNUNET_assert (purpose_size <
+//                 UINT16_MAX - sizeof (struct TALER_CRYPTO_EddsaSignRequest));
+//  {
+//    char buf[sizeof (struct TALER_CRYPTO_EddsaSignRequest) + purpose_size
+//             - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)];
+//    struct TALER_CRYPTO_EddsaSignRequest *sr
+//      = (struct TALER_CRYPTO_EddsaSignRequest *) buf;
+//
+//    sr->header.size = htons (sizeof (buf));
+//    sr->header.type = htons (TALER_HELPER_EDDSA_MT_REQ_SIGN);
+//    sr->reserved = htonl (0);
+//    GNUNET_memcpy (&sr->purpose,
+//                   purpose,
+//                   purpose_size);
+//    if (GNUNET_OK !=
+//        TALER_crypto_helper_send_all (dsh->sock,
+//                                      buf,
+//                                      sizeof (buf)))
+//    {
+//      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+//                                "send",
+//                                dsh->sa.sun_path);
+//      do_disconnect (dsh);
+//      return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE;
+//    }
+//  }
+//
+//  {
+//    char buf[UINT16_MAX];
+//    size_t off = 0;
+//    const struct GNUNET_MessageHeader *hdr
+//      = (const struct GNUNET_MessageHeader *) buf;
+//    bool finished = false;
+//    enum TALER_ErrorCode ec = TALER_EC_INVALID;
+//
+//    while (1)
+//    {
+//      ssize_t ret;
+//      uint16_t msize;
+//
+//      ret = recv (dsh->sock,
+//                  &buf[off],
+//                  sizeof (buf) - off,
+//                  (finished && (0 == off))
+//                  ? MSG_DONTWAIT
+//                  : 0);
+//      if (ret < 0)
+//      {
+//        if (EINTR == errno)
+//          continue;
+//        if (EAGAIN == errno)
+//        {
+//          GNUNET_assert (finished);
+//          GNUNET_assert (0 == off);
+//          break;
+//        }
+//        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+//                             "recv");
+//        do_disconnect (dsh);
+//        return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE;
+//      }
+//      if (0 == ret)
+//      {
+//        GNUNET_break (0 == off);
+//        if (finished)
+//          return TALER_EC_NONE;
+//        return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
+//      }
+//      off += ret;
+// more:
+//      if (off < sizeof (struct GNUNET_MessageHeader))
+//        continue;
+//      msize = ntohs (hdr->size);
+//      if (off < msize)
+//        continue;
+//      switch (ntohs (hdr->type))
+//      {
+//      case TALER_HELPER_EDDSA_MT_RES_SIGNATURE:
+//        if (msize != sizeof (struct TALER_CRYPTO_EddsaSignResponse))
+//        {
+//          GNUNET_break_op (0);
+//          do_disconnect (dsh);
+//          return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
+//        }
+//        if (finished)
+//        {
+//          GNUNET_break_op (0);
+//          do_disconnect (dsh);
+//          return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
+//        }
+//        {
+//          const struct TALER_CRYPTO_EddsaSignResponse *sr =
+//            (const struct TALER_CRYPTO_EddsaSignResponse *) buf;
+//          *exchange_sig = sr->exchange_sig;
+//          *exchange_pub = sr->exchange_pub;
+//          finished = true;
+//          ec = TALER_EC_NONE;
+//          break;
+//        }
+//      case TALER_HELPER_EDDSA_MT_RES_SIGN_FAILURE:
+//        if (msize != sizeof (struct TALER_CRYPTO_EddsaSignFailure))
+//        {
+//          GNUNET_break_op (0);
+//          do_disconnect (dsh);
+//          return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
+//        }
+//        {
+//          const struct TALER_CRYPTO_EddsaSignFailure *sf =
+//            (const struct TALER_CRYPTO_EddsaSignFailure *) buf;
+//
+//          finished = true;
+//          ec = (enum TALER_ErrorCode) ntohl (sf->ec);
+//          break;
+//        }
+//      case TALER_HELPER_EDDSA_MT_AVAIL:
+//        if (GNUNET_OK !=
+//            handle_mt_avail (dsh,
+//                             hdr))
+//        {
+//          GNUNET_break_op (0);
+//          do_disconnect (dsh);
+//          return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
+//        }
+//        break; /* while(1) loop ensures we recv() again */
+//      case TALER_HELPER_EDDSA_MT_PURGE:
+//        if (GNUNET_OK !=
+//            handle_mt_purge (dsh,
+//                             hdr))
+//        {
+//          GNUNET_break_op (0);
+//          do_disconnect (dsh);
+//          return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
+//        }
+//        break; /* while(1) loop ensures we recv() again */
+//      case TALER_HELPER_EDDSA_SYNCED:
+//        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+//                    "Synchronized add odd time with EdDSA helper!\n");
+//        dsh->synced = true;
+//        break;
+//      default:
+//        GNUNET_break_op (0);
+//        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+//                    "Received unexpected message of type %u\n",
+//                    ntohs (hdr->type));
+//        do_disconnect (dsh);
+//        return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
+//      }
+//      memmove (buf,
+//               &buf[msize],
+//               off - msize);
+//      off -= msize;
+//      goto more;
+//    } /* while(1) */
+//    return ec;
+//  }
+// }
+
+
+// void
+// DONAU_CRYPTO_helper_esign_revoke (
+//  struct DONAU_CRYPTO_DonauSignHelper *dsh,
+//  const struct DONAU_DonauPublicKeyP *exchange_pub)
+// {
+//  if (GNUNET_OK !=
+//      try_connect (dsh))
+//    return; /* give up */
+//  {
+//    struct TALER_CRYPTO_EddsaRevokeRequest rr = {
+//      .header.size = htons (sizeof (rr)),
+//      .header.type = htons (TALER_HELPER_EDDSA_MT_REQ_REVOKE),
+//      .exchange_pub = *exchange_pub
+//    };
+//
+//    if (GNUNET_OK !=
+//        TALER_crypto_helper_send_all (dsh->sock,
+//                                      &rr,
+//                                      sizeof (rr)))
+//    {
+//      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+//                           "send");
+//      do_disconnect (dsh);
+//      return;
+//    }
+//  }
+// }
+
+
+void
+DONAU_CRYPTO_helper_esign_disconnect (
+  struct DONAU_CRYPTO_DonauSignHelper *dsh)
+{
+  if (-1 != dsh->sock)
+    do_disconnect (dsh);
+  GNUNET_free (dsh);
+}
+
+
+/* end of crypto_helper_esign.c */
diff --git a/src/util/crypto_helper_rsa.c b/src/util/crypto_helper_rsa.c
new file mode 100644
index 0000000..91edd3e
--- /dev/null
+++ b/src/util/crypto_helper_rsa.c
@@ -0,0 +1,917 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2020-2024 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
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file util/crypto_helper_rsa.c
+ * @brief utility functions for running out-of-process private key operations
+ * @author Christian Grothoff
+ * @author Pius Loosli
+ */
+#include <taler/platform.h>
+#include <taler/taler_util.h>
+#include <taler/taler_signatures.h>
+#include <taler/taler-exchange-secmod-rsa.h>
+#include <poll.h>
+#include <crypto_helper_common.h>
+#include "donau_util.h"
+
+struct DONAU_CRYPTO_RsaDonationUnitHelper
+{
+  /**
+   * Function to call with updates to available key material.
+   */
+  DONAU_CRYPTO_RsaDonationUnitKeyStatusCallback dkc;
+
+  /**
+   * Closure for @e dkc
+   */
+  void *dkc_cls;
+
+  /**
+   * Socket address of the donation unitination helper process.
+   * Used to reconnect if the connection breaks.
+   */
+  struct sockaddr_un sa;
+
+  /**
+   * The UNIX domain socket, -1 if we are currently not connected.
+   */
+  int sock;
+
+  /**
+   * Have we ever been sync'ed?
+   */
+  bool synced;
+};
+
+
+/**
+ * Disconnect from the helper process.  Updates
+ * @e sock field in @a dh.
+ *
+ * @param[in,out] dh handle to tear down connection of
+ */
+static void
+do_disconnect (struct DONAU_CRYPTO_RsaDonationUnitHelper *dh)
+{
+  GNUNET_break (0 == close (dh->sock));
+  dh->sock = -1;
+  dh->synced = false;
+}
+
+
+/**
+ * Try to connect to the helper process.  Updates
+ * @e sock field in @a dh.
+ *
+ * @param[in,out] dh handle to establish connection for
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+try_connect (struct DONAU_CRYPTO_RsaDonationUnitHelper *dh)
+{
+  if (-1 != dh->sock)
+    return GNUNET_OK;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Establishing connection!\n");
+  dh->sock = socket (AF_UNIX,
+                     SOCK_STREAM,
+                     0);
+  if (-1 == dh->sock)
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                         "socket");
+    return GNUNET_SYSERR;
+  }
+  if (0 !=
+      connect (dh->sock,
+               (const struct sockaddr *) &dh->sa,
+               sizeof (dh->sa)))
+  {
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                              "connect",
+                              dh->sa.sun_path);
+    do_disconnect (dh);
+    return GNUNET_SYSERR;
+  }
+  DONAU_CRYPTO_helper_rsa_poll (dh);
+  return GNUNET_OK;
+}
+
+
+struct DONAU_CRYPTO_RsaDonationUnitHelper *
+DONAU_CRYPTO_helper_rsa_connect (
+  const struct GNUNET_CONFIGURATION_Handle *cfg,
+  const char *section,
+  DONAU_CRYPTO_RsaDonationUnitKeyStatusCallback dkc,
+  void *dkc_cls)
+{
+  struct DONAU_CRYPTO_RsaDonationUnitHelper *dh;
+  char *unixpath;
+  char *secname;
+
+  GNUNET_asprintf (&secname,
+                   "%s-exchange-secmod-rsa",
+                   section);
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (cfg,
+                                               secname,
+                                               "UNIXPATH",
+                                               &unixpath))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               secname,
+                               "UNIXPATH");
+    GNUNET_free (secname);
+    return NULL;
+  }
+  /* we use >= here because we want the sun_path to always
+     be 0-terminated */
+  if (strlen (unixpath) >= sizeof (dh->sa.sun_path))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+                               "taler-exchange-secmod-rsa",
+                               "UNIXPATH",
+                               "path too long");
+    GNUNET_free (unixpath);
+    GNUNET_free (secname);
+    return NULL;
+  }
+  GNUNET_free (secname);
+  dh = GNUNET_new (struct DONAU_CRYPTO_RsaDonationUnitHelper);
+  dh->dkc = dkc;
+  dh->dkc_cls = dkc_cls;
+  dh->sa.sun_family = AF_UNIX;
+  strncpy (dh->sa.sun_path,
+           unixpath,
+           sizeof (dh->sa.sun_path) - 1);
+  GNUNET_free (unixpath);
+  dh->sock = -1;
+  if (GNUNET_OK !=
+      try_connect (dh))
+  {
+    DONAU_CRYPTO_helper_rsa_disconnect (dh);
+    return NULL;
+  }
+  return dh;
+}
+
+
+/**
+ * Handle a #TALER_HELPER_RSA_MT_AVAIL message from the helper.
+ *
+ * @param dh helper context
+ * @param hdr message that we received
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+handle_mt_avail (struct DONAU_CRYPTO_RsaDonationUnitHelper *dh,
+                 const struct GNUNET_MessageHeader *hdr)
+{
+  const struct TALER_CRYPTO_RsaKeyAvailableNotification *kan
+    = (const struct TALER_CRYPTO_RsaKeyAvailableNotification *) hdr;
+  const char *buf = (const char *) &kan[1];
+  const char *section_name;
+  uint16_t ps;
+  uint16_t snl;
+
+  if (sizeof (*kan) > ntohs (hdr->size))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  ps = ntohs (kan->pub_size);
+  snl = ntohs (kan->section_name_len);
+  if (ntohs (hdr->size) != sizeof (*kan) + ps + snl)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  if (0 == snl)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  section_name = &buf[ps];
+  if ('\0' != section_name[snl - 1])
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+
+  {
+    struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub;
+    struct TALER_RsaPubHashP h_rsa;
+
+    bs_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
+    bs_pub->cipher = GNUNET_CRYPTO_BSA_RSA;
+    bs_pub->details.rsa_public_key
+      = GNUNET_CRYPTO_rsa_public_key_decode (buf,
+                                             ntohs (kan->pub_size));
+    if (NULL == bs_pub->details.rsa_public_key)
+    {
+      GNUNET_break_op (0);
+      GNUNET_free (bs_pub);
+      return GNUNET_SYSERR;
+    }
+    bs_pub->rc = 1;
+    GNUNET_CRYPTO_rsa_public_key_hash (bs_pub->details.rsa_public_key,
+                                       &bs_pub->pub_key_hash);
+    h_rsa.hash = bs_pub->pub_key_hash;
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Received RSA key %s (%s)\n",
+                GNUNET_h2s (&bs_pub->pub_key_hash),
+                section_name);
+    if (GNUNET_OK !=
+        TALER_exchange_secmod_rsa_verify (
+          &h_rsa,
+          section_name,
+          GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
+          GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
+          &kan->secm_pub,
+          &kan->secm_sig))
+    {
+      GNUNET_break_op (0);
+      GNUNET_CRYPTO_blind_sign_pub_decref (bs_pub);
+      return GNUNET_SYSERR;
+    }
+    dh->dkc (dh->dkc_cls,
+             section_name,
+             GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
+             GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
+             &h_rsa,
+             bs_pub,
+             &kan->secm_pub,
+             &kan->secm_sig);
+    GNUNET_CRYPTO_blind_sign_pub_decref (bs_pub);
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle a #TALER_HELPER_RSA_MT_PURGE message from the helper.
+ *
+ * @param dh helper context
+ * @param hdr message that we received
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+handle_mt_purge (struct DONAU_CRYPTO_RsaDonationUnitHelper *dh,
+                 const struct GNUNET_MessageHeader *hdr)
+{
+  const struct TALER_CRYPTO_RsaKeyPurgeNotification *pn
+    = (const struct TALER_CRYPTO_RsaKeyPurgeNotification *) hdr;
+
+  if (sizeof (*pn) != ntohs (hdr->size))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Received revocation of donation unit key %s\n",
+              GNUNET_h2s (&pn->h_rsa.hash));
+  dh->dkc (dh->dkc_cls,
+           NULL,
+           GNUNET_TIME_UNIT_ZERO_TS,
+           GNUNET_TIME_UNIT_ZERO,
+           &pn->h_rsa,
+           NULL,
+           NULL,
+           NULL);
+  return GNUNET_OK;
+}
+
+
+void
+DONAU_CRYPTO_helper_rsa_poll (struct DONAU_CRYPTO_RsaDonationUnitHelper *dh)
+{
+  char buf[UINT16_MAX];
+  size_t off = 0;
+  unsigned int retry_limit = 3;
+  const struct GNUNET_MessageHeader *hdr
+    = (const struct GNUNET_MessageHeader *) buf;
+
+  if (GNUNET_OK !=
+      try_connect (dh))
+    return; /* give up */
+  while (1)
+  {
+    uint16_t msize;
+    ssize_t ret;
+
+    ret = recv (dh->sock,
+                buf + off,
+                sizeof (buf) - off,
+                (dh->synced && (0 == off))
+                ? MSG_DONTWAIT
+                : 0);
+    if (ret < 0)
+    {
+      if (EINTR == errno)
+        continue;
+      if (EAGAIN == errno)
+      {
+        GNUNET_assert (dh->synced);
+        GNUNET_assert (0 == off);
+        break;
+      }
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                           "recv");
+      do_disconnect (dh);
+      if (0 == retry_limit)
+        return; /* give up */
+      if (GNUNET_OK !=
+          try_connect (dh))
+        return; /* give up */
+      retry_limit--;
+      continue;
+    }
+    if (0 == ret)
+    {
+      GNUNET_break (0 == off);
+      return;
+    }
+    off += ret;
+more:
+    if (off < sizeof (struct GNUNET_MessageHeader))
+      continue;
+    msize = ntohs (hdr->size);
+    if (off < msize)
+      continue;
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Received message of type %u and length %u\n",
+                (unsigned int) ntohs (hdr->type),
+                (unsigned int) msize);
+    switch (ntohs (hdr->type))
+    {
+    case TALER_HELPER_RSA_MT_AVAIL:
+      if (GNUNET_OK !=
+          handle_mt_avail (dh,
+                           hdr))
+      {
+        GNUNET_break_op (0);
+        do_disconnect (dh);
+        return;
+      }
+      break;
+    case TALER_HELPER_RSA_MT_PURGE:
+      if (GNUNET_OK !=
+          handle_mt_purge (dh,
+                           hdr))
+      {
+        GNUNET_break_op (0);
+        do_disconnect (dh);
+        return;
+      }
+      break;
+    case TALER_HELPER_RSA_SYNCED:
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  "Now synchronized with RSA helper\n");
+      dh->synced = true;
+      break;
+    default:
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Received unexpected message of type %d (len: %u)\n",
+                  (unsigned int) ntohs (hdr->type),
+                  (unsigned int) msize);
+      GNUNET_break_op (0);
+      do_disconnect (dh);
+      return;
+    }
+    memmove (buf,
+             &buf[msize],
+             off - msize);
+    off -= msize;
+    goto more;
+  }
+}
+
+
+enum TALER_ErrorCode
+DONAU_CRYPTO_helper_rsa_sign (
+  struct DONAU_CRYPTO_RsaDonationUnitHelper *dh,
+  const struct TALER_CRYPTO_RsaSignRequest *rsr,
+  struct DONAU_BlindedDonationUnitSignature *bs)
+{
+  enum TALER_ErrorCode ec = TALER_EC_INVALID;
+
+  memset (bs,
+          0,
+          sizeof (*bs));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Starting signature process\n");
+  if (GNUNET_OK !=
+      try_connect (dh))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Failed to connect to helper\n");
+    return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Requesting signature\n");
+  {
+    char buf[sizeof (struct TALER_CRYPTO_SignRequest) + rsr->msg_size];
+    struct TALER_CRYPTO_SignRequest *sr
+      = (struct TALER_CRYPTO_SignRequest *) buf;
+
+    sr->header.size = htons (sizeof (buf));
+    sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN);
+    sr->reserved = htonl (0);
+    sr->h_rsa = *rsr->h_rsa;
+    GNUNET_memcpy (&sr[1],
+                   rsr->msg,
+                   rsr->msg_size);
+    if (GNUNET_OK !=
+        TALER_crypto_helper_send_all (dh->sock,
+                                      buf,
+                                      sizeof (buf)))
+    {
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                           "send");
+      do_disconnect (dh);
+      return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+    }
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Awaiting reply\n");
+  {
+    char buf[UINT16_MAX];
+    size_t off = 0;
+    const struct GNUNET_MessageHeader *hdr
+      = (const struct GNUNET_MessageHeader *) buf;
+    bool finished = false;
+
+    while (1)
+    {
+      uint16_t msize;
+      ssize_t ret;
+
+      ret = recv (dh->sock,
+                  &buf[off],
+                  sizeof (buf) - off,
+                  (finished && (0 == off))
+                  ? MSG_DONTWAIT
+                  : 0);
+      if (ret < 0)
+      {
+        if (EINTR == errno)
+          continue;
+        if (EAGAIN == errno)
+        {
+          GNUNET_assert (finished);
+          GNUNET_assert (0 == off);
+          return ec;
+        }
+        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                             "recv");
+        do_disconnect (dh);
+        ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+        break;
+      }
+      if (0 == ret)
+      {
+        GNUNET_break (0 == off);
+        if (! finished)
+          ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
+        return ec;
+      }
+      off += ret;
+more:
+      if (off < sizeof (struct GNUNET_MessageHeader))
+        continue;
+      msize = ntohs (hdr->size);
+      if (off < msize)
+        continue;
+      switch (ntohs (hdr->type))
+      {
+      case TALER_HELPER_RSA_MT_RES_SIGNATURE:
+        if (msize < sizeof (struct TALER_CRYPTO_SignResponse))
+        {
+          GNUNET_break_op (0);
+          do_disconnect (dh);
+          ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          goto end;
+        }
+        if (finished)
+        {
+          GNUNET_break_op (0);
+          do_disconnect (dh);
+          ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          goto end;
+        }
+        {
+          const struct TALER_CRYPTO_SignResponse *sr =
+            (const struct TALER_CRYPTO_SignResponse *) buf;
+          struct GNUNET_CRYPTO_RsaSignature *rsa_signature;
+          struct GNUNET_CRYPTO_BlindedSignature *blind_sig;
+
+          rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (
+            &sr[1],
+            msize - sizeof (*sr));
+          if (NULL == rsa_signature)
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+            goto end;
+          }
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Received signature\n");
+          ec = TALER_EC_NONE;
+          finished = true;
+          blind_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
+          blind_sig->cipher = GNUNET_CRYPTO_BSA_RSA;
+          blind_sig->rc = 1;
+          blind_sig->details.blinded_rsa_signature = rsa_signature;
+          bs->blinded_sig = blind_sig;
+          break;
+        }
+      case TALER_HELPER_RSA_MT_RES_SIGN_FAILURE:
+        if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
+        {
+          GNUNET_break_op (0);
+          do_disconnect (dh);
+          ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          goto end;
+        }
+        {
+          const struct TALER_CRYPTO_SignFailure *sf =
+            (const struct TALER_CRYPTO_SignFailure *) buf;
+
+          ec = (enum TALER_ErrorCode) ntohl (sf->ec);
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Signing failed!\n");
+          finished = true;
+          break;
+        }
+      case TALER_HELPER_RSA_MT_AVAIL:
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Received new key!\n");
+        if (GNUNET_OK !=
+            handle_mt_avail (dh,
+                             hdr))
+        {
+          GNUNET_break_op (0);
+          do_disconnect (dh);
+          ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          goto end;
+        }
+        break; /* while(1) loop ensures we recvfrom() again */
+      case TALER_HELPER_RSA_MT_PURGE:
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Received revocation!\n");
+        if (GNUNET_OK !=
+            handle_mt_purge (dh,
+                             hdr))
+        {
+          GNUNET_break_op (0);
+          do_disconnect (dh);
+          ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          goto end;
+        }
+        break; /* while(1) loop ensures we recvfrom() again */
+      case TALER_HELPER_RSA_SYNCED:
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                    "Synchronized add odd time with RSA helper!\n");
+        dh->synced = true;
+        break;
+      default:
+        GNUNET_break_op (0);
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                    "Received unexpected message of type %u\n",
+                    ntohs (hdr->type));
+        do_disconnect (dh);
+        ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+        goto end;
+      }
+      memmove (buf,
+               &buf[msize],
+               off - msize);
+      off -= msize;
+      goto more;
+    } /* while(1) */
+end:
+    if (finished)
+//      DONAU_blinded_donation_unit_sig_free(bs);
+      return ec;
+  }
+}
+
+
+enum TALER_ErrorCode
+DONAU_CRYPTO_helper_rsa_batch_sign (
+  struct DONAU_CRYPTO_RsaDonationUnitHelper *dh,
+  unsigned int rsrs_length,
+  const struct TALER_CRYPTO_RsaSignRequest rsrs[static rsrs_length],
+  struct DONAU_BlindedDonationUnitSignature bss[static rsrs_length])
+{
+  enum TALER_ErrorCode ec = TALER_EC_INVALID;
+  unsigned int rpos;
+  unsigned int rend;
+  unsigned int wpos;
+
+  memset (bss,
+          0,
+          sizeof (*bss) * rsrs_length);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Starting signature process\n");
+  if (GNUNET_OK !=
+      try_connect (dh))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Failed to connect to helper\n");
+    return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Requesting %u signatures\n",
+              rsrs_length);
+  rpos = 0;
+  rend = 0;
+  wpos = 0;
+  while (rpos < rsrs_length)
+  {
+    unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchSignRequest);
+
+    while ( (rend < rsrs_length) &&
+            (mlen
+             + sizeof (struct TALER_CRYPTO_SignRequest)
+             + rsrs[rend].msg_size < UINT16_MAX) )
+    {
+      mlen += sizeof (struct TALER_CRYPTO_SignRequest) + rsrs[rend].msg_size;
+      rend++;
+    }
+    {
+      char obuf[mlen] GNUNET_ALIGN;
+      struct TALER_CRYPTO_BatchSignRequest *bsr
+        = (struct TALER_CRYPTO_BatchSignRequest *) obuf;
+      void *wbuf;
+
+      bsr->header.type = htons (TALER_HELPER_RSA_MT_REQ_BATCH_SIGN);
+      bsr->header.size = htons (mlen);
+      bsr->batch_size = htonl (rend - rpos);
+      wbuf = &bsr[1];
+      for (unsigned int i = rpos; i<rend; i++)
+      {
+        struct TALER_CRYPTO_SignRequest *sr = wbuf;
+        const struct TALER_CRYPTO_RsaSignRequest *rsr = &rsrs[i];
+
+        sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN);
+        sr->header.size = htons (sizeof (*sr) + rsr->msg_size);
+        sr->reserved = htonl (0);
+        sr->h_rsa = *rsr->h_rsa;
+        GNUNET_memcpy (&sr[1],
+                       rsr->msg,
+                       rsr->msg_size);
+        wbuf += sizeof (*sr) + rsr->msg_size;
+      }
+      GNUNET_assert (wbuf == &obuf[mlen]);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Sending batch request [%u-%u)\n",
+                  rpos,
+                  rend);
+      if (GNUNET_OK !=
+          TALER_crypto_helper_send_all (dh->sock,
+                                        obuf,
+                                        sizeof (obuf)))
+      {
+        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                             "send");
+        do_disconnect (dh);
+        return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+      }
+    }
+    rpos = rend;
+    {
+      char buf[UINT16_MAX];
+      size_t off = 0;
+      const struct GNUNET_MessageHeader *hdr
+        = (const struct GNUNET_MessageHeader *) buf;
+      bool finished = false;
+
+      while (1)
+      {
+        uint16_t msize;
+        ssize_t ret;
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Awaiting reply at %u (up to %u)\n",
+                    wpos,
+                    rend);
+        ret = recv (dh->sock,
+                    &buf[off],
+                    sizeof (buf) - off,
+                    (finished && (0 == off))
+                  ? MSG_DONTWAIT
+                  : 0);
+        if (ret < 0)
+        {
+          if (EINTR == errno)
+            continue;
+          if (EAGAIN == errno)
+          {
+            GNUNET_assert (finished);
+            GNUNET_assert (0 == off);
+            break;
+          }
+          GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                               "recv");
+          do_disconnect (dh);
+          ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+          break;
+        }
+        if (0 == ret)
+        {
+          GNUNET_break (0 == off);
+          if (! finished)
+            ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
+          if (TALER_EC_NONE == ec)
+            break;
+          return ec;
+        }
+        off += ret;
+more:
+        if (off < sizeof (struct GNUNET_MessageHeader))
+          continue;
+        msize = ntohs (hdr->size);
+        if (off < msize)
+          continue;
+        switch (ntohs (hdr->type))
+        {
+        case TALER_HELPER_RSA_MT_RES_SIGNATURE:
+          if (msize < sizeof (struct TALER_CRYPTO_SignResponse))
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          }
+          if (finished)
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          }
+          {
+            const struct TALER_CRYPTO_SignResponse *sr =
+              (const struct TALER_CRYPTO_SignResponse *) buf;
+            struct GNUNET_CRYPTO_RsaSignature *rsa_signature;
+            struct GNUNET_CRYPTO_BlindedSignature *blind_sig;
+
+            rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (
+              &sr[1],
+              msize - sizeof (*sr));
+            if (NULL == rsa_signature)
+            {
+              GNUNET_break_op (0);
+              do_disconnect (dh);
+              return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+            }
+            GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                        "Received %u signature\n",
+                        wpos);
+            blind_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
+            blind_sig->cipher = GNUNET_CRYPTO_BSA_RSA;
+            blind_sig->rc = 1;
+            blind_sig->details.blinded_rsa_signature = rsa_signature;
+            bss[wpos].blinded_sig = blind_sig;
+            wpos++;
+            if (wpos == rend)
+            {
+              if (TALER_EC_INVALID == ec)
+                ec = TALER_EC_NONE;
+              finished = true;
+            }
+            break;
+          }
+        case TALER_HELPER_RSA_MT_RES_SIGN_FAILURE:
+          if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          }
+          {
+            const struct TALER_CRYPTO_SignFailure *sf =
+              (const struct TALER_CRYPTO_SignFailure *) buf;
+
+            ec = (enum TALER_ErrorCode) ntohl (sf->ec);
+            GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                        "Signing %u failed with status %d!\n",
+                        wpos,
+                        ec);
+            wpos++;
+            if (wpos == rend)
+            {
+              finished = true;
+            }
+            break;
+          }
+        case TALER_HELPER_RSA_MT_AVAIL:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Received new key!\n");
+          if (GNUNET_OK !=
+              handle_mt_avail (dh,
+                               hdr))
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          }
+          break; /* while(1) loop ensures we recvfrom() again */
+        case TALER_HELPER_RSA_MT_PURGE:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Received revocation!\n");
+          if (GNUNET_OK !=
+              handle_mt_purge (dh,
+                               hdr))
+          {
+            GNUNET_break_op (0);
+            do_disconnect (dh);
+            return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+          }
+          break; /* while(1) loop ensures we recvfrom() again */
+        case TALER_HELPER_RSA_SYNCED:
+          GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                      "Synchronized add odd time with RSA helper!\n");
+          dh->synced = true;
+          break;
+        default:
+          GNUNET_break_op (0);
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                      "Received unexpected message of type %u\n",
+                      ntohs (hdr->type));
+          do_disconnect (dh);
+          return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+        }
+        memmove (buf,
+                 &buf[msize],
+                 off - msize);
+        off -= msize;
+        goto more;
+      } /* while(1) */
+    } /* scope */
+  }   /* while (rpos < rsrs_length) */
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Existing with %u signatures and status %d\n",
+              wpos,
+              ec);
+  return ec;
+}
+
+
+void
+DONAU_CRYPTO_helper_rsa_revoke (
+  struct DONAU_CRYPTO_RsaDonationUnitHelper *dh,
+  const struct TALER_RsaPubHashP *h_rsa)
+{
+  struct TALER_CRYPTO_RevokeRequest rr = {
+    .header.size = htons (sizeof (rr)),
+    .header.type = htons (TALER_HELPER_RSA_MT_REQ_REVOKE),
+    .h_rsa = *h_rsa
+  };
+
+  if (GNUNET_OK !=
+      try_connect (dh))
+    return; /* give up */
+  if (GNUNET_OK !=
+      TALER_crypto_helper_send_all (dh->sock,
+                                    &rr,
+                                    sizeof (rr)))
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                         "send");
+    do_disconnect (dh);
+    return;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Requested revocation of donation unit key %s\n",
+              GNUNET_h2s (&h_rsa->hash));
+}
+
+
+void
+DONAU_CRYPTO_helper_rsa_disconnect (
+  struct DONAU_CRYPTO_RsaDonationUnitHelper *dh)
+{
+  if (-1 != dh->sock)
+    do_disconnect (dh);
+  GNUNET_free (dh);
+}
+
+
+/* end of crypto_helper_donation_unit.c */

-- 
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]