rps.conf is generated from rps.conf.in
[oweals/gnunet.git] / src / util / crypto_ecc.c
index 60f70e0834f99f7a24d7b16febf7ecf42ad7229c..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:
- * - 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 || 1
+#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__)
 
  * 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;
-};
-
-
-/**
- * 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 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)
 
 
 /**
 
 
 /**
@@ -107,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;
@@ -117,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++)
@@ -157,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.
  *
@@ -164,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;
 
 
-  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);
-  adjust (&pub->key[0], size, GNUNET_CRYPTO_ECC_MAX_PUBLIC_KEY_LENGTH);
-  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;
 }
 
 
 }
 
 
@@ -192,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 (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)
   {
@@ -223,16 +357,16 @@ GNUNET_CRYPTO_ecc_public_key_to_string (struct GNUNET_CRYPTO_EccPublicKeyBinaryE
  * 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;
@@ -241,134 +375,107 @@ GNUNET_CRYPTO_ecc_public_key_from_string (const char *enc,
     return GNUNET_SYSERR;
 
   if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
     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) )
+                                                 pub,
+                                                 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_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)))
-  {
-    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
-    return NULL;
-  }
-  rc = gcry_sexp_build (&result, &erroff, "(public-key(ecc((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;
-  }
-  return result;
+  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;
 }
 
 
 /**
 }
 
 
 /**
- * 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'
- * @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)
+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;
-  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 (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));
 }
 
 
 }
 
 
@@ -377,21 +484,28 @@ GNUNET_CRYPTO_ecc_decode_key (const char *buf,
  *
  * @return fresh private key
  */
  *
  * @return fresh private key
  */
-static struct GNUNET_CRYPTO_EccPrivateKey *
-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 10:NIST P-521)))")))
+                                  "(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);
@@ -399,667 +513,952 @@ 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;
 
 
-  /* hostkey 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)))
-    {
-      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;  
+  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;
 }
 
 }
 
-
 /**
 /**
- * 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);
-}
-
-
-/**
- * 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 = 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 (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 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;
+    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))))
+  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 (GNUNET_ERROR_TYPE_INFO,
-         _("I am host `%s'.  Read private key from `%s'.\n"), GNUNET_i2s (&pid),
-         filename);
+    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.
+   * 'anonymous' pseudonym (global static, d=1, public key = G
+   * (generator).
    */
    */
-  GNUNET_CRYPTO_EccKeyCallback cont;
+  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;
+}
 
 
-  /**
-   * Closure for 'cont'.
-   */
-  void *cont_cls;
 
 
-  /**
-   * Name of the file.
-   */
-  char *filename;
+/**
+ * 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));
+}
 
 
-  /**
-   * 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 the data specified in the given purpose argument to an
+ * S-expression suitable for signature operations.
+ *
+ * @param purpose data to convert
+ * @return converted s-expression
+ */
+static gcry_sexp_t
+data_to_eddsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
+{
+  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 eddsa)(hash-algo %s)(value %b))",
+                                 "sha512",
+                                 (int)sizeof (hc), &hc)))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
+    return NULL;
+  }
+  return data;
+}
 
 
 /**
 
 
 /**
- * Abort ECC key generation.
+ * Convert the data specified in the given purpose argument to an
+ * S-expression suitable for signature operations.
  *
  *
- * @param gc key generation context to abort
+ * @param purpose data to convert
+ * @return converted s-expression
  */
  */
-void
-GNUNET_CRYPTO_ecc_key_create_stop (struct GNUNET_CRYPTO_EccKeyGenerationContext *gc)
+static gcry_sexp_t
+data_to_ecdsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
 {
 {
-  if (GNUNET_SCHEDULER_NO_TASK != gc->read_task)
+  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)))
   {
   {
-    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)
+  return data;
+}
+
+
+/**
+ * Sign a given block.
+ *
+ * @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
+GNUNET_CRYPTO_ecdsa_sign (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
+                          const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+                          struct GNUNET_CRYPTO_EcdsaSignature *sig)
+{
+  gcry_sexp_t priv_sexp;
+  gcry_sexp_t sig_sexp;
+  gcry_sexp_t data;
+  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)))
   {
   {
-    (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 (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;
   }
   }
+  gcry_sexp_release (priv_sexp);
+  gcry_sexp_release (data);
 
 
-  if (NULL != gc->filename)
+  /* 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")))
   {
   {
-    if (0 != UNLINK (gc->filename))
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", gc->filename);
-    GNUNET_free (gc->filename);
+    GNUNET_break (0);
+    gcry_sexp_release (sig_sexp);
+    return GNUNET_SYSERR;
   }
   }
-  if (NULL != gc->pk)
-    GNUNET_CRYPTO_ecc_key_free (gc->pk);
-  GNUNET_free (gc);
+  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;
 }
 
 
 /**
 }
 
 
 /**
- * Task called upon shutdown or process termination of 'gnunet-ecc' during
- * ECC key generation.  Check where we are and perform the appropriate
- * action.
+ * Sign a given block.
  *
  *
- * @param cls the 'struct GNUNET_CRYPTO_EccKeyGenerationContext'
- * @param tc scheduler context
+ * @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 void
-check_key_generation_completion (void *cls,
-                                const struct GNUNET_SCHEDULER_TaskContext *tc)
+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_EccKeyGenerationContext *gc = cls;
-  struct GNUNET_CRYPTO_EccPrivateKey *pk;
+  gcry_sexp_t priv_sexp;
+  gcry_sexp_t sig_sexp;
+  gcry_sexp_t data;
+  int rc;
+  gcry_mpi_t rs[2];
 
 
-  gc->read_task = GNUNET_SCHEDULER_NO_TASK;
-  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+  priv_sexp = decode_private_eddsa_key (priv);
+  data = data_to_eddsa_value (purpose);
+  if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
   {
   {
-    gc->cont (gc->cont_cls, NULL, _("interrupted by shutdown"));
-    GNUNET_CRYPTO_ecc_key_create_stop (gc);
-    return;
+    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;
   }
   }
-  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)))
+  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);
   {
     GNUNET_break (0);
-    gc->cont (gc->cont_cls, NULL, _("gnunet-ecc failed"));
-    GNUNET_CRYPTO_ecc_key_create_stop (gc);
-    return;
+    gcry_sexp_release (sig_sexp);
+    return GNUNET_SYSERR;
   }
   }
-  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 (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 the private ECC key which already existed on disk
- * (asynchronously) to the caller.
+ * Verify signature.
  *
  *
- * @param cls the 'struct GNUNET_CRYPTO_EccKeyGenerationContext'
- * @param tc scheduler context (unused)
+ * @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
  */
  */
-static void
-async_return_key (void *cls,
-                 const struct GNUNET_SCHEDULER_TaskContext *tc)
+int
+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)
 {
 {
-  struct GNUNET_CRYPTO_EccKeyGenerationContext *gc = cls;
+  gcry_sexp_t data;
+  gcry_sexp_t sig_sexpr;
+  gcry_sexp_t pub_sexpr;
+  int rc;
 
 
-  gc->cont (gc->cont_cls,
-           gc->pk,
-           NULL);
-  GNUNET_free (gc);
+  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 (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;
 }
 
 
 }
 
 
+
 /**
 /**
- * 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.
+ * Verify signature.
  *
  *
- * @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 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
  */
  */
-struct GNUNET_CRYPTO_EccKeyGenerationContext *
-GNUNET_CRYPTO_ecc_key_create_start (const char *filename,
-                                   GNUNET_CRYPTO_EccKeyCallback cont,
-                                   void *cont_cls)
+int
+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)
 {
 {
-  struct GNUNET_CRYPTO_EccKeyGenerationContext *gc;
-  struct GNUNET_CRYPTO_EccPrivateKey *pk;
-  const char *weak_random;
+  gcry_sexp_t data;
+  gcry_sexp_t sig_sexpr;
+  gcry_sexp_t pub_sexpr;
+  int rc;
 
 
-  if (NULL != (pk = try_read_key (filename)))
+  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(eddsa(r %b)(s %b)))",
+                                  (int)sizeof (sig->r), sig->r,
+                                  (int)sizeof (sig->s), sig->s)))
   {
   {
-    /* 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;
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
+    return GNUNET_SYSERR;
   }
   }
-  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)
+  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)))
   {
   {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "pipe");
-    GNUNET_free (gc->filename);
-    GNUNET_free (gc);
-    return NULL;
+    gcry_sexp_release (data);
+    gcry_sexp_release (sig_sexpr);
+    return GNUNET_SYSERR;
   }
   }
-  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)
+  rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
+  gcry_sexp_release (pub_sexpr);
+  gcry_sexp_release (data);
+  gcry_sexp_release (sig_sexpr);
+  if (0 != rc)
   {
   {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fork");
-    GNUNET_DISK_pipe_close (gc->gnunet_ecc_out);
-    GNUNET_free (gc->filename);
-    GNUNET_free (gc);
-    return NULL;
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         _("EdDSA signature verification failed at %s:%d: %s\n"), __FILE__,
+         __LINE__, gcry_strerror (rc));
+    return GNUNET_SYSERR;
   }
   }
-  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 GNUNET_OK;
 }
 
 
 /**
 }
 
 
 /**
- * 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).
+ * Derive key material from a public and a private ECDHE key.
  *
  *
- * @param cfg_name name of the configuration file to use
+ * @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
  */
  */
-void
-GNUNET_CRYPTO_ecc_setup_hostkey (const char *cfg_name)
+int
+GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
+                        const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
+                        struct GNUNET_HashCode *key_material)
 {
 {
-  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))
+  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))
   {
   {
-    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, "get_affine failed", 0);
+    gcry_mpi_point_release (result);
+    gcry_ctx_release (ctx);
+    return GNUNET_SYSERR;
   }
   }
-  GNUNET_CONFIGURATION_destroy (cfg);
+  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;
 }
 
 
 /**
 }
 
 
 /**
- * Convert the data specified in the given purpose argument to an
- * S-expression suitable for signature operations.
+ * Derive the 'h' value for key derivation, where
+ * 'h = H(l,P)'.
  *
  *
- * @param purpose data to convert
- * @return converted s-expression
+ * @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_sexp_t
-data_to_pkcs1 (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
+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;
   struct GNUNET_HashCode hc;
-  size_t bufSize;
-  gcry_sexp_t data;
+  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;
+}
 
 
-  GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
-#define FORMATSTRING "(4:data(5:flags5:pkcs1)(4:hash6:sha51264:0123456789012345678901234567890123456789012345678901234567890123))"
-  bufSize = strlen (FORMATSTRING) + 1;
+
+/**
+ * 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++)
   {
   {
-    char buff[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));
+    tmp = buffer[i];
+    buffer[i] = buffer[length-1-i];
+    buffer[length-1-i] = tmp;
   }
   }
-#undef FORMATSTRING
-  return data;
 }
 
 
 /**
 }
 
 
 /**
- * Sign a given block.
+ * Convert the secret @a d of an EdDSA key to the
+ * value that is actually used in the EdDSA computation.
  *
  *
- * @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 d secret input
+ * @return value used for the calculation in EdDSA
  */
  */
-int
-GNUNET_CRYPTO_ecc_sign (const struct GNUNET_CRYPTO_EccPrivateKey *key,
-                        const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
-                        struct GNUNET_CRYPTO_EccSignature *sig)
+static gcry_mpi_t
+eddsa_d_to_a (gcry_mpi_t d)
 {
 {
-  gcry_sexp_t result;
-  gcry_sexp_t data;
-  size_t ssize;
+  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;
+}
 
 
-  data = data_to_pkcs1 (purpose);
-  GNUNET_assert (0 == gcry_pk_sign (&result, data, key->sexp));
-  gcry_sexp_release (data);
-  ssize = gcry_sexp_sprint (result, 
-                           GCRYSEXP_FMT_DEFAULT,
-                           sig->sexpr,
-                           GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH);
-  if (0 == ssize)
+
+/**
+ * @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))
   {
   {
-    GNUNET_break (0);
+    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;
   }
-  sig->size = htons ((uint16_t) (ssize + sizeof (uint16_t)));
-  /* padd with zeros */
-  memset (&sig->sexpr[ssize], 0, GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH - ssize);
-  gcry_sexp_release (result);
+  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;
 }
 
   return GNUNET_OK;
 }
 
-
 /**
 /**
- * Verify signature.
+ * @ingroup crypto
+ * Derive key material from a ECDH public key and a private ECDSA key.
+ * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
  *
  *
- * @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 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
  */
 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_ecdsa_ecdh (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
+                          const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
+                          struct GNUNET_HashCode *key_material)
 {
 {
-  gcry_sexp_t data;
-  gcry_sexp_t sigdata;
-  size_t size;
-  gcry_sexp_t psexp;
-  size_t erroff;
-  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_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)))
+  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))
   {
   {
-    gcry_sexp_release (data);
-    gcry_sexp_release (sigdata);
+    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;
   }
-  rc = gcry_pk_verify (sigdata, data, psexp);
-  gcry_sexp_release (psexp);
-  gcry_sexp_release (data);
-  gcry_sexp_release (sigdata);
-  if (0 != rc)
+  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 (GNUNET_ERROR_TYPE_WARNING,
-         _("ECC signature verification failed at %s:%d: %s\n"), __FILE__,
-         __LINE__, gcry_strerror (rc));
+    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;
 }
 
   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 */