rps.conf is generated from rps.conf.in
[oweals/gnunet.git] / src / util / crypto_ecc.c
index 1ef1ec7b53e5c2948f06cf9df6290fa4f8ac20c0..4bba395b32b8fc77a7d5425078ba7bf12ad20b3f 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2012 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2012, 2013, 2015 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      GNUnet 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 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
  * @file util/crypto_ecc.c
  * @brief public key cryptography (ECC) with libgcrypt
  * @author Christian Grothoff
 */
 
 /**
  * @file util/crypto_ecc.c
  * @brief public key cryptography (ECC) with libgcrypt
  * @author Christian Grothoff
- *
- * This is just a first, completely untested, draft hack for future ECC support.
- * TODO:
- * - declare public API in gnunet_crypto_lib (move some structs, etc.)
- * - implement gnunet-ecc binary
- * - convert existing RSA testcases
- * - adjust encoding length and other parameters
- * - actually test it!
  */
 #include "platform.h"
 #include <gcrypt.h>
  */
 #include "platform.h"
 #include <gcrypt.h>
-#include "gnunet_common.h"
-#include "gnunet_util_lib.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_strings_lib.h"
 
 
-#define EXTRA_CHECKS ALLOW_EXTRA_CHECKS
+#define EXTRA_CHECKS 0
 
 
-#define CURVE "NIST P-521"
+/**
+ * Name of the curve we are using.  Note that we have hard-coded
+ * structs that use 256 bits, so using a bigger curve will require
+ * changes that break stuff badly.  The name of the curve given here
+ * must be agreed by all peers and be supported by libgcrypt.
+ */
+#define CURVE "Ed25519"
 
 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
 
 
 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
 
 
 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
 
 
 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
 
-
-/**
- * FIXME: what is an acceptable value here?
- */
-#define GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH 64
-
-/**
- * Length of the q-point (Q = dP) in the public key.
- * FIXME: double-check that this is right.
- */
-#define GNUNET_CRYPTO_ECC_PUBLIC_KEY_LENGTH 64
-
-
-/**
- * @brief an ECC signature
- */
-struct GNUNET_CRYPTO_EccSignature
-{
-  unsigned char sig[GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH];
-};
-
-
-GNUNET_NETWORK_STRUCT_BEGIN
-
-/**
- * @brief header of what an ECC signature signs
- *        this must be followed by "size - 8" bytes of
- *        the actual signed data
- */
-struct GNUNET_CRYPTO_EccSignaturePurpose
-{
-  /**
-   * How many bytes does this signature sign?
-   * (including this purpose header); in network
-   * byte order (!).
-   */
-  uint32_t size GNUNET_PACKED;
-
-  /**
-   * What does this signature vouch for?  This
-   * must contain a GNUNET_SIGNATURE_PURPOSE_XXX
-   * constant (from gnunet_signatures.h).  In
-   * network byte order!
-   */
-  uint32_t purpose GNUNET_PACKED;
-
-};
-
-
-/**
- * Public ECC key (always for NIST P-521) encoded in a format suitable
- * for network transmission.
- */
-struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded 
-{
-  /**
-   * Size of the encoding, in network byte order.
-   */
-  uint16_t size;
-
-  /**
-   * Actual length of the q-point binary encoding.
-   */
-  uint16_t len;
-
-  /**
-   * 0-padded q-point in binary encoding (GCRYPT_MPI_FMT_USG).
-   */
-  unsigned char key[GNUNET_CRYPTO_ECC_PUBLIC_KEY_LENGTH];
-};
-
-
-struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded
-{
-  /**
-   * Overall size of the private key.
-   */
-  uint16_t size;
-
-  /**
-   * Size of the q and d components of the private key.
-   * Note that the other parameters are from NIST P-521.
-   */
-  uint16_t sizes[2];
-};
-
-
-/**
- * ECC Encrypted data.
- */
-struct GNUNET_CRYPTO_EccEncryptedData
-{
-  unsigned char encoding[GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH];
-};
-
-GNUNET_NETWORK_STRUCT_END
-
-
-
-/**
- * The private information of an ECC private key.
- */
-struct GNUNET_CRYPTO_EccPrivateKey
-{
-  
-  /**
-   * Libgcrypt S-expression for the ECC key.
-   */
-  gcry_sexp_t sexp;
-};
-
-
-/**
- * Function called upon completion of 'GNUNET_CRYPTO_ecc_key_create_async'.
- *
- * @param cls closure
- * @param pk NULL on error, otherwise the private key (which must be free'd by the callee)
- * @param emsg NULL on success, otherwise an error message
- */
-typedef void (*GNUNET_CRYPTO_EccKeyCallback)(void *cls,
-                                            struct GNUNET_CRYPTO_EccPrivateKey *pk,
-                                            const char *emsg);
-
-
-
 /**
  * Log an error message at log-level 'level' that indicates
  * a failure of the command 'cmd' with the message given
  * by gcry_strerror(rc).
  */
 /**
  * Log an error message at log-level 'level' that indicates
  * a failure of the command 'cmd' with the message given
  * by gcry_strerror(rc).
  */
-#define LOG_GCRY(level, cmd, rc) do { LOG(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, gcry_strerror(rc)); } while(0);
-
-
-/**
- * If target != size, move target bytes to the
- * end of the size-sized buffer and zero out the
- * first target-size bytes.
- *
- * @param buf original buffer
- * @param size number of bytes in the buffer
- * @param target target size of the buffer
- */
-static void
-adjust (unsigned char *buf, size_t size, size_t target)
-{
-  if (size < target)
-  {
-    memmove (&buf[target - size], buf, size);
-    memset (buf, 0, target - size);
-  }
-}
-
-
-/**
- * Free memory occupied by hostkey
- * @param privatekey pointer to the memory to free
- */
-void
-GNUNET_CRYPTO_ecc_key_free (struct GNUNET_CRYPTO_EccPrivateKey *privatekey)
-{
-  gcry_sexp_release (privatekey->sexp);
-  GNUNET_free (privatekey);
-}
+#define LOG_GCRY(level, cmd, rc) do { LOG(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, gcry_strerror(rc)); } while(0)
 
 
 /**
 
 
 /**
@@ -221,7 +62,9 @@ GNUNET_CRYPTO_ecc_key_free (struct GNUNET_CRYPTO_EccPrivateKey *privatekey)
  * @return 0 on success
  */
 static int
  * @return 0 on success
  */
 static int
-key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
+key_from_sexp (gcry_mpi_t * array,
+               gcry_sexp_t sexp,
+               const char *topname,
                const char *elems)
 {
   gcry_sexp_t list;
                const char *elems)
 {
   gcry_sexp_t list;
@@ -231,13 +74,13 @@ key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
   unsigned int idx;
 
   list = gcry_sexp_find_token (sexp, topname, 0);
   unsigned int idx;
 
   list = gcry_sexp_find_token (sexp, topname, 0);
-  if (! list)  
-    return 1;  
+  if (! list)
+    return 1;
   l2 = gcry_sexp_cadr (list);
   gcry_sexp_release (list);
   list = l2;
   l2 = gcry_sexp_cadr (list);
   gcry_sexp_release (list);
   list = l2;
-  if (! list)  
-    return 2;  
+  if (! list)
+    return 2;
 
   idx = 0;
   for (s = elems; *s; s++, idx++)
 
   idx = 0;
   for (s = elems; *s; s++, idx++)
@@ -272,1043 +115,826 @@ key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
 
 
 /**
 
 
 /**
- * Extract the public key for the given private key.
- *
- * @param priv the private key
- * @param pub where to write the public key
- */
-void
-GNUNET_CRYPTO_ecc_key_get_public (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
-                                  struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub)
-{
-  gcry_mpi_t skey;
-  size_t size;
-  int rc;
-
-  rc = key_from_sexp (&skey, priv->sexp, "public-key", "q");
-  if (rc)
-    rc = key_from_sexp (&skey, priv->sexp, "private-key", "q");
-  if (rc)
-    rc = key_from_sexp (&skey, priv->sexp, "ecc", "q");
-  GNUNET_assert (0 == rc);
-  pub->size = htons (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded));
-  size = GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH;
-  GNUNET_assert (0 ==
-                 gcry_mpi_print (GCRYMPI_FMT_USG, pub->key, size, &size,
-                                 skey));
-  pub->len = htons (size);
-  adjust (&pub->key[0], size, GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH);
-  gcry_mpi_release (skey);
-}
-
-
-/**
- * Convert a public key to a string.
- *
- * @param pub key to convert
- * @return string representing  'pub'
- */
-char *
-GNUNET_CRYPTO_ecc_public_key_to_string (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub)
-{
-  char *pubkeybuf;
-  size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) * 8;
-  char *end;
-
-  if (keylen % 5 > 0)
-    keylen += 5 - keylen % 5;
-  keylen /= 5;
-  pubkeybuf = GNUNET_malloc (keylen + 1);
-  end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub, 
-                                      sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded), 
-                                      pubkeybuf, 
-                                      keylen);
-  if (NULL == end)
-  {
-    GNUNET_free (pubkeybuf);
-    return NULL;
-  }
-  *end = '\0';
-  return pubkeybuf;
-}
-
-
-/**
- * Convert a string representing a public key to a public key.
- *
- * @param enc encoded public key
- * @param enclen number of bytes in enc (without 0-terminator)
- * @param pub where to store the public key
- * @return GNUNET_OK on success
- */
-int
-GNUNET_CRYPTO_ecc_public_key_from_string (const char *enc, 
-                                         size_t enclen,
-                                         struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub)
-{
-  size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) * 8;
-
-  if (keylen % 5 > 0)
-    keylen += 5 - keylen % 5;
-  keylen /= 5;
-  if (enclen != keylen)
-    return GNUNET_SYSERR;
-
-  if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
-                                                (unsigned char*) pub,
-                                                sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)))
-    return GNUNET_SYSERR;
-  if ( (ntohs (pub->size) != sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) ||
-       (ntohs (pub->len) > GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH) )
-    return GNUNET_SYSERR;
-  return GNUNET_OK;
-}
-
-
-/**
- * Convert the given public key from the network format to the
+ * Convert the given private key from the network format to the
  * S-expression that can be used by libgcrypt.
  *
  * S-expression that can be used by libgcrypt.
  *
- * @param publicKey public key to decode
+ * @param priv private key to decode
  * @return NULL on error
  */
 static gcry_sexp_t
  * @return NULL on error
  */
 static gcry_sexp_t
-decode_public_key (const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *publicKey)
+decode_private_ecdsa_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
 {
   gcry_sexp_t result;
 {
   gcry_sexp_t result;
-  gcry_mpi_t q;
-  size_t size;
-  size_t erroff;
   int rc;
 
   int rc;
 
-  if (ntohs (publicKey->len) > GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH) 
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
-  size = ntohs (publicKey->size);
-  if (0 != (rc = gcry_mpi_scan (&q, GCRYMPI_FMT_USG, publicKey->key, size, &size)))
+  rc = gcry_sexp_build (&result, NULL,
+                       "(private-key(ecc(curve \"" CURVE "\")"
+                        "(d %b)))",
+                       (int) sizeof (priv->d), priv->d);
+  if (0 != rc)
   {
   {
-    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
-    return NULL;
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
+    GNUNET_assert (0);
   }
   }
-  rc = gcry_sexp_build (&result, &erroff, "(public-key(ecc((curve \"" CURVE "\")(q %m)))", q);
-  gcry_mpi_release (q);
-  if (0 != rc)
+#if EXTRA_CHECKS
+  if (0 != (rc = gcry_pk_testkey (result)))
   {
   {
-    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);  /* erroff gives more info */
-    return NULL;
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
+    GNUNET_assert (0);
   }
   }
+#endif
   return result;
 }
 
 
 /**
   return result;
 }
 
 
 /**
- * Encode the private key in a format suitable for
- * storing it into a file.
+ * Convert the given private key from the network format to the
+ * S-expression that can be used by libgcrypt.
  *
  *
- * @returns encoding of the private key.
- *    The first 4 bytes give the size of the array, as usual.
+ * @param priv private key to decode
+ * @return NULL on error
  */
  */
-struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *
-GNUNET_CRYPTO_ecc_encode_key (const struct GNUNET_CRYPTO_EccPrivateKey *hostkey)
+static gcry_sexp_t
+decode_private_eddsa_key (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
 {
 {
-  struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *retval;
-  gcry_mpi_t pkv[2];
-  void *pbu[2];
-  size_t sizes[2];
-  size_t off;
+  gcry_sexp_t result;
   int rc;
   int rc;
-  unsigned int i;
-  size_t size;
-
-#if EXTRA_CHECKS
-  if (gcry_pk_testkey (hostkey->sexp))
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
-#endif
 
 
-  memset (pkv, 0, sizeof (gcry_mpi_t) * 2);
-  rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "qd");
-  if (rc)
-    rc = key_from_sexp (pkv, hostkey->sexp, "ecc", "qd");
-  GNUNET_assert (0 == rc);
-  size = sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded);
-  for (i=0;i<2;i++)
+  rc = gcry_sexp_build (&result, NULL,
+                       "(private-key(ecc(curve \"" CURVE "\")"
+                        "(flags eddsa)(d %b)))",
+                       (int)sizeof (priv->d), priv->d);
+  if (0 != rc)
   {
   {
-    if (NULL != pkv[i])
-    {
-      GNUNET_assert (0 ==
-                     gcry_mpi_aprint (GCRYMPI_FMT_USG,
-                                      (unsigned char **) &pbu[i], &sizes[i],
-                                      pkv[i]));
-      size += sizes[i];
-    }
-    else
-    {
-      pbu[i] = NULL;
-      sizes[i] = 0;
-    }
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
+    GNUNET_assert (0);
   }
   }
-  GNUNET_assert (size < 65536);
-  retval = GNUNET_malloc (size);
-  retval->size = htons (size);
-  off = 0;
-  for (i=0;i<2;i++)
+#if EXTRA_CHECKS
+  if (0 != (rc = gcry_pk_testkey (result)))
   {
   {
-    retval->sizes[i] = htons (sizes[0]);
-    memcpy (&((char *) (&retval[1]))[off], pbu[i], sizes[i]);
-    off += sizes[i];
-    if (NULL != pkv[i])
-      gcry_mpi_release (pkv[i]);
-    if (NULL != pbu[i])
-      free (pbu[i]);  
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
+    GNUNET_assert (0);
   }
   }
-  return retval;
+#endif
+  return result;
 }
 
 
 /**
 }
 
 
 /**
- * Decode the private key from the file-format back
- * to the "normal", internal format.
+ * Convert the given private key from the network format to the
+ * S-expression that can be used by libgcrypt.
  *
  *
- * @param buf the buffer where the private key data is stored
- * @param len the length of the data in 'buffer'
+ * @param priv private key to decode
  * @return NULL on error
  */
  * @return NULL on error
  */
-struct GNUNET_CRYPTO_EccPrivateKey *
-GNUNET_CRYPTO_ecc_decode_key (const char *buf, uint16_t len)
+static gcry_sexp_t
+decode_private_ecdhe_key (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv)
 {
 {
-  struct GNUNET_CRYPTO_EccPrivateKey *ret;
-  const struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *encoding =
-      (const struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *) buf;
-  gcry_sexp_t res;
-  gcry_mpi_t q;
-  gcry_mpi_t d;
+  gcry_sexp_t result;
   int rc;
   int rc;
-  size_t size;
-  size_t pos;
-  uint16_t enc_len;
-  size_t erroff;
 
 
-  enc_len = ntohs (encoding->size);
-  if (len != enc_len)
-    return NULL;
-  pos = 0;
-  size = ntohs (encoding->sizes[0]);
-  rc = gcry_mpi_scan (&q, GCRYMPI_FMT_USG,
-                      &((const unsigned char *) (&encoding[1]))[pos], size,
-                      &size);
-  pos += ntohs (encoding->sizes[0]);
-  if (0 != rc)
-  {
-    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
-    return NULL;
-  }
-  size = ntohs (encoding->sizes[1]);
-  rc = gcry_mpi_scan (&d, GCRYMPI_FMT_USG,
-                      &((const unsigned char *) (&encoding[1]))[pos], size,
-                      &size);
-  pos += ntohs (encoding->sizes[1]);
+  rc = gcry_sexp_build (&result, NULL,
+                       "(private-key(ecc(curve \"" CURVE "\")"
+                        "(d %b)))",
+                       (int)sizeof (priv->d), priv->d);
   if (0 != rc)
   {
   if (0 != rc)
   {
-    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
-    gcry_mpi_release (d);
-    return NULL;
-  }
-  rc = gcry_sexp_build (&res, &erroff,
-                       "(private-key(ecc(q %m)(d %m)(curve \"" CURVE "\")))",
-                       q, d);
-  gcry_mpi_release (q);
-  gcry_mpi_release (d);
-  if (0 != rc)
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
+    GNUNET_assert (0);
+  }
 #if EXTRA_CHECKS
 #if EXTRA_CHECKS
-  if (0 != (rc = gcry_pk_testkey (res)))
+  if (0 != (rc = gcry_pk_testkey (result)))
   {
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
   {
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
-    return NULL;
+    GNUNET_assert (0);
   }
 #endif
   }
 #endif
-  ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
-  ret->sexp = res;
-  return ret;
+  return result;
 }
 
 
 /**
 }
 
 
 /**
- * Create a new private key. Caller must free return value.
+ * Extract the public key for the given private key.
  *
  *
- * @return fresh private key
+ * @param priv the private key
+ * @param pub where to write the public key
  */
  */
-static struct GNUNET_CRYPTO_EccPrivateKey *
-ecc_key_create ()
+void
+GNUNET_CRYPTO_ecdsa_key_get_public (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
+                                    struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
 {
 {
-  struct GNUNET_CRYPTO_EccPrivateKey *ret;
-  gcry_sexp_t s_key;
-  gcry_sexp_t s_keyparam;
+  gcry_sexp_t sexp;
+  gcry_ctx_t ctx;
+  gcry_mpi_t q;
 
 
-  GNUNET_assert (0 ==
-                 gcry_sexp_build (&s_keyparam, NULL,
-                                  "(genkey(ecc(curve \"" CURVE "\")))"));
-  GNUNET_assert (0 == gcry_pk_genkey (&s_key, s_keyparam));
-  gcry_sexp_release (s_keyparam);
-#if EXTRA_CHECKS
-  GNUNET_assert (0 == gcry_pk_testkey (s_key));
-#endif
-  ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
-  ret->sexp = s_key;
-  return ret;
+  sexp = decode_private_ecdsa_key (priv);
+  GNUNET_assert (NULL != sexp);
+  GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
+  gcry_sexp_release (sexp);
+  q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
+  GNUNET_assert (NULL != q);
+  GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
+  gcry_mpi_release (q);
+  gcry_ctx_release (ctx);
 }
 
 
 /**
 }
 
 
 /**
- * Try to read the private key from the given file.
+ * Extract the public key for the given private key.
  *
  *
- * @param filename file to read the key from
- * @return NULL on error
+ * @param priv the private key
+ * @param pub where to write the public key
  */
  */
-static struct GNUNET_CRYPTO_EccPrivateKey *
-try_read_key (const char *filename)
+void
+GNUNET_CRYPTO_eddsa_key_get_public (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
+                                    struct GNUNET_CRYPTO_EddsaPublicKey *pub)
 {
 {
-  struct GNUNET_CRYPTO_EccPrivateKey *ret;
-  struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *enc;
-  struct GNUNET_DISK_FileHandle *fd;
-  OFF_T fs;
-  uint16_t len;
-
-  if (GNUNET_YES != GNUNET_DISK_file_test (filename))
-    return NULL;
-
-  /* hostkey file exists already, read it! */
-  if (NULL == (fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
-                                          GNUNET_DISK_PERM_NONE)))
-  {
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
-    return NULL;
-  }
-  if (GNUNET_OK != (GNUNET_DISK_file_handle_size (fd, &fs)))
-  {
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "stat", filename);
-    (void) GNUNET_DISK_file_close (fd);
-    return NULL;
-  }
-  if (0 == fs)
-  {
-    GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
-    return NULL;
-  }
-  if (fs > UINT16_MAX)
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR,
-         _("File `%s' does not contain a valid private key (too long, %llu bytes).  Deleting it.\n"),  
-         filename,
-        (unsigned long long) fs);
-    GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
-    if (0 != UNLINK (filename))    
-      LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
-    return NULL;
-  }
-
-  enc = GNUNET_malloc (fs);
-  GNUNET_break (fs == GNUNET_DISK_file_read (fd, enc, fs));
-  len = ntohs (enc->size);
-  ret = NULL;
-  if ((len != fs) ||
-      (NULL == (ret = GNUNET_CRYPTO_ecc_decode_key ((char *) enc, len))))
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR,
-         _("File `%s' does not contain a valid private key (failed decode, %llu bytes).  Deleting it.\n"),
-         filename,
-        (unsigned long long) fs);
-    GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
-    if (0 != UNLINK (filename))    
-      LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
-    GNUNET_free (enc);
-    return NULL;
-  }
-  GNUNET_free (enc);
+  gcry_sexp_t sexp;
+  gcry_ctx_t ctx;
+  gcry_mpi_t q;
 
 
-  GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
-  return ret;  
+  sexp = decode_private_eddsa_key (priv);
+  GNUNET_assert (NULL != sexp);
+  GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
+  gcry_sexp_release (sexp);
+  q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
+  GNUNET_assert (q);
+  GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
+  gcry_mpi_release (q);
+  gcry_ctx_release (ctx);
 }
 
 
 /**
 }
 
 
 /**
- * Wait for a short time (we're trying to lock a file or want
- * to give another process a shot at finishing a disk write, etc.).
- * Sleeps for 100ms (as that should be long enough for virtually all
- * modern systems to context switch and allow another process to do
- * some 'real' work).
+ * Extract the public key for the given private key.
+ *
+ * @param priv the private key
+ * @param pub where to write the public key
  */
  */
-static void
-short_wait ()
+void
+GNUNET_CRYPTO_ecdhe_key_get_public (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
+                                    struct GNUNET_CRYPTO_EcdhePublicKey *pub)
 {
 {
-  struct GNUNET_TIME_Relative timeout;
+  gcry_sexp_t sexp;
+  gcry_ctx_t ctx;
+  gcry_mpi_t q;
 
 
-  timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
-  (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
+  sexp = decode_private_ecdhe_key (priv);
+  GNUNET_assert (NULL != sexp);
+  GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
+  gcry_sexp_release (sexp);
+  q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
+  GNUNET_assert (q);
+  GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
+  gcry_mpi_release (q);
+  gcry_ctx_release (ctx);
 }
 
 
 /**
 }
 
 
 /**
- * Create a new private key by reading it from a file.  If the
- * files does not exist, create a new key and write it to the
- * file.  Caller must free return value.  Note that this function
- * can not guarantee that another process might not be trying
- * the same operation on the same file at the same time.
- * If the contents of the file
- * are invalid the old file is deleted and a fresh key is
- * created.
+ * Convert a public key to a string.
  *
  *
- * @return new private key, NULL on error (for example,
- *   permission denied)
+ * @param pub key to convert
+ * @return string representing @a pub
  */
  */
-struct GNUNET_CRYPTO_EccPrivateKey *
-GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
+char *
+GNUNET_CRYPTO_ecdsa_public_key_to_string (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
 {
 {
-  struct GNUNET_CRYPTO_EccPrivateKey *ret;
-  struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *enc;
-  uint16_t len;
-  struct GNUNET_DISK_FileHandle *fd;
-  unsigned int cnt;
-  int ec;
-  uint64_t fs;
-  struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pub;
-  struct GNUNET_PeerIdentity pid;
-
-  if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
-    return NULL;
-  while (GNUNET_YES != GNUNET_DISK_file_test (filename))
-  {
-    fd = GNUNET_DISK_file_open (filename,
-                                GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
-                                | GNUNET_DISK_OPEN_FAILIFEXISTS,
-                                GNUNET_DISK_PERM_USER_READ |
-                                GNUNET_DISK_PERM_USER_WRITE);
-    if (NULL == fd)
-    {
-      if (errno == EEXIST)
-      {
-        if (GNUNET_YES != GNUNET_DISK_file_test (filename))
-        {
-          /* must exist but not be accessible, fail for good! */
-          if (0 != ACCESS (filename, R_OK))
-            LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
-          else
-            GNUNET_break (0);   /* what is going on!? */
-          return NULL;
-        }
-        continue;
-      }
-      LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
-      return NULL;
-    }
-    cnt = 0;
+  char *pubkeybuf;
+  size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
+  char *end;
 
 
-    while (GNUNET_YES !=
-           GNUNET_DISK_file_lock (fd, 0,
-                                  sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded),
-                                  GNUNET_YES))
-    {
-      short_wait ();
-      if (0 == ++cnt % 10)
-      {
-        ec = errno;
-        LOG (GNUNET_ERROR_TYPE_ERROR,
-             _("Could not acquire lock on file `%s': %s...\n"), filename,
-             STRERROR (ec));
-      }
-    }
-    LOG (GNUNET_ERROR_TYPE_INFO,
-         _("Creating a new private key.  This may take a while.\n"));
-    ret = ecc_key_create ();
-    GNUNET_assert (ret != NULL);
-    enc = GNUNET_CRYPTO_ecc_encode_key (ret);
-    GNUNET_assert (enc != NULL);
-    GNUNET_assert (ntohs (enc->size) ==
-                   GNUNET_DISK_file_write (fd, enc, ntohs (enc->size)));
-    GNUNET_free (enc);
-
-    GNUNET_DISK_file_sync (fd);
-    if (GNUNET_YES !=
-        GNUNET_DISK_file_unlock (fd, 0,
-                                 sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)))
-      LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
-    GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
-    GNUNET_CRYPTO_ecc_key_get_public (ret, &pub);
-    GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey);
-    LOG (GNUNET_ERROR_TYPE_INFO,
-         _("I am host `%s'.  Stored new private key in `%s'.\n"),
-         GNUNET_i2s (&pid), filename);
-    return ret;
-  }
-  /* hostkey file exists already, read it! */
-  fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
-                              GNUNET_DISK_PERM_NONE);
-  if (NULL == fd)
+  if (keylen % 5 > 0)
+    keylen += 5 - keylen % 5;
+  keylen /= 5;
+  pubkeybuf = GNUNET_malloc (keylen + 1);
+  end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
+                                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
+                                      pubkeybuf,
+                                      keylen);
+  if (NULL == end)
   {
   {
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
+    GNUNET_free (pubkeybuf);
     return NULL;
   }
     return NULL;
   }
-  cnt = 0;
-  while (1)
-  {
-    if (GNUNET_YES !=
-        GNUNET_DISK_file_lock (fd, 0,
-                               sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded),
-                               GNUNET_NO))
-    {
-      if (0 == ++cnt % 60)
-      {
-        ec = errno;
-        LOG (GNUNET_ERROR_TYPE_ERROR,
-             _("Could not acquire lock on file `%s': %s...\n"), filename,
-             STRERROR (ec));
-        LOG (GNUNET_ERROR_TYPE_ERROR,
-             _
-             ("This may be ok if someone is currently generating a hostkey.\n"));
-      }
-      short_wait ();
-      continue;
-    }
-    if (GNUNET_YES != GNUNET_DISK_file_test (filename))
-    {
-      /* eh, what!? File we opened is now gone!? */
-      LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
-      if (GNUNET_YES !=
-          GNUNET_DISK_file_unlock (fd, 0,
-                                   sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)))
-        LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
-      GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
-
-      return NULL;
-    }
-    if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
-      fs = 0;
-    if (fs < sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded))
-    {
-      /* maybe we got the read lock before the hostkey generating
-       * process had a chance to get the write lock; give it up! */
-      if (GNUNET_YES !=
-          GNUNET_DISK_file_unlock (fd, 0,
-                                   sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)))
-        LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
-      if (0 == ++cnt % 10)
-      {
-        LOG (GNUNET_ERROR_TYPE_ERROR,
-             _
-             ("When trying to read hostkey file `%s' I found %u bytes but I need at least %u.\n"),
-             filename, (unsigned int) fs,
-             (unsigned int) sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded));
-        LOG (GNUNET_ERROR_TYPE_ERROR,
-             _
-             ("This may be ok if someone is currently generating a hostkey.\n"));
-      }
-      short_wait ();                /* wait a bit longer! */
-      continue;
-    }
-    break;
-  }
-  enc = GNUNET_malloc (fs);
-  GNUNET_assert (fs == GNUNET_DISK_file_read (fd, enc, fs));
-  len = ntohs (enc->size);
-  ret = NULL;
-  if ((len != fs) ||
-      (NULL == (ret = GNUNET_CRYPTO_ecc_decode_key ((char *) enc, len))))
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR,
-         _("File `%s' does not contain a valid private key.  Deleting it.\n"),
-         filename);
-    if (0 != UNLINK (filename))
-    {
-      LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
-    }
-  }
-  GNUNET_free (enc);
-  if (GNUNET_YES !=
-      GNUNET_DISK_file_unlock (fd, 0,
-                               sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)))
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
-  GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
-  if (ret != NULL)
+  *end = '\0';
+  return pubkeybuf;
+}
+
+
+/**
+ * Convert a public key to a string.
+ *
+ * @param pub key to convert
+ * @return string representing @a pub
+ */
+char *
+GNUNET_CRYPTO_eddsa_public_key_to_string (const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
+{
+  char *pubkeybuf;
+  size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
+  char *end;
+
+  if (keylen % 5 > 0)
+    keylen += 5 - keylen % 5;
+  keylen /= 5;
+  pubkeybuf = GNUNET_malloc (keylen + 1);
+  end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
+                                      sizeof (struct GNUNET_CRYPTO_EddsaPublicKey),
+                                      pubkeybuf,
+                                      keylen);
+  if (NULL == end)
   {
   {
-    GNUNET_CRYPTO_ecc_key_get_public (ret, &pub);
-    GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey);
-    LOG (GNUNET_ERROR_TYPE_INFO,
-         _("I am host `%s'.  Read private key from `%s'.\n"), GNUNET_i2s (&pid),
-         filename);
+    GNUNET_free (pubkeybuf);
+    return NULL;
   }
   }
-  return ret;
+  *end = '\0';
+  return pubkeybuf;
 }
 
 
 /**
 }
 
 
 /**
- * Handle to cancel private key generation and state for the
- * key generation operation.
+ * Convert a string representing a public key to a public key.
+ *
+ * @param enc encoded public key
+ * @param enclen number of bytes in @a enc (without 0-terminator)
+ * @param pub where to store the public key
+ * @return #GNUNET_OK on success
  */
  */
-struct GNUNET_CRYPTO_EccKeyGenerationContext
+int
+GNUNET_CRYPTO_ecdsa_public_key_from_string (const char *enc,
+                                            size_t enclen,
+                                            struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
 {
 {
-  
-  /**
-   * Continuation to call upon completion.
-   */
-  GNUNET_CRYPTO_EccKeyCallback cont;
+  size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
 
 
-  /**
-   * Closure for 'cont'.
-   */
-  void *cont_cls;
+  if (keylen % 5 > 0)
+    keylen += 5 - keylen % 5;
+  keylen /= 5;
+  if (enclen != keylen)
+    return GNUNET_SYSERR;
 
 
-  /**
-   * Name of the file.
-   */
-  char *filename;
+  if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
+                                                 pub,
+                                                 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
+    return GNUNET_SYSERR;
+  return GNUNET_OK;
+}
 
 
-  /**
-   * Handle to the helper process which does the key generation.
-   */ 
-  struct GNUNET_OS_Process *gnunet_ecc;
-  
-  /**
-   * Handle to 'stdout' of gnunet-ecc.  We 'read' on stdout to detect
-   * process termination (instead of messing with SIGCHLD).
-   */
-  struct GNUNET_DISK_PipeHandle *gnunet_ecc_out;
 
 
-  /**
-   * Location where we store the private key if it already existed.
-   * (if this is used, 'filename', 'gnunet_ecc' and 'gnunet_ecc_out' will
-   * not be used).
-   */
-  struct GNUNET_CRYPTO_EccPrivateKey *pk;
-  
-  /**
-   * Task reading from 'gnunet_ecc_out' to wait for process termination.
-   */
-  GNUNET_SCHEDULER_TaskIdentifier read_task;
-  
-};
+/**
+ * Convert a string representing a public key to a public key.
+ *
+ * @param enc encoded public key
+ * @param enclen number of bytes in @a enc (without 0-terminator)
+ * @param pub where to store the public key
+ * @return #GNUNET_OK on success
+ */
+int
+GNUNET_CRYPTO_eddsa_public_key_from_string (const char *enc,
+                                            size_t enclen,
+                                            struct GNUNET_CRYPTO_EddsaPublicKey *pub)
+{
+  size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
+
+  if (keylen % 5 > 0)
+    keylen += 5 - keylen % 5;
+  keylen /= 5;
+  if (enclen != keylen)
+    return GNUNET_SYSERR;
+
+  if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
+                                                 pub,
+                                                 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
+    return GNUNET_SYSERR;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Convert a string representing a private key to a private key.
+ *
+ * @param enc encoded public key
+ * @param enclen number of bytes in @a enc (without 0-terminator)
+ * @param priv where to store the private key
+ * @return #GNUNET_OK on success
+ */
+int
+GNUNET_CRYPTO_eddsa_private_key_from_string (const char *enc,
+                                             size_t enclen,
+                                             struct GNUNET_CRYPTO_EddsaPrivateKey *pub)
+{
+  size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
+
+  if (keylen % 5 > 0)
+    keylen += 5 - keylen % 5;
+  keylen /= 5;
+  if (enclen != keylen)
+    return GNUNET_SYSERR;
+
+  if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
+                                                 pub,
+                                                 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
+    return GNUNET_SYSERR;
+  return GNUNET_OK;
+}
+
+
+/**
+ * @ingroup crypto
+ * Clear memory that was used to store a private key.
+ *
+ * @param pk location of the key
+ */
+void
+GNUNET_CRYPTO_ecdhe_key_clear (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
+{
+  memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
+}
+
+
+/**
+ * @ingroup crypto
+ * Clear memory that was used to store a private key.
+ *
+ * @param pk location of the key
+ */
+void
+GNUNET_CRYPTO_ecdsa_key_clear (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
+{
+  memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
+}
 
 
 /**
 
 
 /**
- * Abort ECC key generation.
+ * @ingroup crypto
+ * Clear memory that was used to store a private key.
  *
  *
- * @param gc key generation context to abort
+ * @param pk location of the key
  */
 void
  */
 void
-GNUNET_CRYPTO_ecc_key_create_stop (struct GNUNET_CRYPTO_EccKeyGenerationContext *gc)
+GNUNET_CRYPTO_eddsa_key_clear (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
 {
 {
-  if (GNUNET_SCHEDULER_NO_TASK != gc->read_task)
+  memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
+}
+
+
+/**
+ * Create a new private key. Caller must free return value.
+ *
+ * @return fresh private key
+ */
+struct GNUNET_CRYPTO_EcdhePrivateKey *
+GNUNET_CRYPTO_ecdhe_key_create ()
+{
+  struct GNUNET_CRYPTO_EcdhePrivateKey *priv;
+  gcry_sexp_t priv_sexp;
+  gcry_sexp_t s_keyparam;
+  gcry_mpi_t d;
+  int rc;
+
+  /* NOTE: For libgcrypt >= 1.7, we do not need the 'eddsa' flag here,
+     but should also be harmless. For libgcrypt < 1.7, using 'eddsa'
+     disables an expensive key testing routine. We do not want to run
+     the expensive check for ECDHE, as we generate TONS of keys to
+     use for a very short time. */
+  if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
+                                  "(genkey(ecc(curve \"" CURVE "\")"
+                                  "(flags eddsa no-keytest)))")))
   {
   {
-    GNUNET_SCHEDULER_cancel (gc->read_task);
-    gc->read_task = GNUNET_SCHEDULER_NO_TASK;
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
+    return NULL;
   }
   }
-  if (NULL != gc->gnunet_ecc)
+  if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
   {
   {
-    (void) GNUNET_OS_process_kill (gc->gnunet_ecc, SIGKILL);
-    GNUNET_break (GNUNET_OK ==
-                 GNUNET_OS_process_wait (gc->gnunet_ecc));
-    GNUNET_OS_process_destroy (gc->gnunet_ecc);
-    GNUNET_DISK_pipe_close (gc->gnunet_ecc_out);
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
+    gcry_sexp_release (s_keyparam);
+    return NULL;
   }
   }
-
-  if (NULL != gc->filename)
+  gcry_sexp_release (s_keyparam);
+#if EXTRA_CHECKS
+  if (0 != (rc = gcry_pk_testkey (priv_sexp)))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
+    gcry_sexp_release (priv_sexp);
+    return NULL;
+  }
+#endif
+  if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
   {
   {
-    if (0 != UNLINK (gc->filename))
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", gc->filename);
-    GNUNET_free (gc->filename);
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
+    gcry_sexp_release (priv_sexp);
+    return NULL;
   }
   }
-  if (NULL != gc->pk)
-    GNUNET_CRYPTO_ecc_key_free (gc->pk);
-  GNUNET_free (gc);
+  gcry_sexp_release (priv_sexp);
+  priv = GNUNET_new (struct GNUNET_CRYPTO_EcdhePrivateKey);
+  GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
+  gcry_mpi_release (d);
+  return priv;
 }
 
 
 /**
 }
 
 
 /**
- * Task called upon shutdown or process termination of 'gnunet-ecc' during
- * ECC key generation.  Check where we are and perform the appropriate
- * action.
+ * Create a new private key. Caller must free return value.
+ *
+ * @return fresh private key
+ */
+struct GNUNET_CRYPTO_EcdsaPrivateKey *
+GNUNET_CRYPTO_ecdsa_key_create ()
+{
+  struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
+  gcry_sexp_t priv_sexp;
+  gcry_sexp_t s_keyparam;
+  gcry_mpi_t d;
+  int rc;
+
+  if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
+                                  "(genkey(ecc(curve \"" CURVE "\")"
+                                  "(flags)))")))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
+    return NULL;
+  }
+  if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
+    gcry_sexp_release (s_keyparam);
+    return NULL;
+  }
+  gcry_sexp_release (s_keyparam);
+#if EXTRA_CHECKS
+  if (0 != (rc = gcry_pk_testkey (priv_sexp)))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
+    gcry_sexp_release (priv_sexp);
+    return NULL;
+  }
+#endif
+  if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
+    gcry_sexp_release (priv_sexp);
+    return NULL;
+  }
+  gcry_sexp_release (priv_sexp);
+  priv = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
+  GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
+  gcry_mpi_release (d);
+  return priv;
+}
+
+/**
+ * Create a new private key. Caller must free return value.
  *
  *
- * @param cls the 'struct GNUNET_CRYPTO_EccKeyGenerationContext'
- * @param tc scheduler context
+ * @return fresh private key
  */
  */
-static void
-check_key_generation_completion (void *cls,
-                                const struct GNUNET_SCHEDULER_TaskContext *tc)
+struct GNUNET_CRYPTO_EddsaPrivateKey *
+GNUNET_CRYPTO_eddsa_key_create ()
 {
 {
-  struct GNUNET_CRYPTO_EccKeyGenerationContext *gc = cls;
-  struct GNUNET_CRYPTO_EccPrivateKey *pk;
+  struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
+  gcry_sexp_t priv_sexp;
+  gcry_sexp_t s_keyparam;
+  gcry_mpi_t d;
+  int rc;
 
 
-  gc->read_task = GNUNET_SCHEDULER_NO_TASK;
-  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+  if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
+                                  "(genkey(ecc(curve \"" CURVE "\")"
+                                  "(flags eddsa)))")))
   {
   {
-    gc->cont (gc->cont_cls, NULL, _("interrupted by shutdown"));
-    GNUNET_CRYPTO_ecc_key_create_stop (gc);
-    return;
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
+    return NULL;
   }
   }
-  GNUNET_assert (GNUNET_OK == 
-                GNUNET_OS_process_wait (gc->gnunet_ecc));
-  GNUNET_OS_process_destroy (gc->gnunet_ecc);
-  gc->gnunet_ecc = NULL;
-  if (NULL == (pk = try_read_key (gc->filename)))
+  if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
   {
   {
-    GNUNET_break (0);
-    gc->cont (gc->cont_cls, NULL, _("gnunet-ecc failed"));
-    GNUNET_CRYPTO_ecc_key_create_stop (gc);
-    return;
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
+    gcry_sexp_release (s_keyparam);
+    return NULL;
   }
   }
-  gc->cont (gc->cont_cls, pk, NULL);
-  GNUNET_DISK_pipe_close (gc->gnunet_ecc_out);
-  GNUNET_free (gc->filename);
-  GNUNET_free (gc);
+  gcry_sexp_release (s_keyparam);
+#if EXTRA_CHECKS
+  if (0 != (rc = gcry_pk_testkey (priv_sexp)))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
+    gcry_sexp_release (priv_sexp);
+    return NULL;
+  }
+#endif
+  if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
+    gcry_sexp_release (priv_sexp);
+    return NULL;
+  }
+  gcry_sexp_release (priv_sexp);
+  priv = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
+  GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
+  gcry_mpi_release (d);
+  return priv;
 }
 
 
 /**
 }
 
 
 /**
- * Return the private ECC key which already existed on disk
- * (asynchronously) to the caller.
+ * Get the shared private key we use for anonymous users.
  *
  *
- * @param cls the 'struct GNUNET_CRYPTO_EccKeyGenerationContext'
- * @param tc scheduler context (unused)
+ * @return "anonymous" private key
  */
  */
-static void
-async_return_key (void *cls,
-                 const struct GNUNET_SCHEDULER_TaskContext *tc)
+const struct GNUNET_CRYPTO_EcdsaPrivateKey *
+GNUNET_CRYPTO_ecdsa_key_get_anonymous ()
 {
 {
-  struct GNUNET_CRYPTO_EccKeyGenerationContext *gc = cls;
+  /**
+   * 'anonymous' pseudonym (global static, d=1, public key = G
+   * (generator).
+   */
+  static struct GNUNET_CRYPTO_EcdsaPrivateKey anonymous;
+  static int once;
+
+  if (once)
+    return &anonymous;
+  GNUNET_CRYPTO_mpi_print_unsigned (anonymous.d,
+            sizeof (anonymous.d),
+            GCRYMPI_CONST_ONE);
+  once = 1;
+  return &anonymous;
+}
+
 
 
-  gc->cont (gc->cont_cls,
-           gc->pk,
-           NULL);
-  GNUNET_free (gc);
+/**
+ * Compare two Peer Identities.
+ *
+ * @param first first peer identity
+ * @param second second peer identity
+ * @return bigger than 0 if first > second,
+ *         0 if they are the same
+ *         smaller than 0 if second > first
+ */
+int
+GNUNET_CRYPTO_cmp_peer_identity (const struct GNUNET_PeerIdentity *first,
+                                 const struct GNUNET_PeerIdentity *second)
+{
+  return memcmp (first, second, sizeof (struct GNUNET_PeerIdentity));
 }
 
 
 /**
 }
 
 
 /**
- * Create a new private key by reading it from a file.  If the files
- * does not exist, create a new key and write it to the file.  If the
- * contents of the file are invalid the old file is deleted and a
- * fresh key is created.
+ * Convert the data specified in the given purpose argument to an
+ * S-expression suitable for signature operations.
  *
  *
- * @param filename name of file to use for storage
- * @param cont function to call when done (or on errors)
- * @param cont_cls closure for 'cont'
- * @return handle to abort operation, NULL on fatal errors (cont will not be called if NULL is returned)
+ * @param purpose data to convert
+ * @return converted s-expression
  */
  */
-struct GNUNET_CRYPTO_EccKeyGenerationContext *
-GNUNET_CRYPTO_ecc_key_create_start (const char *filename,
-                                   GNUNET_CRYPTO_EccKeyCallback cont,
-                                   void *cont_cls)
+static gcry_sexp_t
+data_to_eddsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
 {
 {
-  struct GNUNET_CRYPTO_EccKeyGenerationContext *gc;
-  struct GNUNET_CRYPTO_EccPrivateKey *pk;
-  const char *weak_random;
+  struct GNUNET_HashCode hc;
+  gcry_sexp_t data;
+  int rc;
 
 
-  if (NULL != (pk = try_read_key (filename)))
-  {
-    /* quick happy ending: key already exists! */
-    gc = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccKeyGenerationContext));
-    gc->pk = pk;
-    gc->cont = cont;
-    gc->cont_cls = cont_cls;
-    gc->read_task = GNUNET_SCHEDULER_add_now (&async_return_key,
-                                             gc);
-    return gc;
-  }
-  gc = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccKeyGenerationContext));
-  gc->filename = GNUNET_strdup (filename);
-  gc->cont = cont;
-  gc->cont_cls = cont_cls;
-  gc->gnunet_ecc_out = GNUNET_DISK_pipe (GNUNET_NO,
-                                        GNUNET_NO,
-                                        GNUNET_NO,
-                                        GNUNET_YES);
-  if (NULL == gc->gnunet_ecc_out)
-  {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "pipe");
-    GNUNET_free (gc->filename);
-    GNUNET_free (gc);
-    return NULL;
-  }
-  weak_random = NULL;
-  if (GNUNET_YES ==
-      GNUNET_CRYPTO_random_is_weak ())
-    weak_random = "-w";
-  gc->gnunet_ecc = GNUNET_OS_start_process (GNUNET_NO,
-                                           GNUNET_OS_INHERIT_STD_ERR,
-                                           NULL, 
-                                           gc->gnunet_ecc_out,
-                                           "gnunet-ecc",
-                                           "gnunet-ecc",                                           
-                                           gc->filename,
-                                           weak_random,
-                                           NULL);
-  if (NULL == gc->gnunet_ecc)
+  GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
+  if (0 != (rc = gcry_sexp_build (&data, NULL,
+                                 "(data(flags eddsa)(hash-algo %s)(value %b))",
+                                 "sha512",
+                                 (int)sizeof (hc), &hc)))
   {
   {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fork");
-    GNUNET_DISK_pipe_close (gc->gnunet_ecc_out);
-    GNUNET_free (gc->filename);
-    GNUNET_free (gc);
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
     return NULL;
   }
     return NULL;
   }
-  GNUNET_assert (GNUNET_OK ==
-                GNUNET_DISK_pipe_close_end (gc->gnunet_ecc_out,
-                                            GNUNET_DISK_PIPE_END_WRITE));
-  gc->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
-                                                 GNUNET_DISK_pipe_handle (gc->gnunet_ecc_out,
-                                                                          GNUNET_DISK_PIPE_END_READ),
-                                                 &check_key_generation_completion,
-                                                 gc);
-  return gc;
+  return data;
 }
 
 
 /**
 }
 
 
 /**
- * Setup a hostkey file for a peer given the name of the
- * configuration file (!).  This function is used so that
- * at a later point code can be certain that reading a
- * hostkey is fast (for example in time-dependent testcases).
+ * Convert the data specified in the given purpose argument to an
+ * S-expression suitable for signature operations.
  *
  *
- * @param cfg_name name of the configuration file to use
+ * @param purpose data to convert
+ * @return converted s-expression
  */
  */
-void
-GNUNET_CRYPTO_ecc_setup_hostkey (const char *cfg_name)
+static gcry_sexp_t
+data_to_ecdsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
 {
 {
-  struct GNUNET_CONFIGURATION_Handle *cfg;
-  struct GNUNET_CRYPTO_EccPrivateKey *pk;
-  char *fn;
-
-  cfg = GNUNET_CONFIGURATION_create ();
-  (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
-  if (GNUNET_OK == 
-      GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", &fn))
+  struct GNUNET_HashCode hc;
+  gcry_sexp_t data;
+  int rc;
+
+  GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
+  if (0 != (rc = gcry_sexp_build (&data, NULL,
+                                 "(data(flags rfc6979)(hash %s %b))",
+                                 "sha512",
+                                 (int)sizeof (hc), &hc)))
   {
   {
-    pk = GNUNET_CRYPTO_ecc_key_create_from_file (fn);
-    if (NULL != pk)
-      GNUNET_CRYPTO_ecc_key_free (pk);
-    GNUNET_free (fn);
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
+    return NULL;
   }
   }
-  GNUNET_CONFIGURATION_destroy (cfg);
+  return data;
 }
 
 
 /**
 }
 
 
 /**
- * Encrypt a block with the public key of another host that uses the
- * same cipher.
+ * Sign a given block.
  *
  *
- * @param block the block to encrypt
- * @param size the size of block
- * @param publicKey the encoded public key used to encrypt
- * @param target where to store the encrypted block
- * @returns GNUNET_SYSERR on error, GNUNET_OK if ok
+ * @param priv private key to use for the signing
+ * @param purpose what to sign (size, purpose)
+ * @param sig where to write the signature
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
  */
 int
  */
 int
-GNUNET_CRYPTO_ecc_encrypt (const void *block, size_t size,
-                           const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded
-                           *publicKey,
-                           struct GNUNET_CRYPTO_EccEncryptedData *target)
+GNUNET_CRYPTO_ecdsa_sign (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
+                          const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+                          struct GNUNET_CRYPTO_EcdsaSignature *sig)
 {
 {
-  gcry_sexp_t result;
+  gcry_sexp_t priv_sexp;
+  gcry_sexp_t sig_sexp;
   gcry_sexp_t data;
   gcry_sexp_t data;
-  gcry_sexp_t psexp;
-  gcry_mpi_t val;
-  gcry_mpi_t rval;
-  size_t isize;
-  size_t erroff;
-
-  GNUNET_assert (size <= sizeof (struct GNUNET_HashCode));
-  if (! (psexp = decode_public_key (publicKey)))
+  int rc;
+  gcry_mpi_t rs[2];
+
+  priv_sexp = decode_private_ecdsa_key (priv);
+  data = data_to_ecdsa_value (purpose);
+  if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         _("ECC signing failed at %s:%d: %s\n"), __FILE__,
+         __LINE__, gcry_strerror (rc));
+    gcry_sexp_release (data);
+    gcry_sexp_release (priv_sexp);
     return GNUNET_SYSERR;
     return GNUNET_SYSERR;
-  isize = size;
-  GNUNET_assert (0 ==
-                 gcry_mpi_scan (&val, GCRYMPI_FMT_USG, block, isize, &isize));
-  GNUNET_assert (0 ==
-                 gcry_sexp_build (&data, &erroff,
-                                  "(data (flags pkcs1)(value %m))", val));
-  gcry_mpi_release (val);
-  GNUNET_assert (0 == gcry_pk_encrypt (&result, data, psexp));
+  }
+  gcry_sexp_release (priv_sexp);
   gcry_sexp_release (data);
   gcry_sexp_release (data);
-  gcry_sexp_release (psexp);
 
 
-  GNUNET_assert (0 == key_from_sexp (&rval, result, "ecc", "a"));
-  gcry_sexp_release (result);
-  isize = sizeof (struct GNUNET_CRYPTO_EccEncryptedData);
-  GNUNET_assert (0 ==
-                 gcry_mpi_print (GCRYMPI_FMT_USG, (unsigned char *) target,
-                                 isize, &isize, rval));
-  gcry_mpi_release (rval);
-  adjust (&target->encoding[0], isize,
-          sizeof (struct GNUNET_CRYPTO_EccEncryptedData));
+  /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
+     'signature' */
+  if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
+  {
+    GNUNET_break (0);
+    gcry_sexp_release (sig_sexp);
+    return GNUNET_SYSERR;
+  }
+  gcry_sexp_release (sig_sexp);
+  GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof (sig->r), rs[0]);
+  GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof (sig->s), rs[1]);
+  gcry_mpi_release (rs[0]);
+  gcry_mpi_release (rs[1]);
   return GNUNET_OK;
 }
 
 
 /**
   return GNUNET_OK;
 }
 
 
 /**
- * Decrypt a given block with the hostkey.
+ * Sign a given block.
  *
  *
- * @param key the key with which to decrypt this block
- * @param block the data to decrypt, encoded as returned by encrypt
- * @param result pointer to a location where the result can be stored
- * @param max the maximum number of bits to store for the result, if
- *        the decrypted block is bigger, an error is returned
- * @return the size of the decrypted block, -1 on error
+ * @param priv private key to use for the signing
+ * @param purpose what to sign (size, purpose)
+ * @param sig where to write the signature
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
  */
  */
-ssize_t
-GNUNET_CRYPTO_ecc_decrypt (const struct GNUNET_CRYPTO_EccPrivateKey * key,
-                           const struct GNUNET_CRYPTO_EccEncryptedData * block,
-                           void *result, size_t max)
+int
+GNUNET_CRYPTO_eddsa_sign (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
+                          const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+                          struct GNUNET_CRYPTO_EddsaSignature *sig)
 {
 {
-  gcry_sexp_t resultsexp;
+  gcry_sexp_t priv_sexp;
+  gcry_sexp_t sig_sexp;
   gcry_sexp_t data;
   gcry_sexp_t data;
-  size_t erroff;
-  size_t size;
-  gcry_mpi_t val;
-  unsigned char *endp;
-  unsigned char *tmp;
+  int rc;
+  gcry_mpi_t rs[2];
 
 
-#if EXTRA_CHECKS
-  GNUNET_assert (0 == gcry_pk_testkey (key->sexp));
-#endif
-  size = sizeof (struct GNUNET_CRYPTO_EccEncryptedData);
-  GNUNET_assert (0 ==
-                 gcry_mpi_scan (&val, GCRYMPI_FMT_USG, &block->encoding[0],
-                                size, &size));
-  GNUNET_assert (0 ==
-                 gcry_sexp_build (&data, &erroff, "(enc-val(flags)(ecc(a %m)))",
-                                  val));
-  gcry_mpi_release (val);
-  GNUNET_assert (0 == gcry_pk_decrypt (&resultsexp, data, key->sexp));
+  priv_sexp = decode_private_eddsa_key (priv);
+  data = data_to_eddsa_value (purpose);
+  if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         _("EdDSA signing failed at %s:%d: %s\n"), __FILE__,
+         __LINE__, gcry_strerror (rc));
+    gcry_sexp_release (data);
+    gcry_sexp_release (priv_sexp);
+    return GNUNET_SYSERR;
+  }
+  gcry_sexp_release (priv_sexp);
   gcry_sexp_release (data);
   gcry_sexp_release (data);
-  /* resultsexp has format "(value %m)" */
-  GNUNET_assert (NULL !=
-                 (val = gcry_sexp_nth_mpi (resultsexp, 1, GCRYMPI_FMT_USG)));
-  gcry_sexp_release (resultsexp);
-  size = max + GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH * 2;
-  tmp = GNUNET_malloc (size);
-  GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, tmp, size, &size, val));
-  gcry_mpi_release (val);
-  endp = tmp;
-  endp += (size - max);
-  size = max;
-  memcpy (result, endp, size);
-  GNUNET_free (tmp);
-  return size;
+
+  /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
+     'signature' */
+  if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
+  {
+    GNUNET_break (0);
+    gcry_sexp_release (sig_sexp);
+    return GNUNET_SYSERR;
+  }
+  gcry_sexp_release (sig_sexp);
+  GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof (sig->r), rs[0]);
+  GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof (sig->s), rs[1]);
+  gcry_mpi_release (rs[0]);
+  gcry_mpi_release (rs[1]);
+  return GNUNET_OK;
 }
 
 
 /**
 }
 
 
 /**
- * Sign a given block.
+ * Verify signature.
  *
  *
- * @param key private key to use for the signing
- * @param purpose what to sign (size, purpose)
- * @param sig where to write the signature
- * @return GNUNET_SYSERR on error, GNUNET_OK on success
+ * @param purpose what is the purpose that the signature should have?
+ * @param validate block to validate (size, purpose, data)
+ * @param sig signature that is being validated
+ * @param pub public key of the signer
+ * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
  */
 int
  */
 int
-GNUNET_CRYPTO_ecc_sign (const struct GNUNET_CRYPTO_EccPrivateKey *key,
-                        const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
-                        struct GNUNET_CRYPTO_EccSignature *sig)
+GNUNET_CRYPTO_ecdsa_verify (uint32_t purpose,
+                            const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
+                            const struct GNUNET_CRYPTO_EcdsaSignature *sig,
+                            const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
 {
 {
-  gcry_sexp_t result;
   gcry_sexp_t data;
   gcry_sexp_t data;
-  size_t ssize;
-  gcry_mpi_t rval;
-  struct GNUNET_HashCode hc;
-  char *buff;
-  int bufSize;
+  gcry_sexp_t sig_sexpr;
+  gcry_sexp_t pub_sexpr;
+  int rc;
 
 
-  GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
-#define FORMATSTRING "(4:data(5:flags5:pkcs1)(4:hash6:sha51264:0123456789012345678901234567890123456789012345678901234567890123))"
-  bufSize = strlen (FORMATSTRING) + 1;
-  buff = GNUNET_malloc (bufSize);
-  memcpy (buff, FORMATSTRING, bufSize);
-  memcpy (&buff
-          [bufSize -
-           strlen
-           ("0123456789012345678901234567890123456789012345678901234567890123))")
-           - 1], &hc, sizeof (struct GNUNET_HashCode));
-  GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0));
-  GNUNET_free (buff);
-  GNUNET_assert (0 == gcry_pk_sign (&result, data, key->sexp));
+  if (purpose != ntohl (validate->purpose))
+    return GNUNET_SYSERR;       /* purpose mismatch */
+
+  /* build s-expression for signature */
+  if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
+                                 "(sig-val(ecdsa(r %b)(s %b)))",
+                                  (int) sizeof (sig->r), sig->r,
+                                  (int) sizeof (sig->s), sig->s)))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
+    return GNUNET_SYSERR;
+  }
+  data = data_to_ecdsa_value (validate);
+  if (0 != (rc = gcry_sexp_build (&pub_sexpr, NULL,
+                                  "(public-key(ecc(curve " CURVE ")(q %b)))",
+                                  (int) sizeof (pub->q_y), pub->q_y)))
+  {
+    gcry_sexp_release (data);
+    gcry_sexp_release (sig_sexpr);
+    return GNUNET_SYSERR;
+  }
+  rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
+  gcry_sexp_release (pub_sexpr);
   gcry_sexp_release (data);
   gcry_sexp_release (data);
-  GNUNET_assert (0 == key_from_sexp (&rval, result, "ecc", "s"));
-  gcry_sexp_release (result);
-  ssize = sizeof (struct GNUNET_CRYPTO_EccSignature);
-  GNUNET_assert (0 ==
-                 gcry_mpi_print (GCRYMPI_FMT_USG, (unsigned char *) sig, ssize,
-                                 &ssize, rval));
-  gcry_mpi_release (rval);
-  adjust (sig->sig, ssize, sizeof (struct GNUNET_CRYPTO_EccSignature));
+  gcry_sexp_release (sig_sexpr);
+  if (0 != rc)
+  {
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         _("ECDSA signature verification failed at %s:%d: %s\n"), __FILE__,
+         __LINE__, gcry_strerror (rc));
+    return GNUNET_SYSERR;
+  }
   return GNUNET_OK;
 }
 
 
   return GNUNET_OK;
 }
 
 
+
 /**
  * Verify signature.
  *
  * @param purpose what is the purpose that the signature should have?
  * @param validate block to validate (size, purpose, data)
  * @param sig signature that is being validated
 /**
  * Verify signature.
  *
  * @param purpose what is the purpose that the signature should have?
  * @param validate block to validate (size, purpose, data)
  * @param sig signature that is being validated
- * @param publicKey public key of the signer
- * @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid
+ * @param pub public key of the signer
+ * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
  */
 int
  */
 int
-GNUNET_CRYPTO_ecc_verify (uint32_t purpose,
-                          const struct GNUNET_CRYPTO_EccSignaturePurpose
-                          *validate,
-                          const struct GNUNET_CRYPTO_EccSignature *sig,
-                          const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded
-                          *publicKey)
+GNUNET_CRYPTO_eddsa_verify (uint32_t purpose,
+                            const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
+                            const struct GNUNET_CRYPTO_EddsaSignature *sig,
+                            const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
 {
   gcry_sexp_t data;
 {
   gcry_sexp_t data;
-  gcry_sexp_t sigdata;
-  size_t size;
-  gcry_mpi_t val;
-  gcry_sexp_t psexp;
-  struct GNUNET_HashCode hc;
-  char *buff;
-  int bufSize;
-  size_t erroff;
+  gcry_sexp_t sig_sexpr;
+  gcry_sexp_t pub_sexpr;
   int rc;
 
   if (purpose != ntohl (validate->purpose))
     return GNUNET_SYSERR;       /* purpose mismatch */
   int rc;
 
   if (purpose != ntohl (validate->purpose))
     return GNUNET_SYSERR;       /* purpose mismatch */
-  GNUNET_CRYPTO_hash (validate, ntohl (validate->size), &hc);
-  size = sizeof (struct GNUNET_CRYPTO_EccSignature);
-  GNUNET_assert (0 ==
-                 gcry_mpi_scan (&val, GCRYMPI_FMT_USG,
-                                (const unsigned char *) sig, size, &size));
-  GNUNET_assert (0 ==
-                 gcry_sexp_build (&sigdata, &erroff, "(sig-val(ecc(s %m)))",
-                                  val));
-  gcry_mpi_release (val);
-  bufSize = strlen (FORMATSTRING) + 1;
-  buff = GNUNET_malloc (bufSize);
-  memcpy (buff, FORMATSTRING, bufSize);
-  memcpy (&buff
-          [strlen (FORMATSTRING) -
-           strlen
-           ("0123456789012345678901234567890123456789012345678901234567890123))")],
-          &hc, sizeof (struct GNUNET_HashCode));
-  GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0));
-  GNUNET_free (buff);
-  if (! (psexp = decode_public_key (publicKey)))
+
+  /* build s-expression for signature */
+  if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
+                                 "(sig-val(eddsa(r %b)(s %b)))",
+                                  (int)sizeof (sig->r), sig->r,
+                                  (int)sizeof (sig->s), sig->s)))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
+    return GNUNET_SYSERR;
+  }
+  data = data_to_eddsa_value (validate);
+  if (0 != (rc = gcry_sexp_build (&pub_sexpr, NULL,
+                                  "(public-key(ecc(curve " CURVE ")(flags eddsa)(q %b)))",
+                                  (int)sizeof (pub->q_y), pub->q_y)))
   {
     gcry_sexp_release (data);
   {
     gcry_sexp_release (data);
-    gcry_sexp_release (sigdata);
+    gcry_sexp_release (sig_sexpr);
     return GNUNET_SYSERR;
   }
     return GNUNET_SYSERR;
   }
-  rc = gcry_pk_verify (sigdata, data, psexp);
-  gcry_sexp_release (psexp);
+  rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
+  gcry_sexp_release (pub_sexpr);
   gcry_sexp_release (data);
   gcry_sexp_release (data);
-  gcry_sexp_release (sigdata);
-  if (rc)
+  gcry_sexp_release (sig_sexpr);
+  if (0 != rc)
   {
   {
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         _("ECC signature verification failed at %s:%d: %s\n"), __FILE__,
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         _("EdDSA signature verification failed at %s:%d: %s\n"), __FILE__,
          __LINE__, gcry_strerror (rc));
     return GNUNET_SYSERR;
   }
          __LINE__, gcry_strerror (rc));
     return GNUNET_SYSERR;
   }
@@ -1316,4 +942,523 @@ GNUNET_CRYPTO_ecc_verify (uint32_t purpose,
 }
 
 
 }
 
 
+/**
+ * Derive key material from a public and a private ECDHE key.
+ *
+ * @param priv private key to use for the ECDH (x)
+ * @param pub public key to use for the ECDH (yG)
+ * @param key_material where to write the key material (xyG)
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
+ */
+int
+GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
+                        const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
+                        struct GNUNET_HashCode *key_material)
+{
+  gcry_mpi_point_t result;
+  gcry_mpi_point_t q;
+  gcry_mpi_t d;
+  gcry_ctx_t ctx;
+  gcry_sexp_t pub_sexpr;
+  gcry_mpi_t result_x;
+  unsigned char xbuf[256 / 8];
+  size_t rsize;
+
+  /* first, extract the q = dP value from the public key */
+  if (0 != gcry_sexp_build (&pub_sexpr, NULL,
+                            "(public-key(ecc(curve " CURVE ")(q %b)))",
+                            (int)sizeof (pub->q_y), pub->q_y))
+    return GNUNET_SYSERR;
+  GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
+  gcry_sexp_release (pub_sexpr);
+  q = gcry_mpi_ec_get_point ("q", ctx, 0);
+
+  /* second, extract the d value from our private key */
+  GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
+
+  /* then call the 'multiply' function, to compute the product */
+  result = gcry_mpi_point_new (0);
+  gcry_mpi_ec_mul (result, d, q, ctx);
+  gcry_mpi_point_release (q);
+  gcry_mpi_release (d);
+
+  /* finally, convert point to string for hashing */
+  result_x = gcry_mpi_new (256);
+  if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
+    gcry_mpi_point_release (result);
+    gcry_ctx_release (ctx);
+    return GNUNET_SYSERR;
+  }
+  gcry_mpi_point_release (result);
+  gcry_ctx_release (ctx);
+
+  rsize = sizeof (xbuf);
+  GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
+  /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
+     as that does not include the sign bit; x should be a 255-bit
+     value, so with the sign it should fit snugly into the 256-bit
+     xbuf */
+  GNUNET_assert (0 ==
+                 gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
+                                 result_x));
+  GNUNET_CRYPTO_hash (xbuf,
+                      rsize,
+                      key_material);
+  gcry_mpi_release (result_x);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Derive the 'h' value for key derivation, where
+ * 'h = H(l,P)'.
+ *
+ * @param pub public key for deriviation
+ * @param label label for deriviation
+ * @param context additional context to use for HKDF of 'h';
+ *        typically the name of the subsystem/application
+ * @return h value
+ */
+static gcry_mpi_t
+derive_h (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
+         const char *label,
+         const char *context)
+{
+  gcry_mpi_t h;
+  struct GNUNET_HashCode hc;
+  static const char *const salt = "key-derivation";
+
+  GNUNET_CRYPTO_kdf (&hc, sizeof (hc),
+                    salt, strlen (salt),
+                    pub, sizeof (*pub),
+                    label, strlen (label),
+                    context, strlen (context),
+                    NULL, 0);
+  GNUNET_CRYPTO_mpi_scan_unsigned (&h,
+                                  (unsigned char *) &hc,
+                                  sizeof (hc));
+  return h;
+}
+
+
+/**
+ * Derive a private key from a given private key and a label.
+ * Essentially calculates a private key 'd = H(l,P) * x mod n'
+ * where n is the size of the ECC group and P is the public
+ * key associated with the private key 'd'.
+ *
+ * @param priv original private key
+ * @param label label to use for key deriviation
+ * @param context additional context to use for HKDF of 'h';
+ *        typically the name of the subsystem/application
+ * @return derived private key
+ */
+struct GNUNET_CRYPTO_EcdsaPrivateKey *
+GNUNET_CRYPTO_ecdsa_private_key_derive (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
+                                        const char *label,
+                                        const char *context)
+{
+  struct GNUNET_CRYPTO_EcdsaPublicKey pub;
+  struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
+  gcry_mpi_t h;
+  gcry_mpi_t x;
+  gcry_mpi_t d;
+  gcry_mpi_t n;
+  gcry_ctx_t ctx;
+
+  GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
+
+  n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
+  GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
+
+  h = derive_h (&pub, label, context);
+  GNUNET_CRYPTO_mpi_scan_unsigned (&x,
+                                  priv->d,
+                                  sizeof (priv->d));
+  d = gcry_mpi_new (256);
+  gcry_mpi_mulm (d, h, x, n);
+  gcry_mpi_release (h);
+  gcry_mpi_release (x);
+  gcry_mpi_release (n);
+  gcry_ctx_release (ctx);
+  ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
+  GNUNET_CRYPTO_mpi_print_unsigned (ret->d, sizeof (ret->d), d);
+  gcry_mpi_release (d);
+  return ret;
+}
+
+
+/**
+ * Derive a public key from a given public key and a label.
+ * Essentially calculates a public key 'V = H(l,P) * P'.
+ *
+ * @param pub original public key
+ * @param label label to use for key derivation
+ * @param context additional context to use for HKDF of 'h';
+ *        typically the name of the subsystem/application
+ * @param result where to write the derived public key
+ */
+void
+GNUNET_CRYPTO_ecdsa_public_key_derive (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
+                                       const char *label,
+                                       const char *context,
+                                       struct GNUNET_CRYPTO_EcdsaPublicKey *result)
+{
+  gcry_ctx_t ctx;
+  gcry_mpi_t q_y;
+  gcry_mpi_t h;
+  gcry_mpi_t n;
+  gcry_mpi_t h_mod_n;
+  gcry_mpi_point_t q;
+  gcry_mpi_point_t v;
+
+  GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
+
+  /* obtain point 'q' from original public key.  The provided 'q' is
+     compressed thus we first store it in the context and then get it
+     back as a (decompresssed) point.  */
+  q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8*sizeof (pub->q_y));
+  GNUNET_assert (NULL != q_y);
+  GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
+  gcry_mpi_release (q_y);
+  q = gcry_mpi_ec_get_point ("q", ctx, 0);
+  GNUNET_assert (q);
+
+  /* calculate h_mod_n = h % n */
+  h = derive_h (pub, label, context);
+  n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
+  h_mod_n = gcry_mpi_new (256);
+  gcry_mpi_mod (h_mod_n, h, n);
+  /* calculate v = h_mod_n * q */
+  v = gcry_mpi_point_new (0);
+  gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
+  gcry_mpi_release (h_mod_n);
+  gcry_mpi_release (h);
+  gcry_mpi_release (n);
+  gcry_mpi_point_release (q);
+
+  /* convert point 'v' to public key that we return */
+  GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
+  gcry_mpi_point_release (v);
+  q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
+  GNUNET_assert (q_y);
+  GNUNET_CRYPTO_mpi_print_unsigned (result->q_y,
+                                    sizeof (result->q_y),
+                                    q_y);
+  gcry_mpi_release (q_y);
+  gcry_ctx_release (ctx);
+}
+
+
+/**
+ * Reverse the sequence of the bytes in @a buffer
+ *
+ * @param[in|out] buffer buffer to invert
+ * @param length number of bytes in @a buffer
+ */
+static void
+reverse_buffer (unsigned char *buffer,
+               size_t length)
+{
+  unsigned char tmp;
+  size_t i;
+
+  for (i=0; i < length/2; i++)
+  {
+    tmp = buffer[i];
+    buffer[i] = buffer[length-1-i];
+    buffer[length-1-i] = tmp;
+  }
+}
+
+
+/**
+ * Convert the secret @a d of an EdDSA key to the
+ * value that is actually used in the EdDSA computation.
+ *
+ * @param d secret input
+ * @return value used for the calculation in EdDSA
+ */
+static gcry_mpi_t
+eddsa_d_to_a (gcry_mpi_t d)
+{
+  unsigned char rawmpi[32]; /* 256-bit value */
+  size_t rawmpilen;
+  unsigned char digest[64]; /* 512-bit hash value */
+  gcry_buffer_t hvec[2];
+  int b;
+  gcry_mpi_t a;
+
+  b = 256 / 8; /* number of bytes in `d` */
+
+  /* Note that we clear DIGEST so we can use it as input to left pad
+     the key with zeroes for hashing.  */
+  memset (hvec, 0, sizeof hvec);
+  rawmpilen = sizeof (rawmpi);
+  GNUNET_assert (0 ==
+                 gcry_mpi_print (GCRYMPI_FMT_USG,
+                                rawmpi, rawmpilen, &rawmpilen,
+                                 d));
+  hvec[0].data = digest;
+  hvec[0].off = 0;
+  hvec[0].len = b > rawmpilen? b - rawmpilen : 0;
+  hvec[1].data = rawmpi;
+  hvec[1].off = 0;
+  hvec[1].len = rawmpilen;
+  GNUNET_assert (0 ==
+                gcry_md_hash_buffers (GCRY_MD_SHA512,
+                                      0 /* flags */,
+                                      digest,
+                                      hvec, 2));
+  /* Compute the A value.  */
+  reverse_buffer (digest, 32);  /* Only the first half of the hash.  */
+  digest[0]   = (digest[0] & 0x7f) | 0x40;
+  digest[31] &= 0xf8;
+
+  GNUNET_CRYPTO_mpi_scan_unsigned (&a,
+                                  digest,
+                                  32);
+  return a;
+}
+
+
+/**
+ * @ingroup crypto
+ * Derive key material from a ECDH public key and a private EdDSA key.
+ * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
+ *
+ * @param priv private key from EdDSA to use for the ECDH (x)
+ * @param pub public key to use for the ECDH (yG)
+ * @param key_material where to write the key material H(h(x)yG)
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
+ */
+int
+GNUNET_CRYPTO_eddsa_ecdh (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
+                          const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
+                          struct GNUNET_HashCode *key_material)
+{
+  gcry_mpi_point_t result;
+  gcry_mpi_point_t q;
+  gcry_mpi_t d;
+  gcry_mpi_t a;
+  gcry_ctx_t ctx;
+  gcry_sexp_t pub_sexpr;
+  gcry_mpi_t result_x;
+  unsigned char xbuf[256 / 8];
+  size_t rsize;
+
+  /* first, extract the q = dP value from the public key */
+  if (0 != gcry_sexp_build (&pub_sexpr, NULL,
+                            "(public-key(ecc(curve " CURVE ")(q %b)))",
+                            (int)sizeof (pub->q_y), pub->q_y))
+    return GNUNET_SYSERR;
+  GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
+  gcry_sexp_release (pub_sexpr);
+  q = gcry_mpi_ec_get_point ("q", ctx, 0);
+
+  /* second, extract the d value from our private key */
+  GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
+
+  /* NOW, because this is EdDSA, HASH 'd' first! */
+  a = eddsa_d_to_a (d);
+  gcry_mpi_release (d);
+
+  /* then call the 'multiply' function, to compute the product */
+  result = gcry_mpi_point_new (0);
+  gcry_mpi_ec_mul (result, a, q, ctx);
+  gcry_mpi_point_release (q);
+  gcry_mpi_release (a);
+
+  /* finally, convert point to string for hashing */
+  result_x = gcry_mpi_new (256);
+  if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
+    gcry_mpi_point_release (result);
+    gcry_ctx_release (ctx);
+    return GNUNET_SYSERR;
+  }
+  gcry_mpi_point_release (result);
+  gcry_ctx_release (ctx);
+
+  rsize = sizeof (xbuf);
+  GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
+  /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
+     as that does not include the sign bit; x should be a 255-bit
+     value, so with the sign it should fit snugly into the 256-bit
+     xbuf */
+  GNUNET_assert (0 ==
+                 gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
+                                 result_x));
+  GNUNET_CRYPTO_hash (xbuf,
+                      rsize,
+                      key_material);
+  gcry_mpi_release (result_x);
+  return GNUNET_OK;
+}
+
+/**
+ * @ingroup crypto
+ * Derive key material from a ECDH public key and a private ECDSA key.
+ * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
+ *
+ * @param priv private key from ECDSA to use for the ECDH (x)
+ * @param pub public key to use for the ECDH (yG)
+ * @param key_material where to write the key material H(h(x)yG)
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
+ */
+int
+GNUNET_CRYPTO_ecdsa_ecdh (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
+                          const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
+                          struct GNUNET_HashCode *key_material)
+{
+  gcry_mpi_point_t result;
+  gcry_mpi_point_t q;
+  gcry_mpi_t d;
+  gcry_ctx_t ctx;
+  gcry_sexp_t pub_sexpr;
+  gcry_mpi_t result_x;
+  unsigned char xbuf[256 / 8];
+  size_t rsize;
+
+  /* first, extract the q = dP value from the public key */
+  if (0 != gcry_sexp_build (&pub_sexpr, NULL,
+                            "(public-key(ecc(curve " CURVE ")(q %b)))",
+                            (int)sizeof (pub->q_y), pub->q_y))
+    return GNUNET_SYSERR;
+  GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
+  gcry_sexp_release (pub_sexpr);
+  q = gcry_mpi_ec_get_point ("q", ctx, 0);
+
+  /* second, extract the d value from our private key */
+  GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
+
+  /* then call the 'multiply' function, to compute the product */
+  result = gcry_mpi_point_new (0);
+  gcry_mpi_ec_mul (result, d, q, ctx);
+  gcry_mpi_point_release (q);
+  gcry_mpi_release (d);
+
+  /* finally, convert point to string for hashing */
+  result_x = gcry_mpi_new (256);
+  if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
+    gcry_mpi_point_release (result);
+    gcry_ctx_release (ctx);
+    return GNUNET_SYSERR;
+  }
+  gcry_mpi_point_release (result);
+  gcry_ctx_release (ctx);
+
+  rsize = sizeof (xbuf);
+  GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
+  /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
+     as that does not include the sign bit; x should be a 255-bit
+     value, so with the sign it should fit snugly into the 256-bit
+     xbuf */
+  GNUNET_assert (0 ==
+                 gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
+                                 result_x));
+  GNUNET_CRYPTO_hash (xbuf,
+                      rsize,
+                      key_material);
+  gcry_mpi_release (result_x);
+  return GNUNET_OK;
+}
+
+
+
+/**
+ * @ingroup crypto
+ * Derive key material from a EdDSA public key and a private ECDH key.
+ * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
+ *
+ * @param priv private key to use for the ECDH (y)
+ * @param pub public key from EdDSA to use for the ECDH (X=h(x)G)
+ * @param key_material where to write the key material H(yX)=H(h(x)yG)
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
+ */
+int
+GNUNET_CRYPTO_ecdh_eddsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
+                          const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
+                          struct GNUNET_HashCode *key_material)
+{
+  gcry_mpi_point_t result;
+  gcry_mpi_point_t q;
+  gcry_mpi_t d;
+  gcry_ctx_t ctx;
+  gcry_sexp_t pub_sexpr;
+  gcry_mpi_t result_x;
+  unsigned char xbuf[256 / 8];
+  size_t rsize;
+
+  /* first, extract the q = dP value from the public key */
+  if (0 != gcry_sexp_build (&pub_sexpr, NULL,
+                            "(public-key(ecc(curve " CURVE ")(q %b)))",
+                            (int)sizeof (pub->q_y), pub->q_y))
+    return GNUNET_SYSERR;
+  GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
+  gcry_sexp_release (pub_sexpr);
+  q = gcry_mpi_ec_get_point ("q", ctx, 0);
+
+  /* second, extract the d value from our private key */
+  GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
+
+  /* then call the 'multiply' function, to compute the product */
+  result = gcry_mpi_point_new (0);
+  gcry_mpi_ec_mul (result, d, q, ctx);
+  gcry_mpi_point_release (q);
+  gcry_mpi_release (d);
+
+  /* finally, convert point to string for hashing */
+  result_x = gcry_mpi_new (256);
+  if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
+    gcry_mpi_point_release (result);
+    gcry_ctx_release (ctx);
+    return GNUNET_SYSERR;
+  }
+  gcry_mpi_point_release (result);
+  gcry_ctx_release (ctx);
+
+  rsize = sizeof (xbuf);
+  GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
+  /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
+     as that does not include the sign bit; x should be a 255-bit
+     value, so with the sign it should fit snugly into the 256-bit
+     xbuf */
+  GNUNET_assert (0 ==
+                 gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
+                                 result_x));
+  GNUNET_CRYPTO_hash (xbuf,
+                      rsize,
+                      key_material);
+  gcry_mpi_release (result_x);
+  return GNUNET_OK;
+}
+
+/**
+ * @ingroup crypto
+ * Derive key material from a ECDSA public key and a private ECDH key.
+ * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
+ *
+ * @param priv private key to use for the ECDH (y)
+ * @param pub public key from ECDSA to use for the ECDH (X=h(x)G)
+ * @param key_material where to write the key material H(yX)=H(h(x)yG)
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
+ */
+int
+GNUNET_CRYPTO_ecdh_ecdsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
+                          const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
+                          struct GNUNET_HashCode *key_material)
+{
+  return GNUNET_CRYPTO_ecdh_eddsa (priv,
+                                   (const struct GNUNET_CRYPTO_EddsaPublicKey *)pub,
+                                   key_material);
+}
+
 /* end of crypto_ecc.c */
 /* end of crypto_ecc.c */