Enable AMD64 SHA512 implementations for WIN64
[libgcrypt.git] / cipher / ecc.c
index 6f65070..2f5e401 100644 (file)
-/* ecc.c  -  ECElGamal Public Key encryption & ECDSA signature algorithm
- * Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+/* ecc.c  -  Elliptic Curve Cryptography
+ * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2013 g10 Code GmbH
  *
- * This file is part of GnuPG.
+ * This file is part of Libgcrypt.
  *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
  *
- * GnuPG is distributed in the hope that it will be useful,
+ * Libgcrypt is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA. 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-/* TODO wk
+/* This code is originally based on the Patch 0.1.6 for the gnupg
+   1.4.x branch as retrieved on 2007-03-21 from
+   http://www.calcurco.cat/eccGnuPG/src/gnupg-1.4.6-ecc0.2.0beta1.diff.bz2
+   The original authors are:
+     Written by
+      Sergi Blanch i Torne <d4372211 at alumnes.eup.udl.es>,
+      Ramiro Moreno Chiral <ramiro at eup.udl.es>
+     Maintainers
+      Sergi Blanch i Torne
+      Ramiro Moreno Chiral
+      Mikael Mylnikov (mmr)
+  For use in Libgcrypt the code has been heavily modified and cleaned
+  up. In fact there is not much left of the orginally code except for
+  some variable names and the text book implementaion of the sign and
+  verification algorithms.  The arithmetic functions have entirely
+  been rewritten and moved to mpi/ec.c.
+
+  ECDH encrypt and decrypt code written by Andrey Jivsov.
+*/
 
-  - Check whether we can LGPL the code.
 
+/* TODO:
 
-*/
+  - In mpi/ec.c we use mpi_powm for x^2 mod p: Either implement a
+    special case in mpi_powm or check whether mpi_mulm is faster.
 
-/* This code is a based on the 
- * Patch 0.1.6 for the gnupg 1.4.x branch
- * as retrieved on 2007-03-21 from
- * http://www.calcurco.cat/eccGnuPG/src/gnupg-1.4.6-ecc0.2.0beta1.diff.bz2
- *
- * Written by 
- *  Sergi Blanch i Torne <d4372211 at alumnes.eup.udl.es>, 
- *  Ramiro Moreno Chiral <ramiro at eup.udl.es>
- * Maintainers
- *  Sergi Blanch i Torne
- *  Ramiro Moreno Chiral
- *  Mikael Mylnikov (mmr)
- */
+*/
 
-/*
- * This module are under development, it would not have to be used 
- * in a production environments. It can have bugs!
- * 
- * Made work:
- *  alex: found a bug over the passphrase.
- *  mmr: signature bug found and solved (afine conversion).
- *  mmr: found too many mistakes in the mathematical background transcription.
- *  mmr: improve the mathematical performance.
- *  mmr: solve ECElGamal IFP weakness.
- *  more polite gen_k() and its calls.
- *  mmr: extend the check_secret_key()
- * In process:
- *  gen_big_point(): Randomize the point generation.
- *  improve te memory uses.
- *  Separation between sign & encrypt keys to facility the subkeys creation.
- *  read & reread the code in a bug search!
- * To do:
- *  2-isogeny: randomize the elliptic curves.
- *  E(F_{2^m})
- */
 
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 
 #include "g10lib.h"
 #include "mpi.h"
 #include "cipher.h"
-
-/* 
-    ECC over F_p; E(F_p)
-    T=(p,a,b,G,n,h)
-             p:    big odd number
-             a,b:  curve generators
-             G:    Subgroup generator point
-             n:    big int, in G order
-             h:    cofactor
-     y^2=x^3+ax+b --> (Y^2)Z=X^3+aX(Z^2)+b(Z^3)
-    
-    
-             Q=[d]G, 1<=d<=n-1
-*/
-
-
-/* Point representation in projective coordinates. */
-typedef struct
-{
-  gcry_mpi_t x_;
-  gcry_mpi_t y_;
-  gcry_mpi_t z_;
-} point_t;
-
-
-/* Definition of a curve.  */
-typedef struct
-{
-  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 teh Weierstrass equation.  */
-  point_t G;      /* Base point (generator).  */
-  gcry_mpi_t n_;  /* Order of G.  */
-  /*gcry_mpi_t h_; =1  fixme: We will need to change this value in 2-isogeny */
-} elliptic_curve_t;             /* Fixme: doubtful name */
-
-
-typedef struct
-{
-  elliptic_curve_t E;
-  point_t Q;                    /* Q=[d]G */
-} ECC_public_key;               /* Q */
-
-typedef struct
-{
-  elliptic_curve_t E;
-  point_t Q;                    /* Q=[d]G */
-  gcry_mpi_t d;
-} ECC_secret_key;               /* d */
+#include "context.h"
+#include "ec-context.h"
+#include "pubkey-internal.h"
+#include "ecc-common.h"
 
 
-/* This static table defines all available curves.  */
-static const struct
-{
-  const char *desc;           /* Description of the curve.  */
-  unsigned int nbits;         /* Number of bits.  */
-  const char  *p, *a, *b, *n; /* Parameters.  */
-  const char *g_x, *g_y;      /* G_z is always 1.  */
-} domain_parms[] = 
+static const char *ecc_names[] =
   {
-    { 
-      "NIST P-192", 192,
-      "0xfffffffffffffffffffffffffffffffeffffffffffffffff",
-      "0xfffffffffffffffffffffffffffffffefffffffffffffffc",
-      "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
-      "0xffffffffffffffffffffffff99def836146bc9b1b4d22831",
-      
-      "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
-      "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"
-    },
-    { 
-      "NIST P-224", 224,
-      "0xffffffffffffffffffffffffffffffff000000000000000000000001",
-      "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe",
-      "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
-      "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" ,
-
-      "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
-      "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"
-    },
-    { 
-      "NIST P-256", 256,
-      "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
-      "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc",
-      "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
-      "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
-      
-      "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
-      "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
-    },
-    {
-      "NIST P-384", 384,
-      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
-      "ffffffff0000000000000000ffffffff",
-      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
-      "ffffffff0000000000000000fffffffc",  
-      "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a"
-      "c656398d8a2ed19d2a85c8edd3ec2aef",
-      "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf"
-      "581a0db248b0a77aecec196accc52973",
-
-      "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38"
-      "5502f25dbf55296c3a545e3872760ab7",
-      "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0"
-      "0a60b1ce1d7e819d7a431d7c90ea0e5f"
-    },
-    {
-      "NIST P-521", 521,
-      "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
-      "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
-      "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
-      "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc",
-      "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10"
-      "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
-      "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
-      "ffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409",
-
-      "0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3d"
-      "baa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
-      "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e6"
-      "62c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"
-    },
-    { NULL, 0, NULL, NULL, NULL, NULL }
+    "ecc",
+    "ecdsa",
+    "ecdh",
+    "eddsa",
+    "gost",
+    NULL,
   };
 
 
@@ -201,21 +78,11 @@ static void (*progress_cb) (void *, const char*, int, int, int);
 static void *progress_cb_data;
 
 
-
 \f
 /* Local prototypes. */
-static gcry_mpi_t gen_k (gcry_mpi_t p, int secure);
 static void test_keys (ECC_secret_key * sk, unsigned int nbits);
-static int check_secret_key (ECC_secret_key * sk);
-static gpg_err_code_t sign (gcry_mpi_t input, ECC_secret_key *skey, 
-                            gcry_mpi_t r, gcry_mpi_t s);
-static gpg_err_code_t verify (gcry_mpi_t input, ECC_public_key *pkey,
-                              gcry_mpi_t r, gcry_mpi_t s);
-
-
-static int point_at_infinity (point_t query);
-
-static gcry_mpi_t gen_y_2 (gcry_mpi_t x, elliptic_curve_t * base);
+static void test_ecdh_only_keys (ECC_secret_key * sk, unsigned int nbits);
+static unsigned int ecc_get_nbits (gcry_sexp_t parms);
 
 
 
@@ -229,1791 +96,1761 @@ _gcry_register_pk_ecc_progress (void (*cb) (void *, const char *,
   progress_cb_data = cb_data;
 }
 
-static void
-progress (int c)
-{
-  if (progress_cb)
-    progress_cb (progress_cb_data, "pk_dsa", c, 0, 0);
-  else
-    fputc (c, stderr);
-}
+/* static void */
+/* progress (int c) */
+/* { */
+/*   if (progress_cb) */
+/*     progress_cb (progress_cb_data, "pk_ecc", c, 0, 0); */
+/* } */
 
 
 \f
-/*
-
-    O B J E C T   M A I N T E N A N C E
+/* Standard version of the key generation.  */
+static gpg_err_code_t
+nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
+                   gcry_random_level_t random_level, unsigned int nbits)
+{
+  mpi_point_struct Q;
 
- */
+  point_init (&Q);
 
-/* Intialize a point object, so that its elements may be sued directly
-   as MPI functions.  point_free is required for each initialzied
-   point. */
-static void
-point_init (point_t *P)
-{
-  P->x_ = mpi_new (0);
-  P->y_ = mpi_new (0);
-  P->z_ = mpi_new (0);
-}
+  /* Generate a secret.  */
+  if (ctx->dialect == ECC_DIALECT_ED25519)
+    {
+      char *rndbuf;
+
+      sk->d = mpi_snew (256);
+      rndbuf = _gcry_random_bytes_secure (32, random_level);
+      rndbuf[0] &= 0x7f;  /* Clear bit 255. */
+      rndbuf[0] |= 0x40;  /* Set bit 254.   */
+      rndbuf[31] &= 0xf8; /* Clear bits 2..0 so that d mod 8 == 0  */
+      _gcry_mpi_set_buffer (sk->d, rndbuf, 32, 0);
+      xfree (rndbuf);
+    }
+  else
+    sk->d = _gcry_dsa_gen_k (E->n, random_level);
 
 
-/*
- * Release a point object.
- */
-static void
-point_free (point_t *P)
-{
-  mpi_free (P->x_); P->x_ = NULL;
-  mpi_free (P->y_); P->y_ = NULL;
-  mpi_free (P->z_); P->z_ = NULL;
-}
+  /* Compute Q.  */
+  _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.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);
+  sk->E.h = mpi_copy (E->h);
+  point_init (&sk->Q);
+
+  /* We want the Q=(x,y) be a "compliant key" in terms of the
+   * http://tools.ietf.org/html/draft-jivsov-ecc-compact, which simply
+   * means that we choose either Q=(x,y) or -Q=(x,p-y) such that we
+   * end up with the min(y,p-y) as the y coordinate.  Such a public
+   * key allows the most efficient compression: y can simply be
+   * dropped because we know that it's a minimum of the two
+   * possibilities without any loss of security.  Note that we don't
+   * do that for Ed25519 so that we do not violate the special
+   * construction of the secret key.  */
+  if (E->dialect == ECC_DIALECT_ED25519)
+    point_set (&sk->Q, &Q);
+  else
+    {
+      gcry_mpi_t x, y, negative;
+      const unsigned int pbits = mpi_get_nbits (E->p);
 
-/*
- * Return a copy of a point object.
- */
-static point_t
-point_copy (point_t P)
-{
-  point_t R;
+      x = mpi_new (pbits);
+      y = mpi_new (pbits);
+      negative = mpi_new (pbits);
 
-  R.x_ = mpi_copy (P.x_);
-  R.y_ = mpi_copy (P.y_);
-  R.z_ = mpi_copy (P.z_);
+      if (_gcry_mpi_ec_get_affine (x, y, &Q, ctx))
+        log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q");
 
-  return R;
-}
+      if (E->model == MPI_EC_WEIERSTRASS)
+        mpi_sub (negative, E->p, y);      /* negative = p - y */
+      else
+        mpi_sub (negative, E->p, x);      /* negative = p - x */
 
+      if (mpi_cmp (negative, 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 */
+          if (E->model == MPI_EC_WEIERSTRASS)
+            mpi_point_snatch_set (&sk->Q, x, negative,
+                                       mpi_alloc_set_ui (1));
+          else
+            mpi_point_snatch_set (&sk->Q, negative, y, mpi_alloc_set_ui (1));
 
-/*
- * Release a curve object.
- */
-static void
-curve_free (elliptic_curve_t *E)
-{
-  mpi_free (E->p_); E->p_ = NULL;
-  mpi_free (E->a_); E->a_ = NULL;
-  mpi_free (E->b_);  E->b_ = NULL;
-  point_free (&E->G);
-  mpi_free (E->n_);  E->n_ = NULL;
-}
+          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);
+          if (DBG_CIPHER)
+            log_debug ("ecgen didn't need to convert Q to a compliant point\n");
 
+          mpi_free (negative);
+          if (E->model == MPI_EC_WEIERSTRASS)
+            mpi_free (x);
+          else
+            mpi_free (y);
+        }
 
-/*
- * Return a copy of a curve object.
- */
-static elliptic_curve_t
-curve_copy (elliptic_curve_t E)
-{
-  elliptic_curve_t R;
+      if (E->model == MPI_EC_WEIERSTRASS)
+        mpi_free (y);
+      else
+        mpi_free (x);
+    }
 
-  R.p_ = mpi_copy (E.p_);
-  R.a_ = mpi_copy (E.a_);
-  R.b_ = mpi_copy (E.b_);
-  R.G  = point_copy (E.G);
-  R.n_ = mpi_copy (E.n_);
+  point_free (&Q);
+  /* Now we can test our keys (this should never fail!).  */
+  if (sk->E.model != MPI_EC_MONTGOMERY)
+    test_keys (sk, nbits - 64);
+  else
+    test_ecdh_only_keys (sk, nbits - 64);
 
-  return R;
+  return 0;
 }
 
 
-\f
 /*
+ * To verify correct skey it use a random information.
+ * First, encrypt and decrypt this dummy value,
+ * test if the information is recuperated.
+ * Second, test with the sign and verify functions.
+ */
+static void
+test_keys (ECC_secret_key *sk, unsigned int nbits)
+{
+  ECC_public_key pk;
+  gcry_mpi_t test = mpi_new (nbits);
+  mpi_point_struct R_;
+  gcry_mpi_t c = mpi_new (nbits);
+  gcry_mpi_t out = mpi_new (nbits);
+  gcry_mpi_t r = mpi_new (nbits);
+  gcry_mpi_t s = mpi_new (nbits);
 
-    A D D I T I O N A L   M P I   F U N C T I O N S
+  if (DBG_CIPHER)
+    log_debug ("Testing key.\n");
 
- */
+  point_init (&R_);
 
+  pk.E = _gcry_ecc_curve_copy (sk->E);
+  point_init (&pk.Q);
+  point_set (&pk.Q, &sk->Q);
 
-/****************
- * Find, if it exist, the square root of one integer modulo a big prime.
- * Return the square root or NULL if it is not found.
- */
-#if 0
-static gcry_mpi_t
-exist_square_root (gcry_mpi_t integer, gcry_mpi_t modulus)
-{
-  unsigned long int i = 0;
-  gcry_mpi_t one, two, three, four, five, eight;
-  gcry_mpi_t k, r, z, k1;
-  gcry_mpi_t t1, t2, t3, t4;
-
-  one = mpi_alloc_set_ui (1);
-  two = mpi_alloc_set_ui (2);
-  three = mpi_alloc_set_ui (3);
-  four = mpi_alloc_set_ui (4);
-  five = mpi_alloc_set_ui (5);
-  eight = mpi_alloc_set_ui (8);
-  k = mpi_alloc (mpi_get_nlimbs (modulus));
-  r = mpi_alloc (mpi_get_nlimbs (modulus));
-  z = mpi_alloc (mpi_get_nlimbs (modulus));
-  k1 = mpi_alloc (mpi_get_nlimbs (modulus));
-  t1 = mpi_alloc (mpi_get_nlimbs (modulus));
-  t2 = mpi_alloc (mpi_get_nlimbs (modulus));
-  t3 = mpi_alloc (mpi_get_nlimbs (modulus));
-  t4 = mpi_alloc (mpi_get_nlimbs (modulus));
+  _gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
 
-  if (DBG_CIPHER)
-    log_mpidump ("?exist Square Root of ", integer);
+  if (_gcry_ecc_ecdsa_sign (test, sk, r, s, 0, 0) )
+    log_fatal ("ECDSA operation: sign failed\n");
 
-  mpi_fdiv_qr (k, r, modulus, four);
-  if (mpi_cmp (r, three))
-    {                           /* p=3 (mod 4) */
-      mpi_addm (k1, k, one, modulus);
-      mpi_powm (z, integer, k1, modulus);
-      if (DBG_CIPHER)
-        {
-          log_mpidump ("z=", z);
-        }
-      return z;                 /* value found */
-    }
-  mpi_fdiv_qr (k, r, modulus, eight);
-  if (mpi_cmp (r, five))
-    {                           /* p=5 (mod 8) */
-      mpi_mulm (t1, two, integer, modulus);
-      mpi_powm (t2, t1, k, modulus);
-      mpi_powm (t2, t2, two, modulus);
-      mpi_mulm (t2, t1, t2, modulus);
-      mpi_mulm (t3, integer, t1, modulus);
-      mpi_subm (t4, t2, one, modulus);
-      mpi_mulm (z, t3, t4, modulus);
-      if (DBG_CIPHER)
-        {
-          log_mpidump ("z=", z);
-        }
-      return z;                 /* value found */
-    }
-  if (mpi_cmp (r, one))
-    {                           /* p=1 (mod 8) */
-      while (i < 0xFF)
-        {                       /* while not find z after 256 iterations */
-          if (DBG_CIPHER)
-            log_debug ("Square root bucle.\n");
-          t1 = mpi_copy (integer);
-          t2 = gen_k (modulus, 0);
-          mpi_add_ui (t3, modulus, 1);  /* t3=p+1 */
-          mpi_rshift (t3, t3, 1);       /* t3=t3/2 */
-          lucas (t1, t2, t3, modulus, t4, t3);  /* t4=V_k */
-          mpi_rshift (z, t4, 1);        /* z=V/2 */
-          mpi_sub_ui (t3, modulus, 1);  /* t3=p-1 */
-          mpi_rshift (t4, t3, 2);       /* t4=t3/2 */
-          lucas (t1, t2, t4, modulus, t4, t1);  /* t1=Q_0 */
-          mpi_powm (t2, z, two, modulus);       /* t2=z^2 */
-          if (mpi_cmp (t1, integer))
-            {
-              if (DBG_CIPHER)
-                {
-                  log_mpidump ("z=", z);
-                }
-              return z;         /* value found */
-            }
-          if (t4 > mpi_alloc_set_ui (1) && t4 < t3)
-            {
-              if (DBG_CIPHER)
-                log_debug ("Rejected.\n");
-              return (0);       /* NULL */
-            }
-          if (DBG_CIPHER)
-            log_debug ("Another loop.\n");
-        }
+  if (_gcry_ecc_ecdsa_verify (test, &pk, r, s))
+    {
+      log_fatal ("ECDSA operation: sign, verify failed\n");
     }
+
   if (DBG_CIPHER)
-    log_debug ("iterations limit.\n");
-  return (0);                   /* because this algorithm not always finish. */
+    log_debug ("ECDSA operation: sign, verify ok.\n");
+
+  point_free (&pk.Q);
+  _gcry_ecc_curve_free (&pk.E);
+
+  point_free (&R_);
+  mpi_free (s);
+  mpi_free (r);
+  mpi_free (out);
+  mpi_free (c);
+  mpi_free (test);
 }
-#endif /*0*/
 
-/****************
- * Formal definition:
- * V_0 = 2; V_1 = p
- * V_k = (p*V_(k-1)) - (q*V_(k-2))   for k >= 2
- */
-#if 0
+
 static void
-lucas (gcry_mpi_t n, gcry_mpi_t p_, gcry_mpi_t q_,
-       gcry_mpi_t k, gcry_mpi_t V_n, gcry_mpi_t Q_0)
+test_ecdh_only_keys (ECC_secret_key *sk, unsigned int nbits)
 {
+  ECC_public_key pk;
+  gcry_mpi_t test;
+  mpi_point_struct R_;
+  gcry_mpi_t x0, x1;
+  mpi_ec_t ec;
 
-  gcry_mpi_t v0, v1, q0, q1;
-  gcry_mpi_t t1, t2;
-  unsigned int r, i;
+  if (DBG_CIPHER)
+    log_debug ("Testing key.\n");
 
-  v0 = mpi_alloc_set_ui (2);
-  v1 = mpi_copy (p_);
-  q0 = mpi_alloc_set_ui (1);
-  q1 = mpi_alloc_set_ui (1);
-  t1 = mpi_alloc_set_ui (0);
-  t2 = mpi_alloc_set_ui (0);
+  point_init (&R_);
 
-  if (DBG_CIPHER)
-    {
-      log_debug ("Generating lucas sequence.\n");
-      log_mpidump ("k=", k);
-    }
+  pk.E = _gcry_ecc_curve_copy (sk->E);
+  point_init (&pk.Q);
+  point_set (&pk.Q, &sk->Q);
 
-  r = mpi_get_nbits (k) - 1;
-  i = 0;
-  while (mpi_test_bit (k, i) != 1)
-    {                           /* search the first bit with value '1' */
-      i++;
-    }
-  while (i < r)
+  if (sk->E.dialect == ECC_DIALECT_ED25519)
     {
-      if (DBG_CIPHER)
-        {
-          log_debug ("Lucas sequence bucle.\n");
-          log_mpidump ("i=", mpi_alloc_set_ui (i));
-          log_mpidump ("r=", mpi_alloc_set_ui (r));
-        }
-      mpi_mulm (q0, q0, q1, n);
-      if (mpi_test_bit (k, i) == 1)
-        {
-          mpi_mulm (q1, q0, q_, n);
-          mpi_mul (t1, v0, v1);
-          mpi_mul (t2, p_, q0);
-          mpi_subm (v0, t1, t2, n);
-          mpi_powm (t1, v1, mpi_alloc_set_ui (2), n);
-          mpi_mul (t2, mpi_alloc_set_ui (2), q1);
-          mpi_subm (v1, t1, t2, n);
-        }
-      else
-        {
-          q1 = mpi_copy (q0);
-          mpi_mul (t1, v0, v1);
-          mpi_mul (t2, p_, q0);
-          mpi_subm (v1, t1, t2, n);
-          mpi_powm (t1, v0, mpi_alloc_set_ui (2), n);
-          mpi_mul (t2, mpi_alloc_set_ui (2), q0);
-          mpi_subm (v0, t1, t2, n);
-        }
-      i++;
+      char *rndbuf;
+
+      test = mpi_new (256);
+      rndbuf = _gcry_random_bytes (32, GCRY_WEAK_RANDOM);
+      rndbuf[0] &= 0x7f;  /* Clear bit 255. */
+      rndbuf[0] |= 0x40;  /* Set bit 254.   */
+      rndbuf[31] &= 0xf8; /* Clear bits 2..0 so that d mod 8 == 0  */
+      _gcry_mpi_set_buffer (test, rndbuf, 32, 0);
+      xfree (rndbuf);
     }
-  V_n = mpi_copy (v0);
-  Q_0 = mpi_copy (q0);
-  if (DBG_CIPHER)
+  else
     {
-      log_debug ("Lucas sequence generated.\n");
-      log_mpidump ("V_n=", V_n);
-      log_mpidump ("Q_0=", Q_0);
+      test = mpi_new (nbits);
+      _gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
     }
-}
-#endif /*0*/
 
-\f
-/* 
+  ec = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect, 0,
+                                    pk.E.p, pk.E.a, pk.E.b);
+  x0 = mpi_new (0);
+  x1 = mpi_new (0);
 
-   P O I N T   A N D   C U R V E   O P E R A T I O N S
+  /* R_ = hkQ  <=>  R_ = hkdG  */
+  _gcry_mpi_ec_mul_point (&R_, test, &pk.Q, ec);
+  if (sk->E.dialect != ECC_DIALECT_ED25519)
+    _gcry_mpi_ec_mul_point (&R_, ec->h, &R_, ec);
+  if (_gcry_mpi_ec_get_affine (x0, NULL, &R_, ec))
+    log_fatal ("ecdh: Failed to get affine coordinates for hkQ\n");
 
- */
+  _gcry_mpi_ec_mul_point (&R_, test, &pk.E.G, ec);
+  _gcry_mpi_ec_mul_point (&R_, sk->d, &R_, ec);
+  /* R_ = hdkG */
+  if (sk->E.dialect != ECC_DIALECT_ED25519)
+    _gcry_mpi_ec_mul_point (&R_, ec->h, &R_, ec);
 
-/* fixme:
- * The point at infinity is needed to make 
- * a group structure to the elliptic curve.
- * Know if one point is it, is needed so 
- * much times in this code.
- *
- *  return true(1), false(0), or error(-1) for an invalid point
- */
-static int
-point_at_infinity (point_t query)
-{
-  if (!mpi_cmp_ui (query.z_, 0)) /* Z == 0 */
+  if (_gcry_mpi_ec_get_affine (x1, NULL, &R_, ec))
+    log_fatal ("ecdh: Failed to get affine coordinates for hdkG\n");
+
+  if (mpi_cmp (x0, x1))
     {
-      if ( /*mpi_cmp_ui(Query.x_,0) && */ mpi_cmp_ui (query.y_, 0))
-        {
-          /* X && Y != 0 & Z == 0 */
-          /* Fixme: The above condition is not asserted.  We may get
-             to here if X is 0 ! */
-          if (DBG_CIPHER)
-            log_debug ("True:It is a Point at Infinite.\n");
-          return 1;
-        }
-      if (DBG_CIPHER)
-        log_debug ("Error:It isn't an elliptic curve valid point.\n");
-      return -1;
+      log_fatal ("ECDH test failed.\n");
     }
-  return 0;  /* It is a valid curve point, but not the point at infinity.  */
+
+  mpi_free (x0);
+  mpi_free (x1);
+  _gcry_mpi_ec_free (ec);
+
+  point_free (&pk.Q);
+  _gcry_ecc_curve_free (&pk.E);
+
+  point_free (&R_);
+  mpi_free (test);
 }
 
 
 /*
- * Turn a projective coordinate P to affine.
- * Returns 0 on success and the affine coordinates at X and Y.
- *
- * Note, that Y is never used as we can do without it.
+ * To check the validity of the value, recalculate the correspondence
+ * between the public value and the secret one.
  */
 static int
-point_affine (point_t *P, gcry_mpi_t x, gcry_mpi_t y, elliptic_curve_t *base)
+check_secret_key (ECC_secret_key *sk, mpi_ec_t ec, int flags)
 {
-  gcry_mpi_t z1, z2, z3;
+  int rc = 1;
+  mpi_point_struct Q;
+  gcry_mpi_t x1, y1;
+  gcry_mpi_t x2 = NULL;
+  gcry_mpi_t y2 = NULL;
+
+  point_init (&Q);
+  x1 = mpi_new (0);
+  if (ec->model == MPI_EC_MONTGOMERY)
+    y1 = NULL;
+  else
+    y1 = mpi_new (0);
 
-  if (point_at_infinity (*P))
+  /* G in E(F_p) */
+  if (!_gcry_mpi_ec_curve_point (&sk->E.G, ec))
     {
       if (DBG_CIPHER)
-        log_debug ("ecc point_affine: "
-                   "Point at Infinity does NOT exist in the affine plane!\n");
-      return 1;
+        log_debug ("Bad check: Point 'G' does not belong to curve 'E'!\n");
+      goto leave;
     }
 
-  z1 = mpi_new (0);
-  z2 = mpi_new (0);
-  z3 = mpi_new (0);
-
-  mpi_invm (z1, P->z_, base->p_);       /*       z1 =Z^{-1} (mod p) */
-  mpi_mulm (z2, z1, z1, base->p_);      /*       z2 =Z^(-2) (mod p) */
-  mpi_mulm (z3, z2, z1, base->p_);      /*       z3 =Z^(-3) (mod p) */
-  mpi_mulm (x, P->x_, z2, base->p_);
-  mpi_mulm (y, P->y_, z3, base->p_);
-
-  mpi_free (z1);
-  mpi_free (z2);
-  mpi_free (z3);
-  return 0;
-}
+  /* G != PaI */
+  if (!mpi_cmp_ui (sk->E.G.z, 0))
+    {
+      if (DBG_CIPHER)
+        log_debug ("Bad check: 'G' cannot be Point at Infinity!\n");
+      goto leave;
+    }
 
+  /* Check order of curve.  */
+  if (sk->E.dialect != ECC_DIALECT_ED25519)
+    {
+      _gcry_mpi_ec_mul_point (&Q, sk->E.n, &sk->E.G, ec);
+      if (mpi_cmp_ui (Q.z, 0))
+        {
+          if (DBG_CIPHER)
+            log_debug ("check_secret_key: E is not a curve of order n\n");
+          goto leave;
+        }
+    }
 
-/*
- * The point inversion over F_p is a simple modular inversion of the Y
- * coordinate.
- */
-static void
-invert_point (point_t *P, elliptic_curve_t *base)
-{
-  mpi_subm (P->y_, base->p_, P->y_, base->p_);  /* y = p - y mod p */
-}
+  /* Pubkey cannot be PaI */
+  if (!mpi_cmp_ui (sk->Q.z, 0))
+    {
+      if (DBG_CIPHER)
+        log_debug ("Bad check: Q can not be a Point at Infinity!\n");
+      goto leave;
+    }
 
+  /* pubkey = [d]G over E */
+  if (!_gcry_ecc_compute_public (&Q, ec, &sk->E.G, sk->d))
+    {
+      if (DBG_CIPHER)
+        log_debug ("Bad check: computation of dG failed\n");
+      goto leave;
+    }
+  if (_gcry_mpi_ec_get_affine (x1, y1, &Q, ec))
+    {
+      if (DBG_CIPHER)
+        log_debug ("Bad check: Q can not be a Point at Infinity!\n");
+      goto leave;
+    }
 
-/*
- * Scalar multiplication of one point, with the integer fixed to 2.
- *  R = 2P
- */
-static void
-duplicate_point (point_t *R, point_t *P, elliptic_curve_t * base)
-{
-  gcry_mpi_t one, two, three, four, eight;
-  gcry_mpi_t p, p_3, a;
-  gcry_mpi_t t1, t2, t3, t4, t5, t6, t7;
-  gcry_mpi_t aux;
-
-  one = mpi_alloc_set_ui (1);
-  two = mpi_alloc_set_ui (2);
-  three = mpi_alloc_set_ui (3);
-  four = mpi_alloc_set_ui (4);
-  eight = mpi_alloc_set_ui (8);
-  p = mpi_copy (base->p_);
-  p_3 = mpi_alloc (mpi_get_nlimbs (p));
-  mpi_sub_ui (p_3, p, 3);
-  a = mpi_copy (base->a_);
-  t1 = mpi_alloc (mpi_get_nlimbs (p));
-  t2 = mpi_alloc (mpi_get_nlimbs (p));
-  t3 = mpi_alloc (mpi_get_nlimbs (p));
-  t4 = mpi_alloc (mpi_get_nlimbs (p));
-  t5 = mpi_alloc (mpi_get_nlimbs (p));
-  t6 = mpi_alloc (mpi_get_nlimbs (p));
-  t7 = mpi_alloc (mpi_get_nlimbs (p));
-  aux = mpi_alloc (mpi_get_nlimbs (p));
-
-  t1 = mpi_copy (P->x_);        /* t1=x1 */
-  t2 = mpi_copy (P->y_);        /* t2=y1 */
-  t3 = mpi_copy (P->z_);        /* t3=z1 */
-
-  if (!mpi_cmp_ui (t2, 0) || !mpi_cmp_ui (t3, 0))
-    {                           /* t2==0 | t3==0 => [1:1:0] */
-      mpi_set_ui (R->x_, 1);
-      mpi_set_ui (R->y_, 1);
-      mpi_set_ui (R->z_, 0);
+  if ((flags & PUBKEY_FLAG_EDDSA))
+    ; /* Fixme: EdDSA is special.  */
+  else if (!mpi_cmp_ui (sk->Q.z, 1))
+    {
+      /* Fast path if Q is already in affine coordinates.  */
+      if (mpi_cmp (x1, sk->Q.x) || (!y1 && mpi_cmp (y1, sk->Q.y)))
+        {
+          if (DBG_CIPHER)
+            log_debug
+              ("Bad check: There is NO correspondence between 'd' and 'Q'!\n");
+          goto leave;
+        }
     }
   else
     {
-      mpi_mod (a, a, p);        /* a mod p */
-      if (!mpi_cmp (a, p_3))
-        {                       /* a==p-3 */
-          mpi_powm (t4, t3, two, p);    /* t4=t3^2 mod p */
-          mpi_subm (t5, t1, t4, p);     /* t5=t1-t4 mod p */
-          mpi_addm (t4, t1, t4, p);     /* t4=t1+t4 mod p */
-          mpi_mulm (t5, t4, t5, p);     /* t5=t4*t5 mod p */
-          mpi_mulm (t4, three, t5, p);  /* t4=3*t5 mod p */
+      x2 = mpi_new (0);
+      y2 = mpi_new (0);
+      if (_gcry_mpi_ec_get_affine (x2, y2, &sk->Q, ec))
+        {
+          if (DBG_CIPHER)
+            log_debug ("Bad check: Q can not be a Point at Infinity!\n");
+          goto leave;
         }
-      else
+
+      if (mpi_cmp (x1, x2) || mpi_cmp (y1, y2))
         {
-          t4 = mpi_copy (a);    /* t4=a */
-          mpi_powm (t5, t3, two, p);    /* t5=t3^2 mod p */
-          mpi_powm (t5, t5, two, p);    /* t5=t5^2 mod p */
-          mpi_mulm (t5, t4, t5, p);     /* t5=t4*t5 mod p */
-          mpi_powm (t4, t1, two, p);    /* t4=t1^2 mod p */
-          mpi_mulm (t4, three, t4, p);  /* t4=3*t4 mod p */
-          mpi_addm (t4, t4, t5, p);     /* t4=t4+t5 mod p */
+          if (DBG_CIPHER)
+            log_debug
+              ("Bad check: There is NO correspondence between 'd' and 'Q'!\n");
+          goto leave;
         }
-      mpi_mulm (t3, t2, t3, p); /* t3=t2*t3 mod p */
-      mpi_mulm (t3, two, t3, p);        /* t3=2*t3 mod p  */
-      mpi_powm (aux, t2, two, p);       /* t2=t2^2 mod p */
-      t2 = mpi_copy (aux);
-      mpi_mulm (t5, t1, t2, p); /* t5=t1*t2 mod p */
-      mpi_mulm (t5, four, t5, p);       /* t5=4*t5 mod p */
-      mpi_powm (t1, t4, two, p);        /* t1=t4^2 mod p */
-      mpi_mulm (aux, two, t5, p);
-      mpi_subm (t1, t1, aux, p);        /* t1=t1-2*t5 mod p */
-      mpi_powm (aux, t2, two, p);       /* t2=t2^2 mod p */
-      t2 = mpi_copy (aux);
-      mpi_mulm (t2, eight, t2, p);      /* t2=8*t2 mod p */
-      mpi_subm (t5, t5, t1, p); /* t5=t5-t1 mod p */
-      mpi_mulm (t5, t4, t5, p); /* t5=t4*t5 mod p */
-      mpi_subm (t2, t5, t2, p); /* t2=t5-t2 mod p */
-
-      mpi_set (R->x_, t1);
-      mpi_set (R->y_, t2);
-      mpi_set (R->z_, t3);
-    }
-
-  mpi_free (aux);
-  mpi_free (t7);
-  mpi_free (t6);
-  mpi_free (t5);
-  mpi_free (t4);
-  mpi_free (t3);
-  mpi_free (t2);
-  mpi_free (t1);
-  mpi_free (p);
-  mpi_free (p_3);
-  mpi_free (a);
-  mpi_free (eight);
-  mpi_free (four);
-  mpi_free (three);
-  mpi_free (two);
-  mpi_free (one);
+    }
+  rc = 0; /* Okay.  */
+
+ leave:
+  mpi_free (x2);
+  mpi_free (x1);
+  mpi_free (y1);
+  mpi_free (y2);
+  point_free (&Q);
+  return rc;
 }
 
 
-/*
-   Point addition is the group operation.
+\f
+/*********************************************
+ **************  interface  ******************
+ *********************************************/
 
-   R = P0 + P1
- */
-static void
-sum_points (point_t *R, point_t *P0, point_t *P1, elliptic_curve_t * base)
+static gcry_err_code_t
+ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
 {
-  gcry_mpi_t one, two;
-  gcry_mpi_t p;
-  gcry_mpi_t t1, t2, t3, t4, t5, t6, t7;
+  gpg_err_code_t rc;
   unsigned int nbits;
+  elliptic_curve_t E;
+  ECC_secret_key sk;
+  gcry_mpi_t x = NULL;
+  gcry_mpi_t y = NULL;
+  char *curve_name = NULL;
+  gcry_sexp_t l1;
+  gcry_random_level_t random_level;
+  mpi_ec_t ctx = NULL;
+  gcry_sexp_t curve_info = NULL;
+  gcry_sexp_t curve_flags = NULL;
+  gcry_mpi_t base = NULL;
+  gcry_mpi_t public = NULL;
+  gcry_mpi_t secret = NULL;
+  int flags = 0;
+
+  memset (&E, 0, sizeof E);
+  memset (&sk, 0, sizeof sk);
+
+  rc = _gcry_pk_util_get_nbits (genparms, &nbits);
+  if (rc)
+    return rc;
+
+  /* Parse the optional "curve" parameter. */
+  l1 = sexp_find_token (genparms, "curve", 0);
+  if (l1)
+    {
+      curve_name = _gcry_sexp_nth_string (l1, 1);
+      sexp_release (l1);
+      if (!curve_name)
+        return GPG_ERR_INV_OBJ; /* No curve name or value too large. */
+    }
 
-  one = mpi_alloc_set_ui (1);
-  two = mpi_alloc_set_ui (2);
-  p = mpi_copy (base->p_);
-  nbits = mpi_get_nbits (p);
-  t1 = mpi_new (nbits);
-  t2 = mpi_new (nbits);
-  t3 = mpi_new (nbits);
-  t4 = mpi_new (nbits);
-  t5 = mpi_new (nbits);
-  t6 = mpi_new (nbits);
-  t7 = mpi_new (nbits);
-
-  if ( (!mpi_cmp (P1->x_, P0->x_))
-       && (!mpi_cmp (P1->y_, P0->y_))
-       && (!mpi_cmp (P1->z_, P0->z_)) ) /* P1 == P0 */
-    {                           
-      duplicate_point (R, P0, base);
-    }
-  else if (point_at_infinity (*P0)) /* R == 0 && P1 == P1 */
-    {                           
-      /* (!mpi_cmp_ui(P0->y_,0) || !mpi_cmp_ui(P0->z_,0))*/
-      mpi_set (R->x_, P1->x_);
-      mpi_set (R->y_, P1->y_);
-      mpi_set (R->z_, P1->z_);
-    }
-  else if (point_at_infinity (*P1)) /* R == P0 && P0 == 0 */
-    {           
-      /* (!mpi_cmp_ui(P1->y_,0) || !mpi_cmp_ui(P1->z_,0)) */
-      mpi_set (R->x_, P0->x_);
-      mpi_set (R->y_, P0->y_);
-      mpi_set (R->z_, P0->z_);
+  /* Parse the optional flags list.  */
+  l1 = sexp_find_token (genparms, "flags", 0);
+  if (l1)
+    {
+      rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL);
+      sexp_release (l1);
+      if (rc)
+        goto leave;
     }
-  else
+
+  /* Parse the deprecated optional transient-key flag.  */
+  l1 = sexp_find_token (genparms, "transient-key", 0);
+  if (l1)
     {
-      t1 = mpi_copy (P0->x_);   /* t1=x0 */
-      t2 = mpi_copy (P0->y_);   /* t2=y0 */
-      t3 = mpi_copy (P0->z_);   /* t3=z0 */
-      t4 = mpi_copy (P1->x_);   /* t4=x1 */
-      t5 = mpi_copy (P1->y_);   /* t5=y2 */
-      if (mpi_cmp (P1->z_, one))  /* z1 != 1 */
-        {                       
-          /* fixme: Release old t6 or just set it. */
-          t6 = mpi_copy (P1->z_);       /* t6=z1 */
-          mpi_powm (t7, t6, two, p);    /* t7=t6^2 mod p */
-          mpi_mulm (t1, t1, t7, p);     /* t1=t1*t7 mod p */
-          mpi_mulm (t7, t6, t7, p);     /* t7=t6*t7 mod p */
-          mpi_mulm (t2, t2, t7, p);     /* t2=t2*t7 mod p */
-        }
-      mpi_powm (t7, t3, two, p);/* t7=t3^2 mod p */
-      mpi_mulm (t4, t4, t7, p); /* t4=t4*t7 mod p */
-      mpi_mulm (t7, t3, t7, p); /* t7=t3*t7 mod p */
-      mpi_mulm (t5, t5, t7, p); /* t5=t5*t7 mod p */
-      mpi_subm (t4, t1, t4, p); /* t4=t1-t4 mod p */
-      mpi_subm (t5, t2, t5, p); /* t5=t2-t5 mod p */
-
-      if (!mpi_cmp_ui (t4, 0)) /* t4==0 */
-        {                       
-          if (!mpi_cmp_ui (t5, 0))
-            {                   
-              /* return (0:0:0), it has a special mean. */
-              if (DBG_CIPHER)
-                log_debug ("ecc sum_points: [0:0:0]!\n");
-              mpi_set_ui (R->x_, 0);
-              mpi_set_ui (R->y_, 0);
-              mpi_set_ui (R->z_, 0);
-            }
-          else
-            {           
-              if (DBG_CIPHER)
-                log_debug ("ecc sum_points: [1:1:0]!\n");
-              mpi_set_ui (R->x_, 1);
-              mpi_set_ui (R->y_, 1);
-              mpi_set_ui (R->z_, 0);
-            }
-        }
-      else
-        {
-          mpi_mulm (t1, two, t1, p);
-          mpi_subm (t1, t1, t4, p);     /* t1=2*t1-t4 mod p */
-          mpi_mulm (t2, two, t2, p);
-          mpi_subm (t2, t2, t5, p);     /* t2=2*t2-t5 mod p */
-          if (mpi_cmp (P1->z_, one)) /* z1 != 1 */
-            {           
-              mpi_mulm (t3, t3, t6, p); /* t3=t3*t6 */
-            }
-          mpi_mulm (t3, t3, t4, p);     /* t3=t3*t4 mod p */
-          mpi_powm (t7, t4, two, p);    /* t7=t4^2 mod p */
-          mpi_mulm (t4, t4, t7, p);     /* t4=t4*t7 mod p */
-          mpi_mulm (t7, t1, t7, p);     /* t7=t1*t7 mod p */
-          mpi_powm (t1, t5, two, p);    /* t1=t5^2 mod p */
-          mpi_subm (t1, t1, t7, p);     /* t1=t1-t7 mod p */
-          mpi_mulm (t6, two, t1, p);
-          mpi_subm (t7, t7, t6, p);     /* t7=t7-2*t1 mod p */
-          mpi_mulm (t5, t5, t7, p);     /* t5=t5*t7 mod p */
-          mpi_mulm (t4, t2, t4, p);     /* t4=t2*t4 mod p */
-          mpi_subm (t2, t5, t4, p);     /* t2=t5-t4 mod p */
-          mpi_invm (t6, two, p);
-          mpi_mulm (t2, t2, t6, p);     /* t2 = t2/2 */
-
-          mpi_set (R->x_, t1);
-          mpi_set (R->y_, t2);
-          mpi_set (R->z_, t3);
-        }
+      flags |= PUBKEY_FLAG_TRANSIENT_KEY;
+      sexp_release (l1);
     }
 
-  mpi_free (t7);
-  mpi_free (t6);
-  mpi_free (t5);
-  mpi_free (t4);
-  mpi_free (t3);
-  mpi_free (t2);
-  mpi_free (t1);
-  mpi_free (p);
-  mpi_free (two);
-  mpi_free (one);
-}
+  /* NBITS is required if no curve name has been given.  */
+  if (!nbits && !curve_name)
+    return GPG_ERR_NO_OBJ; /* No NBITS parameter. */
 
-/****************
- * The modular power used without EC, 
- * is this function over EC.
-   return R = escalarP
-
-   ESCALAR = input
-   P       = input
-   BASE    = input
-   R       = output (caller must have intialized this point)
-
- */
-static void
-escalar_mult (point_t *R, gcry_mpi_t escalar, point_t *P,
-              elliptic_curve_t *base)
-{
-
-  gcry_mpi_t one, two, three;
-  gcry_mpi_t p;
-  gcry_mpi_t x1, y1, z1, z2, z3, k, h; 
-  gcry_mpi_t xx, yy, zz;
-  unsigned int i, loops;
-  point_t P1, P2, P1_;
+  rc = _gcry_ecc_fill_in_curve (nbits, curve_name, &E, &nbits);
+  xfree (curve_name); curve_name = NULL;
+  if (rc)
+    goto leave;
 
   if (DBG_CIPHER)
-    log_debug ("escalar_mult: begin\n");
-
-  one   = mpi_alloc_set_ui (1);
-  two   = mpi_alloc_set_ui (2);
-  three = mpi_alloc_set_ui (3);
-
-  p  = mpi_copy (base->p_);
-
-  x1 = mpi_alloc_like (P->x_);
-  y1 = mpi_alloc_like (P->y_);
-  /* z1 is not yet intialized.  */
-  z2 = mpi_alloc_like (P->z_);
-  z3 = mpi_alloc_like (P->z_);
-  /* k is not yet intialized.  */
-  h  = mpi_alloc_like (P->z_);
+    {
+      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_printmpi ("ecgen curve   h", E.h);
+      log_printpnt ("ecgen curve G", &E.G, NULL);
+    }
 
+  if ((flags & PUBKEY_FLAG_TRANSIENT_KEY))
+    random_level = GCRY_STRONG_RANDOM;
+  else
+    random_level = GCRY_VERY_STRONG_RANDOM;
 
-  if (!mpi_cmp_ui (escalar, 0) || mpi_cmp_ui (P->z_, 0))
-    {                           /* n=0 | Z=0 => [1:1:0] */
-      mpi_set_ui (R->x_, 1);
-      mpi_set_ui (R->y_, 1);
-      mpi_set_ui (R->z_, 0);
-    }
-  xx = mpi_copy (P->x_);
-  zz = mpi_copy (P->z_);
-  z1 = mpi_copy (one);
+  ctx = _gcry_mpi_ec_p_internal_new (E.model, E.dialect, 0, E.p, E.a, E.b);
+  x = mpi_new (0);
+  y = mpi_new (0);
 
-  if (mpi_is_neg (escalar))
-    {                           /* (-n)P=n(-P) */
-      escalar->sign = 0;        /* +n */
-      k = mpi_copy (escalar);
-      yy = mpi_copy (P->y_);    /* -P */
-      mpi_invm (yy, yy, p);
-    }
+  if ((flags & PUBKEY_FLAG_EDDSA))
+    rc = _gcry_ecc_eddsa_genkey (&sk, &E, ctx, random_level);
   else
+    rc = nist_generate_key (&sk, &E, ctx, random_level, nbits);
+  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");
+  base = _gcry_ecc_ec2os (x, y, sk.E.p);
+  if (sk.E.dialect == ECC_DIALECT_ED25519 && !(flags & PUBKEY_FLAG_NOCOMP))
     {
-      k = mpi_copy (escalar);
-      yy = mpi_copy (P->y_);
-    }
-  if (!mpi_cmp (zz, one))
-    {                           /* zz==1 */
-      x1 = mpi_copy (xx);
-      y1 = mpi_copy (yy);
+      unsigned char *encpk;
+      unsigned int encpklen;
+
+      rc = _gcry_ecc_eddsa_encodepoint (&sk.Q, ctx, x, y,
+                                        !!(flags & PUBKEY_FLAG_COMP),
+                                        &encpk, &encpklen);
+      if (rc)
+        return rc;
+      public = mpi_new (0);
+      mpi_set_opaque (public, encpk, encpklen*8);
+      encpk = NULL;
     }
   else
     {
-      mpi_mulm (z2, zz, zz, p); /* z^2 */
-      mpi_mulm (z3, zz, z2, p); /* z^3 */
-      mpi_invm (z2, z2, p);     /* 1/Z^2 */
-      mpi_mulm (x1, xx, z2, p); /* xx/z^2 */
-      mpi_invm (z3, z3, p);     /* 1/z^3 */
-      mpi_mulm (y1, yy, z3, p); /* yy/z^3 */
-    }
-  mpi_mul (h, three, k);        /* h=3k */
-  loops = mpi_get_nbits (h);
-  i = loops - 2;                /*  i = l-1 = loops-2 */
-  mpi_set (R->x_, xx);
-  mpi_set (R->y_, yy);
-  mpi_set (R->z_, zz);
-  P1.x_ = mpi_copy (x1);
-  P1.y_ = mpi_copy (y1);
-  P1.z_ = mpi_copy (z1);
-  while (i > 0)
-    {                           /*  A.10.9. step 11  i from l-1 downto 1 */
-      duplicate_point (R, R, base);
-      if (mpi_test_bit (h, i) == 1 && mpi_test_bit (k, i) == 0)
-        {                       /* h_i=1 & k_i=0 */
-          P2 = point_copy (*R);
-          sum_points (R, &P2, &P1, base); /* R=P2+P1 over the base elliptic curve */
-        }
-      if (mpi_test_bit (h, i) == 0 && mpi_test_bit (k, i) == 1)
-        {                       /* h_i=0 & k_i=1 */
-          P2 = point_copy (*R);
-          P1_ = point_copy (P1);
-          invert_point (&P1_, base);
-          sum_points (R, &P2, &P1_, base); /* R=P2+P1_ over the base elliptic curve */
-        }
-      i--;
+      if (_gcry_mpi_ec_get_affine (x, y, &sk.Q, ctx))
+        log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q");
+      public = _gcry_ecc_ec2os (x, y, sk.E.p);
+    }
+  secret = sk.d; sk.d = NULL;
+  if (E.name)
+    {
+      rc = sexp_build (&curve_info, NULL, "(curve %s)", E.name);
+      if (rc)
+        goto leave;
     }
 
-  if (DBG_CIPHER)
-    log_debug ("escalar_mult: ready\n");
-
-  point_free (&P1);
-  point_free (&P2);
-  point_free (&P1_);
-  mpi_free (h);
-  mpi_free (k);
-  mpi_free (z3);
-  mpi_free (z2);
-  mpi_free (z1);
-  mpi_free (y1);
-  mpi_free (x1);
-  mpi_free (zz);
-  mpi_free (yy);
-  mpi_free (xx);
-  mpi_free (p);
-  mpi_free (three);
-  mpi_free (two);
-  mpi_free (one);
-}
-
-
-/****************
- * Solve the right side of the equation that defines a curve.
- */
-static gcry_mpi_t
-gen_y_2 (gcry_mpi_t x, elliptic_curve_t *base)
-{
-  gcry_mpi_t three;
-  gcry_mpi_t x_3, ax, axb, y;
-  gcry_mpi_t a, b, p;
-  unsigned int nbits;
-
-  three = mpi_alloc_set_ui (3);
-  a = mpi_copy (base->a_);
-  b = mpi_copy (base->b_);
-  p = mpi_copy (base->p_);
-  nbits = mpi_get_nbits (p);
-  x_3 = mpi_new (nbits);
-  ax  = mpi_new (nbits);
-  axb = mpi_new (nbits);
-  y   = mpi_new (nbits);
-
-  if (DBG_CIPHER)
-    log_debug ("ecc gen_y_2: Solving an elliptic equation.\n");
+  if ((flags & PUBKEY_FLAG_PARAM) || (flags & PUBKEY_FLAG_EDDSA))
+    {
+      rc = sexp_build
+        (&curve_flags, NULL,
+         ((flags & PUBKEY_FLAG_PARAM) && (flags & PUBKEY_FLAG_EDDSA))?
+         "(flags param eddsa)" :
+         ((flags & PUBKEY_FLAG_PARAM))?
+         "(flags param)" :
+         "(flags eddsa)");
+      if (rc)
+        goto leave;
+    }
 
-  mpi_powm (x_3, x, three, p);  /* x_3=x^3 mod p */
-  mpi_mulm (ax, a, x, p);       /* ax=a*x mod p */
-  mpi_addm (axb, ax, b, p);     /* axb=ax+b mod p */
-  mpi_addm (y, x_3, axb, p);    /* y=x^3+ax+b mod p */
+  if ((flags & PUBKEY_FLAG_PARAM) && E.name)
+    rc = sexp_build (r_skey, NULL,
+                     "(key-data"
+                     " (public-key"
+                     "  (ecc%S%S(p%m)(a%m)(b%m)(g%m)(n%m)(h%m)(q%m)))"
+                     " (private-key"
+                     "  (ecc%S%S(p%m)(a%m)(b%m)(g%m)(n%m)(h%m)(q%m)(d%m)))"
+                     " )",
+                     curve_info, curve_flags,
+                     sk.E.p, sk.E.a, sk.E.b, base, sk.E.n, sk.E.h, public,
+                     curve_info, curve_flags,
+                     sk.E.p, sk.E.a, sk.E.b, base, sk.E.n, sk.E.h, public, secret);
+  else
+    rc = sexp_build (r_skey, NULL,
+                     "(key-data"
+                     " (public-key"
+                     "  (ecc%S%S(q%m)))"
+                     " (private-key"
+                     "  (ecc%S%S(q%m)(d%m)))"
+                     " )",
+                     curve_info, curve_flags,
+                     public,
+                     curve_info, curve_flags,
+                     public, secret);
+  if (rc)
+    goto leave;
 
   if (DBG_CIPHER)
-    log_debug ("ecc gen_y_2: Solved.\n");
+    {
+      log_printmpi ("ecgen result  p", sk.E.p);
+      log_printmpi ("ecgen result  a", sk.E.a);
+      log_printmpi ("ecgen result  b", sk.E.b);
+      log_printmpi ("ecgen result  G", base);
+      log_printmpi ("ecgen result  n", sk.E.n);
+      log_printmpi ("ecgen result  h", sk.E.h);
+      log_printmpi ("ecgen result  Q", public);
+      log_printmpi ("ecgen result  d", secret);
+      if ((flags & PUBKEY_FLAG_EDDSA))
+        log_debug ("ecgen result  using Ed25519+EdDSA\n");
+    }
 
-  return y; /* The quadratic value of the coordinate if it exist. */
+ leave:
+  mpi_free (secret);
+  mpi_free (public);
+  mpi_free (base);
+  {
+    _gcry_ecc_curve_free (&sk.E);
+    point_free (&sk.Q);
+    mpi_free (sk.d);
+  }
+  _gcry_ecc_curve_free (&E);
+  mpi_free (x);
+  mpi_free (y);
+  _gcry_mpi_ec_free (ctx);
+  sexp_release (curve_flags);
+  sexp_release (curve_info);
+  return rc;
 }
 
 
-
-
-
-\f
-/*
-
-   E C C  C O R E  F U N C T I O N S
- */
-
-
-
-/* Generate a random secret scalar k with an order of p
-
-   At the beginning this was identical to the code is in elgamal.c.
-   Later imporved by mmr.   Further simplified by wk.  */
-static gcry_mpi_t
-gen_k (gcry_mpi_t p, int secure)
+static gcry_err_code_t
+ecc_check_secret_key (gcry_sexp_t keyparms)
 {
-  gcry_mpi_t k;
-  unsigned int nbits;
+  gcry_err_code_t rc;
+  gcry_sexp_t l1 = NULL;
+  int flags = 0;
+  char *curvename = NULL;
+  gcry_mpi_t mpi_g = NULL;
+  gcry_mpi_t mpi_q = NULL;
+  ECC_secret_key sk;
+  mpi_ec_t ec = NULL;
 
-  nbits = mpi_get_nbits (p);
-  k = (secure
-       ? mpi_alloc_secure ( mpi_get_nlimbs (p) )
-       : mpi_alloc ( mpi_get_nlimbs (p) ));
+  memset (&sk, 0, sizeof sk);
 
-  if (DBG_CIPHER)
-    log_debug ("choosing a random k of %u bits\n", nbits);
-  
-  gcry_mpi_randomize (k, nbits, GCRY_STRONG_RANDOM);
+  /* Look for flags. */
+  l1 = sexp_find_token (keyparms, "flags", 0);
+  if (l1)
+    {
+      rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL);
+      if (rc)
+        goto leave;
+    }
 
-  mpi_mod (k, k, p);  /*  k = k mod p  */
+  /* Extract the parameters.  */
+  if ((flags & PUBKEY_FLAG_PARAM))
+    rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?h?/q?+d",
+                             &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
+                             &sk.E.h, &mpi_q, &sk.d, NULL);
+  else
+    rc = sexp_extract_param (keyparms, NULL, "/q?+d",
+                             &mpi_q, &sk.d, NULL);
+  if (rc)
+    goto leave;
+
+  /* Add missing parameters using the optional curve parameter.  */
+  sexp_release (l1);
+  l1 = sexp_find_token (keyparms, "curve", 5);
+  if (l1)
+    {
+      curvename = sexp_nth_string (l1, 1);
+      if (curvename)
+        {
+          rc = _gcry_ecc_update_curve_param (curvename,
+                                             &sk.E.model, &sk.E.dialect,
+                                             &sk.E.p, &sk.E.a, &sk.E.b,
+                                             &mpi_g, &sk.E.n, &sk.E.h);
+          if (rc)
+            return rc;
+        }
+    }
+  if (mpi_g)
+    {
+      point_init (&sk.E.G);
+      rc = _gcry_ecc_os2ec (&sk.E.G, mpi_g);
+      if (rc)
+        goto leave;
+    }
 
+  /* Guess required fields if a curve parameter has not been given.
+     FIXME: This is a crude hacks.  We need to fix that.  */
+  if (!curvename)
+    {
+      sk.E.model = ((flags & PUBKEY_FLAG_EDDSA)
+               ? MPI_EC_EDWARDS
+               : MPI_EC_WEIERSTRASS);
+      sk.E.dialect = ((flags & PUBKEY_FLAG_EDDSA)
+                      ? ECC_DIALECT_ED25519
+                      : ECC_DIALECT_STANDARD);
+    }
   if (DBG_CIPHER)
-    progress ('\n');
+    {
+      log_debug ("ecc_testkey inf: %s/%s\n",
+                 _gcry_ecc_model2str (sk.E.model),
+                 _gcry_ecc_dialect2str (sk.E.dialect));
+      if (sk.E.name)
+        log_debug  ("ecc_testkey nam: %s\n", sk.E.name);
+      log_printmpi ("ecc_testkey   p", sk.E.p);
+      log_printmpi ("ecc_testkey   a", sk.E.a);
+      log_printmpi ("ecc_testkey   b", sk.E.b);
+      log_printpnt ("ecc_testkey g",   &sk.E.G, NULL);
+      log_printmpi ("ecc_testkey   n", sk.E.n);
+      log_printmpi ("ecc_testkey   h", sk.E.h);
+      log_printmpi ("ecc_testkey   q", mpi_q);
+      if (!fips_mode ())
+        log_printmpi ("ecc_testkey   d", sk.d);
+    }
+  if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.E.h || !sk.d)
+    {
+      rc = GPG_ERR_NO_OBJ;
+      goto leave;
+    }
 
-  return k;
-}
+  ec = _gcry_mpi_ec_p_internal_new (sk.E.model, sk.E.dialect, 0,
+                                    sk.E.p, sk.E.a, sk.E.b);
 
+  if (mpi_q)
+    {
+      point_init (&sk.Q);
+      if (ec->dialect == ECC_DIALECT_ED25519)
+        rc = _gcry_ecc_eddsa_decodepoint (mpi_q, ec, &sk.Q, NULL, NULL);
+      else
+        rc = _gcry_ecc_os2ec (&sk.Q, mpi_q);
+      if (rc)
+        goto leave;
+    }
+  else
+    {
+      /* The secret key test requires Q.  */
+      rc = GPG_ERR_NO_OBJ;
+      goto leave;
+    }
 
-/* Helper to scan a hex string. */
-static gcry_mpi_t
-scanval (const char *string)
-{
-  gpg_error_t err;
-  gcry_mpi_t val;
-  
-  err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
-  if (err)
-    log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (err));
-  return val;
+  if (check_secret_key (&sk, ec, flags))
+    rc = GPG_ERR_BAD_SECKEY;
+
+ leave:
+  _gcry_mpi_ec_free (ec);
+  _gcry_mpi_release (sk.E.p);
+  _gcry_mpi_release (sk.E.a);
+  _gcry_mpi_release (sk.E.b);
+  _gcry_mpi_release (mpi_g);
+  point_free (&sk.E.G);
+  _gcry_mpi_release (sk.E.n);
+  _gcry_mpi_release (sk.E.h);
+  _gcry_mpi_release (mpi_q);
+  point_free (&sk.Q);
+  _gcry_mpi_release (sk.d);
+  xfree (curvename);
+  sexp_release (l1);
+  if (DBG_CIPHER)
+    log_debug ("ecc_testkey   => %s\n", gpg_strerror (rc));
+  return rc;
 }
 
 
-/****************
- * Generate the crypto system setup.
- * As of now the fix NIST recommended values are used.
- * The subgroup generator point is in another function: gen_big_point.
- */
-static gpg_err_code_t
-generate_curve (unsigned int nbits, elliptic_curve_t *curve)
+static gcry_err_code_t
+ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
 {
-  int idx;
+  gcry_err_code_t rc;
+  struct pk_encoding_ctx ctx;
+  gcry_mpi_t data = NULL;
+  gcry_sexp_t l1 = NULL;
+  char *curvename = NULL;
+  gcry_mpi_t mpi_g = NULL;
+  gcry_mpi_t mpi_q = NULL;
+  ECC_secret_key sk;
+  gcry_mpi_t sig_r = NULL;
+  gcry_mpi_t sig_s = NULL;
 
-  for (idx = 0; domain_parms[idx].desc; idx++)
-    if (nbits == domain_parms[idx].nbits)
-      break;
-  if (!domain_parms[idx].desc)
-    return GPG_ERR_INV_VALUE;
-
-  curve->p_ = scanval (domain_parms[idx].p);
-  curve->a_ = scanval (domain_parms[idx].a);
-  curve->b_ = scanval (domain_parms[idx].b);
-  curve->n_ = scanval (domain_parms[idx].n);
-  curve->G.x_ = scanval (domain_parms[idx].g_x);
-  curve->G.y_ = scanval (domain_parms[idx].g_y);
-  curve->G.z_ = mpi_alloc_set_ui (1);
-
-  /* Gx, Gy, Gz are planned to be generated by code like this:
-     if ( gen_big_point (&curve->n_, curve, &curve->G, nbits) == -1)
-      {
-         log_fatal ("ECC operation: Point generation failed\n");
-      }
+  memset (&sk, 0, sizeof sk);
 
-     A point of order 'n' is needed to generate a cyclic subgroup.
-     Over this cyclic subgroup it's defined the ECDLP.  Now it use a
-     fix values from NIST FIPS PUB 186-2.  Returns -1 if it isn't
-     possible.
-     static int
-     gen_big_point (gcry_mpi_t * prime, elliptic_curve_t * base, point_t * G,
-                    unsigned int nbits)
-     {
-         unsigned int i=0;
-         gcry_mpi_t one;
-         point_t Big, P;
-    
-         one = mpi_alloc_set_ui(1);
-         G->x_ = mpi_alloc(mpi_get_nlimbs(*prime));
-         G->y_ = mpi_alloc(mpi_get_nlimbs(*prime));
-         G->z_ = mpi_alloc(mpi_get_nlimbs(*prime));
-    
-         if( DBG_CIPHER )log_debug("Generating a Big point.\n");
-         do{
-         do{
-         *P = genPoint(*prime,*base);
-         }while(PointAtInfinity(*P));//A random point in the curve that it's not PaI
-         escalarMult(base.h,&P,&G,&base);//cofactor (1 o 2), could be improved
-         }while(PointAtInfinity(G));
-         if( DBG_CIPHER )log_debug("Big point generated.\n");
-         if( DBG_CIPHER ){
-         log_mpidump("Gx=",G->x_);log_mpidump("Gy=",G->y_);log_mpidump("Gz=",G->z_);
-         }
-     return 0;
-     }
-  */
+  _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, 0);
 
+  /* Extract the data.  */
+  rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
+  if (rc)
+    goto leave;
   if (DBG_CIPHER)
+    log_mpidump ("ecc_sign   data", data);
+
+  /*
+   * Extract the key.
+   */
+  if ((ctx.flags & PUBKEY_FLAG_PARAM))
+    rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?h?/q?+d",
+                             &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
+                             &sk.E.h, &mpi_q, &sk.d, NULL);
+  else
+    rc = sexp_extract_param (keyparms, NULL, "/q?+d",
+                             &mpi_q, &sk.d, NULL);
+  if (rc)
+    goto leave;
+  if (mpi_g)
     {
-      progress ('\n');
-      log_mpidump ("ecc generation  p= ", curve->p_);
-      log_mpidump ("ecc generation  a= ", curve->a_);
-      log_mpidump ("ecc generation  b= ", curve->b_);
-      log_mpidump ("ecc generation  n= ", curve->n_);
-      log_mpidump ("ecc generation  Gx= ", curve->G.x_);
-      log_mpidump ("ecc generation  Gy= ", curve->G.y_);
-      log_mpidump ("ecc generation  Gz= ", curve->G.z_);
+      point_init (&sk.E.G);
+      rc = _gcry_ecc_os2ec (&sk.E.G, mpi_g);
+      if (rc)
+        goto leave;
+    }
+  /* Add missing parameters using the optional curve parameter.  */
+  sexp_release (l1);
+  l1 = sexp_find_token (keyparms, "curve", 5);
+  if (l1)
+    {
+      curvename = sexp_nth_string (l1, 1);
+      if (curvename)
+        {
+          rc = _gcry_ecc_fill_in_curve (0, curvename, &sk.E, NULL);
+          if (rc)
+            return rc;
+        }
+    }
+  /* Guess required fields if a curve parameter has not been given.
+     FIXME: This is a crude hacks.  We need to fix that.  */
+  if (!curvename)
+    {
+      sk.E.model = ((ctx.flags & PUBKEY_FLAG_EDDSA)
+                    ? MPI_EC_EDWARDS
+                    : MPI_EC_WEIERSTRASS);
+      sk.E.dialect = ((ctx.flags & PUBKEY_FLAG_EDDSA)
+                      ? ECC_DIALECT_ED25519
+                      : ECC_DIALECT_STANDARD);
     }
   if (DBG_CIPHER)
-    progress ('\n');
-
-  return 0;
-}
+    {
+      log_debug ("ecc_sign   info: %s/%s%s\n",
+                 _gcry_ecc_model2str (sk.E.model),
+                 _gcry_ecc_dialect2str (sk.E.dialect),
+                 (ctx.flags & PUBKEY_FLAG_EDDSA)? "+EdDSA":"");
+      if (sk.E.name)
+        log_debug  ("ecc_sign   name: %s\n", sk.E.name);
+      log_printmpi ("ecc_sign      p", sk.E.p);
+      log_printmpi ("ecc_sign      a", sk.E.a);
+      log_printmpi ("ecc_sign      b", sk.E.b);
+      log_printpnt ("ecc_sign    g",   &sk.E.G, NULL);
+      log_printmpi ("ecc_sign      n", sk.E.n);
+      log_printmpi ("ecc_sign      h", sk.E.h);
+      log_printmpi ("ecc_sign      q", mpi_q);
+      if (!fips_mode ())
+        log_printmpi ("ecc_sign      d", sk.d);
+    }
+  if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.E.h || !sk.d)
+    {
+      rc = GPG_ERR_NO_OBJ;
+      goto leave;
+    }
 
 
-/****************
- * First obtain the setup.  Over the finite field randomize an scalar
- * secret value, and calculate the public point.
- */
-static gpg_err_code_t
-generate_key (ECC_secret_key *sk, unsigned int nbits)
-{
-  gpg_err_code_t err;
-  elliptic_curve_t E;
-  gcry_mpi_t d;
-  point_t Q, G;
+  sig_r = mpi_new (0);
+  sig_s = mpi_new (0);
+  if ((ctx.flags & PUBKEY_FLAG_EDDSA))
+    {
+      /* EdDSA requires the public key.  */
+      rc = _gcry_ecc_eddsa_sign (data, &sk, sig_r, sig_s, ctx.hash_algo, mpi_q);
+      if (!rc)
+        rc = sexp_build (r_sig, NULL,
+                         "(sig-val(eddsa(r%M)(s%M)))", sig_r, sig_s);
+    }
+  else if ((ctx.flags & PUBKEY_FLAG_GOST))
+    {
+      rc = _gcry_ecc_gost_sign (data, &sk, sig_r, sig_s);
+      if (!rc)
+        rc = sexp_build (r_sig, NULL,
+                         "(sig-val(gost(r%M)(s%M)))", sig_r, sig_s);
+    }
+  else
+    {
+      rc = _gcry_ecc_ecdsa_sign (data, &sk, sig_r, sig_s,
+                                 ctx.flags, ctx.hash_algo);
+      if (!rc)
+        rc = sexp_build (r_sig, NULL,
+                         "(sig-val(ecdsa(r%M)(s%M)))", sig_r, sig_s);
+    }
 
-  err = generate_curve (nbits, &E);
-  if (err)
-    return err;
 
-  d = mpi_snew (nbits);
+ leave:
+  _gcry_mpi_release (sk.E.p);
+  _gcry_mpi_release (sk.E.a);
+  _gcry_mpi_release (sk.E.b);
+  _gcry_mpi_release (mpi_g);
+  point_free (&sk.E.G);
+  _gcry_mpi_release (sk.E.n);
+  _gcry_mpi_release (sk.E.h);
+  _gcry_mpi_release (mpi_q);
+  point_free (&sk.Q);
+  _gcry_mpi_release (sk.d);
+  _gcry_mpi_release (sig_r);
+  _gcry_mpi_release (sig_s);
+  xfree (curvename);
+  _gcry_mpi_release (data);
+  sexp_release (l1);
+  _gcry_pk_util_free_encoding_ctx (&ctx);
   if (DBG_CIPHER)
-    log_debug ("choosing a random x of size %u\n", nbits);
-  d = gen_k (E.n_, 2);          /* generate_secret_prime(nbits); */
-  G = point_copy (E.G);
-
-  /* Compute Q.  */
-  point_init (&Q);
-  escalar_mult (&Q, d, &E.G, &E);
-
-  /* Copy the stuff to the key structures. */
-  sk->E.p_ = mpi_copy (E.p_);
-  sk->E.a_ = mpi_copy (E.a_);
-  sk->E.b_ = mpi_copy (E.b_);
-  sk->E.G  = point_copy (E.G);
-  sk->E.n_ = mpi_copy (E.n_);
-  sk->Q    = point_copy (Q);
-  sk->d    = mpi_copy (d);
-
-  /* Now we can test our keys (this should never fail!). */
-  test_keys (sk, nbits - 64);
-
-  point_free (&Q);
-  mpi_free (d);
-  curve_free (&E);
-
-  return 0;
+    log_debug ("ecc_sign      => %s\n", gpg_strerror (rc));
+  return rc;
 }
 
 
-/****************
- * To verify correct skey it use a random information.
- * First, encrypt and decrypt this dummy value, 
- * test if the information is recuperated.
- * Second, test with the sign and verify functions.
- */
-static void
-test_keys (ECC_secret_key *sk, unsigned int nbits)
+static gcry_err_code_t
+ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
 {
+  gcry_err_code_t rc;
+  struct pk_encoding_ctx ctx;
+  gcry_sexp_t l1 = NULL;
+  char *curvename = NULL;
+  gcry_mpi_t mpi_g = NULL;
+  gcry_mpi_t mpi_q = NULL;
+  gcry_mpi_t sig_r = NULL;
+  gcry_mpi_t sig_s = NULL;
+  gcry_mpi_t data = NULL;
   ECC_public_key pk;
-  gcry_mpi_t test = mpi_new (nbits);
-  point_t R_;
-  gcry_mpi_t c = mpi_new (nbits);
-  gcry_mpi_t out = mpi_new (nbits);
-  gcry_mpi_t r = mpi_new (nbits);
-  gcry_mpi_t s = mpi_new (nbits);
-
-  if (DBG_CIPHER)
-    log_debug ("Testing key.\n");
-
-  point_init (&R_);
-
-  pk.E = curve_copy (sk->E);
-  pk.Q = point_copy (sk->Q);
-
-  gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
+  int sigflags;
 
-#if 0  
-  doEncrypt (test, &pk, &R_, c);
+  memset (&pk, 0, sizeof pk);
+  _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY,
+                                   ecc_get_nbits (s_keyparms));
 
-  out = decrypt (out, sk, R_, c);
-
-  if (mpi_cmp (test, out))      /* test!=out */
-    log_fatal ("ECELG operation: encrypt, decrypt failed\n");
+  /* Extract the data.  */
+  rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
+  if (rc)
+    goto leave;
+  if (DBG_CIPHER)
+    log_mpidump ("ecc_verify data", data);
+
+  /*
+   * Extract the signature value.
+   */
+  rc = _gcry_pk_util_preparse_sigval (s_sig, ecc_names, &l1, &sigflags);
+  if (rc)
+    goto leave;
+  rc = sexp_extract_param (l1, NULL, (sigflags & PUBKEY_FLAG_EDDSA)? "/rs":"rs",
+                           &sig_r, &sig_s, NULL);
+  if (rc)
+    goto leave;
   if (DBG_CIPHER)
-    log_debug ("ECELG operation: encrypt, decrypt ok.\n");
-#endif
-
-  if (sign (test, sk, r, s) )
-    log_fatal ("ECDSA operation: sign failed\n");
-
-  if (verify (test, &pk, r, s))
     {
-      log_fatal ("ECDSA operation: sign, verify failed\n");
+      log_mpidump ("ecc_verify  s_r", sig_r);
+      log_mpidump ("ecc_verify  s_s", sig_s);
+    }
+  if ((ctx.flags & PUBKEY_FLAG_EDDSA) ^ (sigflags & PUBKEY_FLAG_EDDSA))
+    {
+      rc = GPG_ERR_CONFLICT; /* Inconsistent use of flag/algoname.  */
+      goto leave;
     }
 
-  if (DBG_CIPHER)
-    log_debug ("ECDSA operation: sign, verify ok.\n");
-
-  point_free (&pk.Q);
-  curve_free (&pk.E);
-
-  point_free (&R_);
-  mpi_free (s);
-  mpi_free (r);
-  mpi_free (out);
-  mpi_free (c);
-  mpi_free (test);
-}
-
-/****************
- * To check the validity of the value, recalculate the correspondence
- * between the public value and de secret one.
- */
-static int
-check_secret_key (ECC_secret_key * sk)
-{
-  point_t Q;
-  gcry_mpi_t y_2, y2 = mpi_alloc (0);
 
-  /* ?primarity test of 'p' */
-  /*  (...) //!! */
-  /* G in E(F_p) */
-  y_2 = gen_y_2 (sk->E.G.x_, &sk->E);   /*  y^2=x^3+a*x+b */
-  mpi_mulm (y2, sk->E.G.y_, sk->E.G.y_, sk->E.p_);      /*  y^2=y*y */
-  if (mpi_cmp (y_2, y2))
+  /*
+   * Extract the key.
+   */
+  if ((ctx.flags & PUBKEY_FLAG_PARAM))
+    rc = sexp_extract_param (s_keyparms, NULL, "-p?a?b?g?n?h?/q",
+                             &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n,
+                             &pk.E.n, &mpi_q, NULL);
+  else
+    rc = sexp_extract_param (s_keyparms, NULL, "/q",
+                             &mpi_q, NULL);
+  if (rc)
+    goto leave;
+  if (mpi_g)
     {
-      if (DBG_CIPHER)
-        log_debug ("Bad check: Point 'G' does not belong to curve 'E'!\n");
-      return (1);
+      point_init (&pk.E.G);
+      rc = _gcry_ecc_os2ec (&pk.E.G, mpi_g);
+      if (rc)
+        goto leave;
     }
-  /* G != PaI */
-  if (point_at_infinity (sk->E.G))
+  /* Add missing parameters using the optional curve parameter.  */
+  sexp_release (l1);
+  l1 = sexp_find_token (s_keyparms, "curve", 5);
+  if (l1)
     {
-      if (DBG_CIPHER)
-        log_debug ("Bad check: 'G' cannot be Point at Infinity!\n");
-      return (1);
+      curvename = sexp_nth_string (l1, 1);
+      if (curvename)
+        {
+          rc = _gcry_ecc_fill_in_curve (0, curvename, &pk.E, NULL);
+          if (rc)
+            return rc;
+        }
+    }
+  /* Guess required fields if a curve parameter has not been given.
+     FIXME: This is a crude hacks.  We need to fix that.  */
+  if (!curvename)
+    {
+      pk.E.model = ((sigflags & PUBKEY_FLAG_EDDSA)
+                    ? MPI_EC_EDWARDS
+                    : MPI_EC_WEIERSTRASS);
+      pk.E.dialect = ((sigflags & PUBKEY_FLAG_EDDSA)
+                      ? ECC_DIALECT_ED25519
+                      : ECC_DIALECT_STANDARD);
     }
-  /* ?primarity test of 'n' */
-  /*  (...) //!! */
-  /* ?(p-sqrt(p)) < n < (p+sqrt(p)) */
-  /* ?n!=p */
-  /* ?(n^k) mod p !=1 for k=1 to 31 (from GOST) or k=1 to 50 (from MIRACL) */
-  /* Q=[n]G over E = PaI */
 
-  point_init (&Q);
-  escalar_mult (&Q, sk->E.n_, &sk->E.G, &sk->E);
-  if (!point_at_infinity (Q))
+  if (DBG_CIPHER)
     {
-      if (DBG_CIPHER)
-        log_debug ("check_secret_key: E is not a curve of order n\n");
-      point_free (&Q);
-      return 1;
+      log_debug ("ecc_verify info: %s/%s%s\n",
+                 _gcry_ecc_model2str (pk.E.model),
+                 _gcry_ecc_dialect2str (pk.E.dialect),
+                 (sigflags & PUBKEY_FLAG_EDDSA)? "+EdDSA":"");
+      if (pk.E.name)
+        log_debug  ("ecc_verify name: %s\n", pk.E.name);
+      log_printmpi ("ecc_verify    p", pk.E.p);
+      log_printmpi ("ecc_verify    a", pk.E.a);
+      log_printmpi ("ecc_verify    b", pk.E.b);
+      log_printpnt ("ecc_verify  g",   &pk.E.G, NULL);
+      log_printmpi ("ecc_verify    n", pk.E.n);
+      log_printmpi ("ecc_verify    h", pk.E.h);
+      log_printmpi ("ecc_verify    q", mpi_q);
     }
-  /* pubkey cannot be PaI */
-  if (point_at_infinity (sk->Q))
+  if (!pk.E.p || !pk.E.a || !pk.E.b || !pk.E.G.x || !pk.E.n || !pk.E.h || !mpi_q)
     {
-      if (DBG_CIPHER)
-        log_debug ("Bad check: Q can not be a Point at Infinity!\n");
-      return (1);
+      rc = GPG_ERR_NO_OBJ;
+      goto leave;
     }
-  /* pubkey = [d]G over E */
-  escalar_mult (&Q, sk->d, &sk->E.G, &sk->E);
-  if ((Q.x_ == sk->Q.x_) && (Q.y_ == sk->Q.y_) && (Q.z_ == sk->Q.z_))
+
+
+  /*
+   * Verify the signature.
+   */
+  if ((sigflags & PUBKEY_FLAG_EDDSA))
     {
-      if (DBG_CIPHER)
-        log_debug
-          ("Bad check: There is NO correspondence between 'd' and 'Q'!\n");
-      return (1);
+      rc = _gcry_ecc_eddsa_verify (data, &pk, sig_r, sig_s,
+                                   ctx.hash_algo, mpi_q);
     }
-  point_free (&Q);
-  return 0;
-}
+  else if ((sigflags & PUBKEY_FLAG_GOST))
+    {
+      point_init (&pk.Q);
+      rc = _gcry_ecc_os2ec (&pk.Q, mpi_q);
+      if (rc)
+        goto leave;
 
+      rc = _gcry_ecc_gost_verify (data, &pk, sig_r, sig_s);
+    }
+  else
+    {
+      point_init (&pk.Q);
+      if (pk.E.dialect == ECC_DIALECT_ED25519)
+        {
+          mpi_ec_t ec;
 
-#if 0
-/****************
- * Encrypt a number and obtain and struct (R,c)
- */
-static void
-doEncrypt (gcry_mpi_t input, ECC_public_key * pkey, point_t * R, gcry_mpi_t c)
-{
+          /* Fixme: Factor the curve context setup out of eddsa_verify
+             and ecdsa_verify. So that we don't do it twice.  */
+          ec = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect, 0,
+                                            pk.E.p, pk.E.a, pk.E.b);
 
-  gcry_mpi_t k, p, x, y;
-  point_t P, Q, G;
-  elliptic_curve_t E;
+          rc = _gcry_ecc_eddsa_decodepoint (mpi_q, ec, &pk.Q, NULL, NULL);
+          _gcry_mpi_ec_free (ec);
+        }
+      else
+        {
+          rc = _gcry_ecc_os2ec (&pk.Q, mpi_q);
+        }
+      if (rc)
+        goto leave;
 
-  k = mpi_alloc (0);
-  p = mpi_copy (pkey->E.p_);
-  x = mpi_alloc (0);
-  y = mpi_alloc (0);
-  Q = point_copy (pkey->Q);
-  G = point_copy (pkey->E.G);
-  E = curve_copy (pkey->E);
-
-  k = gen_k (p, 1);             /* 2nd parametre: how much security? */
-  escalarMult (k, &Q, &P, &E);  /* P=[k]Q=[k]([d]G) */
-  escalarMult (k, &G, R, &E);   /* R=[k]G */
-  /* IFP weakness//mpi_mul(c,input,Q.x_);//c=input*Q_x */
-  /* MMR Use affine conversion befor extract x-coordinate */
-  if (point_affine (&P, x, y, &E))
-    {                           /* Q cannot turn to affine coordinate */
-      if (DBG_CIPHER)
+      if (mpi_is_opaque (data))
         {
-          log_debug ("Encrypting: Cannot turn to affine.\n");
+          const void *abuf;
+          unsigned int abits, qbits;
+          gcry_mpi_t a;
+
+          qbits = mpi_get_nbits (pk.E.n);
+
+          abuf = mpi_get_opaque (data, &abits);
+          rc = _gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, (abits+7)/8, NULL);
+          if (!rc)
+            {
+              if (abits > qbits)
+                mpi_rshift (a, a, abits - qbits);
+
+              rc = _gcry_ecc_ecdsa_verify (a, &pk, sig_r, sig_s);
+              _gcry_mpi_release (a);
+            }
         }
+      else
+        rc = _gcry_ecc_ecdsa_verify (data, &pk, sig_r, sig_s);
     }
-  /* MMR According to the standard P1363 we can not use x-coordinate directly. */
-  /*  It is necessary to add hash-operation later.  */
-  /*  As the maximal length of a key for the symmetric cipher is 256 bit it is possible to take hash-function SHA256. */
-  sha256_hashing (x, &x);
-  aes256_encrypting (x, input, &c);
 
+ leave:
+  _gcry_mpi_release (pk.E.p);
+  _gcry_mpi_release (pk.E.a);
+  _gcry_mpi_release (pk.E.b);
+  _gcry_mpi_release (mpi_g);
+  point_free (&pk.E.G);
+  _gcry_mpi_release (pk.E.n);
+  _gcry_mpi_release (pk.E.h);
+  _gcry_mpi_release (mpi_q);
+  point_free (&pk.Q);
+  _gcry_mpi_release (data);
+  _gcry_mpi_release (sig_r);
+  _gcry_mpi_release (sig_s);
+  xfree (curvename);
+  sexp_release (l1);
+  _gcry_pk_util_free_encoding_ctx (&ctx);
   if (DBG_CIPHER)
-    {
-      log_debug ("doEncrypt: end.\n");
-    }
+    log_debug ("ecc_verify    => %s\n", rc?gpg_strerror (rc):"Good");
+  return rc;
 }
-#endif /*0*/
 
-#if 0
-/****************
- * Undo the ciphertext
+
+/* ecdh raw is classic 2-round DH protocol published in 1976.
+ *
+ * Overview of ecc_encrypt_raw and ecc_decrypt_raw.
+ *
+ * As with any PK operation, encrypt version uses a public key and
+ * decrypt -- private.
+ *
+ * Symbols used below:
+ *     G - field generator point
+ *     d - private long-term scalar
+ *    dG - public long-term key
+ *     k - ephemeral scalar
+ *    kG - ephemeral public key
+ *   dkG - shared secret
+ *
+ * ecc_encrypt_raw description:
+ *   input:
+ *     data[0] : private scalar (k)
+ *   output: A new S-expression with the parameters:
+ *     s : shared point (kdG)
+ *     e : generated ephemeral public key (kG)
+ *
+ * ecc_decrypt_raw description:
+ *   input:
+ *     data[0] : a point kG (ephemeral public key)
+ *   output:
+ *     result[0] : shared point (kdG)
  */
-static gcry_mpi_t
-decrypt (gcry_mpi_t output, ECC_secret_key * skey, point_t R, gcry_mpi_t c)
+static gcry_err_code_t
+ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
 {
+  gcry_err_code_t rc;
+  struct pk_encoding_ctx ctx;
+  gcry_sexp_t l1 = NULL;
+  char *curvename = NULL;
+  gcry_mpi_t mpi_g = NULL;
+  gcry_mpi_t mpi_q = NULL;
+  gcry_mpi_t mpi_s = NULL;
+  gcry_mpi_t mpi_e = NULL;
+  gcry_mpi_t data = NULL;
+  ECC_public_key pk;
+  mpi_ec_t ec = NULL;
+
+  memset (&pk, 0, sizeof pk);
+  _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT,
+                                   ecc_get_nbits (keyparms));
+
+  /*
+   * Extract the data.
+   */
+  rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
+  if (rc)
+    goto leave;
+  if (DBG_CIPHER)
+    log_mpidump ("ecc_encrypt data", data);
+  if (mpi_is_opaque (data))
+    {
+      rc = GPG_ERR_INV_DATA;
+      goto leave;
+    }
 
-  gcry_mpi_t p, inv, x, y;
-  point_t P, Q;
-  elliptic_curve_t E;
 
-  p = mpi_copy (skey->E.p_);
-  inv = mpi_alloc (0);
-  x = mpi_alloc (0);
-  y = mpi_alloc (0);
-  Q = point_copy (skey->Q);
-  E = curve_copy (skey->E);
-
-  escalarMult (skey->d, &R, &P, &E);    /* P=[d]R */
-  /* That is like: mpi_fdiv_q(output,c,Q.x_); */
-  /* IFP weakness//mpi_invm(inv,Q.x_,p);//inv=Q{_x}^-1 (mod p) */
-  /* IFP weakness//mpi_mulm(output,c,inv,p);//output=c*inv (mod p) */
-  /* MMR Use affine conversion befor extract x-coordinate */
-  if (point_affine (&P, x, y, &E))
-    {                           /* Q cannot turn to affine coordinate */
-      if (DBG_CIPHER)
+  /*
+   * Extract the key.
+   */
+  rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?h?+q",
+                           &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n, &pk.E.h,
+                           &mpi_q, NULL);
+  if (rc)
+    goto leave;
+  if (mpi_g)
+    {
+      point_init (&pk.E.G);
+      rc = _gcry_ecc_os2ec (&pk.E.G, mpi_g);
+      if (rc)
+        goto leave;
+    }
+  /* Add missing parameters using the optional curve parameter.  */
+  sexp_release (l1);
+  l1 = sexp_find_token (keyparms, "curve", 5);
+  if (l1)
+    {
+      curvename = sexp_nth_string (l1, 1);
+      if (curvename)
         {
-          log_debug ("Encrypting: Cannot turn to affine.\n");
+          rc = _gcry_ecc_fill_in_curve (0, curvename, &pk.E, NULL);
+          if (rc)
+            return rc;
         }
     }
-  sha256_hashing (x, &x);
-  aes256_decrypting (x, c, &output);
+  /* Guess required fields if a curve parameter has not been given.  */
+  if (!curvename)
+    {
+      pk.E.model = MPI_EC_WEIERSTRASS;
+      pk.E.dialect = ECC_DIALECT_STANDARD;
+    }
 
   if (DBG_CIPHER)
     {
-      log_debug ("decrypt: end.\n");
+      log_debug ("ecc_encrypt info: %s/%s\n",
+                 _gcry_ecc_model2str (pk.E.model),
+                 _gcry_ecc_dialect2str (pk.E.dialect));
+      if (pk.E.name)
+        log_debug  ("ecc_encrypt name: %s\n", pk.E.name);
+      log_printmpi ("ecc_encrypt    p", pk.E.p);
+      log_printmpi ("ecc_encrypt    a", pk.E.a);
+      log_printmpi ("ecc_encrypt    b", pk.E.b);
+      log_printpnt ("ecc_encrypt  g",   &pk.E.G, NULL);
+      log_printmpi ("ecc_encrypt    n", pk.E.n);
+      log_printmpi ("ecc_encrypt    h", pk.E.h);
+      log_printmpi ("ecc_encrypt    q", mpi_q);
+    }
+  if (!pk.E.p || !pk.E.a || !pk.E.b || !pk.E.G.x || !pk.E.n || !pk.E.h || !mpi_q)
+    {
+      rc = GPG_ERR_NO_OBJ;
+      goto leave;
     }
-  return (output);
-}
-#endif /*0*/
 
+  /* Convert the public key.  */
+  if (mpi_q)
+    {
+      point_init (&pk.Q);
+      rc = _gcry_ecc_os2ec (&pk.Q, mpi_q);
+      if (rc)
+        goto leave;
+    }
 
-/*
- * Return the signature struct (r,s) from the message hash.  The caller
- * must have allocated R and S.
- */
-static gpg_err_code_t
-sign (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s)
-{
-  gpg_err_code_t err = 0;
-  gcry_mpi_t k, i, dr, sum, k_1, x, y;
-  point_t G, I;
-  elliptic_curve_t E;
+  /* Compute the encrypted value.  */
+  ec = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect, 0,
+                                    pk.E.p, pk.E.a, pk.E.b);
 
-  k = NULL;
-  i = mpi_alloc (0); /* Fixme: we could do trivially without it.  */
-  dr = mpi_alloc (0);
-  sum = mpi_alloc (0);
-  k_1 = mpi_alloc (0);
-  x = mpi_alloc (0);
-  y = mpi_alloc (0);
-  G = point_copy (skey->E.G);
-  E = curve_copy (skey->E);
-  point_init (&I);
-
-  mpi_set_ui (s, 0);
-  mpi_set_ui (r, 0);
-
-  while (!mpi_cmp_ui (s, 0)) /* s == 0 */
-    {                           
-      while (!mpi_cmp_ui (r, 0)) /* r == 0 */
-        {               
-          /* Note, that we are guaranteed to enter this loop at least
-             once because r has been intialized to 0.  We casn use a
-             do_while because we want to keep the value of R value
-             even if S has to be recomputed.  */
-          mpi_free (k);
-          k = gen_k (E.p_, 1);
-          escalar_mult (&I, k, &G, &E); /* I = [k]G */
-          if (point_affine (&I, x, y, &E))
-            {
-              if (DBG_CIPHER)
-                log_debug ("ecc sign: Cannot turn to affine. "
-                           " Cannot complete sign.\n");
-              err = GPG_ERR_BAD_SIGNATURE;
-              goto leave;
-            }
-          mpi_set (i, x);         /* i = I_x     */
-          mpi_mod (r, i, E.n_);   /* r = i mod n */
-        }
-      mpi_mulm (dr, skey->d, r, E.n_);  /* dr = d*r mod n */
-      mpi_addm (sum, input, dr, E.n_);  /* sum = hash + (d*r) mod n */
-      mpi_invm (k_1, k, E.n_);          /* k_1 = k^(-1) mod n */
-      mpi_mulm (s, k_1, sum, E.n_);     /* s = k^(-1)*(hash+(d*r)) mod n */
-    }
+  /* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so */
+  {
+    mpi_point_struct R;  /* Result that we return.  */
+    gcry_mpi_t x, y;
 
-  /* Fixme:  What about releasing G and E?  Why do we need copies at all? */
- leave:
-  point_free (&I);
-  mpi_free (y);
-  mpi_free (x);
-  mpi_free (k_1);
-  mpi_free (sum);
-  mpi_free (dr);
-  mpi_free (i);
-  mpi_free (k);
+    x = mpi_new (0);
+    y = mpi_new (0);
 
-  return err;
-}
+    point_init (&R);
 
-/*
- * Check if R and S verifies INPUT.
- */
-static gpg_err_code_t
-verify (gcry_mpi_t input, ECC_public_key *pkey, gcry_mpi_t r, gcry_mpi_t s)
-{
-  gpg_err_code_t err = 0;
-  gcry_mpi_t h, h1, h2, x, y;
-  point_t Q, Q1, Q2, G;
-  elliptic_curve_t E;
+    /* R = kQ  <=>  R = kdG  */
+    _gcry_mpi_ec_mul_point (&R, data, &pk.Q, ec);
 
-  /* Check that the input parameters are valid.  */
-  {
-    gcry_mpi_t r_ = mpi_alloc_like (r);
-    gcry_mpi_t s_ = mpi_alloc_like (s);
-    mpi_mod (r_, r, pkey->E.n_);  /* r = r mod E_n */
-    mpi_mod (s_, s, pkey->E.n_);  /* s = s mod E_n */
-    err = (mpi_cmp (r_, r) || mpi_cmp (s_, s));
-    mpi_free (r_);
-    mpi_free (s_);
-    if (err)
-      {                           
-        if (DBG_CIPHER)
-          log_debug ("ecc verification: No valid values.\n");
-        return GPG_ERR_BAD_SIGNATURE;
-      }
-  }
+    if (_gcry_mpi_ec_get_affine (x, y, &R, ec))
+      log_fatal ("ecdh: Failed to get affine coordinates for kdG\n");
+    mpi_s = _gcry_ecc_ec2os (x, y, pk.E.p);
 
-  h  = mpi_alloc (0);
-  h1 = mpi_alloc (0);
-  h2 = mpi_alloc (0);
-  x = mpi_alloc (0);
-  y = mpi_alloc (0);
-  point_init (&Q);
-  point_init (&Q1);
-  point_init (&Q2);
-  G = point_copy (pkey->E.G);  /* Fixme: We don't need the copy. */
-  E = curve_copy (pkey->E);    /* Fixme: We don't need the copy. */
+    /* R = kG */
+    _gcry_mpi_ec_mul_point (&R, data, &pk.E.G, ec);
 
-  mpi_invm (h, s, E.n_);                /* h  = s^(-1) (mod n) */
-  mpi_mulm (h1, input, h, E.n_);        /* h1 = hash * s^(-1) (mod n) */
-  escalar_mult (&Q1, h1, &G, &E);       /* Q1 = [ hash * s^(-1) ]G  */
-  mpi_mulm (h2, r, h, E.n_);            /* h2 = r * s^(-1) (mod n) */
-  escalar_mult (&Q2, h2, &pkey->Q, &E); /* Q2 = [ r * s^(-1) ]Q */
-  sum_points (&Q, &Q1, &Q2, &E);/* Q  = ([hash * s^(-1)]G) + ([r * s^(-1)]Q) */
+    if (_gcry_mpi_ec_get_affine (x, y, &R, ec))
+      log_fatal ("ecdh: Failed to get affine coordinates for kG\n");
+    mpi_e = _gcry_ecc_ec2os (x, y, pk.E.p);
 
-  if (point_at_infinity (Q))
-    {
-      if (DBG_CIPHER)
-          log_debug ("ecc verification: Rejected.\n");
-      err = GPG_ERR_BAD_SIGNATURE;
-      goto leave;
-    }
-  if (point_affine (&Q, x, y, &E))
-    {                   
-      if (DBG_CIPHER)
-        log_debug ("ecc verification: Cannot turn to affine. Rejected.\n");
-      err = GPG_ERR_BAD_SIGNATURE;
-      goto leave;
-    }
-  mpi_mod (x, x, E.n_); /* x = x mod E_n */
-  if (mpi_cmp (x, r))   /* x != r */
-    {                           
-      if (DBG_CIPHER)
-        log_debug ("ecc verification: Not verified.\n");
-      err = GPG_ERR_BAD_SIGNATURE;
-      goto leave;
-    }
-  if (DBG_CIPHER)
-    log_debug ("ecc verification: Accepted.\n");
+    mpi_free (x);
+    mpi_free (y);
+
+    point_free (&R);
+  }
+
+  rc = sexp_build (r_ciph, NULL, "(enc-val(ecdh(s%m)(e%m)))", mpi_s, mpi_e);
 
  leave:
-  curve_free (&E);
-  point_free (&G);
-  point_free (&Q2);
-  point_free (&Q1);
-  point_free (&Q);
-  mpi_free (y);
-  mpi_free (x);
-  mpi_free (h2);
-  mpi_free (h1);
-  mpi_free (h);
-  return err;
+  _gcry_mpi_release (pk.E.p);
+  _gcry_mpi_release (pk.E.a);
+  _gcry_mpi_release (pk.E.b);
+  _gcry_mpi_release (mpi_g);
+  point_free (&pk.E.G);
+  _gcry_mpi_release (pk.E.n);
+  _gcry_mpi_release (pk.E.h);
+  _gcry_mpi_release (mpi_q);
+  point_free (&pk.Q);
+  _gcry_mpi_release (data);
+  _gcry_mpi_release (mpi_s);
+  _gcry_mpi_release (mpi_e);
+  xfree (curvename);
+  _gcry_mpi_ec_free (ec);
+  _gcry_pk_util_free_encoding_ctx (&ctx);
+  if (DBG_CIPHER)
+    log_debug ("ecc_encrypt    => %s\n", gpg_strerror (rc));
+  return rc;
 }
 
 
-/****************
- * Generate a random point over an Elliptic curve is the first step to
- * find a random cyclic subgroup generator.
+/*  input:
+ *     data[0] : a point kG (ephemeral public key)
+ *   output:
+ *     resaddr[0] : shared point kdG
  *
- *        !! At this moment it isn't used !!  //!!
+ *  see ecc_encrypt_raw for details.
  */
-#if 0
-static point_t
-gen_point (gcry_mpi_t prime, elliptic_curve_t base)
+static gcry_err_code_t
+ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
 {
-
-  unsigned int i = 0;
-  gcry_mpi_t x, y_2, y;
-  gcry_mpi_t one, one_neg, bit;
-  point_t P;
-
-  x = mpi_alloc (mpi_get_nlimbs (base.p_));
-  y_2 = mpi_alloc (mpi_get_nlimbs (base.p_));
-  y = mpi_alloc (mpi_get_nlimbs (base.p_));
-  one = mpi_alloc_set_ui (1);
-  one_neg = mpi_alloc (mpi_get_nlimbs (one));
-  mpi_invm (one_neg, one, base.p_);
-
+  gpg_err_code_t rc;
+  struct pk_encoding_ctx ctx;
+  gcry_sexp_t l1 = NULL;
+  gcry_mpi_t data_e = NULL;
+  ECC_secret_key sk;
+  gcry_mpi_t mpi_g = NULL;
+  char *curvename = NULL;
+  mpi_ec_t ec = NULL;
+  mpi_point_struct kG;
+  mpi_point_struct R;
+  gcry_mpi_t r = NULL;
+
+  memset (&sk, 0, sizeof sk);
+  point_init (&kG);
+  point_init (&R);
+
+  _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT,
+                                   ecc_get_nbits (keyparms));
+
+  /*
+   * Extract the data.
+   */
+  rc = _gcry_pk_util_preparse_encval (s_data, ecc_names, &l1, &ctx);
+  if (rc)
+    goto leave;
+  rc = sexp_extract_param (l1, NULL, "e", &data_e, NULL);
+  if (rc)
+    goto leave;
   if (DBG_CIPHER)
-    log_debug ("Generating a normal point.\n");
-  do
+    log_printmpi ("ecc_decrypt  d_e", data_e);
+  if (mpi_is_opaque (data_e))
+    {
+      rc = GPG_ERR_INV_DATA;
+      goto leave;
+    }
+
+  /*
+   * Extract the key.
+   */
+  rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?h?+d",
+                           &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
+                           &sk.E.h, &sk.d, NULL);
+  if (rc)
+    goto leave;
+  if (mpi_g)
+    {
+      point_init (&sk.E.G);
+      rc = _gcry_ecc_os2ec (&sk.E.G, mpi_g);
+      if (rc)
+        goto leave;
+    }
+  /* Add missing parameters using the optional curve parameter.  */
+  sexp_release (l1);
+  l1 = sexp_find_token (keyparms, "curve", 5);
+  if (l1)
     {
-      x = gen_k (base.p_, 1);   /* generate_public_prime(mpi_get_nlimbs(base.n_)*BITS_PER_MPI_LIMB); */
-      do
+      curvename = sexp_nth_string (l1, 1);
+      if (curvename)
         {
-          y_2 = gen_y_2 (x, &base);     /* x^3+ax+b (mod p) */
-          mpi_add_ui (x, x, 1);
-          i++;
+          rc = _gcry_ecc_fill_in_curve (0, curvename, &sk.E, NULL);
+          if (rc)
+            return rc;
         }
-      while (!mpi_cmp_ui (y_2, 0) && i < 0xf);  /* Try to find a valid value until 16 iterations. */
-      i = 0;
-      y = existSquareRoot (y_2, base.p_);
     }
-  while (!mpi_cmp_ui (y, 0));   /* Repeat until a valid coordinate is found. */
-  bit = gen_bit ();             /* generate one bit */
-  if (mpi_cmp_ui (bit, 1))
-    {                           /* choose the y coordinate */
-      mpi_invm (y, y, base.p_); /* mpi_powm(y, y, one_neg,base.p_); */
+  /* Guess required fields if a curve parameter has not been given.  */
+  if (!curvename)
+    {
+      sk.E.model = MPI_EC_WEIERSTRASS;
+      sk.E.dialect = ECC_DIALECT_STANDARD;
     }
   if (DBG_CIPHER)
-    log_debug ("Normal point generated.\n");
-
-  P.x_ = mpi_copy (x);
-  P.y_ = mpi_copy (y);
-  P.z_ = mpi_copy (one);
-
-  mpi_free (bit);
-  mpi_free (one_neg);
-  mpi_free (one);
-  mpi_free (y);
-  mpi_free (y_2);
-  mpi_free (x);
-
-  return (P);
-}
-#endif /*0*/
-
-/****************
- * Boolean generator to choose between to coordinates.
- */
-#if 0
-static gcry_mpi_t
-gen_bit ()
-{
-  gcry_mpi_t aux = mpi_alloc_set_ui (0);
-
-  /* FIXME: This is highly ineffective but the whole function is used
-     only at one place. */
-
-  /* Get one random bit, with less security level, and translate it to
-     an MPI. */
-  mpi_set_buffer (aux, get_random_bits (1, 0, 1), 1, 0);        /* gen_k(...) */
+    {
+      log_debug ("ecc_decrypt info: %s/%s\n",
+                 _gcry_ecc_model2str (sk.E.model),
+                 _gcry_ecc_dialect2str (sk.E.dialect));
+      if (sk.E.name)
+        log_debug  ("ecc_decrypt name: %s\n", sk.E.name);
+      log_printmpi ("ecc_decrypt    p", sk.E.p);
+      log_printmpi ("ecc_decrypt    a", sk.E.a);
+      log_printmpi ("ecc_decrypt    b", sk.E.b);
+      log_printpnt ("ecc_decrypt  g",   &sk.E.G, NULL);
+      log_printmpi ("ecc_decrypt    n", sk.E.n);
+      log_printmpi ("ecc_decrypt    h", sk.E.h);
+      if (!fips_mode ())
+        log_printmpi ("ecc_decrypt    d", sk.d);
+    }
+  if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.E.h || !sk.d)
+    {
+      rc = GPG_ERR_NO_OBJ;
+      goto leave;
+    }
 
-  return aux;                   /* b; */
-}
-#endif /*0*/
 
+  /*
+   * Compute the plaintext.
+   */
+  rc = _gcry_ecc_os2ec (&kG, data_e);
+  if (rc)
+    {
+      point_free (&kG);
+      return rc;
+    }
 
-\f
-#if 0
-/* Function to solve an IFP ECElGamal weakness: */
-/*  sha256_hashing() */
-/*  aes256_encrypting() */
-/*  aes356_decrypting() */
-
-/****************
- * Compute 256 bit hash value from input MPI.
- * Use SHA256 Algorithm.
- */
-static void
-sha256_hashing (gcry_mpi_t input, gcry_mpi_t * output)
-{                               /*   */
+  ec = _gcry_mpi_ec_p_internal_new (sk.E.model, sk.E.dialect, 0,
+                                    sk.E.p, sk.E.a, sk.E.b);
 
-  int sign;
-  byte *hash_inp_buf;
-  byte hash_out_buf[32];
-  MD_HANDLE hash = md_open (8, 1);      /* algo SHA256 in secure mode */
+  /* R = dkG */
+  _gcry_mpi_ec_mul_point (&R, sk.d, &kG, ec);
 
-  unsigned int nbytes;
+  /* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so:  */
+  {
+    gcry_mpi_t x, y;
 
-  hash_inp_buf = mpi_get_secure_buffer (input, &nbytes, &sign); /* convert gcry_mpi_t input to string */
+    x = mpi_new (0);
+    y = mpi_new (0);
 
-  md_write (hash, hash_inp_buf, nbytes);        /* hashing input string */
-  wipememory (hash_inp_buf, sizeof hash_inp_buf);       /*  burn temp value  */
-  xfree (hash_inp_buf);
+    if (_gcry_mpi_ec_get_affine (x, y, &R, ec))
+      log_fatal ("ecdh: Failed to get affine coordinates\n");
 
-  md_digest (hash, 8, hash_out_buf, 32);
-  mpi_set_buffer (*output, hash_out_buf, 32, 0);        /*  convert 256 bit digest to MPI */
+    r = _gcry_ecc_ec2os (x, y, sk.E.p);
+    if (!r)
+      rc = gpg_err_code_from_syserror ();
+    else
+      rc = 0;
+    mpi_free (x);
+    mpi_free (y);
+  }
+  if (DBG_CIPHER)
+    log_printmpi ("ecc_decrypt  res", r);
 
-  wipememory (hash_out_buf, sizeof hash_out_buf);       /*  burn temp value  */
-  md_close (hash);              /*  destroy and free hash state. */
+  if (!rc)
+    rc = sexp_build (r_plain, NULL, "(value %m)", r);
 
+ leave:
+  point_free (&R);
+  point_free (&kG);
+  _gcry_mpi_release (r);
+  _gcry_mpi_release (sk.E.p);
+  _gcry_mpi_release (sk.E.a);
+  _gcry_mpi_release (sk.E.b);
+  _gcry_mpi_release (mpi_g);
+  point_free (&sk.E.G);
+  _gcry_mpi_release (sk.E.n);
+  _gcry_mpi_release (sk.E.h);
+  _gcry_mpi_release (sk.d);
+  _gcry_mpi_release (data_e);
+  xfree (curvename);
+  sexp_release (l1);
+  _gcry_mpi_ec_free (ec);
+  _gcry_pk_util_free_encoding_ctx (&ctx);
+  if (DBG_CIPHER)
+    log_debug ("ecc_decrypt    => %s\n", gpg_strerror (rc));
+  return rc;
 }
 
-/****************
- * Encrypt input MPI.
- * Use AES256 algorithm.
- */
-
-static void
-aes256_encrypting (gcry_mpi_t key, gcry_mpi_t input, gcry_mpi_t * output)
-{                               /*   */
 
-  int sign;
-  byte *key_buf;
-  byte *cipher_buf;
-
-  unsigned int keylength;
-  unsigned int nbytes;
-
-
-  CIPHER_HANDLE cipher = cipher_open (9, CIPHER_MODE_CFB, 1);   /* algo AES256 CFB mode in secure memory */
-  cipher_setiv (cipher, NULL, 0);       /*  Zero IV */
+/* Return the number of bits for the key described by PARMS.  On error
+ * 0 is returned.  The format of PARMS starts with the algorithm name;
+ * for example:
+ *
+ *   (ecc
+ *     (p <mpi>)
+ *     (a <mpi>)
+ *     (b <mpi>)
+ *     (g <mpi>)
+ *     (n <mpi>)
+ *     (q <mpi>))
+ *
+ * More parameters may be given currently P is needed.  FIXME: We
+ * need allow for a "curve" parameter.
+ */
+static unsigned int
+ecc_get_nbits (gcry_sexp_t parms)
+{
+  gcry_sexp_t l1;
+  gcry_mpi_t p;
+  unsigned int nbits = 0;
+  char *curve;
+
+  l1 = sexp_find_token (parms, "p", 1);
+  if (!l1)
+    { /* Parameter P not found - check whether we have "curve".  */
+      l1 = sexp_find_token (parms, "curve", 5);
+      if (!l1)
+        return 0; /* Neither P nor CURVE found.  */
+
+      curve = sexp_nth_string (l1, 1);
+      sexp_release (l1);
+      if (!curve)
+        return 0;  /* No curve name given (or out of core). */
+
+      if (_gcry_ecc_fill_in_curve (0, curve, NULL, &nbits))
+        nbits = 0;
+      xfree (curve);
+    }
+  else
+    {
+      p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+      sexp_release (l1);
+      if (p)
+        {
+          nbits = mpi_get_nbits (p);
+          _gcry_mpi_release (p);
+        }
+    }
+  return nbits;
+}
 
-  key_buf = mpi_get_secure_buffer (key, &keylength, &sign);     /* convert MPI key to string */
-  cipher_setkey (cipher, key_buf, keylength);
-  wipememory (key_buf, sizeof key_buf); /*  burn temp value  */
-  xfree (key_buf);
 
-  cipher_buf = mpi_get_secure_buffer (input, &nbytes, &sign);   /* convert MPI input to string */
+/* See rsa.c for a description of this function.  */
+static gpg_err_code_t
+compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparms)
+{
+#define N_COMPONENTS 7
+  static const char names[N_COMPONENTS] = "pabgnhq";
+  gpg_err_code_t rc;
+  gcry_sexp_t l1;
+  gcry_mpi_t values[N_COMPONENTS];
+  int idx;
+  char *curvename = NULL;
+  int flags = 0;
+  enum gcry_mpi_ec_models model = 0;
+  enum ecc_dialects dialect = 0;
 
-  cipher_encrypt (cipher, cipher_buf + 1, cipher_buf + 1, nbytes - 1);  /*  */
-  cipher_close (cipher);        /*  destroy and free cipher state. */
+  /* Clear the values first.  */
+  for (idx=0; idx < N_COMPONENTS; idx++)
+    values[idx] = NULL;
 
-  mpi_set_buffer (*output, cipher_buf, nbytes, 0);      /*  convert encrypted string to MPI */
-  wipememory (cipher_buf, sizeof cipher_buf);   /*  burn temp value  */
-  xfree (cipher_buf);
-}
 
-/****************
- * Decrypt input MPI.
- * Use AES256 algorithm.
- */
+  /* Look for flags. */
+  l1 = sexp_find_token (keyparms, "flags", 0);
+  if (l1)
+    {
+      rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL);
+      if (rc)
+        goto leave;
+    }
 
-static void
-aes256_decrypting (gcry_mpi_t key, gcry_mpi_t input, gcry_mpi_t * output)
-{                               /*   */
+  /* Extract the parameters.  */
+  if ((flags & PUBKEY_FLAG_PARAM))
+    {
+      if ((flags & PUBKEY_FLAG_EDDSA))
+        rc = sexp_extract_param (keyparms, NULL, "p?a?b?g?n?h?/q",
+                                 &values[0], &values[1], &values[2],
+                                 &values[3], &values[4], &values[5],
+                                 &values[6], NULL);
+      else
+        rc = sexp_extract_param (keyparms, NULL, "p?a?b?g?n?h?q",
+                                 &values[0], &values[1], &values[2],
+                                 &values[3], &values[4], &values[5],
+                                 &values[6], NULL);
+    }
+  else
+    {
+      if ((flags & PUBKEY_FLAG_EDDSA))
+        rc = sexp_extract_param (keyparms, NULL, "/q",
+                                 &values[6], NULL);
+      else
+        rc = sexp_extract_param (keyparms, NULL, "q",
+                                 &values[6], NULL);
+    }
+  if (rc)
+    goto leave;
+
+  /* Check whether a curve parameter is available and use that to fill
+     in missing values.  */
+  sexp_release (l1);
+  l1 = sexp_find_token (keyparms, "curve", 5);
+  if (l1)
+    {
+      curvename = sexp_nth_string (l1, 1);
+      if (curvename)
+        {
+          rc = _gcry_ecc_update_curve_param (curvename,
+                                             &model, &dialect,
+                                             &values[0], &values[1], &values[2],
+                                             &values[3], &values[4], &values[5]);
+          if (rc)
+            goto leave;
+        }
+    }
 
-  int sign;
-  byte *key_buf;
-  byte *cipher_buf;
+  /* Guess required fields if a curve parameter has not been given.
+     FIXME: This is a crude hacks.  We need to fix that.  */
+  if (!curvename)
+    {
+      model = ((flags & PUBKEY_FLAG_EDDSA)
+               ? MPI_EC_EDWARDS
+               : MPI_EC_WEIERSTRASS);
+      dialect = ((flags & PUBKEY_FLAG_EDDSA)
+                 ? ECC_DIALECT_ED25519
+                 : ECC_DIALECT_STANDARD);
+    }
 
-  unsigned int keylength;
-  unsigned int nbytes;
+  /* Check that all parameters are known and normalize all MPIs (that
+     should not be required but we use an internal function later and
+     thus we better make 100% sure that they are normalized). */
+  for (idx = 0; idx < N_COMPONENTS; idx++)
+    if (!values[idx])
+      {
+        rc = GPG_ERR_NO_OBJ;
+        goto leave;
+      }
+    else
+      _gcry_mpi_normalize (values[idx]);
+
+  /* Uncompress the public key with the exception of EdDSA where
+     compression is the default and we thus compute the keygrip using
+     the compressed version.  Because we don't support any non-eddsa
+     compression, the only thing we need to do is to compress
+     EdDSA.  */
+  if ((flags & PUBKEY_FLAG_EDDSA))
+    {
+      if (dialect == ECC_DIALECT_ED25519)
+        rc = _gcry_ecc_eddsa_ensure_compact (values[6], 256);
+      else
+        rc = GPG_ERR_NOT_IMPLEMENTED;
+      if (rc)
+        goto leave;
+    }
 
+  /* Hash them all.  */
+  for (idx = 0; idx < N_COMPONENTS; idx++)
+    {
+      char buf[30];
 
-  CIPHER_HANDLE cipher = cipher_open (9, CIPHER_MODE_CFB, 1);   /* algo AES256 CFB mode in secure memory */
-  cipher_setiv (cipher, NULL, 0);       /*  Zero IV */
+      if (idx == 5)
+        continue;               /* Skip cofactor. */
 
-  key_buf = mpi_get_secure_buffer (key, &keylength, &sign);     /* convert MPI input to string */
-  cipher_setkey (cipher, key_buf, keylength);
-  wipememory (key_buf, sizeof key_buf); /*  burn temp value  */
-  xfree (key_buf);
+      if (mpi_is_opaque (values[idx]))
+        {
+          const unsigned char *raw;
+          unsigned int n;
+
+          raw = mpi_get_opaque (values[idx], &n);
+          n = (n + 7)/8;
+          snprintf (buf, sizeof buf, "(1:%c%u:", names[idx], n);
+          _gcry_md_write (md, buf, strlen (buf));
+          _gcry_md_write (md, raw, n);
+          _gcry_md_write (md, ")", 1);
+        }
+      else
+        {
+          unsigned char *rawmpi;
+          unsigned int rawmpilen;
 
-  cipher_buf = mpi_get_secure_buffer (input, &nbytes, &sign);   /* convert MPI input to string; */
+          rawmpi = _gcry_mpi_get_buffer (values[idx], 0, &rawmpilen, NULL);
+          if (!rawmpi)
+            {
+              rc = gpg_err_code_from_syserror ();
+              goto leave;
+            }
+          snprintf (buf, sizeof buf, "(1:%c%u:", names[idx], rawmpilen);
+          _gcry_md_write (md, buf, strlen (buf));
+          _gcry_md_write (md, rawmpi, rawmpilen);
+          _gcry_md_write (md, ")", 1);
+          xfree (rawmpi);
+        }
+    }
 
-  cipher_decrypt (cipher, cipher_buf + 1, cipher_buf + 1, nbytes - 1);  /*  */
-  cipher_close (cipher);        /*  destroy and free cipher state. */
+ leave:
+  xfree (curvename);
+  sexp_release (l1);
+  for (idx = 0; idx < N_COMPONENTS; idx++)
+    _gcry_mpi_release (values[idx]);
 
-  mpi_set_buffer (*output, cipher_buf, nbytes, 0);      /*  convert encrypted string to MPI */
-  wipememory (cipher_buf, sizeof cipher_buf);   /*  burn temp value  */
-  xfree (cipher_buf);
+  return rc;
+#undef N_COMPONENTS
 }
 
-/* End of IFP ECElGamal weakness functions. */
-#endif /*0*/
 
-/*********************************************
- **************  interface  ******************
- *********************************************/
+\f
+/*
+   Low-level API helper functions.
+ */
 
-static gcry_err_code_t
-ecc_generate (int algo, unsigned int nbits, unsigned long dummy,
-              gcry_mpi_t *skey, gcry_mpi_t **retfactors)
+/* This is the worker function for gcry_pubkey_get_sexp for ECC
+   algorithms.  Note that the caller has already stored NULL at
+   R_SEXP.  */
+gpg_err_code_t
+_gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, mpi_ec_t ec)
 {
-  gpg_err_code_t err;
-  ECC_secret_key sk;
+  gpg_err_code_t rc;
+  gcry_mpi_t mpi_G = NULL;
+  gcry_mpi_t mpi_Q = NULL;
 
-  (void)algo;
+  if (!ec->p || !ec->a || !ec->b || !ec->G || !ec->n || !ec->h)
+    return GPG_ERR_BAD_CRYPT_CTX;
 
-  /* Make an empty list of factors.  */
-  *retfactors = gcry_calloc ( 1, sizeof **retfactors );
-  if (!*retfactors)
-    return gpg_err_code_from_syserror ();
+  if (mode == GCRY_PK_GET_SECKEY && !ec->d)
+    return GPG_ERR_NO_SECKEY;
 
-  err = generate_key (&sk, nbits);
-  if (err)
+  /* Compute the public point if it is missing.  */
+  if (!ec->Q && ec->d)
+    ec->Q = _gcry_ecc_compute_public (NULL, ec, NULL, NULL);
+
+  /* Encode G and Q.  */
+  mpi_G = _gcry_mpi_ec_ec2os (ec->G, ec);
+  if (!mpi_G)
     {
-      gcry_free (*retfactors);
-      *retfactors = NULL;
-      return err;
+      rc = GPG_ERR_BROKEN_PUBKEY;
+      goto leave;
     }
-
-  skey[0] = sk.E.p_;
-  skey[1] = sk.E.a_;
-  skey[2] = sk.E.b_;
-  skey[3] = sk.E.G.x_;
-  skey[4] = sk.E.G.y_;
-  skey[5] = sk.E.G.z_;
-  skey[6] = sk.E.n_;
-  skey[7] = sk.Q.x_;
-  skey[8] = sk.Q.y_;
-  skey[9] = sk.Q.z_;
-  skey[10] = sk.d;
-
-  if (DBG_CIPHER)
+  if (!ec->Q)
     {
-      progress ('\n');
-
-      log_mpidump ("[ecc]  p= ", skey[0]);
-      log_mpidump ("[ecc]  a= ", skey[1]);
-      log_mpidump ("[ecc]  b= ", skey[2]);
-      log_mpidump ("[ecc]  Gx= ", skey[3]);
-      log_mpidump ("[ecc]  Gy= ", skey[4]);
-      log_mpidump ("[ecc]  Gz= ", skey[5]);
-      log_mpidump ("[ecc]  n= ", skey[6]);
-      log_mpidump ("[ecc]  Qx= ", skey[7]);
-      log_mpidump ("[ecc]  Qy= ", skey[8]);
-      log_mpidump ("[ecc]  Qz= ", skey[9]);
-      log_mpidump ("[ecc]  d= ", skey[10]);
+      rc = GPG_ERR_BAD_CRYPT_CTX;
+      goto leave;
     }
 
-  if (DBG_CIPHER)
+  if (ec->dialect == ECC_DIALECT_ED25519)
     {
-      log_debug ("ECC key Generated.\n");
+      unsigned char *encpk;
+      unsigned int encpklen;
+
+      rc = _gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL, 0,
+                                        &encpk, &encpklen);
+      if (rc)
+        goto leave;
+      mpi_Q = mpi_set_opaque (NULL, encpk, encpklen*8);
+      encpk = NULL;
     }
-  return 0;
-}
-
-
-static gcry_err_code_t
-ecc_check_secret_key (int algo, gcry_mpi_t *skey)
-{
-  ECC_secret_key sk;
-
-  (void)algo;
-
-  if (!skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] || !skey[5]
-      || !skey[6] || !skey[7] || !skey[8] || !skey[9] || !skey[10])
-    return GPG_ERR_BAD_MPI;
-
-  if (DBG_CIPHER)
+  else
     {
-      log_debug ("ECC check secret key.\n");
+      mpi_Q = _gcry_mpi_ec_ec2os (ec->Q, ec);
     }
-  sk.E.p_ = skey[0];
-  sk.E.a_ = skey[1];
-  sk.E.b_ = skey[2];
-  sk.E.G.x_ = skey[3];
-  sk.E.G.y_ = skey[4];
-  sk.E.G.z_ = skey[5];
-  sk.E.n_ = skey[6];
-  sk.Q.x_ = skey[7];
-  sk.Q.y_ = skey[8];
-  sk.Q.z_ = skey[9];
-  sk.d = skey[10];
-
-  if (check_secret_key (&sk))
+  if (!mpi_Q)
     {
-      if (DBG_CIPHER)
-        log_debug ("Bad check: Bad secret key.\n");
-      return GPG_ERR_BAD_SECKEY;
+      rc = GPG_ERR_BROKEN_PUBKEY;
+      goto leave;
     }
-  return 0;
-}
 
+  /* Fixme: We should return a curve name instead of the parameters if
+     if know that they match a curve.  */
 
-#if 0
-static int
-ecc_encrypt_FIXME (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, gcry_mpi_t * pkey)
-{
-  ECC_public_key pk;
-  point R;
-
-  if (algo != PUBKEY_ALGO_ECC && algo != PUBKEY_ALGO_ECC_E)
-    return G10ERR_PUBKEY_ALGO;
-  if (!data || !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] || !pkey[4]
-      || !pkey[5] || !pkey[6] || !pkey[7] || !pkey[8] || !pkey[9])
-    return G10ERR_BAD_MPI;
-
-  if (DBG_CIPHER)
+  if (ec->d && (!mode || mode == GCRY_PK_GET_SECKEY))
     {
-      log_debug ("ECC encrypt.\n");
-    }
-  pk.E.p_ = pkey[0];
-  pk.E.a_ = pkey[1];
-  pk.E.b_ = pkey[2];
-  pk.E.G.x_ = pkey[3];
-  pk.E.G.y_ = pkey[4];
-  pk.E.G.z_ = pkey[5];
-  pk.E.n_ = pkey[6];
-  pk.Q.x_ = pkey[7];
-  pk.Q.y_ = pkey[8];
-  pk.Q.z_ = pkey[9];
-
-  R.x_ = resarr[0] = mpi_alloc (mpi_get_nlimbs (pk.Q.x_));
-  R.y_ = resarr[1] = mpi_alloc (mpi_get_nlimbs (pk.Q.y_));
-  R.z_ = resarr[2] = mpi_alloc (mpi_get_nlimbs (pk.Q.z_));
-  resarr[3] = mpi_alloc (mpi_get_nlimbs (pk.E.p_));
-
-  doEncrypt (data, &pk, &R, resarr[3]);
-
-  resarr[0] = mpi_copy (R.x_);
-  resarr[1] = mpi_copy (R.y_);
-  resarr[2] = mpi_copy (R.z_);
-  return 0;
+      /* Let's return a private key. */
+      rc = sexp_build (r_sexp, NULL,
+                       "(private-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(h%m)(q%m)(d%m)))",
+                       ec->p, ec->a, ec->b, mpi_G, ec->n, ec->h, mpi_Q, ec->d);
+    }
+  else if (ec->Q)
+    {
+      /* Let's return a public key.  */
+      rc = sexp_build (r_sexp, NULL,
+                       "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(h%m)(q%m)))",
+                       ec->p, ec->a, ec->b, mpi_G, ec->n, ec->h, mpi_Q);
+    }
+  else
+    rc = GPG_ERR_BAD_CRYPT_CTX;
+
+ leave:
+  mpi_free (mpi_Q);
+  mpi_free (mpi_G);
+  return rc;
 }
 
-int
-ecc_decrypt_FIXME (int algo, gcry_mpi_t * result, gcry_mpi_t * data, gcry_mpi_t * skey)
-{
-  ECC_secret_key sk;
-  point R;
 
-  if (algo != PUBKEY_ALGO_ECC && algo != PUBKEY_ALGO_ECC_E)
-    return G10ERR_PUBKEY_ALGO;
-  if (!data[0] || !data[1] || !data[2] || !data[3] || !skey[0] || !skey[1]
-      || !skey[2] || !skey[3] || !skey[4] || !skey[5] || !skey[6] || !skey[7]
-      || !skey[8] || !skey[9] || !skey[10])
-    return G10ERR_BAD_MPI;
+\f
+/*
+     Self-test section.
+ */
 
-  if (DBG_CIPHER)
-    {
-      log_debug ("ECC decrypt.\n");
-    }
-  R.x_ = data[0];
-  R.y_ = data[1];
-  R.z_ = data[2];
-  sk.E.p_ = skey[0];
-  sk.E.a_ = skey[1];
-  sk.E.b_ = skey[2];
-  sk.E.G.x_ = skey[3];
-  sk.E.G.y_ = skey[4];
-  sk.E.G.z_ = skey[5];
-  sk.E.n_ = skey[6];
-  sk.Q.x_ = skey[7];
-  sk.Q.y_ = skey[8];
-  sk.Q.z_ = skey[9];
-  sk.d = skey[10];
-
-  *result = mpi_alloc_secure (mpi_get_nlimbs (sk.E.p_));
-  *result = decrypt (*result, &sk, R, data[3]);
-  return 0;
-}
-#endif /*0*/
 
-static gcry_err_code_t
-ecc_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey)
+static gpg_err_code_t
+selftests_ecdsa (selftest_report_func_t report)
 {
-  gpg_err_code_t err;
-  ECC_secret_key sk;
-
-  (void)algo;
-
-  if (!data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4]
-      || !skey[5] || !skey[6] || !skey[7] || !skey[8] || !skey[9]
-      || !skey[10])
-    return GPG_ERR_BAD_MPI;
-
-  sk.E.p_ = skey[0];
-  sk.E.a_ = skey[1];
-  sk.E.b_ = skey[2];
-  sk.E.G.x_ = skey[3];
-  sk.E.G.y_ = skey[4];
-  sk.E.G.z_ = skey[5];
-  sk.E.n_ = skey[6];
-  sk.Q.x_ = skey[7];
-  sk.Q.y_ = skey[8];
-  sk.Q.z_ = skey[9];
-  sk.d = skey[10];
-
-  resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.E.p_));
-  resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.E.p_));
-  err = sign (data, &sk, resarr[0], resarr[1]);
-  if (err)
-    {
-      mpi_free (resarr[0]);
-      mpi_free (resarr[1]);
-      resarr[0] = NULL; /* Mark array as released.  */
-    }
-  return err;
-}
+  const char *what;
+  const char *errtxt;
 
-static gcry_err_code_t
-ecc_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
-            int (*cmp)(void *, gcry_mpi_t), void *opaquev)
-{
-  ECC_public_key pk;
+  what = "low-level";
+  errtxt = NULL; /*selftest ();*/
+  if (errtxt)
+    goto failed;
 
-  (void)algo;
+  /* FIXME:  need more tests.  */
 
-  if (!data[0] || !data[1] || !hash || !pkey[0] || !pkey[1] || !pkey[2]
-      || !pkey[3] || !pkey[4] || !pkey[5] || !pkey[6] || !pkey[7] || !pkey[8]
-      || !pkey[9])
-    return GPG_ERR_BAD_MPI;
+  return 0; /* Succeeded. */
 
-  if (DBG_CIPHER)
-    log_debug ("ECC verify.\n");
-  pk.E.p_ = pkey[0];
-  pk.E.a_ = pkey[1];
-  pk.E.b_ = pkey[2];
-  pk.E.G.x_ = pkey[3];
-  pk.E.G.y_ = pkey[4];
-  pk.E.G.z_ = pkey[5];
-  pk.E.n_ = pkey[6];
-  pk.Q.x_ = pkey[7];
-  pk.Q.y_ = pkey[8];
-  pk.Q.z_ = pkey[9];
-
-  return verify (hash, &pk, data[0], data[1]);
+ failed:
+  if (report)
+    report ("pubkey", GCRY_PK_ECC, what, errtxt);
+  return GPG_ERR_SELFTEST_FAILED;
 }
 
 
-
-static unsigned int
-ecc_get_nbits (int algo, gcry_mpi_t *pkey)
+/* Run a full self-test for ALGO and return 0 on success.  */
+static gpg_err_code_t
+run_selftests (int algo, int extended, selftest_report_func_t report)
 {
-  (void)algo;
+  (void)extended;
 
-  if (DBG_CIPHER)
-    {
-      log_debug ("ECC get nbits.\n");
-    }
+  if (algo != GCRY_PK_ECC)
+    return GPG_ERR_PUBKEY_ALGO;
 
-  if (DBG_CIPHER)
-    {
-      progress ('\n');
-
-      log_mpidump ("[ecc]  p= ", pkey[0]);
-      log_mpidump ("[ecc]  a= ", pkey[1]);
-      log_mpidump ("[ecc]  b= ", pkey[2]);
-      log_mpidump ("[ecc]  Gx= ", pkey[3]);
-      log_mpidump ("[ecc]  Gy= ", pkey[4]);
-      log_mpidump ("[ecc]  Gz= ", pkey[5]);
-      log_mpidump ("[ecc]  n= ", pkey[6]);
-      log_mpidump ("[ecc]  Qx= ", pkey[7]);
-      log_mpidump ("[ecc]  Qy= ", pkey[8]);
-      log_mpidump ("[ecc]  Qz= ", pkey[9]);
-    }
-
-  return mpi_get_nbits (pkey[0]);
+  return selftests_ecdsa (report);
 }
 
 
-static const char *ecdsa_names[] =
-  {
-    "ecdsa",
-    NULL,
-  };
 
-gcry_pk_spec_t _gcry_pubkey_spec_ecdsa =
+\f
+gcry_pk_spec_t _gcry_pubkey_spec_ecc =
   {
-    "ECDSA", ecdsa_names, 
-    "pabxyznXYZ", "pabxyznXYZd", "", "rs", "pabxyznXYZ",
-    GCRY_PK_USAGE_SIGN,
+    GCRY_PK_ECC, { 0, 0 },
+    (GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR),
+    "ECC", ecc_names,
+    "pabgnhq", "pabgnhqd", "sw", "rs", "pabgnhq",
     ecc_generate,
     ecc_check_secret_key,
-    NULL,
-    NULL,
+    ecc_encrypt_raw,
+    ecc_decrypt_raw,
     ecc_sign,
     ecc_verify,
-    ecc_get_nbits
+    ecc_get_nbits,
+    run_selftests,
+    compute_keygrip,
+    _gcry_ecc_get_curve,
+    _gcry_ecc_get_param_sexp
   };
-
-
-