[git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-238-g63cd347

by Werner Koch cvs at cvs.gnupg.org
Wed Sep 18 13:45:56 CEST 2013


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU crypto library".

The branch, master has been updated
       via  63cd3474425cb5a7ec4d1a56be15b248ecda4680 (commit)
       via  89fe2173649a72019d75e059e6c6938efd10421f (commit)
      from  a7a9cdcaaf3979baa18dad51e722882581349f45 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 63cd3474425cb5a7ec4d1a56be15b248ecda4680
Author: Werner Koch <wk at gnupg.org>
Date:   Sat Sep 7 10:06:46 2013 +0200

    ecc: Add Ed25519 key generation and prepare for optimizations.
    
    * src/mpi.h (enum ecc_dialects): New.
    * src/ec-context.h (mpi_ec_ctx_s): Add field DIALECT.
    * cipher/ecc-common.h (elliptic_curve_t): Ditto.
    * cipher/ecc-curves.c (ecc_domain_parms_t): Ditto.
    (domain_parms): Add dialect values.
    (_gcry_ecc_fill_in_curve): Set dialect.
    (_gcry_ecc_get_curve): Ditto.
    (_gcry_mpi_ec_new): Ditto.
    (_gcry_ecc_get_param): Use ECC_DIALECT_STANDARD for now.
    * cipher/ecc-misc.c (_gcry_ecc_curve_copy): Copy dialect.
    (_gcry_ecc_dialect2str): New.
    * mpi/ec.c (ec_p_init): Add arg DIALECT.
    (_gcry_mpi_ec_p_internal_new): Ditto.
    (_gcry_mpi_ec_p_new): Ditto.
    
    * mpi/mpiutil.c (gcry_mpi_set_opaque): Set the secure flag.
    (_gcry_mpi_set_opaque_copy): New.
    
    * cipher/ecc-misc.c (_gcry_ecc_os2ec): Take care of an opaque MPI.
    * cipher/ecc.c (eddsa_generate_key): New.
    (generate_key): Rename to nist_generate_key and factor some code out
    to ...
    (ecc_generate_ext): here.  Divert to eddsa_generate_key if desired.
    (eddsa_decodepoint): Take care of an opaque MPI.
    (ecc_check_secret_key): Ditto.
    (ecc_sign): Ditto.
    * cipher/pubkey.c (sexp_elements_extract_ecc): Store public and secret
    key as opaque MPIs.
    (gcry_pk_genkey): Add the curve_name also to the private key part of
    the result.
    
    * tests/benchmark.c (ecc_bench): Support Ed25519.
    (main): Add option --debug.
    * tests/curves.c (sample_key_2): Make sure that P and N are positive.
    * tests/keygen.c (show): New.
    (check_ecc_keys): Support Ed25519.
    --
    
    There are two main purposes of this patch: Add a key generation
    feature for Ed25519 and add the "dialect" thingy which will eventually
    be used to add curve specific optimization.
    
    Note that the entire way of how we interface between the public key
    modules and pubkey.c is overly complex and probably also the cause for
    a lot of performance overhead.  Given that we don't have the loadable
    module system anymore, we should entirely get rid of the MPI-array
    based internal interface and move parts of the s-expression handling
    direct into the pubkey modules.  This needs to be fixed or we are
    turning Libgcrypt into another software incarnation of Heathrow
    Airport.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/cipher/ecc-common.h b/cipher/ecc-common.h
index 614baae..e806059 100644
--- a/cipher/ecc-common.h
+++ b/cipher/ecc-common.h
@@ -20,10 +20,12 @@
 #ifndef GCRY_ECC_COMMON_H
 #define GCRY_ECC_COMMON_H
 
+
 /* Definition of a curve.  */
 typedef struct
 {
   enum gcry_mpi_ec_models model;/* The model descrinbing this curve.  */
+  enum ecc_dialects dialect;    /* The dialect used with the curve.   */
   gcry_mpi_t p;         /* Prime specifying the field GF(p).  */
   gcry_mpi_t a;         /* First coefficient of the Weierstrass equation.  */
   gcry_mpi_t b;         /* Second coefficient of the Weierstrass equation.
@@ -76,6 +78,7 @@ gcry_sexp_t     _gcry_ecc_get_param_sexp (const char *name);
 void _gcry_ecc_curve_free (elliptic_curve_t *E);
 elliptic_curve_t _gcry_ecc_curve_copy (elliptic_curve_t E);
 const char *_gcry_ecc_model2str (enum gcry_mpi_ec_models model);
+const char *_gcry_ecc_dialect2str (enum ecc_dialects dialect);
 gcry_mpi_t   _gcry_ecc_ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p);
 gcry_error_t _gcry_ecc_os2ec (mpi_point_t result, gcry_mpi_t value);
 
diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c
index c17c7fe..49c0959 100644
--- a/cipher/ecc-curves.c
+++ b/cipher/ecc-curves.c
@@ -78,7 +78,13 @@ typedef struct
   unsigned int nbits;         /* Number of bits.  */
   unsigned int fips:1;        /* True if this is a FIPS140-2 approved curve. */
 
-  enum gcry_mpi_ec_models model;/* The model describing this curve.  */
+  /* The model describing this curve.  This is mainly used to select
+     the group equation. */
+  enum gcry_mpi_ec_models model;
+
+  /* The actual ECC dialect used.  This is used for curve specific
+     optimizations and to select encodings etc. */
+  enum ecc_dialects dialect;
 
   const char *p;              /* The prime defining the field.  */
   const char *a, *b;          /* The coefficients.  For Twisted Edwards
@@ -94,7 +100,7 @@ static const ecc_domain_parms_t domain_parms[] =
     {
       /* (-x^2 + y^2 = 1 + dx^2y^2) */
       "Ed25519", 256, 0,
-      MPI_EC_TWISTEDEDWARDS,
+      MPI_EC_TWISTEDEDWARDS, ECC_DIALECT_ED25519,
       "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
       "-0x01",
       "-0x98412DFC9311D490018C7338BF8688861767FF8FF5B2BEBE27548A14B235EC8FEDA4",
@@ -104,7 +110,7 @@ static const ecc_domain_parms_t domain_parms[] =
     },
     {
       "NIST P-192", 192, 1,
-      MPI_EC_WEIERSTRASS,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
       "0xfffffffffffffffffffffffffffffffeffffffffffffffff",
       "0xfffffffffffffffffffffffffffffffefffffffffffffffc",
       "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
@@ -115,7 +121,7 @@ static const ecc_domain_parms_t domain_parms[] =
     },
     {
       "NIST P-224", 224, 1,
-      MPI_EC_WEIERSTRASS,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
       "0xffffffffffffffffffffffffffffffff000000000000000000000001",
       "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe",
       "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
@@ -126,7 +132,7 @@ static const ecc_domain_parms_t domain_parms[] =
     },
     {
       "NIST P-256", 256, 1,
-      MPI_EC_WEIERSTRASS,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
       "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
       "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc",
       "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
@@ -137,7 +143,7 @@ static const ecc_domain_parms_t domain_parms[] =
     },
     {
       "NIST P-384", 384, 1,
-      MPI_EC_WEIERSTRASS,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
       "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
       "ffffffff0000000000000000ffffffff",
       "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
@@ -154,7 +160,7 @@ static const ecc_domain_parms_t domain_parms[] =
     },
     {
       "NIST P-521", 521, 1,
-      MPI_EC_WEIERSTRASS,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
       "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
       "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
       "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
@@ -171,7 +177,7 @@ static const ecc_domain_parms_t domain_parms[] =
     },
 
     { "brainpoolP160r1", 160, 0,
-      MPI_EC_WEIERSTRASS,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
       "0xe95e4a5f737059dc60dfc7ad95b3d8139515620f",
       "0x340e7be2a280eb74e2be61bada745d97e8f7c300",
       "0x1e589a8595423412134faa2dbdec95c8d8675e58",
@@ -181,7 +187,7 @@ static const ecc_domain_parms_t domain_parms[] =
     },
 
     { "brainpoolP192r1", 192, 0,
-      MPI_EC_WEIERSTRASS,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
       "0xc302f41d932a36cda7a3463093d18db78fce476de1a86297",
       "0x6a91174076b1e0e19c39c031fe8685c1cae040e5c69a28ef",
       "0x469a28ef7c28cca3dc721d044f4496bcca7ef4146fbf25c9",
@@ -191,7 +197,7 @@ static const ecc_domain_parms_t domain_parms[] =
     },
 
     { "brainpoolP224r1", 224, 0,
-      MPI_EC_WEIERSTRASS,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
       "0xd7c134aa264366862a18302575d1d787b09f075797da89f57ec8c0ff",
       "0x68a5e62ca9ce6c1c299803a6c1530b514e182ad8b0042a59cad29f43",
       "0x2580f63ccfe44138870713b1a92369e33e2135d266dbb372386c400b",
@@ -201,7 +207,7 @@ static const ecc_domain_parms_t domain_parms[] =
     },
 
     { "brainpoolP256r1", 256, 0,
-      MPI_EC_WEIERSTRASS,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
       "0xa9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5377",
       "0x7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9",
       "0x26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6",
@@ -211,7 +217,7 @@ static const ecc_domain_parms_t domain_parms[] =
     },
 
     { "brainpoolP320r1", 320, 0,
-      MPI_EC_WEIERSTRASS,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
       "0xd35e472036bc4fb7e13c785ed201e065f98fcfa6f6f40def4f92b9ec7893ec28"
       "fcd412b1f1b32e27",
       "0x3ee30b568fbab0f883ccebd46d3f3bb8a2a73513f5eb79da66190eb085ffa9f4"
@@ -227,7 +233,7 @@ static const ecc_domain_parms_t domain_parms[] =
     },
 
     { "brainpoolP384r1", 384, 0,
-      MPI_EC_WEIERSTRASS,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
       "0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123"
       "acd3a729901d1a71874700133107ec53",
       "0x7bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f"
@@ -243,7 +249,7 @@ static const ecc_domain_parms_t domain_parms[] =
     },
 
     { "brainpoolP512r1", 512, 0,
-      MPI_EC_WEIERSTRASS,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
       "0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330871"
       "7d4d9b009bc66842aecda12ae6a380e62881ff2f2d82c68528aa6056583a48f3",
       "0x7830a3318b603b89e2327145ac234cc594cbdd8d3df91610a83441caea9863bc"
@@ -258,7 +264,7 @@ static const ecc_domain_parms_t domain_parms[] =
       "b2dcde494a5f485e5bca4bd88a2763aed1ca2b2fa8f0540678cd1e0f3ad80892"
     },
 
-    { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
+    { NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
   };
 
 
@@ -348,6 +354,7 @@ _gcry_ecc_fill_in_curve (unsigned int nbits, const char *name,
     *r_nbits = domain_parms[idx].nbits;
 
   curve->model = domain_parms[idx].model;
+  curve->dialect = domain_parms[idx].dialect;
   curve->p = scanval (domain_parms[idx].p);
   curve->a = scanval (domain_parms[idx].a);
   curve->b = scanval (domain_parms[idx].b);
@@ -391,6 +398,8 @@ _gcry_ecc_get_curve (gcry_mpi_t *pkey, int iterator, unsigned int *r_nbits)
     return NULL;
 
   E.model = MPI_EC_WEIERSTRASS;
+  E.dialect = ECC_DIALECT_STANDARD;
+  E.name = NULL;
   E.p = pkey[0];
   E.a = pkey[1];
   E.b = pkey[2];
@@ -561,6 +570,7 @@ _gcry_mpi_ec_new (gcry_ctx_t *r_ctx,
   gpg_err_code_t errc;
   gcry_ctx_t ctx = NULL;
   enum gcry_mpi_ec_models model = MPI_EC_WEIERSTRASS;
+  enum ecc_dialects dialect = ECC_DIALECT_STANDARD;
   gcry_mpi_t p = NULL;
   gcry_mpi_t a = NULL;
   gcry_mpi_t b = NULL;
@@ -641,6 +651,7 @@ _gcry_mpi_ec_new (gcry_ctx_t *r_ctx,
         }
 
       model = E->model;
+      dialect = E->dialect;
 
       if (!p)
         {
@@ -673,7 +684,7 @@ _gcry_mpi_ec_new (gcry_ctx_t *r_ctx,
       gcry_free (E);
     }
 
-  errc = _gcry_mpi_ec_p_new (&ctx, model, p, a, b);
+  errc = _gcry_mpi_ec_p_new (&ctx, model, dialect, p, a, b);
   if (!errc)
     {
       mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
@@ -735,7 +746,7 @@ _gcry_ecc_get_param (const char *name, gcry_mpi_t *pkey)
 
   g_x = mpi_new (0);
   g_y = mpi_new (0);
-  ctx = _gcry_mpi_ec_p_internal_new (0, E.p, E.a, NULL);
+  ctx = _gcry_mpi_ec_p_internal_new (0, ECC_DIALECT_STANDARD, E.p, E.a, NULL);
   if (_gcry_mpi_ec_get_affine (g_x, g_y, &E.G, ctx))
     log_fatal ("ecc get param: Failed to get affine coordinates\n");
   _gcry_mpi_ec_free (ctx);
diff --git a/cipher/ecc-misc.c b/cipher/ecc-misc.c
index 6c34902..f8db81a 100644
--- a/cipher/ecc-misc.c
+++ b/cipher/ecc-misc.c
@@ -54,6 +54,7 @@ _gcry_ecc_curve_copy (elliptic_curve_t E)
   elliptic_curve_t R;
 
   R.model = E.model;
+  R.dialect = E.dialect;
   R.p = mpi_copy (E.p);
   R.a = mpi_copy (E.a);
   R.b = mpi_copy (E.b);
@@ -82,6 +83,20 @@ _gcry_ecc_model2str (enum gcry_mpi_ec_models model)
 }
 
 
+/*
+ * Return a description of the curve dialect.
+ */
+const char *
+_gcry_ecc_dialect2str (enum ecc_dialects dialect)
+{
+  const char *str = "?";
+  switch (dialect)
+    {
+    case ECC_DIALECT_STANDARD:  str = "Standard"; break;
+    case ECC_DIALECT_ED25519:   str = "Ed25519"; break;
+    }
+  return str;
+}
 
 
 gcry_mpi_t
@@ -151,41 +166,57 @@ _gcry_ecc_os2ec (mpi_point_t result, gcry_mpi_t value)
 {
   gcry_error_t err;
   size_t n;
-  unsigned char *buf;
+  const unsigned char *buf;
+  unsigned char *buf_memory;
   gcry_mpi_t x, y;
 
-  n = (mpi_get_nbits (value)+7)/8;
-  buf = gcry_xmalloc (n);
-  err = gcry_mpi_print (GCRYMPI_FMT_USG, buf, n, &n, value);
-  if (err)
+  if (mpi_is_opaque (value))
     {
-      gcry_free (buf);
-      return err;
+      unsigned int nbits;
+
+      buf = gcry_mpi_get_opaque (value, &nbits);
+      if (!buf)
+        return GPG_ERR_INV_OBJ;
+      n = (nbits + 7)/8;
+      buf_memory = NULL;
+    }
+  else
+    {
+      n = (mpi_get_nbits (value)+7)/8;
+      buf_memory= gcry_xmalloc (n);
+      err = gcry_mpi_print (GCRYMPI_FMT_USG, buf_memory, n, &n, value);
+      if (err)
+        {
+          gcry_free (buf_memory);
+          return err;
+        }
+      buf = buf_memory;
     }
+
   if (n < 1)
     {
-      gcry_free (buf);
+      gcry_free (buf_memory);
       return GPG_ERR_INV_OBJ;
     }
   if (*buf != 4)
     {
-      gcry_free (buf);
+      gcry_free (buf_memory);
       return GPG_ERR_NOT_IMPLEMENTED; /* No support for point compression.  */
     }
   if ( ((n-1)%2) )
     {
-      gcry_free (buf);
+      gcry_free (buf_memory);
       return GPG_ERR_INV_OBJ;
     }
   n = (n-1)/2;
   err = gcry_mpi_scan (&x, GCRYMPI_FMT_USG, buf+1, n, NULL);
   if (err)
     {
-      gcry_free (buf);
+      gcry_free (buf_memory);
       return err;
     }
   err = gcry_mpi_scan (&y, GCRYMPI_FMT_USG, buf+1+n, n, NULL);
-  gcry_free (buf);
+  gcry_free (buf_memory);
   if (err)
     {
       mpi_free (x);
diff --git a/cipher/ecc.c b/cipher/ecc.c
index 7d468ee..9766e9e 100644
--- a/cipher/ecc.c
+++ b/cipher/ecc.c
@@ -132,59 +132,30 @@ gen_y_2 (gcry_mpi_t x, elliptic_curve_t *base)
 }
 
 
-/*
- * First obtain the setup.  Over the finite field randomize an scalar
- * secret value, and calculate the public point.
- */
+/* Standard version of the key generation.  */
 static gpg_err_code_t
-generate_key (ECC_secret_key *sk, unsigned int nbits, const char *name,
-              int transient_key,
-              gcry_mpi_t g_x, gcry_mpi_t g_y,
-              gcry_mpi_t q_x, gcry_mpi_t q_y,
-              const char **r_usedcurve)
+nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
+                   gcry_random_level_t random_level, unsigned int nbits)
 {
-  gpg_err_code_t err;
-  elliptic_curve_t E;
   mpi_point_struct Q;
-  mpi_ec_t ctx;
-  gcry_random_level_t random_level;
-
-  *r_usedcurve = NULL;
 
-  err = _gcry_ecc_fill_in_curve (nbits, name, &E, &nbits);
-  if (err)
-    return err;
-
-  if (DBG_CIPHER)
-    {
-      log_debug ("ecgen curve model: %s\n", _gcry_ecc_model2str (E.model));
-      log_mpidump ("ecgen curve  p", E.p);
-      log_mpidump ("ecgen curve  a", E.a);
-      log_mpidump ("ecgen curve  b", E.b);
-      log_mpidump ("ecgen curve  n", E.n);
-      log_mpidump ("ecgen curve Gx", E.G.x);
-      log_mpidump ("ecgen curve Gy", E.G.y);
-      log_mpidump ("ecgen curve Gz", E.G.z);
-      if (E.name)
-        log_debug ("ecgen curve used: %s\n", E.name);
-    }
+  point_init (&Q);
 
-  random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM;
-  sk->d = _gcry_dsa_gen_k (E.n, random_level);
+  /* Generate a secret.  */
+  sk->d = _gcry_dsa_gen_k (E->n, random_level);
 
   /* Compute Q.  */
-  point_init (&Q);
-  ctx = _gcry_mpi_ec_p_internal_new (E.model, E.p, E.a, E.b);
-  _gcry_mpi_ec_mul_point (&Q, sk->d, &E.G, ctx);
+  _gcry_mpi_ec_mul_point (&Q, sk->d, &E->G, ctx);
 
   /* Copy the stuff to the key structures. */
-  sk->E.model = E.model;
-  sk->E.p = mpi_copy (E.p);
-  sk->E.a = mpi_copy (E.a);
-  sk->E.b = mpi_copy (E.b);
+  sk->E.model = E->model;
+  sk->E.dialect = E->dialect;
+  sk->E.p = mpi_copy (E->p);
+  sk->E.a = mpi_copy (E->a);
+  sk->E.b = mpi_copy (E->b);
   point_init (&sk->E.G);
-  point_set (&sk->E.G, &E.G);
-  sk->E.n = mpi_copy (E.n);
+  point_set (&sk->E.G, &E->G);
+  sk->E.n = mpi_copy (E->n);
   point_init (&sk->Q);
 
   /* We want the Q=(x,y) be a "compliant key" in terms of the
@@ -196,7 +167,7 @@ generate_key (ECC_secret_key *sk, unsigned int nbits, const char *name,
    * possibilities without any loss of security.  */
   {
     gcry_mpi_t x, y, p_y;
-    const unsigned int pbits = mpi_get_nbits (E.p);
+    const unsigned int pbits = mpi_get_nbits (E->p);
 
     x = mpi_new (pbits);
     y = mpi_new (pbits);
@@ -205,22 +176,22 @@ generate_key (ECC_secret_key *sk, unsigned int nbits, const char *name,
     if (_gcry_mpi_ec_get_affine (x, y, &Q, ctx))
       log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q");
 
-    mpi_sub (p_y, E.p, y);	/* p_y = p - y */
+    mpi_sub (p_y, E->p, y);	/* p_y = p - y */
 
     if (mpi_cmp (p_y, y) < 0)   /* p - y < p */
       {
         /* We need to end up with -Q; this assures that new Q's y is
            the smallest one */
-        mpi_sub (sk->d, E.n, sk->d);   /* d = order - d */
-	gcry_mpi_point_snatch_set (&sk->Q, x, p_y, mpi_alloc_set_ui (1));
+        mpi_sub (sk->d, E->n, sk->d);   /* d = order - d */
+        gcry_mpi_point_snatch_set (&sk->Q, x, p_y, mpi_alloc_set_ui (1));
 
-        if (DBG_CIPHER)
-          log_debug ("ecgen converted Q to a compliant point\n");
+      if (DBG_CIPHER)
+        log_debug ("ecgen converted Q to a compliant point\n");
       }
     else /* p - y >= p */
       {
         /* No change is needed exactly 50% of the time: just copy. */
-	point_set (&sk->Q, &Q);
+        point_set (&sk->Q, &Q);
         if (DBG_CIPHER)
           log_debug ("ecgen didn't need to convert Q to a compliant point\n");
 
@@ -230,25 +201,6 @@ generate_key (ECC_secret_key *sk, unsigned int nbits, const char *name,
     mpi_free (y);
   }
 
-  /* We also return copies of G and Q in affine coordinates if
-     requested.  */
-  if (g_x && g_y)
-    {
-      if (_gcry_mpi_ec_get_affine (g_x, g_y, &sk->E.G, ctx))
-        log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "G");
-    }
-  if (q_x && q_y)
-    {
-      if (_gcry_mpi_ec_get_affine (q_x, q_y, &sk->Q, ctx))
-        log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q");
-    }
-  _gcry_mpi_ec_free (ctx);
-
-  point_free (&Q);
-
-  *r_usedcurve = E.name;
-  _gcry_ecc_curve_free (&E);
-
   /* Now we can test our keys (this should never fail!).  */
   test_keys (sk, nbits - 64);
 
@@ -344,7 +296,8 @@ check_secret_key (ECC_secret_key * sk)
       goto leave;
     }
 
-  ctx = _gcry_mpi_ec_p_internal_new (sk->E.model, sk->E.p, sk->E.a, sk->E.b);
+  ctx = _gcry_mpi_ec_p_internal_new (sk->E.model, sk->E.dialect,
+                                     sk->E.p, sk->E.a, sk->E.b);
 
   _gcry_mpi_ec_mul_point (&Q, sk->E.n, &sk->E.G, ctx);
   if (mpi_cmp_ui (Q.z, 0))
@@ -458,7 +411,7 @@ sign_ecdsa (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s,
   mpi_set_ui (s, 0);
   mpi_set_ui (r, 0);
 
-  ctx = _gcry_mpi_ec_p_internal_new (skey->E.model,
+  ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect,
                                      skey->E.p, skey->E.a, skey->E.b);
 
   while (!mpi_cmp_ui (s, 0)) /* s == 0 */
@@ -558,7 +511,7 @@ verify_ecdsa (gcry_mpi_t input, ECC_public_key *pkey,
   point_init (&Q1);
   point_init (&Q2);
 
-  ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model,
+  ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect,
                                      pkey->E.p, pkey->E.a, pkey->E.b);
 
   /* h  = s^(-1) (mod n) */
@@ -700,9 +653,27 @@ eddsa_decodepoint (gcry_mpi_t pk, unsigned int len, mpi_ec_t ctx,
   gcry_mpi_t yy, t, x, p1, p2, p3;
   int sign;
 
-  rawmpi = _gcry_mpi_get_buffer (pk, len, &rawmpilen, NULL);
-  if (!rawmpi)
-    return gpg_err_code_from_syserror ();
+  if (mpi_is_opaque (pk))
+    {
+      const void *buf;
+
+      buf = gcry_mpi_get_opaque (pk, &rawmpilen);
+      if (!buf)
+        return GPG_ERR_INV_OBJ;
+      rawmpilen = (rawmpilen + 7)/8;
+      rawmpi = gcry_malloc (rawmpilen? rawmpilen:1);
+      if (!rawmpi)
+        return gpg_err_code_from_syserror ();
+      memcpy (rawmpi, buf, rawmpilen);
+      reverse_buffer (rawmpi, rawmpilen);
+    }
+  else
+    {
+      rawmpi = _gcry_mpi_get_buffer (pk, len, &rawmpilen, NULL);
+      if (!rawmpi)
+        return gpg_err_code_from_syserror ();
+    }
+
   if (rawmpilen)
     {
       sign = !!(rawmpi[0] & 0x80);
@@ -781,6 +752,78 @@ eddsa_decodepoint (gcry_mpi_t pk, unsigned int len, mpi_ec_t ctx,
 }
 
 
+/* Ed25519 version of the key generation.  */
+static gpg_err_code_t
+eddsa_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
+                    gcry_random_level_t random_level)
+{
+  gpg_err_code_t rc;
+  int b = 256/8;             /* The only size we currently support.  */
+  gcry_mpi_t a, x, y;
+  mpi_point_struct Q;
+  char *dbuf;
+  size_t dlen;
+  gcry_buffer_t hvec[1];
+  unsigned char *hash_d = NULL;
+
+  point_init (&Q);
+  memset (hvec, 0, sizeof hvec);
+
+  a = mpi_snew (0);
+  x = mpi_new (0);
+  y = mpi_new (0);
+
+  /* Generate a secret.  */
+  hash_d = gcry_malloc_secure (2*b);
+  if (!hash_d)
+    {
+      rc = gpg_error_from_syserror ();
+      goto leave;
+    }
+  dlen = b;
+  dbuf = gcry_random_bytes_secure (dlen, random_level);
+
+  /* Compute the A value.  */
+  hvec[0].data = dbuf;
+  hvec[0].len = dlen;
+  rc = _gcry_md_hash_buffers (GCRY_MD_SHA512, 0, hash_d, hvec, 1);
+  if (rc)
+    goto leave;
+  sk->d = _gcry_mpi_set_opaque (NULL, dbuf, dlen*8);
+  dbuf = NULL;
+  reverse_buffer (hash_d, 32);  /* Only the first half of the hash.  */
+  hash_d[0] = (hash_d[0] & 0x7f) | 0x40;
+  hash_d[31] &= 0xf8;
+  _gcry_mpi_set_buffer (a, hash_d, 32, 0);
+  gcry_free (hash_d); hash_d = NULL;
+  /* log_printmpi ("ecgen         a", a); */
+
+  /* Compute Q.  */
+  _gcry_mpi_ec_mul_point (&Q, a, &E->G, ctx);
+  if (DBG_CIPHER)
+    log_printpnt ("ecgen      pk", &Q, ctx);
+
+  /* Copy the stuff to the key structures. */
+  sk->E.model = E->model;
+  sk->E.dialect = E->dialect;
+  sk->E.p = mpi_copy (E->p);
+  sk->E.a = mpi_copy (E->a);
+  sk->E.b = mpi_copy (E->b);
+  point_init (&sk->E.G);
+  point_set (&sk->E.G, &E->G);
+  sk->E.n = mpi_copy (E->n);
+  point_init (&sk->Q);
+  point_set (&sk->Q, &Q);
+
+ leave:
+  gcry_mpi_release (a);
+  gcry_mpi_release (x);
+  gcry_mpi_release (y);
+  gcry_free (hash_d);
+  return rc;
+}
+
+
 /* Compute an EdDSA signature. See:
  *   [ed25519] 23pp. (PDF) Daniel J. Bernstein, Niels Duif, Tanja
  *   Lange, Peter Schwabe, Bo-Yin Yang. High-speed high-security
@@ -831,7 +874,7 @@ sign_eddsa (gcry_mpi_t input, ECC_secret_key *skey,
   x = mpi_new (0);
   y = mpi_new (0);
   r = mpi_new (0);
-  ctx = _gcry_mpi_ec_p_internal_new (skey->E.model,
+  ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect,
                                      skey->E.p, skey->E.a, skey->E.b);
 
   /* Hash the secret key.  We clear DIGEST so we can use it to left
@@ -998,7 +1041,7 @@ verify_eddsa (gcry_mpi_t input, ECC_public_key *pkey,
   h = mpi_new (0);
   s = mpi_new (0);
 
-  ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model,
+  ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect,
                                      pkey->E.p, pkey->E.a, pkey->E.b);
 
   /* Decode and check the public key.  */
@@ -1116,13 +1159,16 @@ ecc_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
                   gcry_mpi_t *skey, gcry_mpi_t **retfactors,
                   gcry_sexp_t *r_extrainfo)
 {
-  gpg_err_code_t ec;
+  gpg_err_code_t rc;
+  elliptic_curve_t E;
   ECC_secret_key sk;
-  gcry_mpi_t g_x, g_y, q_x, q_y;
+  gcry_mpi_t x = NULL;
+  gcry_mpi_t y = NULL;
   char *curve_name = NULL;
   gcry_sexp_t l1;
   int transient_key = 0;
-  const char *usedcurve = NULL;
+  gcry_random_level_t random_level;
+  mpi_ec_t ctx = NULL;
 
   (void)algo;
   (void)evalue;
@@ -1152,52 +1198,106 @@ ecc_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
   if (!nbits && !curve_name)
     return GPG_ERR_NO_OBJ; /* No NBITS parameter. */
 
-  g_x = mpi_new (0);
-  g_y = mpi_new (0);
-  q_x = mpi_new (0);
-  q_y = mpi_new (0);
-  ec = generate_key (&sk, nbits, curve_name, transient_key, g_x, g_y, q_x, q_y,
-                     &usedcurve);
-  gcry_free (curve_name);
-  if (ec)
-    return ec;
-  if (usedcurve)  /* Fixme: No error return checking.  */
-    gcry_sexp_build (r_extrainfo, NULL, "(curve %s)", usedcurve);
-
-  skey[0] = sk.E.p;
-  skey[1] = sk.E.a;
-  skey[2] = sk.E.b;
-  skey[3] = _gcry_ecc_ec2os (g_x, g_y, sk.E.p);
-  skey[4] = sk.E.n;
-  skey[5] = _gcry_ecc_ec2os (q_x, q_y, sk.E.p);
-  skey[6] = sk.d;
-
-  mpi_free (g_x);
-  mpi_free (g_y);
-  mpi_free (q_x);
-  mpi_free (q_y);
+  rc = _gcry_ecc_fill_in_curve (nbits, curve_name, &E, &nbits);
+  gcry_free (curve_name); curve_name = NULL;
+  if (rc)
+    goto leave;
 
-  point_free (&sk.E.G);
-  point_free (&sk.Q);
+  if (DBG_CIPHER)
+    {
+      log_debug ("ecgen curve info: %s/%s\n",
+                 _gcry_ecc_model2str (E.model),
+                 _gcry_ecc_dialect2str (E.dialect));
+      if (E.name)
+        log_debug ("ecgen curve used: %s\n", E.name);
+      log_printmpi ("ecgen curve   p", E.p);
+      log_printmpi ("ecgen curve   a", E.a);
+      log_printmpi ("ecgen curve   b", E.b);
+      log_printmpi ("ecgen curve   n", E.n);
+      log_printpnt ("ecgen curve G", &E.G, NULL);
+    }
+
+  random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM;
+  ctx = _gcry_mpi_ec_p_internal_new (E.model, E.dialect, E.p, E.a, E.b);
+  x = mpi_new (0);
+  y = mpi_new (0);
+
+  switch (E.dialect)
+    {
+    case ECC_DIALECT_STANDARD:
+      rc = nist_generate_key (&sk, &E, ctx, random_level, nbits);
+      break;
+    case ECC_DIALECT_ED25519:
+      rc = eddsa_generate_key (&sk, &E, ctx, random_level);
+      break;
+    default:
+      rc = GPG_ERR_INTERNAL;
+      break;
+    }
+  if (rc)
+    goto leave;
+
+  /* Copy data to the result.  */
+  if (_gcry_mpi_ec_get_affine (x, y, &sk.E.G, ctx))
+    log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "G");
+  skey[3] = _gcry_ecc_ec2os (x, y, sk.E.p);
+  if (sk.E.dialect == ECC_DIALECT_ED25519)
+    {
+      unsigned char *encpk;
+      unsigned int encpklen;
+
+      rc = eddsa_encodepoint (&sk.Q, 256/8, ctx, x, y, &encpk, &encpklen);
+      if (rc)
+        return rc;
+      skey[5] = mpi_new (0);
+      gcry_mpi_set_opaque (skey[5], encpk, encpklen*8);
+      encpk = NULL;
+      if (DBG_CIPHER)
+        log_printmpi ("ecgen      e_pk", skey[5]);
+    }
+  else
+    {
+      if (_gcry_mpi_ec_get_affine (x, y, &sk.Q, ctx))
+        log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q");
+      skey[5] = _gcry_ecc_ec2os (x, y, sk.E.p);
+    }
+  skey[0] = sk.E.p; sk.E.p = NULL;
+  skey[1] = sk.E.a; sk.E.a = NULL;
+  skey[2] = sk.E.b; sk.E.b = NULL;
+  skey[4] = sk.E.n; sk.E.n = NULL;
+  skey[6] = sk.d; sk.d = NULL;
 
-  /* Make an empty list of factors.  */
+  if (E.name)  /* Fixme: No error return checking.  */
+    gcry_sexp_build (r_extrainfo, NULL, "(curve %s)", E.name);
+
+  /* Make an dummy list of factors.  */
   *retfactors = gcry_calloc ( 1, sizeof **retfactors );
   if (!*retfactors)
-    return gpg_err_code_from_syserror ();  /* Fixme: relase mem?  */
+    {
+      rc = gpg_err_code_from_syserror ();
+      goto leave;
+    }
 
   if (DBG_CIPHER)
     {
-      log_debug ("ecgen result model: %s\n", _gcry_ecc_model2str (sk.E.model));
-      log_mpidump ("ecgen result p", skey[0]);
-      log_mpidump ("ecgen result a", skey[1]);
-      log_mpidump ("ecgen result b", skey[2]);
-      log_mpidump ("ecgen result G", skey[3]);
-      log_mpidump ("ecgen result n", skey[4]);
-      log_mpidump ("ecgen result Q", skey[5]);
-      log_mpidump ("ecgen result d", skey[6]);
+      log_printmpi ("ecgen result  p", skey[0]);
+      log_printmpi ("ecgen result  a", skey[1]);
+      log_printmpi ("ecgen result  b", skey[2]);
+      log_printmpi ("ecgen result  G", skey[3]);
+      log_printmpi ("ecgen result  n", skey[4]);
+      log_printmpi ("ecgen result  Q", skey[5]);
+      log_printmpi ("ecgen result  d", skey[6]);
     }
+  rc = 0;
 
-  return 0;
+ leave:
+  point_free (&sk.E.G);
+  point_free (&sk.Q);
+  _gcry_mpi_ec_free (ctx);
+  _gcry_ecc_curve_free (&E);
+  gcry_mpi_release (x);
+  gcry_mpi_release (y);
+  return rc;
 }
 
 
@@ -1244,17 +1344,33 @@ ecc_check_secret_key (int algo, gcry_mpi_t *skey)
       return err;
     }
 
-  sk.d = skey[6];
+  {
+    const unsigned char *buf;
+    unsigned int n;
+
+    gcry_assert (mpi_is_opaque (skey[6]));
+
+    buf = gcry_mpi_get_opaque (skey[6], &n);
+    if (!buf)
+      err = GPG_ERR_INV_OBJ;
+    else
+      {
+        n = (n + 7)/8;
+        sk.d = NULL;
+        err = gcry_mpi_scan (&sk.d, GCRYMPI_FMT_USG, buf, n, NULL);
+        if (!err)
+          {
+            if (check_secret_key (&sk))
+              err = GPG_ERR_BAD_SECKEY;
+            gcry_mpi_release (sk.d);
+            sk.d = NULL;
+          }
+      }
+  }
 
-  if (check_secret_key (&sk))
-    {
-      point_free (&sk.E.G);
-      point_free (&sk.Q);
-      return GPG_ERR_BAD_SECKEY;
-    }
   point_free (&sk.E.G);
   point_free (&sk.Q);
-  return 0;
+  return err;
 }
 
 
@@ -1288,14 +1404,36 @@ ecc_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey,
       return err;
     }
   sk.E.n = skey[4];
-  sk.d = skey[6];
 
   resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.E.p));
   resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.E.p));
-  if ((flags & PUBKEY_FLAG_EDDSA))
-    err = sign_eddsa (data, &sk, resarr[0], resarr[1], hashalgo, skey[5]);
-  else
-    err = sign_ecdsa (data, &sk, resarr[0], resarr[1], flags, hashalgo);
+  {
+    const unsigned char *buf;
+    unsigned int n;
+
+    gcry_assert (mpi_is_opaque (skey[6]));
+
+    buf = gcry_mpi_get_opaque (skey[6], &n);
+    if (!buf)
+      err = GPG_ERR_INV_OBJ;
+    else
+      {
+        n = (n + 7)/8;
+        sk.d = NULL;
+        err = gcry_mpi_scan (&sk.d, GCRYMPI_FMT_USG, buf, n, NULL);
+        if (!err)
+          {
+            if ((flags & PUBKEY_FLAG_EDDSA))
+              err = sign_eddsa (data, &sk, resarr[0], resarr[1],
+                                hashalgo, skey[5]);
+            else
+              err = sign_ecdsa (data, &sk, resarr[0], resarr[1],
+                                flags, hashalgo);
+            gcry_mpi_release (sk.d);
+            sk.d = NULL;
+          }
+      }
+  }
   if (err)
     {
       mpi_free (resarr[0]);
@@ -1453,7 +1591,8 @@ ecc_encrypt_raw (int algo, gcry_mpi_t *resarr, gcry_mpi_t k,
       return err;
     }
 
-  ctx = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.p, pk.E.a, pk.E.b);
+  ctx = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect,
+                                     pk.E.p, pk.E.a, pk.E.b);
 
   /* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so */
   {
@@ -1565,7 +1704,8 @@ ecc_decrypt_raw (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
     }
   sk.d = skey[6];
 
-  ctx = _gcry_mpi_ec_p_internal_new (sk.E.model, sk.E.p, sk.E.a, sk.E.b);
+  ctx = _gcry_mpi_ec_p_internal_new (sk.E.model, sk.E.dialect,
+                                     sk.E.p, sk.E.a, sk.E.b);
 
   /* R = dkG */
   point_init (&R);
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 949c538..8fa7ebf 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -1903,7 +1903,16 @@ sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names,
 	elements[idx] = NULL;
       else
 	{
-	  elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
+          switch (idx)
+            {
+            case 5: /* The public and */
+            case 6: /* the secret key must to be passed opaque.  */
+              elements[idx] = _gcry_sexp_nth_opaque_mpi (list, 1);
+              break;
+            default:
+              elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_STD);
+              break;
+            }
 	  gcry_sexp_release (list);
 	  if (!elements[idx])
             {
@@ -3706,6 +3715,7 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
     size_t nelem=0, nelem_cp = 0, needed=0;
     gcry_mpi_t mpis[30];
     int percent_s_idx = -1;
+    int percent_s_idx2 = -1;
 
     /* Estimate size of format string.  */
     nelem = strlen (pub_elems) + strlen (sec_elems);
@@ -3714,11 +3724,13 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
         for (i = 0; factors[i]; i++)
           nelem++;
       }
+    if (extrainfo)
+      nelem += 2;
     nelem_cp = nelem;
 
     needed += nelem * 10;
-    /* (+5 is for EXTRAINFO ("%S")).  */
-    needed += 2 * strlen (algo_name) + 300 + 5;
+    /* (+10 for two times EXTRAINFO ("%S")).  */
+    needed += 2 * strlen (algo_name) + 300 + 10;
     if (nelem > DIM (mpis))
       BUG ();
 
@@ -3744,7 +3756,7 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
       {
         /* Very ugly hack to insert the used curve parameter into the
            list of public key parameters.  */
-        percent_s_idx = nelem;
+        percent_s_idx = nelem++;
         p = stpcpy (p, "%S");
       }
     p = stpcpy (p, "))");
@@ -3757,15 +3769,24 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
         p = stpcpy (p, "%m)");
         mpis[nelem++] = skey[i];
       }
+    if (extrainfo && (algo == GCRY_PK_ECDSA || algo == GCRY_PK_ECDH))
+      {
+        percent_s_idx2 = nelem++;
+        p = stpcpy (p, "%S");
+      }
     p = stpcpy (p, "))");
 
     /* Hack to make release_mpi_array() work.  */
     skey[i] = NULL;
 
-    if (extrainfo && percent_s_idx == -1)
+    if (extrainfo)
       {
         /* If we have extrainfo we should not have any factors.  */
-        p = stpcpy (p, "%S");
+        if (percent_s_idx == -1)
+          {
+            percent_s_idx = nelem++;
+            p = stpcpy (p, "%S");
+          }
       }
     else if (factors && factors[0])
       {
@@ -3787,8 +3808,12 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
       int elem_n = strlen (pub_elems) + strlen (sec_elems);
       void **arg_list;
 
-      /* Allocate one extra for EXTRAINFO ("%S").  */
-      arg_list = gcry_calloc (nelem_cp+1, sizeof *arg_list);
+      if (percent_s_idx != -1)
+        elem_n++;
+      if (percent_s_idx2 != -1)
+        elem_n++;
+
+      arg_list = gcry_calloc (nelem_cp, sizeof *arg_list);
       if (!arg_list)
         {
           rc = gpg_err_code_from_syserror ();
@@ -3798,10 +3823,13 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
         {
           if (i == percent_s_idx)
             arg_list[j++] = &extrainfo;
-          arg_list[j++] = mpis + i;
+          else if (i == percent_s_idx2)
+            arg_list[j++] = &extrainfo;
+          else
+            arg_list[j++] = mpis + i;
         }
-      if (extrainfo && percent_s_idx == -1)
-        arg_list[j] = &extrainfo;
+      if (extrainfo)
+        ;
       else if (factors && factors[0])
         {
           for (; i < nelem_cp; i++)
diff --git a/mpi/ec.c b/mpi/ec.c
index cb86ade..730f766 100644
--- a/mpi/ec.c
+++ b/mpi/ec.c
@@ -431,6 +431,7 @@ ec_get_two_inv_p (mpi_ec_t ec)
    coefficient.  CTX is expected to be zeroized.  */
 static void
 ec_p_init (mpi_ec_t ctx, enum gcry_mpi_ec_models model,
+           enum ecc_dialects dialect,
            gcry_mpi_t p, gcry_mpi_t a, gcry_mpi_t b)
 {
   int i;
@@ -438,6 +439,7 @@ ec_p_init (mpi_ec_t ctx, enum gcry_mpi_ec_models model,
   /* Fixme: Do we want to check some constraints? e.g.  a < p  */
 
   ctx->model = model;
+  ctx->dialect = dialect;
   ctx->p = mpi_copy (p);
   ctx->a = mpi_copy (a);
   if (b && model == MPI_EC_TWISTEDEDWARDS)
@@ -516,12 +518,13 @@ ec_deinit (void *opaque)
    This context needs to be released using _gcry_mpi_ec_free.  */
 mpi_ec_t
 _gcry_mpi_ec_p_internal_new (enum gcry_mpi_ec_models model,
+                             enum ecc_dialects dialect,
                              gcry_mpi_t p, gcry_mpi_t a, gcry_mpi_t b)
 {
   mpi_ec_t ctx;
 
   ctx = gcry_xcalloc (1, sizeof *ctx);
-  ec_p_init (ctx, model, p, a, b);
+  ec_p_init (ctx, model, dialect, p, a, b);
 
   return ctx;
 }
@@ -537,6 +540,7 @@ _gcry_mpi_ec_p_internal_new (enum gcry_mpi_ec_models model,
 gpg_err_code_t
 _gcry_mpi_ec_p_new (gcry_ctx_t *r_ctx,
                     enum gcry_mpi_ec_models model,
+                    enum ecc_dialects dialect,
                     gcry_mpi_t p, gcry_mpi_t a, gcry_mpi_t b)
 {
   gcry_ctx_t ctx;
@@ -550,7 +554,7 @@ _gcry_mpi_ec_p_new (gcry_ctx_t *r_ctx,
   if (!ctx)
     return gpg_err_code_from_syserror ();
   ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
-  ec_p_init (ec, model, p, a, b);
+  ec_p_init (ec, model, dialect, p, a, b);
 
   *r_ctx = ctx;
   return 0;
diff --git a/mpi/mpiutil.c b/mpi/mpiutil.c
index 57fe72a..3855dc4 100644
--- a/mpi/mpiutil.c
+++ b/mpi/mpiutil.c
@@ -276,10 +276,25 @@ gcry_mpi_set_opaque( gcry_mpi_t a, void *p, unsigned int nbits )
   a->nlimbs = 0;
   a->sign  = nbits;
   a->flags = 4;
+  if (gcry_is_secure (a->d))
+    a->flags |= 1;
   return a;
 }
 
 
+gcry_mpi_t
+_gcry_mpi_set_opaque_copy (gcry_mpi_t a, void *p, unsigned int nbits)
+{
+  void *d;
+  unsigned int n;
+
+  n = (nbits+7)/8;
+  d = gcry_is_secure (p)? gcry_malloc_secure (n) : gcry_malloc (n);
+  memcpy (d, p, n);
+  return gcry_mpi_set_opaque (a, d, nbits);
+}
+
+
 void *
 gcry_mpi_get_opaque( gcry_mpi_t a, unsigned int *nbits )
 {
diff --git a/src/ec-context.h b/src/ec-context.h
index 7df3576..f2ad19b 100644
--- a/src/ec-context.h
+++ b/src/ec-context.h
@@ -25,6 +25,8 @@ struct mpi_ec_ctx_s
 {
   enum gcry_mpi_ec_models model; /* The model describing this curve.  */
 
+  enum ecc_dialects dialect;     /* The ECC dialect used with the curve.  */
+
   /* Domain parameters.  Note that they may not all be set and if set
      the MPIs may be flaged as constant. */
   gcry_mpi_t p;         /* Prime specifying the field GF(p).  */
diff --git a/src/mpi.h b/src/mpi.h
index bd93168..f24e968 100644
--- a/src/mpi.h
+++ b/src/mpi.h
@@ -134,6 +134,8 @@ void _gcry_mpi_m_check( gcry_mpi_t a );
 void _gcry_mpi_swap( gcry_mpi_t a, gcry_mpi_t b);
 gcry_mpi_t _gcry_mpi_new (unsigned int nbits);
 gcry_mpi_t _gcry_mpi_snew (unsigned int nbits);
+gcry_mpi_t _gcry_mpi_set_opaque_copy (gcry_mpi_t a,
+                                      void *p, unsigned int nbits);
 void *_gcry_mpi_get_opaque_copy (gcry_mpi_t a, unsigned int *nbits);
 int _gcry_mpi_is_neg (gcry_mpi_t a);
 void _gcry_mpi_neg (gcry_mpi_t w, gcry_mpi_t u);
@@ -289,6 +291,15 @@ enum gcry_mpi_ec_models
        Note that we use 'b' instead of the commonly used 'd'.  */
   };
 
+/* Dialects used with elliptic curves.  It is easier to keep the
+   definition here than in ecc-common.h. */
+enum ecc_dialects
+  {
+    ECC_DIALECT_STANDARD = 0,
+    ECC_DIALECT_ED25519
+  };
+
+
 /* Context used with elliptic curve functions.  */
 struct mpi_ec_ctx_s;
 typedef struct mpi_ec_ctx_s *mpi_ec_t;
@@ -297,9 +308,11 @@ void _gcry_mpi_point_log (const char *name, mpi_point_t point, mpi_ec_t ctx);
 #define log_printpnt(a,p,c) _gcry_mpi_point_log ((a), (p), (c))
 
 mpi_ec_t _gcry_mpi_ec_p_internal_new (enum gcry_mpi_ec_models model,
+                                      enum ecc_dialects dialect,
                                       gcry_mpi_t p, gcry_mpi_t a, gcry_mpi_t b);
 gpg_err_code_t _gcry_mpi_ec_p_new (gcry_ctx_t *r_ctx,
                                    enum gcry_mpi_ec_models model,
+                                   enum ecc_dialects dialect,
                                    gcry_mpi_t p, gcry_mpi_t a, gcry_mpi_t b);
 void _gcry_mpi_ec_free (mpi_ec_t ctx);
 
diff --git a/tests/benchmark.c b/tests/benchmark.c
index ea472a1..1fa2676 100644
--- a/tests/benchmark.c
+++ b/tests/benchmark.c
@@ -883,7 +883,7 @@ ecc_bench (int iterations, int print_header)
 {
 #if USE_ECC
   gpg_error_t err;
-  int p_sizes[] = { 192, 224, 256, 384, 521 };
+  const char *p_sizes[] = { "192", "224", "256", "384", "521", "Ed25519" };
   int testno;
 
   if (print_header)
@@ -897,12 +897,29 @@ ecc_bench (int iterations, int print_header)
       gcry_sexp_t data;
       gcry_sexp_t sig = NULL;
       int count;
+      int p_size;
+      int is_ed25519;
 
-      printf ("ECDSA %3d bit ", p_sizes[testno]);
+      is_ed25519 = !strcmp (p_sizes[testno], "Ed25519");
+      if (is_ed25519)
+        {
+          p_size = 256;
+          printf ("EdDSA Ed25519 ");
+          fflush (stdout);
+        }
+      else
+        {
+          p_size = atoi (p_sizes[testno]);
+          printf ("ECDSA %3d bit ", p_size);
+        }
       fflush (stdout);
 
-      err = gcry_sexp_build (&key_spec, NULL,
-                             "(genkey (ECDSA (nbits %d)))", p_sizes[testno]);
+      if (is_ed25519)
+        err = gcry_sexp_build (&key_spec, NULL,
+                               "(genkey (ecdsa (curve \"Ed25519\")))");
+      else
+        err = gcry_sexp_build (&key_spec, NULL,
+                               "(genkey (ECDSA (nbits %d)))", p_size);
       if (err)
         die ("creating S-expression failed: %s\n", gcry_strerror (err));
 
@@ -910,7 +927,7 @@ ecc_bench (int iterations, int print_header)
       err = gcry_pk_genkey (&key_pair, key_spec);
       if (err)
         die ("creating %d bit ECC key failed: %s\n",
-             p_sizes[testno], gcry_strerror (err));
+             p_size, gcry_strerror (err));
 
       pub_key = gcry_sexp_find_token (key_pair, "public-key", 0);
       if (! pub_key)
@@ -925,10 +942,16 @@ ecc_bench (int iterations, int print_header)
       printf ("     %s", elapsed_time ());
       fflush (stdout);
 
-      x = gcry_mpi_new (p_sizes[testno]);
-      gcry_mpi_randomize (x, p_sizes[testno], GCRY_WEAK_RANDOM);
-      err = gcry_sexp_build (&data, NULL, "(data (flags raw) (value %m))", x);
+      x = gcry_mpi_new (p_size);
+      gcry_mpi_randomize (x, p_size, GCRY_WEAK_RANDOM);
+      if (is_ed25519)
+        err = gcry_sexp_build (&data, NULL,
+                               "(data (flags eddsa)(hash-algo sha512)"
+                               " (value %m))", x);
+      else
+        err = gcry_sexp_build (&data, NULL, "(data (flags raw) (value %m))", x);
       gcry_mpi_release (x);
+
       if (err)
         die ("converting data failed: %s\n", gcry_strerror (err));
 
@@ -1041,6 +1064,7 @@ main( int argc, char **argv )
   int no_blinding = 0;
   int use_random_daemon = 0;
   int with_progress = 0;
+  int debug = 0;
 
   buffer_alignment = 1;
 
@@ -1067,6 +1091,12 @@ main( int argc, char **argv )
           verbose++;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose += 2;
+          debug++;
+          argc--; argv++;
+        }
       else if (!strcmp (*argv, "--use-random-daemon"))
         {
           use_random_daemon = 1;
@@ -1167,6 +1197,9 @@ main( int argc, char **argv )
       exit (1);
     }
 
+  if (debug)
+    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
+
   if (gcry_fips_mode_active ())
     in_fips_mode = 1;
   else
diff --git a/tests/curves.c b/tests/curves.c
index af2b368..2c3ae53 100644
--- a/tests/curves.c
+++ b/tests/curves.c
@@ -51,12 +51,12 @@ static unsigned int sample_key_1_nbits = 256;
 static char const sample_key_2[] =
 "(public-key\n"
 " (ecdh\n"
-"  (p #e95e4a5f737059dc60dfc7ad95b3d8139515620f#)\n"
+"  (p #00e95e4a5f737059dc60dfc7ad95b3d8139515620f#)\n"
 "  (a #340e7be2a280eb74e2be61bada745d97e8f7c300#)\n"
 "  (b #1e589a8595423412134faa2dbdec95c8d8675e58#)\n"
 "  (g #04bed5af16ea3f6a4f62938c4631eb5af7bdbcdbc3"
         "1667cb477a1a8ec338f94741669c976316da6321#)\n"
-"  (n #e95e4a5f737059dc60df5991d45029409e60fc09#)\n"
+"  (n #00e95e4a5f737059dc60df5991d45029409e60fc09#)\n"
 "  (q #041111111111111111111111111111111111111111"
         "2222222222222222222222222222222222222222#)\n"
 "  ))";
diff --git a/tests/keygen.c b/tests/keygen.c
index 1d1b43e..eed62e1 100644
--- a/tests/keygen.c
+++ b/tests/keygen.c
@@ -34,6 +34,16 @@ static int debug;
 static int error_count;
 
 static void
+show ( const char *format, ... )
+{
+    va_list arg_ptr ;
+
+    va_start( arg_ptr, format ) ;
+    vfprintf (stderr, format, arg_ptr );
+    va_end(arg_ptr);
+}
+
+static void
 fail ( const char *format, ... )
 {
     va_list arg_ptr ;
@@ -266,7 +276,8 @@ check_generated_ecc_key (gcry_sexp_t key)
 static void
 check_ecc_keys (void)
 {
-  const char *curves[] = { "NIST P-521", "NIST P-384", "NIST P-256", NULL };
+  const char *curves[] = { "NIST P-521", "NIST P-384", "NIST P-256",
+                           "Ed25519", NULL };
   int testno;
   gcry_sexp_t keyparm, key;
   int rc;
@@ -285,7 +296,11 @@ check_ecc_keys (void)
         die ("error generating ECC key using curve %s: %s\n",
              curves[testno], gpg_strerror (rc));
 
-      check_generated_ecc_key (key);
+      if (!strcmp (curves[testno], "Ed25519"))
+        show ("Note: gcry_pk_testkey does not yet work for Ed25519\n");
+      else
+        check_generated_ecc_key (key);
+
       gcry_sexp_release (key);
     }
 }
@@ -306,13 +321,13 @@ check_nonce (void)
     {
       gcry_create_nonce (b, sizeof b);
       if (!memcmp (a, b, sizeof a))
-        die ("identical nounce found\n");
+        die ("identical nonce found\n");
     }
   for (i=0; i < 10; i++)
     {
       gcry_create_nonce (a, sizeof a);
       if (!memcmp (a, b, sizeof a))
-        die ("identical nounce found\n");
+        die ("identical nonce found\n");
     }
 
  again:

commit 89fe2173649a72019d75e059e6c6938efd10421f
Author: Werner Koch <wk at gnupg.org>
Date:   Sat Sep 7 10:06:46 2013 +0200

    mpi: Support printing of negative numbers.
    
    * mpi/mpicoder.c (twocompl, onecompl): New.
    (gcry_mpi_print): Use it for STD and SSH.
    (gcry_mpi_scan): Use it for STD and SSH.  Always set NSCANNED.
    (gcry_mpi_aprint): Clear the extra allocated byte.
    * tests/t-convert.c (showhex, showmpi): New.
    (mpi2bitstr_nlz): New.
    (check_formats): New.
    (main): Call new test.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/NEWS b/NEWS
index e5ea856..46b5297 100644
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,9 @@ Noteworthy changes in version 1.6.0 (unreleased)
 
  * Added several MPI helper functions.
 
+ * Added support for negative numbers to gcry_mpi_print,
+   gcry_mpi_aprint and gcry_mpi_scan.
+
  * Interface changes relative to the 1.5.0 release:
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  gcry_ac_*              REMOVED.
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index afef7f7..63fd596 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -3826,7 +3826,8 @@ bytes actually scanned unless @var{nscanned} was given as
 
 @table @code
 @item GCRYMPI_FMT_STD
-2-complement stored without a length header.
+2-complement stored without a length header.  Note that
+ at code{gcry_mpi_print} stores a @code{0} as a string of zero length.
 
 @item GCRYMPI_FMT_PGP
 As used by OpenPGP (only defined as unsigned). This is basically
@@ -3837,8 +3838,10 @@ As used in the Secure Shell protocol.  This is @code{GCRYMPI_FMT_STD}
 with a 4 byte big endian header.
 
 @item GCRYMPI_FMT_HEX
-Stored as a C style string with each byte of the MPI encoded as 2 hex
-digits.  When using this format, @var{buflen} must be zero.
+Stored as a string with each byte of the MPI encoded as 2 hex digits.
+Negative numbers are prefix with a minus sign and in addition the
+high bit is always zero to make clear that an explicit sign ist used.
+When using this format, @var{buflen} must be zero.
 
 @item GCRYMPI_FMT_USG
 Simple unsigned integer.
@@ -3866,6 +3869,12 @@ Convert the MPI @var{a} into an external representation described by
 address will be stored in the variable @var{buffer} points to.  The
 number of bytes stored in this buffer will be stored in the variable
 @var{nbytes} points to, unless @var{nbytes} is @code{NULL}.
+
+Even if @var{nbytes} is zero, the function allocates at least one byte
+and store a zero there.  Thus with formats @code{GCRYMPI_FMT_STD} and
+ at code{GCRYMPI_FMT_USG} the caller may safely set a returned length of
+0 to 1 to represent a zero as a 1 byte string.
+
 @end deftypefun
 
 @deftypefun void gcry_mpi_dump (@w{const gcry_mpi_t @var{a}})
diff --git a/mpi/mpicoder.c b/mpi/mpicoder.c
index 19c8de9..07e91c6 100644
--- a/mpi/mpicoder.c
+++ b/mpi/mpicoder.c
@@ -353,6 +353,65 @@ _gcry_mpi_set_buffer (gcry_mpi_t a, const void *buffer_arg,
 }
 
 
+static void
+onecompl (gcry_mpi_t a)
+{
+  mpi_ptr_t ap;
+  mpi_size_t n;
+  unsigned int i;
+  unsigned int nbits = mpi_get_nbits (a);
+
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
+
+  mpi_normalize (a);
+  ap = a->d;
+  n = a->nlimbs;
+
+  for( i = 0; i < n; i++ )
+    ap[i] ^= (mpi_limb_t)(-1);
+
+  a->sign = 0;
+  mpi_clear_highbit (a, nbits-1);
+}
+
+
+/* Perform a two's complement operation on buffer P of size N bytes.  */
+static void
+twocompl (unsigned char *p, unsigned int n)
+{
+  int i;
+
+  for (i=n-1; i >= 0 && !p[i]; i--)
+    ;
+  if (i >= 0)
+    {
+      if ((p[i] & 0x01))
+        p[i] = (((p[i] ^ 0xfe) | 0x01) & 0xff);
+      else if ((p[i] & 0x02))
+        p[i] = (((p[i] ^ 0xfc) | 0x02) & 0xfe);
+      else if ((p[i] & 0x04))
+        p[i] = (((p[i] ^ 0xf8) | 0x04) & 0xfc);
+      else if ((p[i] & 0x08))
+        p[i] = (((p[i] ^ 0xf0) | 0x08) & 0xf8);
+      else if ((p[i] & 0x10))
+        p[i] = (((p[i] ^ 0xe0) | 0x10) & 0xf0);
+      else if ((p[i] & 0x20))
+        p[i] = (((p[i] ^ 0xc0) | 0x20) & 0xe0);
+      else if ((p[i] & 0x40))
+        p[i] = (((p[i] ^ 0x80) | 0x40) & 0xc0);
+      else
+        p[i] = 0x80;
+
+      for (i--; i >= 0; i--)
+        p[i] ^= 0xff;
+    }
+}
+
+
 /* Convert the external representation of an integer stored in BUFFER
    with a length of BUFLEN into a newly create MPI returned in
    RET_MPI.  If NBYTES is not NULL, it will receive the number of
@@ -380,15 +439,14 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format,
                 : mpi_alloc ((len+BYTES_PER_MPI_LIMB-1)/BYTES_PER_MPI_LIMB);
       if (len)
         {
+          _gcry_mpi_set_buffer (a, s, len, 0);
           a->sign = !!(*s & 0x80);
           if (a->sign)
             {
-              /* FIXME: we have to convert from 2compl to magnitude format */
-              mpi_free (a);
-              return gcry_error (GPG_ERR_INTERNAL);
+              onecompl (a);
+              mpi_add_ui (a, a, 1);
+              a->sign = 1;
 	    }
-          else
-            _gcry_mpi_set_buffer (a, s, len, 0);
 	}
       if (ret_mpi)
         {
@@ -397,6 +455,8 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format,
 	}
       else
         mpi_free(a);
+      if (nscanned)
+        *nscanned = len;
       return 0;
     }
   else if (format == GCRYMPI_FMT_USG)
@@ -414,6 +474,8 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format,
 	}
       else
         mpi_free(a);
+      if (nscanned)
+        *nscanned = len;
       return 0;
     }
   else if (format == GCRYMPI_FMT_PGP)
@@ -458,14 +520,13 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format,
       if (n)
         {
           a->sign = !!(*s & 0x80);
+          _gcry_mpi_set_buffer( a, s, n, 0 );
           if (a->sign)
             {
-              /* FIXME: we have to convert from 2compl to magnitude format */
-              mpi_free(a);
-              return gcry_error (GPG_ERR_INTERNAL);
+              onecompl (a);
+              mpi_add_ui (a, a, 1);
+              a->sign = 1;
 	    }
-          else
-            _gcry_mpi_set_buffer( a, s, n, 0 );
 	}
       if (nscanned)
         *nscanned = n+4;
@@ -497,6 +558,8 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format,
 	}
       else
         mpi_free(a);
+      if (nscanned)
+        *nscanned = strlen ((const char*)buffer);
       return 0;
     }
   else
@@ -541,18 +604,25 @@ gcry_mpi_print (enum gcry_mpi_format format,
       int extra = 0;
       unsigned int n;
 
-      if (negative)
-        return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */
-
       tmp = _gcry_mpi_get_buffer (a, 0, &n, NULL);
       if (!tmp)
         return gpg_error_from_syserror ();
 
-      /* If the high bit of the returned buffer is set, we need to
-         print an extra leading 0x00 so that the output is interpreted
-         as a positive number.  */
-      if (n && (*tmp & 0x80))
+      if (negative)
         {
+          twocompl (tmp, n);
+          if (!(*tmp & 0x80))
+            {
+              /* Need to extend the sign.  */
+              n++;
+              extra = 2;
+            }
+        }
+      else if (n && (*tmp & 0x80))
+        {
+          /* Positive but the high bit of the returned buffer is set.
+             Thus we need to print an extra leading 0x00 so that the
+             output is interpreted as a positive number.  */
           n++;
           extra = 1;
 	}
@@ -567,9 +637,11 @@ gcry_mpi_print (enum gcry_mpi_format format,
         {
           unsigned char *s = buffer;
 
-          if (extra)
+          if (extra == 1)
             *s++ = 0;
-          memcpy (s, tmp, n-extra);
+          else if (extra)
+            *s++ = 0xff;
+          memcpy (s, tmp, n-!!extra);
 	}
       gcry_free(tmp);
       *nwritten = n;
@@ -632,13 +704,21 @@ gcry_mpi_print (enum gcry_mpi_format format,
       int extra = 0;
       unsigned int n;
 
-      if (negative)
-        return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet.  */
-
       tmp = _gcry_mpi_get_buffer (a, 0, &n, NULL);
       if (!tmp)
         return gpg_error_from_syserror ();
-      if (n && (*tmp & 0x80))
+
+      if (negative)
+        {
+          twocompl (tmp, n);
+          if (!(*tmp & 0x80))
+            {
+              /* Need to extend the sign.  */
+              n++;
+              extra = 2;
+            }
+        }
+      else if (n && (*tmp & 0x80))
         {
           n++;
           extra=1;
@@ -658,10 +738,11 @@ gcry_mpi_print (enum gcry_mpi_format format,
           *s++ = n >> 16;
           *s++ = n >> 8;
           *s++ = n;
-          if (extra)
+          if (extra == 1)
             *s++ = 0;
-
-          memcpy (s, tmp, n-extra);
+          else if (extra)
+            *s++ = 0xff;
+          memcpy (s, tmp, n-!!extra);
 	}
       gcry_free (tmp);
       *nwritten = 4+n;
@@ -741,6 +822,10 @@ gcry_mpi_aprint (enum gcry_mpi_format format,
   *buffer = mpi_is_secure(a) ? gcry_malloc_secure (n?n:1) : gcry_malloc (n?n:1);
   if (!*buffer)
     return gpg_error_from_syserror ();
+  /* If the returned buffer will have a length of 0, we nevertheless
+     allocated 1 byte (malloc needs it anyway) and store a 0.  */
+  if (!n)
+    **buffer = 0;
   rc = gcry_mpi_print( format, *buffer, n, &n, a );
   if (rc)
     {
diff --git a/tests/t-convert.c b/tests/t-convert.c
index b7f97fa..d44c439 100644
--- a/tests/t-convert.c
+++ b/tests/t-convert.c
@@ -28,7 +28,10 @@
 
 #include "../src/gcrypt-int.h"
 
-#define PGM "t-mpi-point"
+#define PGM "t-convert"
+
+#define DIM(v)		     (sizeof(v)/sizeof((v)[0]))
+#define DIMof(type,member)   DIM(((type *)0)->member)
 
 static const char *wherestr;
 static int verbose;
@@ -55,6 +58,61 @@ show (const char *format, ...)
 }
 
 static void
+showhex (const char *prefix, const void *buffer, size_t buflen)
+{
+  const unsigned char *s;
+
+  if (!verbose)
+    return;
+  fprintf (stderr, "%s: %s ", PGM, prefix);
+  for (s= buffer; buflen; buflen--, s++)
+    fprintf (stderr, "%02x", *s);
+  putc ('\n', stderr);
+}
+
+
+/* Allocate a bit string consisting of '0' and '1' from the MPI A.  Do
+   not return any leading zero bits.  Caller needs to gcry_free the
+   result. */
+static char *
+mpi2bitstr_nlz (gcry_mpi_t a)
+{
+  char *p, *buf;
+  size_t length = gcry_mpi_get_nbits (a);
+
+  if (!length)
+    {
+      buf = p = xmalloc (3);
+      *p++ = ' ';
+      *p++ = '0';
+    }
+  else
+    {
+      buf = p = xmalloc (length + 1 + 1);
+      *p++ = gcry_mpi_is_neg (a)? '-':' ';
+      while (length-- > 1)
+        *p++ = gcry_mpi_test_bit (a, length) ? '1':'0';
+      *p++ = gcry_mpi_test_bit (a, 0) ? '1':'0';
+    }
+  *p = 0;
+  return buf;
+}
+
+
+static void
+showmpi (const char *prefix, gcry_mpi_t a)
+{
+  char *bitstr;
+
+  if (!verbose)
+    return;
+  bitstr = mpi2bitstr_nlz (a);
+  fprintf (stderr, "%s: %s%s\n", PGM, prefix, bitstr);
+  xfree (bitstr);
+}
+
+
+static void
 fail (const char *format, ...)
 {
   va_list arg_ptr;
@@ -95,10 +153,10 @@ negative_zero (void)
   void *bufaddr = &buf;
   struct { const char *name; enum gcry_mpi_format format; } fmts[] =
     {
-      { "STD", GCRYMPI_FMT_STD },
-      { "PGP", GCRYMPI_FMT_PGP },
-      { "SSH", GCRYMPI_FMT_SSH },
-      { "HEX", GCRYMPI_FMT_HEX },
+      /* { "STD", GCRYMPI_FMT_STD }, */
+      /* { "PGP", GCRYMPI_FMT_PGP }, */
+      /* { "SSH", GCRYMPI_FMT_SSH }, */
+      /* { "HEX", GCRYMPI_FMT_HEX }, */
       { "USG", GCRYMPI_FMT_USG },
       { NULL, 0 }
     };
@@ -134,6 +192,311 @@ negative_zero (void)
 }
 
 
+static void
+check_formats (void)
+{
+  static struct {
+    int value;
+    struct {
+      const char *hex;
+      size_t stdlen;
+      const char *std;
+      size_t sshlen;
+      const char *ssh;
+      size_t usglen;
+      const char *usg;
+    } a;
+  } data[] = {
+    {    0, { "00",
+              0, "",
+              4, "\x00\x00\x00\x00",
+              0, "" }
+    },
+    {    1, { "01",
+              1, "\x01",
+              5, "\x00\x00\x00\x01\x01",
+              1, "\x01" }
+    },
+    {    2, { "02",
+              1, "\x02",
+              5, "\x00\x00\x00\x01\x02",
+              1, "\x02",  }
+    },
+    {  127, { "7F",
+              1, "\x7f",
+              5, "\x00\x00\x00\x01\x7f",
+              1, "\x7f"  }
+    },
+    {  128, { "0080",
+              2, "\x00\x80",
+              6, "\x00\x00\x00\x02\x00\x80",
+              1, "\x80" }
+    },
+    {  129, { "0081",
+              2, "\x00\x81",
+              6, "\x00\x00\x00\x02\x00\x81",
+              1, "\x81"  }
+    },
+    {  255, { "00FF",
+              2, "\x00\xff",
+              6, "\x00\x00\x00\x02\x00\xff",
+              1, "\xff" }
+    },
+    {  256, { "0100",
+              2, "\x01\x00",
+              6, "\x00\x00\x00\x02\x01\x00",
+              2, "\x01\x00" }
+    },
+    {  257, { "0101",
+              2, "\x01\x01",
+              6, "\x00\x00\x00\x02\x01\x01",
+              2, "\x01\x01" }
+    },
+    {   -1, { "-01",
+              1, "\xff",
+              5, "\x00\x00\x00\x01\xff",
+              1,"\x01" }
+    },
+    {   -2, { "-02",
+              1, "\xfe",
+              5, "\x00\x00\x00\x01\xfe",
+              1, "\x02" }
+    },
+    { -127, { "-7F",
+              1, "\x81",
+              5, "\x00\x00\x00\x01\x81",
+              1, "\x7f" }
+    },
+    { -128, { "-0080",
+              1, "\x80",
+              5, "\x00\x00\x00\x01\x80",
+              1, "\x80" }
+    },
+    { -129, { "-0081",
+              2, "\xff\x7f",
+              6, "\x00\x00\x00\x02\xff\x7f",
+              1, "\x81" }
+    },
+    { -255, { "-00FF",
+              2, "\xff\x01",
+              6, "\x00\x00\x00\x02\xff\x01",
+              1, "\xff" }
+    },
+    { -256, { "-0100",
+              2, "\xff\x00",
+              6, "\x00\x00\x00\x02\xff\x00",
+              2, "\x01\x00" }
+    },
+    { -257, { "-0101",
+              2, "\xfe\xff",
+              6, "\x00\x00\x00\x02\xfe\xff",
+              2, "\x01\x01" }
+    },
+    {  65535, { "00FFFF",
+                3, "\x00\xff\xff",
+                7, "\x00\x00\x00\x03\x00\xff\xff",
+                2, "\xff\xff" }
+    },
+    {  65536, { "010000",
+                3, "\x01\00\x00",
+                7, "\x00\x00\x00\x03\x01\x00\x00",
+                3, "\x01\x00\x00" }
+    },
+    {  65537, { "010001",
+                3, "\x01\00\x01",
+                7, "\x00\x00\x00\x03\x01\x00\x01",
+                3, "\x01\x00\x01" }
+    },
+    { -65537, { "-010001",
+                3, "\xfe\xff\xff",
+                7, "\x00\x00\x00\x03\xfe\xff\xff",
+                3, "\x01\x00\x01" }
+    },
+    { -65536, { "-010000",
+                3, "\xff\x00\x00",
+                7, "\x00\x00\x00\x03\xff\x00\x00",
+                3, "\x01\x00\x00" }
+    },
+    { -65535, { "-00FFFF",
+                3, "\xff\x00\x01",
+                7, "\x00\x00\x00\x03\xff\x00\x01",
+                2, "\xff\xff" }
+    }
+  };
+  gpg_error_t err;
+  gcry_mpi_t a, b;
+  char *buf;
+  void *bufaddr = &buf;
+  int idx;
+  size_t buflen;
+
+  a = gcry_mpi_new (0);
+  for (idx=0; idx < DIM(data); idx++)
+    {
+      if (debug)
+        show ("print test %d\n", data[idx].value);
+
+      if (data[idx].value < 0)
+        {
+          gcry_mpi_set_ui (a, -data[idx].value);
+          gcry_mpi_neg (a, a);
+        }
+      else
+        gcry_mpi_set_ui (a, data[idx].value);
+
+      err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a);
+      if (err)
+        fail ("error printing value %d as %s: %s\n",
+              data[idx].value, "HEX", gpg_strerror (err));
+      else
+        {
+          if (strcmp (buf, data[idx].a.hex))
+            {
+              fail ("error printing value %d as %s: %s\n",
+                    data[idx].value, "HEX", "wrong result");
+              show ("expected: '%s'\n", data[idx].a.hex);
+              show ("     got: '%s'\n", buf);
+            }
+          gcry_free (buf);
+        }
+
+      err = gcry_mpi_aprint (GCRYMPI_FMT_STD, bufaddr, &buflen, a);
+      if (err)
+        fail ("error printing value %d as %s: %s\n",
+              data[idx].value, "STD", gpg_strerror (err));
+      else
+        {
+          if (buflen != data[idx].a.stdlen
+              || memcmp (buf, data[idx].a.std, data[idx].a.stdlen))
+            {
+              fail ("error printing value %d as %s: %s\n",
+                    data[idx].value, "STD", "wrong result");
+              showhex ("expected:", data[idx].a.std, data[idx].a.stdlen);
+              showhex ("     got:", buf, buflen);
+            }
+          gcry_free (buf);
+        }
+
+      err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, bufaddr, &buflen, a);
+      if (err)
+        fail ("error printing value %d as %s: %s\n",
+              data[idx].value, "SSH", gpg_strerror (err));
+      else
+        {
+          if (buflen != data[idx].a.sshlen
+              || memcmp (buf, data[idx].a.ssh, data[idx].a.sshlen))
+            {
+              fail ("error printing value %d as %s: %s\n",
+                    data[idx].value, "SSH", "wrong result");
+              showhex ("expected:", data[idx].a.ssh, data[idx].a.sshlen);
+              showhex ("     got:", buf, buflen);
+            }
+          gcry_free (buf);
+        }
+
+      err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufaddr, &buflen, a);
+      if (err)
+        fail ("error printing value %d as %s: %s\n",
+              data[idx].value, "USG", gpg_strerror (err));
+      else
+        {
+          if (buflen != data[idx].a.usglen
+              || memcmp (buf, data[idx].a.usg, data[idx].a.usglen))
+            {
+              fail ("error printing value %d as %s: %s\n",
+                    data[idx].value, "USG", "wrong result");
+              showhex ("expected:", data[idx].a.usg, data[idx].a.usglen);
+              showhex ("     got:", buf, buflen);
+            }
+          gcry_free (buf);
+        }
+    }
+
+
+  /* Now for the other direction.  */
+  for (idx=0; idx < DIM(data); idx++)
+    {
+      if (debug)
+        show ("scan test %d\n", data[idx].value);
+
+      if (data[idx].value < 0)
+        {
+          gcry_mpi_set_ui (a, -data[idx].value);
+          gcry_mpi_neg (a, a);
+        }
+      else
+        gcry_mpi_set_ui (a, data[idx].value);
+
+      err = gcry_mpi_scan (&b, GCRYMPI_FMT_HEX, data[idx].a.hex, 0, &buflen);
+      if (err)
+        fail ("error scanning value %d from %s: %s\n",
+              data[idx].value, "HEX", gpg_strerror (err));
+      else
+        {
+          if (gcry_mpi_cmp (a, b))
+            {
+              fail ("error scanning value %d from %s: %s\n",
+                    data[idx].value, "HEX", "wrong result");
+              showmpi ("expected:", a);
+              showmpi ("     got:", b);
+            }
+          gcry_mpi_release (b);
+        }
+
+      err = gcry_mpi_scan (&b, GCRYMPI_FMT_STD,
+                           data[idx].a.std, data[idx].a.stdlen, &buflen);
+      if (err)
+        fail ("error scanning value %d as %s: %s\n",
+              data[idx].value, "STD", gpg_strerror (err));
+      else
+        {
+          if (gcry_mpi_cmp (a, b) || data[idx].a.stdlen != buflen)
+            {
+              fail ("error scanning value %d from %s: %s (%u)\n",
+                    data[idx].value, "STD", "wrong result", buflen);
+              showmpi ("expected:", a);
+              showmpi ("     got:", b);
+            }
+          gcry_mpi_release (b);
+        }
+
+      err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, bufaddr, &buflen, a);
+      if (err)
+        fail ("error printing value %d as %s: %s\n",
+              data[idx].value, "SSH", gpg_strerror (err));
+      else
+        {
+          if (buflen != data[idx].a.sshlen
+              || memcmp (buf, data[idx].a.ssh, data[idx].a.sshlen))
+            {
+              fail ("error printing value %d as %s: %s\n",
+                    data[idx].value, "SSH", "wrong result");
+              showhex ("expected:", data[idx].a.ssh, data[idx].a.sshlen);
+              showhex ("     got:", buf, buflen);
+            }
+          gcry_free (buf);
+        }
+
+      err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufaddr, &buflen, a);
+      if (err)
+        fail ("error printing value %d as %s: %s\n",
+              data[idx].value, "USG", gpg_strerror (err));
+      else
+        {
+          if (buflen != data[idx].a.usglen
+              || memcmp (buf, data[idx].a.usg, data[idx].a.usglen))
+            {
+              fail ("error printing value %d as %s: %s\n",
+                    data[idx].value, "USG", "wrong result");
+              showhex ("expected:", data[idx].a.usg, data[idx].a.usglen);
+              showhex ("     got:", buf, buflen);
+            }
+          gcry_free (buf);
+        }
+    }
+
+  gcry_mpi_release (a);
+}
 
 
 int
@@ -154,6 +517,7 @@ main (int argc, char **argv)
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 
   negative_zero ();
+  check_formats ();
 
   show ("All tests completed. Errors: %d\n", error_count);
   return error_count ? 1 : 0;

-----------------------------------------------------------------------

Summary of changes:
 NEWS                |    3 +
 cipher/ecc-common.h |    3 +
 cipher/ecc-curves.c |   45 ++++--
 cipher/ecc-misc.c   |   55 ++++++--
 cipher/ecc.c        |  404 ++++++++++++++++++++++++++++++++++-----------------
 cipher/pubkey.c     |   50 +++++--
 doc/gcrypt.texi     |   15 ++-
 mpi/ec.c            |    8 +-
 mpi/mpicoder.c      |  137 ++++++++++++++----
 mpi/mpiutil.c       |   15 ++
 src/ec-context.h    |    2 +
 src/mpi.h           |   13 ++
 tests/benchmark.c   |   49 +++++-
 tests/curves.c      |    4 +-
 tests/keygen.c      |   23 +++-
 tests/t-convert.c   |  374 ++++++++++++++++++++++++++++++++++++++++++++++-
 16 files changed, 978 insertions(+), 222 deletions(-)


hooks/post-receive
-- 
The GNU crypto library
http://git.gnupg.org




More information about the Gnupg-commits mailing list