rps.conf is generated from rps.conf.in
[oweals/gnunet.git] / src / util / crypto_ecc.c
index 79c003b8e855967891b0d26f53329b1b871c05b8..4bba395b32b8fc77a7d5425078ba7bf12ad20b3f 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2012, 2013 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
@@ -14,8 +14,8 @@
 
      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.
 */
 
 /**
 */
 
 /**
  */
 #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-256"
+/**
+ * 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__)
 
  * a failure of the command 'cmd' with the message given
  * by gcry_strerror(rc).
  */
  * 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);
-
-
-/**
- * The private information of an ECC private key.
- */
-struct GNUNET_CRYPTO_EccPrivateKey
-{
-  
-  /**
-   * Libgcrypt S-expression for the ECC key.
-   */
-  gcry_sexp_t sexp;
-};
-
-
-/**
- * Free memory occupied by ECC key
- *
- * @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)
 
 
 /**
 
 
 /**
@@ -82,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;
@@ -92,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++)
@@ -132,6 +114,105 @@ key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
 }
 
 
 }
 
 
+/**
+ * Convert the given private key from the network format to the
+ * S-expression that can be used by libgcrypt.
+ *
+ * @param priv private key to decode
+ * @return NULL on error
+ */
+static gcry_sexp_t
+decode_private_ecdsa_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
+{
+  gcry_sexp_t result;
+  int rc;
+
+  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_sexp_build", rc);
+    GNUNET_assert (0);
+  }
+#if EXTRA_CHECKS
+  if (0 != (rc = gcry_pk_testkey (result)))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
+    GNUNET_assert (0);
+  }
+#endif
+  return result;
+}
+
+
+/**
+ * Convert the given private key from the network format to the
+ * S-expression that can be used by libgcrypt.
+ *
+ * @param priv private key to decode
+ * @return NULL on error
+ */
+static gcry_sexp_t
+decode_private_eddsa_key (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
+{
+  gcry_sexp_t result;
+  int rc;
+
+  rc = gcry_sexp_build (&result, NULL,
+                       "(private-key(ecc(curve \"" CURVE "\")"
+                        "(flags eddsa)(d %b)))",
+                       (int)sizeof (priv->d), priv->d);
+  if (0 != rc)
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
+    GNUNET_assert (0);
+  }
+#if EXTRA_CHECKS
+  if (0 != (rc = gcry_pk_testkey (result)))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
+    GNUNET_assert (0);
+  }
+#endif
+  return result;
+}
+
+
+/**
+ * Convert the given private key from the network format to the
+ * S-expression that can be used by libgcrypt.
+ *
+ * @param priv private key to decode
+ * @return NULL on error
+ */
+static gcry_sexp_t
+decode_private_ecdhe_key (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv)
+{
+  gcry_sexp_t result;
+  int rc;
+
+  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_sexp_build", rc);
+    GNUNET_assert (0);
+  }
+#if EXTRA_CHECKS
+  if (0 != (rc = gcry_pk_testkey (result)))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
+    GNUNET_assert (0);
+  }
+#endif
+  return result;
+}
+
+
 /**
  * Extract the public key for the given private key.
  *
 /**
  * Extract the public key for the given private key.
  *
@@ -139,27 +220,105 @@ key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
  * @param pub where to write the public key
  */
 void
  * @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)
+GNUNET_CRYPTO_ecdsa_key_get_public (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
+                                    struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
 {
 {
-  gcry_mpi_t skey;
-  size_t size;
-  int rc;
+  gcry_sexp_t sexp;
+  gcry_ctx_t ctx;
+  gcry_mpi_t q;
 
 
-  memset (pub, 0, sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded));
-  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_MAX_PUBLIC_KEY_LENGTH;
-  GNUNET_assert (0 ==
-                 gcry_mpi_print (GCRYMPI_FMT_USG, pub->key, size, &size,
-                                 skey));
-  pub->len = htons (size);
-  gcry_mpi_release (skey);
+  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);
+}
+
+
+/**
+ * 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_eddsa_key_get_public (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
+                                    struct GNUNET_CRYPTO_EddsaPublicKey *pub)
+{
+  gcry_sexp_t sexp;
+  gcry_ctx_t ctx;
+  gcry_mpi_t q;
+
+  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);
+}
+
+
+/**
+ * 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_ecdhe_key_get_public (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
+                                    struct GNUNET_CRYPTO_EcdhePublicKey *pub)
+{
+  gcry_sexp_t sexp;
+  gcry_ctx_t ctx;
+  gcry_mpi_t q;
+
+  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);
+}
+
+
+/**
+ * Convert a public key to a string.
+ *
+ * @param pub key to convert
+ * @return string representing @a pub
+ */
+char *
+GNUNET_CRYPTO_ecdsa_public_key_to_string (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
+{
+  char *pubkeybuf;
+  size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 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_EcdsaPublicKey),
+                                      pubkeybuf,
+                                      keylen);
+  if (NULL == end)
+  {
+    GNUNET_free (pubkeybuf);
+    return NULL;
+  }
+  *end = '\0';
+  return pubkeybuf;
 }
 
 
 }
 
 
@@ -167,22 +326,22 @@ GNUNET_CRYPTO_ecc_key_get_public (const struct GNUNET_CRYPTO_EccPrivateKey *priv
  * Convert a public key to a string.
  *
  * @param pub key to convert
  * Convert a public key to a string.
  *
  * @param pub key to convert
- * @return string representing  'pub'
+ * @return string representing @a pub
  */
 char *
  */
 char *
-GNUNET_CRYPTO_ecc_public_key_to_string (const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub)
+GNUNET_CRYPTO_eddsa_public_key_to_string (const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
 {
   char *pubkeybuf;
 {
   char *pubkeybuf;
-  size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) * 8;
+  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);
   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, 
+  end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
+                                      sizeof (struct GNUNET_CRYPTO_EddsaPublicKey),
+                                      pubkeybuf,
                                       keylen);
   if (NULL == end)
   {
                                       keylen);
   if (NULL == end)
   {
@@ -198,16 +357,16 @@ GNUNET_CRYPTO_ecc_public_key_to_string (const struct GNUNET_CRYPTO_EccPublicKeyB
  * Convert a string representing a public key to a public key.
  *
  * @param enc encoded public key
  * 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 enclen number of bytes in @a enc (without 0-terminator)
  * @param pub where to store the public key
  * @param pub where to store the public key
- * @return GNUNET_OK on success
+ * @return #GNUNET_OK on success
  */
 int
  */
 int
-GNUNET_CRYPTO_ecc_public_key_from_string (const char *enc, 
-                                         size_t enclen,
-                                         struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub)
+GNUNET_CRYPTO_ecdsa_public_key_from_string (const char *enc,
+                                            size_t enclen,
+                                            struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
 {
 {
-  size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) * 8;
+  size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
 
   if (keylen % 5 > 0)
     keylen += 5 - keylen % 5;
 
   if (keylen % 5 > 0)
     keylen += 5 - keylen % 5;
@@ -217,150 +376,106 @@ GNUNET_CRYPTO_ecc_public_key_from_string (const char *enc,
 
   if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
                                                  pub,
 
   if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
                                                  pub,
-                                                 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)))
-    return GNUNET_SYSERR;
-  if ( (ntohs (pub->size) != sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) ||
-       (ntohs (pub->len) > GNUNET_CRYPTO_ECC_SIGNATURE_DATA_ENCODING_LENGTH) )
+                                                 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
     return GNUNET_SYSERR;
   return GNUNET_OK;
 }
 
 
 /**
     return GNUNET_SYSERR;
   return GNUNET_OK;
 }
 
 
 /**
- * Convert the given public key from the network format to the
- * S-expression that can be used by libgcrypt.
+ * Convert a string representing a public key to a public key.
  *
  *
- * @param publicKey public key to decode
- * @return NULL on error
+ * @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
  */
  */
-static gcry_sexp_t
-decode_public_key (const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *publicKey)
+int
+GNUNET_CRYPTO_eddsa_public_key_from_string (const char *enc,
+                                            size_t enclen,
+                                            struct GNUNET_CRYPTO_EddsaPublicKey *pub)
 {
 {
-  gcry_sexp_t result;
-  gcry_mpi_t q;
-  size_t size;
-  size_t erroff;
-  int rc;
+  size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
 
 
-  if (ntohs (publicKey->len) > GNUNET_CRYPTO_ECC_SIGNATURE_DATA_ENCODING_LENGTH) 
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
-  size = ntohs (publicKey->len);
-  if (0 != (rc = gcry_mpi_scan (&q, GCRYMPI_FMT_USG, publicKey->key, size, &size)))
-  {
-    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
-    return NULL;
-  }
+  if (keylen % 5 > 0)
+    keylen += 5 - keylen % 5;
+  keylen /= 5;
+  if (enclen != keylen)
+    return GNUNET_SYSERR;
 
 
-  rc = gcry_sexp_build (&result, &erroff, 
-                       "(public-key(ecdsa(curve \"" CURVE "\")(q %m)))",
-                       q);
-  gcry_mpi_release (q);
-  if (0 != rc)
-  {
-    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);  /* erroff gives more info */
-    return NULL;
-  }
-#if EXTRA_CHECKS
-  if (0 != (rc = gcry_pk_testkey (result)))
-  {
-    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
-    gcry_sexp_release (result);
-    return NULL;
-  }
-#endif
-  return result;
+  if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
+                                                 pub,
+                                                 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
+    return GNUNET_SYSERR;
+  return GNUNET_OK;
 }
 
 
 /**
 }
 
 
 /**
- * Encode the private key in a format suitable for
- * storing it into a file.
+ * Convert a string representing a private key to a private key.
  *
  *
- * @param key key to encode
- * @return encoding of the private key.
- *    The first 4 bytes give the size of the array, as usual.
+ * @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
  */
  */
-struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *
-GNUNET_CRYPTO_ecc_encode_key (const struct GNUNET_CRYPTO_EccPrivateKey *key)
+int
+GNUNET_CRYPTO_eddsa_private_key_from_string (const char *enc,
+                                             size_t enclen,
+                                             struct GNUNET_CRYPTO_EddsaPrivateKey *pub)
 {
 {
-  struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *retval;
-  char buf[65536];
-  uint16_t be;
-  size_t size;
+  size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
 
 
-#if EXTRA_CHECKS
-  if (0 != gcry_pk_testkey (key->sexp))
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
-#endif
-  size = gcry_sexp_sprint (key->sexp, 
-                          GCRYSEXP_FMT_DEFAULT,
-                          &buf[2], sizeof (buf) - sizeof (uint16_t));
-  if (0 == size)
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
-  GNUNET_assert (size < 65536 - sizeof (uint16_t));
-  be = htons ((uint16_t) size + (sizeof (be)));
-  memcpy (buf, &be, sizeof (be));
-  size += sizeof (be);
-  retval = GNUNET_malloc (size);
-  memcpy (retval, buf, size);
-  return retval;
+  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;
 }
 
 
 /**
 }
 
 
 /**
- * Decode the private key from the file-format back
- * to the "normal", internal format.
+ * @ingroup crypto
+ * Clear memory that was used to store a private key.
  *
  *
- * @param buf the buffer where the private key data is stored
- * @param len the length of the data in 'buffer'
- * @param validate GNUNET_YES to validate that the key is well-formed,
- *                 GNUNET_NO if the key comes from a totally trusted source 
- *                 and validation is considered too expensive
- * @return NULL on error
+ * @param pk location of the key
  */
  */
-struct GNUNET_CRYPTO_EccPrivateKey *
-GNUNET_CRYPTO_ecc_decode_key (const char *buf, 
-                             size_t len,
-                             int validate)
+void
+GNUNET_CRYPTO_ecdhe_key_clear (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
 {
 {
-  struct GNUNET_CRYPTO_EccPrivateKey *ret;
-  uint16_t be;
-  gcry_sexp_t sexp;
-  int rc;
-  size_t erroff;
+  memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
+}
 
 
-  if (len < sizeof (uint16_t)) 
-    return NULL;
-  memcpy (&be, buf, sizeof (be));
-  if (len < ntohs (be))
-    return NULL;
-  len = ntohs (be);
-  if (0 != (rc = gcry_sexp_sscan (&sexp,
-                                 &erroff,
-                                 &buf[2],
-                                 len - sizeof (uint16_t))))
-  {
-    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_scan", rc);
-    return NULL;
-  }  
-  if ( (GNUNET_YES == validate) &&
-       (0 != (rc = gcry_pk_testkey (sexp))) )
-  {
-    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
-    return NULL;
-  }
-  ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
-  ret->sexp = sexp;
-  return ret;
+
+/**
+ * @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));
+}
+
+
+/**
+ * @ingroup crypto
+ * Clear memory that was used to store a private key.
+ *
+ * @param pk location of the key
+ */
+void
+GNUNET_CRYPTO_eddsa_key_clear (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
+{
+  memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
 }
 
 
 }
 
 
@@ -369,21 +484,28 @@ GNUNET_CRYPTO_ecc_decode_key (const char *buf,
  *
  * @return fresh private key
  */
  *
  * @return fresh private key
  */
-struct GNUNET_CRYPTO_EccPrivateKey *
-GNUNET_CRYPTO_ecc_key_create ()
+struct GNUNET_CRYPTO_EcdhePrivateKey *
+GNUNET_CRYPTO_ecdhe_key_create ()
 {
 {
-  struct GNUNET_CRYPTO_EccPrivateKey *ret;
-  gcry_sexp_t s_key;
+  struct GNUNET_CRYPTO_EcdhePrivateKey *priv;
+  gcry_sexp_t priv_sexp;
   gcry_sexp_t s_keyparam;
   gcry_sexp_t s_keyparam;
+  gcry_mpi_t d;
   int rc;
 
   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,
   if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
-                                  "(genkey(ecdsa(curve \"" CURVE "\")))")))
+                                  "(genkey(ecc(curve \"" CURVE "\")"
+                                  "(flags eddsa no-keytest)))")))
   {
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
     return NULL;
   }
   {
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
     return NULL;
   }
-  if (0 != (rc = gcry_pk_genkey (&s_key, s_keyparam)))
+  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);
   {
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
     gcry_sexp_release (s_keyparam);
@@ -391,697 +513,428 @@ GNUNET_CRYPTO_ecc_key_create ()
   }
   gcry_sexp_release (s_keyparam);
 #if EXTRA_CHECKS
   }
   gcry_sexp_release (s_keyparam);
 #if EXTRA_CHECKS
-  if (0 != (rc = gcry_pk_testkey (s_key)))
+  if (0 != (rc = gcry_pk_testkey (priv_sexp)))
   {
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
   {
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
-    gcry_sexp_release (s_key);
+    gcry_sexp_release (priv_sexp);
     return NULL;
   }
 #endif
     return NULL;
   }
 #endif
-  ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
-  ret->sexp = s_key;
-  return ret;
+  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_EcdhePrivateKey);
+  GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
+  gcry_mpi_release (d);
+  return priv;
 }
 
 
 /**
 }
 
 
 /**
- * Try to read the private key from the given file.
+ * Create a new private key. Caller must free return value.
  *
  *
- * @param filename file to read the key from
- * @return NULL on error
+ * @return fresh private key
  */
  */
-static struct GNUNET_CRYPTO_EccPrivateKey *
-try_read_key (const char *filename)
+struct GNUNET_CRYPTO_EcdsaPrivateKey *
+GNUNET_CRYPTO_ecdsa_key_create ()
 {
 {
-  struct GNUNET_CRYPTO_EccPrivateKey *ret;
-  struct GNUNET_DISK_FileHandle *fd;
-  OFF_T fs;
-
-  if (GNUNET_YES != GNUNET_DISK_file_test (filename))
-    return NULL;
+  struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
+  gcry_sexp_t priv_sexp;
+  gcry_sexp_t s_keyparam;
+  gcry_mpi_t d;
+  int rc;
 
 
-  /* key file exists already, read it! */
-  if (NULL == (fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
-                                          GNUNET_DISK_PERM_NONE)))
+  if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
+                                  "(genkey(ecc(curve \"" CURVE "\")"
+                                  "(flags)))")))
   {
   {
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
     return NULL;
   }
     return NULL;
   }
-  if (GNUNET_OK != (GNUNET_DISK_file_handle_size (fd, &fs)))
+  if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
   {
   {
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "stat", filename);
-    (void) GNUNET_DISK_file_close (fd);
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
+    gcry_sexp_release (s_keyparam);
     return NULL;
   }
     return NULL;
   }
-  if (0 == fs)
+  gcry_sexp_release (s_keyparam);
+#if EXTRA_CHECKS
+  if (0 != (rc = gcry_pk_testkey (priv_sexp)))
   {
   {
-    GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
+    gcry_sexp_release (priv_sexp);
     return NULL;
   }
     return NULL;
   }
-  if (fs > UINT16_MAX)
+#endif
+  if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
   {
   {
-    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);
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
+    gcry_sexp_release (priv_sexp);
     return NULL;
   }
     return NULL;
   }
-  {
-    char enc[fs];
-
-    GNUNET_break (fs == GNUNET_DISK_file_read (fd, enc, fs));
-    if (NULL == (ret = GNUNET_CRYPTO_ecc_decode_key ((char *) enc, fs, GNUNET_YES)))
-    {
-      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);
-      return NULL;
-    }
-  }
-  GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
-  return ret;  
-}
-
-
-/**
- * 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).
- */
-static void
-short_wait ()
-{
-  struct GNUNET_TIME_Relative timeout;
-
-  timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
-  (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
+  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 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.
+ * Create a new private key. Caller must free return value.
  *
  *
- * @return new private key, NULL on error (for example,
- *   permission denied)
+ * @return fresh private key
  */
  */
-struct GNUNET_CRYPTO_EccPrivateKey *
-GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
+struct GNUNET_CRYPTO_EddsaPrivateKey *
+GNUNET_CRYPTO_eddsa_key_create ()
 {
 {
-  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;
+  struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
+  gcry_sexp_t priv_sexp;
+  gcry_sexp_t s_keyparam;
+  gcry_mpi_t d;
+  int rc;
 
 
-    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 = GNUNET_CRYPTO_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);
-    return ret;
-  }
-  /* key file exists already, read it! */
-  fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
-                              GNUNET_DISK_PERM_NONE);
-  if (NULL == fd)
+  if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
+                                  "(genkey(ecc(curve \"" CURVE "\")"
+                                  "(flags eddsa)))")))
   {
   {
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
     return NULL;
   }
     return NULL;
   }
-  cnt = 0;
-  while (1)
+  if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
   {
   {
-    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 private key.\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 key 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 key 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 key.\n"));
-      }
-      short_wait ();                /* wait a bit longer! */
-      continue;
-    }
-    break;
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
+    gcry_sexp_release (s_keyparam);
+    return NULL;
   }
   }
-  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, GNUNET_YES))))
+  gcry_sexp_release (s_keyparam);
+#if EXTRA_CHECKS
+  if (0 != (rc = gcry_pk_testkey (priv_sexp)))
   {
   {
-    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);
-    }
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
+    gcry_sexp_release (priv_sexp);
+    return NULL;
   }
   }
-  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)
+#endif
+  if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
   {
   {
-    GNUNET_CRYPTO_ecc_key_get_public (ret, &pub);
-    GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey);
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
+    gcry_sexp_release (priv_sexp);
+    return NULL;
   }
   }
-  return ret;
+  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;
 }
 
 
 /**
 }
 
 
 /**
- * Handle to cancel private key generation and state for the
- * key generation operation.
+ * Get the shared private key we use for anonymous users.
+ *
+ * @return "anonymous" private key
  */
  */
-struct GNUNET_CRYPTO_EccKeyGenerationContext
+const struct GNUNET_CRYPTO_EcdsaPrivateKey *
+GNUNET_CRYPTO_ecdsa_key_get_anonymous ()
 {
 {
-  
-  /**
-   * Continuation to call upon completion.
-   */
-  GNUNET_CRYPTO_EccKeyCallback cont;
-
   /**
   /**
-   * Closure for 'cont'.
+   * 'anonymous' pseudonym (global static, d=1, public key = G
+   * (generator).
    */
    */
-  void *cont_cls;
-
-  /**
-   * Name of the file.
-   */
-  char *filename;
-
-  /**
-   * 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;
-  
-};
-
-
-/**
- * Abort ECC key generation.
- *
- * @param gc key generation context to abort
- */
-void
-GNUNET_CRYPTO_ecc_key_create_stop (struct GNUNET_CRYPTO_EccKeyGenerationContext *gc)
-{
-  if (GNUNET_SCHEDULER_NO_TASK != gc->read_task)
-  {
-    GNUNET_SCHEDULER_cancel (gc->read_task);
-    gc->read_task = GNUNET_SCHEDULER_NO_TASK;
-  }
-  if (NULL != gc->gnunet_ecc)
-  {
-    (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);
-  }
-
-  if (NULL != gc->filename)
-  {
-    if (0 != UNLINK (gc->filename))
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", gc->filename);
-    GNUNET_free (gc->filename);
-  }
-  if (NULL != gc->pk)
-    GNUNET_CRYPTO_ecc_key_free (gc->pk);
-  GNUNET_free (gc);
+  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;
 }
 
 
 /**
 }
 
 
 /**
- * Task called upon shutdown or process termination of 'gnunet-ecc' during
- * ECC key generation.  Check where we are and perform the appropriate
- * action.
+ * Compare two Peer Identities.
  *
  *
- * @param cls the 'struct GNUNET_CRYPTO_EccKeyGenerationContext'
- * @param tc scheduler context
+ * @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
  */
  */
-static void
-check_key_generation_completion (void *cls,
-                                const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-  struct GNUNET_CRYPTO_EccKeyGenerationContext *gc = cls;
-  struct GNUNET_CRYPTO_EccPrivateKey *pk;
-
-  gc->read_task = GNUNET_SCHEDULER_NO_TASK;
-  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
-  {
-    gc->cont (gc->cont_cls, NULL, _("interrupted by shutdown"));
-    GNUNET_CRYPTO_ecc_key_create_stop (gc);
-    return;
-  }
-  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)))
-  {
-    GNUNET_break (0);
-    gc->cont (gc->cont_cls, NULL, _("gnunet-ecc failed"));
-    GNUNET_CRYPTO_ecc_key_create_stop (gc);
-    return;
-  }
-  gc->cont (gc->cont_cls, pk, NULL);
-  GNUNET_DISK_pipe_close (gc->gnunet_ecc_out);
-  GNUNET_free (gc->filename);
-  GNUNET_free (gc);
-}
-
-
-/**
- * Return the private ECC key which already existed on disk
- * (asynchronously) to the caller.
- *
- * @param cls the 'struct GNUNET_CRYPTO_EccKeyGenerationContext'
- * @param tc scheduler context (unused)
- */
-static void
-async_return_key (void *cls,
-                 const struct GNUNET_SCHEDULER_TaskContext *tc)
+int
+GNUNET_CRYPTO_cmp_peer_identity (const struct GNUNET_PeerIdentity *first,
+                                 const struct GNUNET_PeerIdentity *second)
 {
 {
-  struct GNUNET_CRYPTO_EccKeyGenerationContext *gc = cls;
-
-  gc->cont (gc->cont_cls,
-           gc->pk,
-           NULL);
-  GNUNET_free (gc);
+  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;
+  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;
-  }
-  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,
-                                           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 key 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
- * key 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_key (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, "PEER", "PRIVATE_KEY", &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;
 }
 
 
 /**
 }
 
 
 /**
- * Retrieve the identity of the host's peer.
+ * Sign a given block.
  *
  *
- * @param cfg configuration to use
- * @param dst pointer to where to write the peer identity
- * @return GNUNET_OK on success, GNUNET_SYSERR if the identity
- *         could not be retrieved
+ * @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_get_host_identity (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                                 struct GNUNET_PeerIdentity *dst)
+GNUNET_CRYPTO_ecdsa_sign (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
+                          const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+                          struct GNUNET_CRYPTO_EcdsaSignature *sig)
 {
 {
-  struct GNUNET_CRYPTO_EccPrivateKey *my_private_key;
-  struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded my_public_key;
-  char *keyfile;
+  gcry_sexp_t priv_sexp;
+  gcry_sexp_t sig_sexp;
+  gcry_sexp_t data;
+  int rc;
+  gcry_mpi_t rs[2];
 
 
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY",
-                                               &keyfile))
+  priv_sexp = decode_private_ecdsa_key (priv);
+  data = data_to_ecdsa_value (purpose);
+  if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
   {
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _("Lacking key configuration settings.\n"));
+    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;
   }
-  if (NULL == (my_private_key = GNUNET_CRYPTO_ecc_key_create_from_file (keyfile)))
+  gcry_sexp_release (priv_sexp);
+  gcry_sexp_release (data);
+
+  /* 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_log (GNUNET_ERROR_TYPE_ERROR,
-                _("Could not access hostkey file `%s'.\n"), keyfile);
-    GNUNET_free (keyfile);
+    GNUNET_break (0);
+    gcry_sexp_release (sig_sexp);
     return GNUNET_SYSERR;
   }
     return GNUNET_SYSERR;
   }
-  GNUNET_free (keyfile);
-  GNUNET_CRYPTO_ecc_key_get_public (my_private_key, &my_public_key);
-  GNUNET_CRYPTO_ecc_key_free (my_private_key);
-  GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), &dst->hashPubKey);
+  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;
 }
 
 
 /**
- * Convert the data specified in the given purpose argument to an
- * S-expression suitable for signature operations.
+ * Sign a given block.
  *
  *
- * @param purpose data to convert
- * @return converted s-expression
+ * @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
  */
  */
-static gcry_sexp_t
-data_to_pkcs1 (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
+int
+GNUNET_CRYPTO_eddsa_sign (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
+                          const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+                          struct GNUNET_CRYPTO_EddsaSignature *sig)
 {
 {
-  struct GNUNET_CRYPTO_ShortHashCode hc;
-  size_t bufSize;
+  gcry_sexp_t priv_sexp;
+  gcry_sexp_t sig_sexp;
   gcry_sexp_t data;
   gcry_sexp_t data;
+  int rc;
+  gcry_mpi_t rs[2];
 
 
-  GNUNET_CRYPTO_short_hash (purpose, ntohl (purpose->size), &hc);
-#define FORMATSTRING "(4:data(5:flags3:raw)(5:value32:01234567890123456789012345678901))"
-  bufSize = strlen (FORMATSTRING) + 1;
+  priv_sexp = decode_private_eddsa_key (priv);
+  data = data_to_eddsa_value (purpose);
+  if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
   {
   {
-    char buff[bufSize];
-
-    memcpy (buff, FORMATSTRING, bufSize);
-    memcpy (&buff
-           [bufSize -
-            strlen
-            ("01234567890123456789012345678901))")
-            - 1], &hc, sizeof (struct GNUNET_CRYPTO_ShortHashCode));
-    GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0));
+    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;
   }
   }
-#undef FORMATSTRING
-  return data;
+  gcry_sexp_release (priv_sexp);
+  gcry_sexp_release (data);
+
+  /* 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_sexp_t sig_sexpr;
+  gcry_sexp_t pub_sexpr;
   int rc;
 
   int rc;
 
-  data = data_to_pkcs1 (purpose);
-  if (0 != (rc = 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)))
   {
   {
-    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 (data);
+    gcry_sexp_release (sig_sexpr);
     return GNUNET_SYSERR;
   }
     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);
-  ssize = gcry_sexp_sprint (result, 
-                           GCRYSEXP_FMT_DEFAULT,
-                           sig->sexpr,
-                           GNUNET_CRYPTO_ECC_SIGNATURE_DATA_ENCODING_LENGTH);
-  if (0 == ssize)
+  gcry_sexp_release (sig_sexpr);
+  if (0 != rc)
   {
   {
-    GNUNET_break (0);
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         _("ECDSA signature verification failed at %s:%d: %s\n"), __FILE__,
+         __LINE__, gcry_strerror (rc));
     return GNUNET_SYSERR;
   }
     return GNUNET_SYSERR;
   }
-  sig->size = htons ((uint16_t) (ssize + sizeof (uint16_t)));
-  /* padd with zeros */
-  memset (&sig->sexpr[ssize], 0, GNUNET_CRYPTO_ECC_SIGNATURE_DATA_ENCODING_LENGTH - ssize);
-  gcry_sexp_release (result);
   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_sexp_t psexp;
-  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 */
-  size = ntohs (sig->size);
-  if ( (size < sizeof (uint16_t)) ||
-       (size > GNUNET_CRYPTO_ECC_SIGNATURE_DATA_ENCODING_LENGTH - sizeof (uint16_t)) )
-    return GNUNET_SYSERR; /* size out of range */
-  data = data_to_pkcs1 (validate);
-  GNUNET_assert (0 ==
-                 gcry_sexp_sscan (&sigdata, &erroff, 
-                                 sig->sexpr, size - sizeof (uint16_t)));
-  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);
+  gcry_sexp_release (sig_sexpr);
   if (0 != rc)
   {
   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;
   }
@@ -1090,65 +943,399 @@ GNUNET_CRYPTO_ecc_verify (uint32_t purpose,
 
 
 /**
 
 
 /**
- * Derive key material from a public and a private ECC key.
+ * Derive key material from a public and a private ECDHE key.
  *
  *
- * @param key private key to use for the ECDH (x)
- * @param pub public key to use for the ECDY (yG)
+ * @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)
  * @param key_material where to write the key material (xyG)
- * @return GNUNET_SYSERR on error, GNUNET_OK on success
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
  */
 int
  */
 int
-GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *key,
-                        const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub,
+GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
+                        const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
                         struct GNUNET_HashCode *key_material)
                         struct GNUNET_HashCode *key_material)
-{ 
-  size_t slen;
-  size_t erroff;
-  int rc;
-  unsigned char sdata_buf[2048]; /* big enough to print dh-shared-secret as S-expression */
+{
   gcry_mpi_point_t result;
   gcry_mpi_point_t q;
   gcry_mpi_t d;
   gcry_ctx_t ctx;
   gcry_mpi_point_t result;
   gcry_mpi_point_t q;
   gcry_mpi_t d;
   gcry_ctx_t ctx;
-  gcry_sexp_t psexp;
+  gcry_sexp_t pub_sexpr;
   gcry_mpi_t result_x;
   gcry_mpi_t result_x;
-  gcry_mpi_t result_y;
+  unsigned char xbuf[256 / 8];
+  size_t rsize;
 
   /* first, extract the q = dP value from the public key */
 
   /* first, extract the q = dP value from the public key */
-  if (! (psexp = decode_public_key (pub)))
+  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;
     return GNUNET_SYSERR;
-  if (0 != (rc = gcry_mpi_ec_new (&ctx, psexp, NULL)))
+  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, "gcry_mpi_ec_new", rc);  /* erroff gives more info */
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
+    gcry_mpi_point_release (result);
+    gcry_ctx_release (ctx);
     return GNUNET_SYSERR;
   }
     return GNUNET_SYSERR;
   }
-  gcry_sexp_release (psexp);
+  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);
   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);
   gcry_ctx_release (ctx);
+}
 
 
-  /* second, extract the d value from our private key */
-  rc = key_from_sexp (&d, key->sexp, "private-key", "d");
-  if (rc)
-    rc = key_from_sexp (&d, key->sexp, "ecc", "d");
-  if (0 != rc)
+
+/**
+ * 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++)
   {
   {
-    GNUNET_break (0);
-    gcry_mpi_point_release (q);
-    return GNUNET_SYSERR;
+    tmp = buffer[i];
+    buffer[i] = buffer[length-1-i];
+    buffer[length-1-i] = tmp;
   }
   }
+}
 
 
-  /* create a new context for definitively the correct curve;
-     theoretically the 'public_key' might not use the right curve */
-  if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256")))
+
+/**
+ * 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, "gcry_mpi_ec_new", rc);  /* erroff gives more info */
-    gcry_mpi_release (d);
-    gcry_mpi_point_release (q);
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
+    gcry_mpi_point_release (result);
+    gcry_ctx_release (ctx);
     return GNUNET_SYSERR;
   }
     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 */
 
   /* then call the 'multiply' function, to compute the product */
-  GNUNET_assert (NULL != ctx);
   result = gcry_mpi_point_new (0);
   gcry_mpi_ec_mul (result, d, q, ctx);
   gcry_mpi_point_release (q);
   result = gcry_mpi_point_new (0);
   gcry_mpi_ec_mul (result, d, q, ctx);
   gcry_mpi_point_release (q);
@@ -1156,8 +1343,7 @@ GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *key,
 
   /* finally, convert point to string for hashing */
   result_x = gcry_mpi_new (256);
 
   /* finally, convert point to string for hashing */
   result_x = gcry_mpi_new (256);
-  result_y = gcry_mpi_new (256);
-  if (gcry_mpi_ec_get_affine (result_x, result_y, result, ctx))
+  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);
   {
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
     gcry_mpi_point_release (result);
@@ -1166,25 +1352,113 @@ GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *key,
   }
   gcry_mpi_point_release (result);
   gcry_ctx_release (ctx);
   }
   gcry_mpi_point_release (result);
   gcry_ctx_release (ctx);
-  if (0 != (rc = gcry_sexp_build (&psexp, &erroff, 
-                                 "(dh-shared-secret (x %m)(y %m))",
-                                 result_x,
-                                 result_y)))
+
+  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, "gcry_sexp_build", rc);  /* erroff gives more info */
-    gcry_mpi_release (result_x);
-    gcry_mpi_release (result_y);
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
+    gcry_mpi_point_release (result);
+    gcry_ctx_release (ctx);
     return GNUNET_SYSERR;
   }
     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);
   gcry_mpi_release (result_x);
-  gcry_mpi_release (result_y);
-  slen = gcry_sexp_sprint (psexp, GCRYSEXP_FMT_DEFAULT, sdata_buf, sizeof (sdata_buf));
-  GNUNET_assert (0 != slen);
-  gcry_sexp_release (psexp);
-  /* finally, get a string of the resulting S-expression and hash it to generate the key material */
-  GNUNET_CRYPTO_hash (sdata_buf, slen, key_material);
   return GNUNET_OK;
 }
 
   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 */