ecc: Add Ed25519 key generation and prepare for optimizations.
authorWerner Koch <wk@gnupg.org>
Sat, 7 Sep 2013 08:06:46 +0000 (10:06 +0200)
committerWerner Koch <wk@gnupg.org>
Wed, 18 Sep 2013 11:14:31 +0000 (13:14 +0200)
* 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@gnupg.org>
12 files changed:
cipher/ecc-common.h
cipher/ecc-curves.c
cipher/ecc-misc.c
cipher/ecc.c
cipher/pubkey.c
mpi/ec.c
mpi/mpiutil.c
src/ec-context.h
src/mpi.h
tests/benchmark.c
tests/curves.c
tests/keygen.c

index 614baae..e806059 100644 (file)
 #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);
 
index c17c7fe..49c0959 100644 (file)
@@ -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);
index 6c34902..f8db81a 100644 (file)
@@ -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);
index 7d468ee..9766e9e 100644 (file)
@@ -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);
index 949c538..8fa7ebf 100644 (file)
@@ -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++)
index cb86ade..730f766 100644 (file)
--- 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;
index 57fe72a..3855dc4 100644 (file)
@@ -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 )
 {
index 7df3576..f2ad19b 100644 (file)
@@ -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).  */
index bd93168..f24e968 100644 (file)
--- 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);
 
index ea472a1..1fa2676 100644 (file)
@@ -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
index af2b368..2c3ae53 100644 (file)
@@ -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"
 "  ))";
index 1d1b43e..eed62e1 100644 (file)
@@ -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: