ecc: Fix a minor flaw in the generation of K.
[libgcrypt.git] / cipher / ecc.c
index 6f65070..63ee2d0 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:
 
-*/
+  - If we support point compression we need to uncompress before
+    computing the keygrip
 
-/* 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)
- */
+  - 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.
+
+  - Split this up into several files.  For example the curve
+    management and gcry_mpi_ec_new are independent of the actual ECDSA
+    implementation.  This will also help to support optimized versions
+    of some curves.
+
+*/
 
-/*
- * 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;
-
+#include "context.h"
+#include "ec-context.h"
+#include "pubkey-internal.h"
 
 /* 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 */
+  gcry_mpi_t p;         /* Prime specifying the field GF(p).  */
+  gcry_mpi_t a;         /* First coefficient of the Weierstrass equation.  */
+  gcry_mpi_t b;         /* Second coefficient of the Weierstrass equation.  */
+  mpi_point_struct G;   /* Base point (generator).  */
+  gcry_mpi_t n;         /* Order of G.  */
+  const char *name;     /* Name of the curve or NULL.  */
+} elliptic_curve_t;
 
 
 typedef struct
 {
   elliptic_curve_t E;
-  point_t Q;                    /* Q=[d]G */
-} ECC_public_key;               /* Q */
+  mpi_point_struct Q; /* Q = [d]G  */
+} ECC_public_key;
 
 typedef struct
 {
   elliptic_curve_t E;
-  point_t Q;                    /* Q=[d]G */
+  mpi_point_struct Q;
   gcry_mpi_t d;
-} ECC_secret_key;               /* d */
+} ECC_secret_key;
 
 
-/* This static table defines all available curves.  */
+/* This tables defines aliases for curve names.  */
 static const struct
 {
+  const char *name;  /* Our name.  */
+  const char *other; /* Other name. */
+} curve_aliases[] =
+  {
+    { "NIST P-192", "1.2.840.10045.3.1.1" }, /* X9.62 OID  */
+    { "NIST P-192", "prime192v1" },          /* X9.62 name.  */
+    { "NIST P-192", "secp192r1"  },          /* SECP name.  */
+    { "NIST P-192", "nistp192"   },          /* rfc5656.  */
+
+    { "NIST P-224", "secp224r1" },
+    { "NIST P-224", "1.3.132.0.33" },        /* SECP OID.  */
+    { "NIST P-224", "nistp224"   },          /* rfc5656.  */
+
+    { "NIST P-256", "1.2.840.10045.3.1.7" }, /* From NIST SP 800-78-1.  */
+    { "NIST P-256", "prime256v1" },
+    { "NIST P-256", "secp256r1"  },
+    { "NIST P-256", "nistp256"   },          /* rfc5656.  */
+
+    { "NIST P-384", "secp384r1" },
+    { "NIST P-384", "1.3.132.0.34" },
+    { "NIST P-384", "nistp384"   },          /* rfc5656.  */
+
+    { "NIST P-521", "secp521r1" },
+    { "NIST P-521", "1.3.132.0.35" },
+    { "NIST P-521", "nistp521"   },          /* rfc5656.  */
+
+    { "brainpoolP160r1", "1.3.36.3.3.2.8.1.1.1" },
+    { "brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3" },
+    { "brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5" },
+    { "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7" },
+    { "brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9" },
+    { "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11"},
+    { "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13"},
+
+    { NULL, NULL}
+  };
+
+typedef 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[] = 
+  unsigned int fips:1;        /* True if this is a FIPS140-2 approved curve. */
+  const char  *p;             /* Order of the prime field.  */
+  const char *a, *b;          /* The coefficients. */
+  const char *n;              /* The order of the base point.  */
+  const char *g_x, *g_y;      /* Base point.  */
+} ecc_domain_parms_t;
+
+/* This static table defines all available curves.  */
+static const ecc_domain_parms_t domain_parms[] =
   {
-    { 
-      "NIST P-192", 192,
+    {
+      "NIST P-192", 192, 1,
       "0xfffffffffffffffffffffffffffffffeffffffffffffffff",
       "0xfffffffffffffffffffffffffffffffefffffffffffffffc",
       "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
       "0xffffffffffffffffffffffff99def836146bc9b1b4d22831",
-      
+
       "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
       "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"
     },
-    { 
-      "NIST P-224", 224,
+    {
+      "NIST P-224", 224, 1,
       "0xffffffffffffffffffffffffffffffff000000000000000000000001",
       "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe",
       "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
@@ -150,22 +167,22 @@ static const struct
       "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
       "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"
     },
-    { 
-      "NIST P-256", 256,
+    {
+      "NIST P-256", 256, 1,
       "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
       "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc",
       "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
       "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
-      
+
       "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
       "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
     },
     {
-      "NIST P-384", 384,
+      "NIST P-384", 384, 1,
       "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
       "ffffffff0000000000000000ffffffff",
       "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
-      "ffffffff0000000000000000fffffffc",  
+      "ffffffff0000000000000000fffffffc",
       "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a"
       "c656398d8a2ed19d2a85c8edd3ec2aef",
       "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf"
@@ -177,7 +194,7 @@ static const struct
       "0a60b1ce1d7e819d7a431d7c90ea0e5f"
     },
     {
-      "NIST P-521", 521,
+      "NIST P-521", 521, 1,
       "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
       "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
       "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
@@ -192,7 +209,89 @@ static const struct
       "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e6"
       "62c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"
     },
-    { NULL, 0, NULL, NULL, NULL, NULL }
+
+    { "brainpoolP160r1", 160, 0,
+      "0xe95e4a5f737059dc60dfc7ad95b3d8139515620f",
+      "0x340e7be2a280eb74e2be61bada745d97e8f7c300",
+      "0x1e589a8595423412134faa2dbdec95c8d8675e58",
+      "0xe95e4a5f737059dc60df5991d45029409e60fc09",
+      "0xbed5af16ea3f6a4f62938c4631eb5af7bdbcdbc3",
+      "0x1667cb477a1a8ec338f94741669c976316da6321"
+    },
+
+    { "brainpoolP192r1", 192, 0,
+      "0xc302f41d932a36cda7a3463093d18db78fce476de1a86297",
+      "0x6a91174076b1e0e19c39c031fe8685c1cae040e5c69a28ef",
+      "0x469a28ef7c28cca3dc721d044f4496bcca7ef4146fbf25c9",
+      "0xc302f41d932a36cda7a3462f9e9e916b5be8f1029ac4acc1",
+      "0xc0a0647eaab6a48753b033c56cb0f0900a2f5c4853375fd6",
+      "0x14b690866abd5bb88b5f4828c1490002e6773fa2fa299b8f"
+    },
+
+    { "brainpoolP224r1", 224, 0,
+      "0xd7c134aa264366862a18302575d1d787b09f075797da89f57ec8c0ff",
+      "0x68a5e62ca9ce6c1c299803a6c1530b514e182ad8b0042a59cad29f43",
+      "0x2580f63ccfe44138870713b1a92369e33e2135d266dbb372386c400b",
+      "0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939f",
+      "0x0d9029ad2c7e5cf4340823b2a87dc68c9e4ce3174c1e6efdee12c07d",
+      "0x58aa56f772c0726f24c6b89e4ecdac24354b9e99caa3f6d3761402cd"
+    },
+
+    { "brainpoolP256r1", 256, 0,
+      "0xa9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5377",
+      "0x7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9",
+      "0x26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6",
+      "0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7",
+      "0x8bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262",
+      "0x547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f046997"
+    },
+
+    { "brainpoolP320r1", 320, 0,
+      "0xd35e472036bc4fb7e13c785ed201e065f98fcfa6f6f40def4f92b9ec7893ec28"
+      "fcd412b1f1b32e27",
+      "0x3ee30b568fbab0f883ccebd46d3f3bb8a2a73513f5eb79da66190eb085ffa9f4"
+      "92f375a97d860eb4",
+      "0x520883949dfdbc42d3ad198640688a6fe13f41349554b49acc31dccd88453981"
+      "6f5eb4ac8fb1f1a6",
+      "0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e9"
+      "8691555b44c59311",
+      "0x43bd7e9afb53d8b85289bcc48ee5bfe6f20137d10a087eb6e7871e2a10a599c7"
+      "10af8d0d39e20611",
+      "0x14fdd05545ec1cc8ab4093247f77275e0743ffed117182eaa9c77877aaac6ac7"
+      "d35245d1692e8ee1"
+    },
+
+    { "brainpoolP384r1", 384, 0,
+      "0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123"
+      "acd3a729901d1a71874700133107ec53",
+      "0x7bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f"
+      "8aa5814a503ad4eb04a8c7dd22ce2826",
+      "0x04a8c7dd22ce28268b39b55416f0447c2fb77de107dcd2a62e880ea53eeb62d5"
+      "7cb4390295dbc9943ab78696fa504c11",
+      "0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7"
+      "cf3ab6af6b7fc3103b883202e9046565",
+      "0x1d1c64f068cf45ffa2a63a81b7c13f6b8847a3e77ef14fe3db7fcafe0cbd10e8"
+      "e826e03436d646aaef87b2e247d4af1e",
+      "0x8abe1d7520f9c2a45cb1eb8e95cfd55262b70b29feec5864e19c054ff9912928"
+      "0e4646217791811142820341263c5315"
+    },
+
+    { "brainpoolP512r1", 512, 0,
+      "0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330871"
+      "7d4d9b009bc66842aecda12ae6a380e62881ff2f2d82c68528aa6056583a48f3",
+      "0x7830a3318b603b89e2327145ac234cc594cbdd8d3df91610a83441caea9863bc"
+      "2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94ca",
+      "0x3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a7"
+      "2bf2c7b9e7c1ac4d77fc94cadc083e67984050b75ebae5dd2809bd638016f723",
+      "0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870"
+      "553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90069",
+      "0x81aee4bdd82ed9645a21322e9c4c6a9385ed9f70b5d916c1b43b62eef4d0098e"
+      "ff3b1f78e2d0d48d50d1687b93b97d5f7c6d5047406a5e688b352209bcb9f822",
+      "0x7dde385d566332ecc0eabfa9cf7822fdf209f70024a57b1aa000c55b881f8111"
+      "b2dcde494a5f485e5bca4bd88a2763aed1ca2b2fa8f0540678cd1e0f3ad80892"
+    },
+
+    { NULL, 0, 0, NULL, NULL, NULL, NULL }
   };
 
 
@@ -201,20 +300,20 @@ static void (*progress_cb) (void *, const char*, int, int, int);
 static void *progress_cb_data;
 
 
+#define point_init(a)  _gcry_mpi_point_init ((a))
+#define point_free(a)  _gcry_mpi_point_free_parts ((a))
+
 
 \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, 
+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);
 
 
@@ -229,60 +328,23 @@ _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
-
- */
-
-/* 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);
-}
 
-
-/*
- * Release a point object.
- */
+/* Set the value from S into D.  */
 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;
-}
-
-
-/*
- * Return a copy of a point object.
- */
-static point_t
-point_copy (point_t P)
+point_set (mpi_point_t d, mpi_point_t s)
 {
-  point_t R;
-
-  R.x_ = mpi_copy (P.x_);
-  R.y_ = mpi_copy (P.y_);
-  R.z_ = mpi_copy (P.z_);
-
-  return R;
+  mpi_set (d->x, s->x);
+  mpi_set (d->y, s->y);
+  mpi_set (d->z, s->z);
 }
 
 
@@ -292,11 +354,11 @@ point_copy (point_t P)
 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;
+  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;
+  mpi_free (E->n);  E->n = NULL;
 }
 
 
@@ -308,1703 +370,1790 @@ curve_copy (elliptic_curve_t E)
 {
   elliptic_curve_t R;
 
-  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_);
+  R.p = mpi_copy (E.p);
+  R.a = mpi_copy (E.a);
+  R.b = mpi_copy (E.b);
+  point_init (&R.G);
+  point_set (&R.G, &E.G);
+  R.n = mpi_copy (E.n);
 
   return R;
 }
 
 
-\f
-/*
+/* 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;
+}
 
-    A D D I T I O N A L   M P I   F U N C T I O N S
 
- */
 
+\f
 
 /****************
- * 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.
+ * Solve the right side of the equation that defines a curve.
  */
-#if 0
 static gcry_mpi_t
-exist_square_root (gcry_mpi_t integer, gcry_mpi_t modulus)
+gen_y_2 (gcry_mpi_t x, elliptic_curve_t *base)
 {
-  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;
+  gcry_mpi_t three, x_3, axb, y;
 
-  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));
+  x_3 = mpi_new (0);
+  axb = mpi_new (0);
+  y   = mpi_new (0);
 
-  if (DBG_CIPHER)
-    log_mpidump ("?exist Square Root of ", integer);
+  mpi_powm (x_3, x, three, base->p);
+  mpi_mulm (axb, base->a, x, base->p);
+  mpi_addm (axb, axb, base->b, base->p);
+  mpi_addm (y, x_3, axb, base->p);
 
-  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)
+  mpi_free (x_3);
+  mpi_free (axb);
+  mpi_free (three);
+  return y; /* The quadratic value of the coordinate if it exist. */
+}
+
+
+/* Generate the crypto system setup.  This function takes the NAME of
+   a curve or the desired number of bits and stores at R_CURVE the
+   parameters of the named curve or those of a suitable curve.  If
+   R_NBITS is not NULL, the chosen number of bits is stored there.  */
+static gpg_err_code_t
+fill_in_curve (unsigned int nbits, const char *name,
+               elliptic_curve_t *curve, unsigned int *r_nbits)
+{
+  int idx, aliasno;
+  const char *resname = NULL; /* Set to a found curve name.  */
+
+  if (name)
+    {
+      /* First check our native curves.  */
+      for (idx = 0; domain_parms[idx].desc; idx++)
+        if (!strcmp (name, domain_parms[idx].desc))
+          {
+            resname = domain_parms[idx].desc;
+            break;
+          }
+      /* If not found consult the alias table.  */
+      if (!domain_parms[idx].desc)
         {
-          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)
+          for (aliasno = 0; curve_aliases[aliasno].name; aliasno++)
+            if (!strcmp (name, curve_aliases[aliasno].other))
+              break;
+          if (curve_aliases[aliasno].name)
             {
-              if (DBG_CIPHER)
-                log_debug ("Rejected.\n");
-              return (0);       /* NULL */
+              for (idx = 0; domain_parms[idx].desc; idx++)
+                if (!strcmp (curve_aliases[aliasno].name,
+                             domain_parms[idx].desc))
+                  {
+                    resname = domain_parms[idx].desc;
+                    break;
+                  }
             }
-          if (DBG_CIPHER)
-            log_debug ("Another loop.\n");
         }
     }
-  if (DBG_CIPHER)
-    log_debug ("iterations limit.\n");
-  return (0);                   /* because this algorithm not always finish. */
+  else
+    {
+      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;
+
+  /* In fips mode we only support NIST curves.  Note that it is
+     possible to bypass this check by specifying the curve parameters
+     directly.  */
+  if (fips_mode () && !domain_parms[idx].fips )
+    return GPG_ERR_NOT_SUPPORTED;
+
+  if (r_nbits)
+    *r_nbits = domain_parms[idx].nbits;
+  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);
+  curve->name = resname;
+
+  return 0;
 }
-#endif /*0*/
 
-/****************
- * Formal definition:
- * V_0 = 2; V_1 = p
- * V_k = (p*V_(k-1)) - (q*V_(k-2))   for k >= 2
+
+/*
+ * First obtain the setup.  Over the finite field randomize an scalar
+ * secret value, and calculate the public point.
  */
-#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)
+static gpg_err_code_t
+generate_key (ECC_secret_key *sk, unsigned int nbits, const char *name,
+              int transient_key,
+              gcry_mpi_t g_x, gcry_mpi_t g_y,
+              gcry_mpi_t q_x, gcry_mpi_t q_y,
+              const char **r_usedcurve)
 {
+  gpg_err_code_t err;
+  elliptic_curve_t E;
+  gcry_mpi_t d;
+  mpi_point_struct Q;
+  mpi_ec_t ctx;
+  gcry_random_level_t random_level;
 
-  gcry_mpi_t v0, v1, q0, q1;
-  gcry_mpi_t t1, t2;
-  unsigned int r, i;
+  *r_usedcurve = NULL;
 
-  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);
+  err = fill_in_curve (nbits, name, &E, &nbits);
+  if (err)
+    return err;
 
   if (DBG_CIPHER)
     {
-      log_debug ("Generating lucas sequence.\n");
-      log_mpidump ("k=", k);
+      log_mpidump ("ecgen curve  p", E.p);
+      log_mpidump ("ecgen curve  a", E.a);
+      log_mpidump ("ecgen curve  b", E.b);
+      log_mpidump ("ecgen curve  n", E.n);
+      log_mpidump ("ecgen curve Gx", E.G.x);
+      log_mpidump ("ecgen curve Gy", E.G.y);
+      log_mpidump ("ecgen curve Gz", E.G.z);
+      if (E.name)
+        log_debug   ("ecgen curve used: %s\n", E.name);
     }
 
-  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 (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++;
-    }
-  V_n = mpi_copy (v0);
-  Q_0 = mpi_copy (q0);
-  if (DBG_CIPHER)
-    {
-      log_debug ("Lucas sequence generated.\n");
-      log_mpidump ("V_n=", V_n);
-      log_mpidump ("Q_0=", Q_0);
-    }
-}
-#endif /*0*/
+  random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM;
+  d = _gcry_dsa_gen_k (E.n, random_level);
 
-\f
-/* 
+  /* Compute Q.  */
+  point_init (&Q);
+  ctx = _gcry_mpi_ec_p_internal_new (E.p, E.a);
+  _gcry_mpi_ec_mul_point (&Q, d, &E.G, ctx);
 
-   P O I N T   A N D   C U R V E   O P E R A T I O N S
+  /* 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);
+  point_init (&sk->E.G);
+  point_set (&sk->E.G, &E.G);
+  sk->E.n = mpi_copy (E.n);
+  point_init (&sk->Q);
+
+  /* We want the Q=(x,y) be a "compliant key" in terms of the
+   * 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.  */
+  {
+    gcry_mpi_t x, p_y, y;
+    const unsigned int nbits = mpi_get_nbits (E.p);
 
- */
+    x = mpi_new (nbits);
+    p_y = mpi_new (nbits);
+    y = mpi_new (nbits);
 
-/* 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 ( /*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;
-    }
-  return 0;  /* It is a valid curve point, but not the point at infinity.  */
-}
+    if (_gcry_mpi_ec_get_affine (x, y, &Q, ctx))
+      log_fatal ("ecgen: Failed to get affine coordinates for Q\n");
 
+    mpi_sub( p_y, E.p, y );    /* p_y = p-y */
 
-/*
- * 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.
- */
-static int
-point_affine (point_t *P, gcry_mpi_t x, gcry_mpi_t y, elliptic_curve_t *base)
-{
-  gcry_mpi_t z1, z2, z3;
+    if (mpi_cmp( p_y /*p-y*/, y ) < 0) /* is p-y < p ? */
+      {
+        gcry_mpi_t z = mpi_copy (mpi_const (MPI_C_ONE));
+
+        /* log_mpidump ("ecgen p-y", p_y); */
+        /* log_mpidump ("ecgen y  ", y); */
+        /* log_debug   ("ecgen will replace y with p-y\n"); */
+        /* log_mpidump ("ecgen d before", d); */
+
+        /* We need to end up with -Q; this assures that new Q's y is
+           the smallest one */
+        sk->d = mpi_new (nbits);
+        mpi_sub (sk->d, E.n, d);  /* d = order-d */
+        /* log_mpidump ("ecgen d after ", sk->d); */
+       gcry_mpi_point_set (&sk->Q, x, p_y/*p-y*/, z);  /* Q = -Q */
+        if (DBG_CIPHER)
+          log_debug ("ecgen converted Q to a compliant point\n");
+        mpi_free (z);
+      }
+    else
+      {
+        /* No change is needed exactly 50% of the time: just copy. */
+        sk->d = mpi_copy (d);
+       point_set (&sk->Q, &Q);
+        if (DBG_CIPHER)
+          log_debug ("ecgen didn't need to convert Q to a compliant point\n");
+      }
+    mpi_free (x);
+    mpi_free (p_y);
+    mpi_free (y);
+  }
 
-  if (point_at_infinity (*P))
+  /* We also return copies of G and Q in affine coordinates if
+     requested.  */
+  if (g_x && g_y)
     {
-      if (DBG_CIPHER)
-        log_debug ("ecc point_affine: "
-                   "Point at Infinity does NOT exist in the affine plane!\n");
-      return 1;
+      if (_gcry_mpi_ec_get_affine (g_x, g_y, &sk->E.G, ctx))
+        log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "G");
+    }
+  if (q_x && q_y)
+    {
+      if (_gcry_mpi_ec_get_affine (q_x, q_y, &sk->Q, ctx))
+        log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q");
     }
+  _gcry_mpi_ec_free (ctx);
 
-  z1 = mpi_new (0);
-  z2 = mpi_new (0);
-  z3 = mpi_new (0);
+  point_free (&Q);
+  mpi_free (d);
+
+  *r_usedcurve = E.name;
+  curve_free (&E);
 
-  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_);
+  /* Now we can test our keys (this should never fail!).  */
+  test_keys (sk, nbits - 64);
 
-  mpi_free (z1);
-  mpi_free (z2);
-  mpi_free (z3);
   return 0;
 }
 
 
 /*
- * The point inversion over F_p is a simple modular inversion of the Y
- * coordinate.
+ * 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
-invert_point (point_t *P, elliptic_curve_t *base)
+test_keys (ECC_secret_key *sk, unsigned int nbits)
 {
-  mpi_subm (P->y_, base->p_, P->y_, base->p_);  /* y = p - y mod p */
-}
+  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);
 
+  if (DBG_CIPHER)
+    log_debug ("Testing key.\n");
 
-/*
- * 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;
+  point_init (&R_);
 
-  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);
-    }
-  else
+  pk.E = curve_copy (sk->E);
+  point_init (&pk.Q);
+  point_set (&pk.Q, &sk->Q);
+
+  gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
+
+  if (sign (test, sk, r, s) )
+    log_fatal ("ECDSA operation: sign failed\n");
+
+  if (verify (test, &pk, r, s))
     {
-      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 */
-        }
-      else
-        {
-          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 */
-        }
-      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);
+      log_fatal ("ECDSA operation: sign, verify failed\n");
     }
 
-  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);
+  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);
 }
 
 
 /*
-   Point addition is the group operation.
-
-   R = P0 + P1
+ * To check the validity of the value, recalculate the correspondence
+ * between the public value and the secret one.
  */
-static void
-sum_points (point_t *R, point_t *P0, point_t *P1, elliptic_curve_t * base)
+static int
+check_secret_key (ECC_secret_key * sk)
 {
-  gcry_mpi_t one, two;
-  gcry_mpi_t p;
-  gcry_mpi_t t1, t2, t3, t4, t5, t6, t7;
-  unsigned int nbits;
+  int rc = 1;
+  mpi_point_struct Q;
+  gcry_mpi_t y_2, y2;
+  mpi_ec_t ctx = NULL;
 
-  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_);
+  point_init (&Q);
+
+  /* ?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 */
+  y2 = mpi_alloc (0);
+  mpi_mulm (y2, sk->E.G.y, sk->E.G.y, sk->E.p);      /*  y^2=y*y */
+  if (mpi_cmp (y_2, y2))
+    {
+      if (DBG_CIPHER)
+        log_debug ("Bad check: Point 'G' does not belong to curve 'E'!\n");
+      goto leave;
     }
-  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_);
+  /* 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;
     }
-  else
+
+  ctx = _gcry_mpi_ec_p_internal_new (sk->E.p, sk->E.a);
+
+  _gcry_mpi_ec_mul_point (&Q, sk->E.n, &sk->E.G, ctx);
+  if (mpi_cmp_ui (Q.z, 0))
     {
-      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);
-        }
+      if (DBG_CIPHER)
+        log_debug ("check_secret_key: E is not a curve of order n\n");
+      goto leave;
+    }
+  /* 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 */
+  _gcry_mpi_ec_mul_point (&Q, sk->d, &sk->E.G, ctx);
+  if ((Q.x == sk->Q.x) && (Q.y == sk->Q.y) && (Q.z == sk->Q.z))
+    {
+      if (DBG_CIPHER)
+        log_debug
+          ("Bad check: There is NO correspondence between 'd' and 'Q'!\n");
+      goto leave;
     }
+  rc = 0; /* Okay.  */
 
-  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);
+ leave:
+  _gcry_mpi_ec_free (ctx);
+  mpi_free (y2);
+  mpi_free (y_2);
+  point_free (&Q);
+  return rc;
 }
 
-/****************
- * 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)
 
+/*
+ * Return the signature struct (r,s) from the message hash.  The caller
+ * must have allocated R and S.
  */
-static void
-escalar_mult (point_t *R, gcry_mpi_t escalar, point_t *P,
-              elliptic_curve_t *base)
+static gpg_err_code_t
+sign (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s)
 {
-
-  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_;
+  gpg_err_code_t err = 0;
+  gcry_mpi_t k, dr, sum, k_1, x;
+  mpi_point_struct I;
+  mpi_ec_t ctx;
 
   if (DBG_CIPHER)
-    log_debug ("escalar_mult: begin\n");
+    log_mpidump ("ecdsa sign hash  ", input );
 
-  one   = mpi_alloc_set_ui (1);
-  two   = mpi_alloc_set_ui (2);
-  three = mpi_alloc_set_ui (3);
-
-  p  = mpi_copy (base->p_);
+  k = NULL;
+  dr = mpi_alloc (0);
+  sum = mpi_alloc (0);
+  k_1 = mpi_alloc (0);
+  x = mpi_alloc (0);
+  point_init (&I);
 
-  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_);
+  mpi_set_ui (s, 0);
+  mpi_set_ui (r, 0);
 
+  ctx = _gcry_mpi_ec_p_internal_new (skey->E.p, skey->E.a);
 
-  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);
-
-  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);
-    }
-  else
-    {
-      k = mpi_copy (escalar);
-      yy = mpi_copy (P->y_);
-    }
-  if (!mpi_cmp (zz, one))
-    {                           /* zz==1 */
-      x1 = mpi_copy (xx);
-      y1 = mpi_copy (yy);
-    }
-  else
+  while (!mpi_cmp_ui (s, 0)) /* s == 0 */
     {
-      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 */
+      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 can't use a
+             do_while because we want to keep the value of R even if S
+             has to be recomputed.  */
+          mpi_free (k);
+          k = _gcry_dsa_gen_k (skey->E.n, GCRY_STRONG_RANDOM);
+          _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx);
+          if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx))
+            {
+              if (DBG_CIPHER)
+                log_debug ("ecc sign: Failed to get affine coordinates\n");
+              err = GPG_ERR_BAD_SIGNATURE;
+              goto leave;
+            }
+          mpi_mod (r, x, skey->E.n);  /* r = x mod n */
         }
-      i--;
+      mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n  */
+      mpi_addm (sum, input, dr, skey->E.n); /* sum = hash + (d*r) mod n  */
+      mpi_invm (k_1, k, skey->E.n);         /* k_1 = k^(-1) mod n  */
+      mpi_mulm (s, k_1, sum, skey->E.n);    /* s = k^(-1)*(hash+(d*r)) mod n */
     }
 
   if (DBG_CIPHER)
-    log_debug ("escalar_mult: ready\n");
+    {
+      log_mpidump ("ecdsa sign result r ", r);
+      log_mpidump ("ecdsa sign result s ", s);
+    }
 
-  point_free (&P1);
-  point_free (&P2);
-  point_free (&P1_);
-  mpi_free (h);
+ leave:
+  _gcry_mpi_ec_free (ctx);
+  point_free (&I);
+  mpi_free (x);
+  mpi_free (k_1);
+  mpi_free (sum);
+  mpi_free (dr);
   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);
+
+  return err;
 }
 
 
-/****************
- * Solve the right side of the equation that defines a curve.
+/*
+ * Check if R and S verifies INPUT.
  */
-static gcry_mpi_t
-gen_y_2 (gcry_mpi_t x, elliptic_curve_t *base)
+static gpg_err_code_t
+verify (gcry_mpi_t input, ECC_public_key *pkey, gcry_mpi_t r, gcry_mpi_t s)
 {
-  gcry_mpi_t three;
-  gcry_mpi_t x_3, ax, axb, y;
-  gcry_mpi_t a, b, p;
-  unsigned int nbits;
+  gpg_err_code_t err = 0;
+  gcry_mpi_t h, h1, h2, x, y;
+  mpi_point_struct Q, Q1, Q2;
+  mpi_ec_t ctx;
 
-  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( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, pkey->E.n) < 0) )
+    return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n  failed.  */
+  if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, pkey->E.n) < 0) )
+    return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n  failed.  */
 
-  if (DBG_CIPHER)
-    log_debug ("ecc gen_y_2: Solving an elliptic equation.\n");
-
-  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 */
+  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);
 
+  ctx = _gcry_mpi_ec_p_internal_new (pkey->E.p, pkey->E.a);
+
+  /* h  = s^(-1) (mod n) */
+  mpi_invm (h, s, pkey->E.n);
+/*   log_mpidump ("   h", h); */
+  /* h1 = hash * s^(-1) (mod n) */
+  mpi_mulm (h1, input, h, pkey->E.n);
+/*   log_mpidump ("  h1", h1); */
+  /* Q1 = [ hash * s^(-1) ]G  */
+  _gcry_mpi_ec_mul_point (&Q1, h1, &pkey->E.G, ctx);
+/*   log_mpidump ("Q1.x", Q1.x); */
+/*   log_mpidump ("Q1.y", Q1.y); */
+/*   log_mpidump ("Q1.z", Q1.z); */
+  /* h2 = r * s^(-1) (mod n) */
+  mpi_mulm (h2, r, h, pkey->E.n);
+/*   log_mpidump ("  h2", h2); */
+  /* Q2 = [ r * s^(-1) ]Q */
+  _gcry_mpi_ec_mul_point (&Q2, h2, &pkey->Q, ctx);
+/*   log_mpidump ("Q2.x", Q2.x); */
+/*   log_mpidump ("Q2.y", Q2.y); */
+/*   log_mpidump ("Q2.z", Q2.z); */
+  /* Q  = ([hash * s^(-1)]G) + ([r * s^(-1)]Q) */
+  _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx);
+/*   log_mpidump (" Q.x", Q.x); */
+/*   log_mpidump (" Q.y", Q.y); */
+/*   log_mpidump (" Q.z", Q.z); */
+
+  if (!mpi_cmp_ui (Q.z, 0))
+    {
+      if (DBG_CIPHER)
+          log_debug ("ecc verify: Rejected\n");
+      err = GPG_ERR_BAD_SIGNATURE;
+      goto leave;
+    }
+  if (_gcry_mpi_ec_get_affine (x, y, &Q, ctx))
+    {
+      if (DBG_CIPHER)
+        log_debug ("ecc verify: Failed to get affine coordinates\n");
+      err = GPG_ERR_BAD_SIGNATURE;
+      goto leave;
+    }
+  mpi_mod (x, x, pkey->E.n); /* x = x mod E_n */
+  if (mpi_cmp (x, r))   /* x != r */
+    {
+      if (DBG_CIPHER)
+        {
+          log_mpidump ("     x", x);
+          log_mpidump ("     y", y);
+          log_mpidump ("     r", r);
+          log_mpidump ("     s", s);
+          log_debug ("ecc verify: Not verified\n");
+        }
+      err = GPG_ERR_BAD_SIGNATURE;
+      goto leave;
+    }
   if (DBG_CIPHER)
-    log_debug ("ecc gen_y_2: Solved.\n");
+    log_debug ("ecc verify: Accepted\n");
 
-  return y; /* The quadratic value of the coordinate if it exist. */
+ leave:
+  _gcry_mpi_ec_free (ctx);
+  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;
 }
 
 
-
-
-
 \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.  */
+/*********************************************
+ **************  interface  ******************
+ *********************************************/
 static gcry_mpi_t
-gen_k (gcry_mpi_t p, int secure)
+ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p)
 {
-  gcry_mpi_t k;
-  unsigned int nbits;
+  gpg_error_t err;
+  int pbytes = (mpi_get_nbits (p)+7)/8;
+  size_t n;
+  unsigned char *buf, *ptr;
+  gcry_mpi_t result;
+
+  buf = gcry_xmalloc ( 1 + 2*pbytes );
+  *buf = 04; /* Uncompressed point.  */
+  ptr = buf+1;
+  err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, x);
+  if (err)
+    log_fatal ("mpi_print failed: %s\n", gpg_strerror (err));
+  if (n < pbytes)
+    {
+      memmove (ptr+(pbytes-n), ptr, n);
+      memset (ptr, 0, (pbytes-n));
+    }
+  ptr += pbytes;
+  err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, y);
+  if (err)
+    log_fatal ("mpi_print failed: %s\n", gpg_strerror (err));
+  if (n < pbytes)
+    {
+      memmove (ptr+(pbytes-n), ptr, n);
+      memset (ptr, 0, (pbytes-n));
+    }
 
-  nbits = mpi_get_nbits (p);
-  k = (secure
-       ? mpi_alloc_secure ( mpi_get_nlimbs (p) )
-       : mpi_alloc ( mpi_get_nlimbs (p) ));
+  err = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, buf, 1+2*pbytes, NULL);
+  if (err)
+    log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err));
+  gcry_free (buf);
 
-  if (DBG_CIPHER)
-    log_debug ("choosing a random k of %u bits\n", nbits);
-  
-  gcry_mpi_randomize (k, nbits, GCRY_STRONG_RANDOM);
+  return result;
+}
 
-  mpi_mod (k, k, p);  /*  k = k mod p  */
 
-  if (DBG_CIPHER)
-    progress ('\n');
+/* Convert POINT into affine coordinates using the context CTX and
+   return a newly allocated MPI.  If the conversion is not possible
+   NULL is returned.  This function won't print an error message.  */
+gcry_mpi_t
+_gcry_mpi_ec_ec2os (gcry_mpi_point_t point, mpi_ec_t ectx)
+{
+  gcry_mpi_t g_x, g_y, result;
+
+  g_x = mpi_new (0);
+  g_y = mpi_new (0);
+  if (_gcry_mpi_ec_get_affine (g_x, g_y, point, ectx))
+    result = NULL;
+  else
+    result = ec2os (g_x, g_y, ectx->p);
+  mpi_free (g_x);
+  mpi_free (g_y);
 
-  return k;
+  return result;
 }
 
 
-/* Helper to scan a hex string. */
-static gcry_mpi_t
-scanval (const char *string)
+/* RESULT must have been initialized and is set on success to the
+   point given by VALUE.  */
+static gcry_error_t
+os2ec (mpi_point_t result, gcry_mpi_t value)
 {
-  gpg_error_t err;
-  gcry_mpi_t val;
-  
-  err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
+  gcry_error_t err;
+  size_t n;
+  unsigned char *buf;
+  gcry_mpi_t x, y;
+
+  n = (mpi_get_nbits (value)+7)/8;
+  buf = gcry_xmalloc (n);
+  err = gcry_mpi_print (GCRYMPI_FMT_USG, buf, n, &n, value);
   if (err)
-    log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (err));
-  return val;
+    {
+      gcry_free (buf);
+      return err;
+    }
+  if (n < 1)
+    {
+      gcry_free (buf);
+      return GPG_ERR_INV_OBJ;
+    }
+  if (*buf != 4)
+    {
+      gcry_free (buf);
+      return GPG_ERR_NOT_IMPLEMENTED; /* No support for point compression.  */
+    }
+  if ( ((n-1)%2) )
+    {
+      gcry_free (buf);
+      return GPG_ERR_INV_OBJ;
+    }
+  n = (n-1)/2;
+  err = gcry_mpi_scan (&x, GCRYMPI_FMT_USG, buf+1, n, NULL);
+  if (err)
+    {
+      gcry_free (buf);
+      return err;
+    }
+  err = gcry_mpi_scan (&y, GCRYMPI_FMT_USG, buf+1+n, n, NULL);
+  gcry_free (buf);
+  if (err)
+    {
+      mpi_free (x);
+      return err;
+    }
+
+  mpi_set (result->x, x);
+  mpi_set (result->y, y);
+  mpi_set_ui (result->z, 1);
+
+  mpi_free (x);
+  mpi_free (y);
+
+  return 0;
 }
 
 
-/****************
- * 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)
+/* Extended version of ecc_generate.  */
+static gcry_err_code_t
+ecc_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
+                  const gcry_sexp_t genparms,
+                  gcry_mpi_t *skey, gcry_mpi_t **retfactors,
+                  gcry_sexp_t *r_extrainfo)
 {
-  int idx;
+  gpg_err_code_t ec;
+  ECC_secret_key sk;
+  gcry_mpi_t g_x, g_y, q_x, q_y;
+  char *curve_name = NULL;
+  gcry_sexp_t l1;
+  int transient_key = 0;
+  const char *usedcurve = 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;
+  (void)algo;
+  (void)evalue;
 
-  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);
+  if (genparms)
+    {
+      /* Parse the optional "curve" parameter. */
+      l1 = gcry_sexp_find_token (genparms, "curve", 0);
+      if (l1)
+        {
+          curve_name = _gcry_sexp_nth_string (l1, 1);
+          gcry_sexp_release (l1);
+          if (!curve_name)
+            return GPG_ERR_INV_OBJ; /* No curve name or value too large. */
+        }
 
-  /* 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");
-      }
+      /* Parse the optional transient-key flag.  */
+      l1 = gcry_sexp_find_token (genparms, "transient-key", 0);
+      if (l1)
+        {
+          transient_key = 1;
+          gcry_sexp_release (l1);
+        }
+    }
 
-     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;
-     }
-  */
+  /* NBITS is required if no curve name has been given.  */
+  if (!nbits && !curve_name)
+    return GPG_ERR_NO_OBJ; /* No NBITS parameter. */
+
+  g_x = mpi_new (0);
+  g_y = mpi_new (0);
+  q_x = mpi_new (0);
+  q_y = mpi_new (0);
+  ec = generate_key (&sk, nbits, curve_name, transient_key, g_x, g_y, q_x, q_y,
+                     &usedcurve);
+  gcry_free (curve_name);
+  if (ec)
+    return ec;
+  if (usedcurve)  /* Fixme: No error return checking.  */
+    gcry_sexp_build (r_extrainfo, NULL, "(curve %s)", usedcurve);
+
+  skey[0] = sk.E.p;
+  skey[1] = sk.E.a;
+  skey[2] = sk.E.b;
+  skey[3] = ec2os (g_x, g_y, sk.E.p);
+  skey[4] = sk.E.n;
+  skey[5] = ec2os (q_x, q_y, sk.E.p);
+  skey[6] = sk.d;
+
+  mpi_free (g_x);
+  mpi_free (g_y);
+  mpi_free (q_x);
+  mpi_free (q_y);
+
+  point_free (&sk.E.G);
+  point_free (&sk.Q);
+
+  /* Make an empty list of factors.  */
+  *retfactors = gcry_calloc ( 1, sizeof **retfactors );
+  if (!*retfactors)
+    return gpg_err_code_from_syserror ();  /* Fixme: relase mem?  */
 
   if (DBG_CIPHER)
     {
-      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_);
+      log_mpidump ("ecgen result p", skey[0]);
+      log_mpidump ("ecgen result a", skey[1]);
+      log_mpidump ("ecgen result b", skey[2]);
+      log_mpidump ("ecgen result G", skey[3]);
+      log_mpidump ("ecgen result n", skey[4]);
+      log_mpidump ("ecgen result Q", skey[5]);
+      log_mpidump ("ecgen result d", skey[6]);
     }
-  if (DBG_CIPHER)
-    progress ('\n');
 
   return 0;
 }
 
 
-/****************
- * 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)
+static gcry_err_code_t
+ecc_generate (int algo, unsigned int nbits, unsigned long evalue,
+              gcry_mpi_t *skey, gcry_mpi_t **retfactors)
+{
+  (void)evalue;
+  return ecc_generate_ext (algo, nbits, 0, NULL, skey, retfactors, NULL);
+}
+
+
+/* Return the parameters of the curve NAME in an MPI array.  */
+static gcry_err_code_t
+ecc_get_param (const char *name, gcry_mpi_t *pkey)
 {
   gpg_err_code_t err;
+  unsigned int nbits;
   elliptic_curve_t E;
-  gcry_mpi_t d;
-  point_t Q, G;
+  mpi_ec_t ctx;
+  gcry_mpi_t g_x, g_y;
 
-  err = generate_curve (nbits, &E);
+  err = fill_in_curve (0, name, &E, &nbits);
   if (err)
     return err;
 
-  d = mpi_snew (nbits);
-  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);
+  g_x = mpi_new (0);
+  g_y = mpi_new (0);
+  ctx = _gcry_mpi_ec_p_internal_new (E.p, E.a);
+  if (_gcry_mpi_ec_get_affine (g_x, g_y, &E.G, ctx))
+    log_fatal ("ecc get param: Failed to get affine coordinates\n");
+  _gcry_mpi_ec_free (ctx);
+  point_free (&E.G);
 
-  /* Compute Q.  */
-  point_init (&Q);
-  escalar_mult (&Q, d, &E.G, &E);
+  pkey[0] = E.p;
+  pkey[1] = E.a;
+  pkey[2] = E.b;
+  pkey[3] = ec2os (g_x, g_y, E.p);
+  pkey[4] = E.n;
+  pkey[5] = NULL;
 
-  /* 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);
+  mpi_free (g_x);
+  mpi_free (g_y);
 
   return 0;
 }
 
 
-/****************
- * 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)
+/* Return the parameters of the curve NAME as an S-expression.  */
+static gcry_sexp_t
+ecc_get_param_sexp (const char *name)
 {
-  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);
+  gcry_mpi_t pkey[6];
+  gcry_sexp_t result;
+  int i;
 
-  if (DBG_CIPHER)
-    log_debug ("Testing key.\n");
+  if (ecc_get_param (name, pkey))
+    return NULL;
 
-  point_init (&R_);
+  if (gcry_sexp_build (&result, NULL,
+                       "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)))",
+                       pkey[0], pkey[1], pkey[2], pkey[3], pkey[4]))
+    result = NULL;
 
-  pk.E = curve_copy (sk->E);
-  pk.Q = point_copy (sk->Q);
+  for (i=0; pkey[i]; i++)
+    gcry_mpi_release (pkey[i]);
 
-  gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
+  return result;
+}
 
-#if 0  
-  doEncrypt (test, &pk, &R_, c);
 
-  out = decrypt (out, sk, R_, c);
+/* Return the name matching the parameters in PKEY.  */
+static const char *
+ecc_get_curve (gcry_mpi_t *pkey, int iterator, unsigned int *r_nbits)
+{
+  gpg_err_code_t err;
+  elliptic_curve_t E;
+  int idx;
+  gcry_mpi_t tmp;
+  const char *result = NULL;
 
-  if (mpi_cmp (test, out))      /* test!=out */
-    log_fatal ("ECELG operation: encrypt, decrypt failed\n");
-  if (DBG_CIPHER)
-    log_debug ("ECELG operation: encrypt, decrypt ok.\n");
-#endif
+  if (r_nbits)
+    *r_nbits = 0;
 
-  if (sign (test, sk, r, s) )
-    log_fatal ("ECDSA operation: sign failed\n");
+  if (!pkey)
+    {
+      idx = iterator;
+      if (idx >= 0 && idx < DIM (domain_parms))
+        {
+          result = domain_parms[idx].desc;
+          if (r_nbits)
+            *r_nbits = domain_parms[idx].nbits;
+        }
+      return result;
+    }
 
-  if (verify (test, &pk, r, s))
+  if (!pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] || !pkey[4])
+    return NULL;
+
+  E.p = pkey[0];
+  E.a = pkey[1];
+  E.b = pkey[2];
+  point_init (&E.G);
+  err = os2ec (&E.G, pkey[3]);
+  if (err)
     {
-      log_fatal ("ECDSA operation: sign, verify failed\n");
+      point_free (&E.G);
+      return NULL;
     }
+  E.n = pkey[4];
 
-  if (DBG_CIPHER)
-    log_debug ("ECDSA operation: sign, verify ok.\n");
+  for (idx = 0; domain_parms[idx].desc; idx++)
+    {
+      tmp = scanval (domain_parms[idx].p);
+      if (!mpi_cmp (tmp, E.p))
+        {
+          mpi_free (tmp);
+          tmp = scanval (domain_parms[idx].a);
+          if (!mpi_cmp (tmp, E.a))
+            {
+              mpi_free (tmp);
+              tmp = scanval (domain_parms[idx].b);
+              if (!mpi_cmp (tmp, E.b))
+                {
+                  mpi_free (tmp);
+                  tmp = scanval (domain_parms[idx].n);
+                  if (!mpi_cmp (tmp, E.n))
+                    {
+                      mpi_free (tmp);
+                      tmp = scanval (domain_parms[idx].g_x);
+                      if (!mpi_cmp (tmp, E.G.x))
+                        {
+                          mpi_free (tmp);
+                          tmp = scanval (domain_parms[idx].g_y);
+                          if (!mpi_cmp (tmp, E.G.y))
+                            {
+                              result = domain_parms[idx].desc;
+                              if (r_nbits)
+                                *r_nbits = domain_parms[idx].nbits;
+                              break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+      mpi_free (tmp);
+    }
 
-  point_free (&pk.Q);
-  curve_free (&pk.E);
+  point_free (&E.G);
 
-  point_free (&R_);
-  mpi_free (s);
-  mpi_free (r);
-  mpi_free (out);
-  mpi_free (c);
-  mpi_free (test);
+  return result;
 }
 
-/****************
- * 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)
+
+static gcry_err_code_t
+ecc_check_secret_key (int algo, gcry_mpi_t *skey)
 {
-  point_t Q;
-  gcry_mpi_t y_2, y2 = mpi_alloc (0);
+  gpg_err_code_t err;
+  ECC_secret_key sk;
 
-  /* ?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))
-    {
-      if (DBG_CIPHER)
-        log_debug ("Bad check: Point 'G' does not belong to curve 'E'!\n");
-      return (1);
-    }
-  /* G != PaI */
-  if (point_at_infinity (sk->E.G))
-    {
-      if (DBG_CIPHER)
-        log_debug ("Bad check: 'G' cannot be Point at Infinity!\n");
-      return (1);
-    }
-  /* ?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 */
+  (void)algo;
 
-  point_init (&Q);
-  escalar_mult (&Q, sk->E.n_, &sk->E.G, &sk->E);
-  if (!point_at_infinity (Q))
+  /* FIXME:  This check looks a bit fishy:  Now long is the array?  */
+  if (!skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] || !skey[5]
+      || !skey[6])
+    return GPG_ERR_BAD_MPI;
+
+  sk.E.p = skey[0];
+  sk.E.a = skey[1];
+  sk.E.b = skey[2];
+  point_init (&sk.E.G);
+  err = os2ec (&sk.E.G, skey[3]);
+  if (err)
     {
-      if (DBG_CIPHER)
-        log_debug ("check_secret_key: E is not a curve of order n\n");
-      point_free (&Q);
-      return 1;
+      point_free (&sk.E.G);
+      return err;
     }
-  /* pubkey cannot be PaI */
-  if (point_at_infinity (sk->Q))
+  sk.E.n = skey[4];
+  point_init (&sk.Q);
+  err = os2ec (&sk.Q, skey[5]);
+  if (err)
     {
-      if (DBG_CIPHER)
-        log_debug ("Bad check: Q can not be a Point at Infinity!\n");
-      return (1);
+      point_free (&sk.E.G);
+      point_free (&sk.Q);
+      return err;
     }
-  /* 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_))
+
+  sk.d = skey[6];
+
+  if (check_secret_key (&sk))
     {
-      if (DBG_CIPHER)
-        log_debug
-          ("Bad check: There is NO correspondence between 'd' and 'Q'!\n");
-      return (1);
+      point_free (&sk.E.G);
+      point_free (&sk.Q);
+      return GPG_ERR_BAD_SECKEY;
     }
-  point_free (&Q);
+  point_free (&sk.E.G);
+  point_free (&sk.Q);
   return 0;
 }
 
 
-#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)
+static gcry_err_code_t
+ecc_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey)
 {
+  gpg_err_code_t err;
+  ECC_secret_key sk;
 
-  gcry_mpi_t k, p, x, y;
-  point_t P, Q, G;
-  elliptic_curve_t E;
+  (void)algo;
 
-  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)
-        {
-          log_debug ("Encrypting: Cannot turn to affine.\n");
-        }
+  if (!data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4]
+      || !skey[6] )
+    return GPG_ERR_BAD_MPI;
+
+  sk.E.p = skey[0];
+  sk.E.a = skey[1];
+  sk.E.b = skey[2];
+  point_init (&sk.E.G);
+  err = os2ec (&sk.E.G, skey[3]);
+  if (err)
+    {
+      point_free (&sk.E.G);
+      return err;
     }
-  /* 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);
+  sk.E.n = skey[4];
+  /* Note: We don't have any need for Q here.  */
+  sk.d = skey[6];
 
-  if (DBG_CIPHER)
+  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)
     {
-      log_debug ("doEncrypt: end.\n");
+      mpi_free (resarr[0]);
+      mpi_free (resarr[1]);
+      resarr[0] = NULL; /* Mark array as released.  */
     }
+  point_free (&sk.E.G);
+  return err;
 }
-#endif /*0*/
 
-#if 0
-/****************
- * Undo the ciphertext
- */
-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_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
+            int (*cmp)(void *, gcry_mpi_t), void *opaquev)
 {
+  gpg_err_code_t err;
+  ECC_public_key pk;
 
-  gcry_mpi_t p, inv, x, y;
-  point_t P, Q;
-  elliptic_curve_t E;
+  (void)algo;
+  (void)cmp;
+  (void)opaquev;
 
-  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)
-        {
-          log_debug ("Encrypting: Cannot turn to affine.\n");
-        }
-    }
-  sha256_hashing (x, &x);
-  aes256_decrypting (x, c, &output);
+  if (!data[0] || !data[1] || !hash || !pkey[0] || !pkey[1] || !pkey[2]
+      || !pkey[3] || !pkey[4] || !pkey[5] )
+    return GPG_ERR_BAD_MPI;
 
-  if (DBG_CIPHER)
+  pk.E.p = pkey[0];
+  pk.E.a = pkey[1];
+  pk.E.b = pkey[2];
+  point_init (&pk.E.G);
+  err = os2ec (&pk.E.G, pkey[3]);
+  if (err)
+    {
+      point_free (&pk.E.G);
+      return err;
+    }
+  pk.E.n = pkey[4];
+  point_init (&pk.Q);
+  err = os2ec (&pk.Q, pkey[5]);
+  if (err)
     {
-      log_debug ("decrypt: end.\n");
+      point_free (&pk.E.G);
+      point_free (&pk.Q);
+      return err;
     }
-  return (output);
+
+  err = verify (hash, &pk, data[0], data[1]);
+
+  point_free (&pk.E.G);
+  point_free (&pk.Q);
+  return err;
 }
-#endif /*0*/
 
 
-/*
- * Return the signature struct (r,s) from the message hash.  The caller
- * must have allocated R and S.
+/* 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:
+ *     result[0] : shared point (kdG)
+ *     result[1] : 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 gpg_err_code_t
-sign (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s)
+static gcry_err_code_t
+ecc_encrypt_raw (int algo, gcry_mpi_t *resarr, gcry_mpi_t k,
+                 gcry_mpi_t *pkey, int flags)
 {
-  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;
+  ECC_public_key pk;
+  mpi_ec_t ctx;
+  gcry_mpi_t result[2];
+  int err;
 
-  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);
+  (void)algo;
+  (void)flags;
 
-  mpi_set_ui (s, 0);
-  mpi_set_ui (r, 0);
+  if (!k
+      || !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] || !pkey[4] || !pkey[5])
+    return GPG_ERR_BAD_MPI;
 
-  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 */
+  pk.E.p = pkey[0];
+  pk.E.a = pkey[1];
+  pk.E.b = pkey[2];
+  point_init (&pk.E.G);
+  err = os2ec (&pk.E.G, pkey[3]);
+  if (err)
+    {
+      point_free (&pk.E.G);
+      return err;
+    }
+  pk.E.n = pkey[4];
+  point_init (&pk.Q);
+  err = os2ec (&pk.Q, pkey[5]);
+  if (err)
+    {
+      point_free (&pk.E.G);
+      point_free (&pk.Q);
+      return err;
     }
 
-  /* 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);
+  ctx = _gcry_mpi_ec_p_internal_new (pk.E.p, pk.E.a);
 
-  return err;
-}
+  /* 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;
 
-/*
- * 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;
+    x = mpi_new (0);
+    y = mpi_new (0);
 
-  /* 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;
-      }
-  }
+    point_init (&R);
 
-  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 = kQ  <=>  R = kdG  */
+    _gcry_mpi_ec_mul_point (&R, k, &pk.Q, ctx);
 
-  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, ctx))
+      log_fatal ("ecdh: Failed to get affine coordinates for kdG\n");
 
-  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");
+    result[0] = ec2os (x, y, pk.E.p);
 
- 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;
-}
+    /* R = kG */
+    _gcry_mpi_ec_mul_point (&R, k, &pk.E.G, ctx);
 
+    if (_gcry_mpi_ec_get_affine (x, y, &R, ctx))
+      log_fatal ("ecdh: Failed to get affine coordinates for kG\n");
 
-/****************
- * Generate a random point over an Elliptic curve is the first step to
- * find a random cyclic subgroup generator.
- *
- *        !! At this moment it isn't used !!  //!!
- */
-#if 0
-static point_t
-gen_point (gcry_mpi_t prime, elliptic_curve_t base)
-{
+    result[1] = ec2os (x, y, pk.E.p);
+
+    mpi_free (x);
+    mpi_free (y);
 
-  unsigned int i = 0;
-  gcry_mpi_t x, y_2, y;
-  gcry_mpi_t one, one_neg, bit;
-  point_t P;
+    point_free (&R);
+  }
 
-  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_);
+  _gcry_mpi_ec_free (ctx);
+  point_free (&pk.E.G);
+  point_free (&pk.Q);
 
-  if (DBG_CIPHER)
-    log_debug ("Generating a normal point.\n");
-  do
+  if (!result[0] || !result[1])
     {
-      x = gen_k (base.p_, 1);   /* generate_public_prime(mpi_get_nlimbs(base.n_)*BITS_PER_MPI_LIMB); */
-      do
-        {
-          y_2 = gen_y_2 (x, &base);     /* x^3+ax+b (mod p) */
-          mpi_add_ui (x, x, 1);
-          i++;
-        }
-      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_); */
+      mpi_free (result[0]);
+      mpi_free (result[1]);
+      return GPG_ERR_ENOMEM;
     }
-  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);
+  /* Success.  */
+  resarr[0] = result[0];
+  resarr[1] = result[1];
 
-  return (P);
+  return 0;
 }
-#endif /*0*/
 
-/****************
- * Boolean generator to choose between to coordinates.
+/*  input:
+ *     data[0] : a point kG (ephemeral public key)
+ *   output:
+ *     resaddr[0] : shared point kdG
+ *
+ *  see ecc_encrypt_raw for details.
  */
-#if 0
-static gcry_mpi_t
-gen_bit ()
+static gcry_err_code_t
+ecc_decrypt_raw (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
+                 gcry_mpi_t *skey, int flags)
 {
-  gcry_mpi_t aux = mpi_alloc_set_ui (0);
+  ECC_secret_key sk;
+  mpi_point_struct R;  /* Result that we return.  */
+  mpi_point_struct kG;
+  mpi_ec_t ctx;
+  gcry_mpi_t r;
+  int err;
 
-  /* FIXME: This is highly ineffective but the whole function is used
-     only at one place. */
+  (void)algo;
+  (void)flags;
 
-  /* 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(...) */
+  *result = NULL;
 
-  return aux;                   /* b; */
-}
-#endif /*0*/
+  if (!data || !data[0]
+      || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4]
+      || !skey[5] || !skey[6] )
+    return GPG_ERR_BAD_MPI;
 
+  point_init (&kG);
+  err = os2ec (&kG, data[0]);
+  if (err)
+    {
+      point_free (&kG);
+      return err;
+    }
 
-\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)
-{                               /*   */
+  sk.E.p = skey[0];
+  sk.E.a = skey[1];
+  sk.E.b = skey[2];
+  point_init (&sk.E.G);
+  err = os2ec (&sk.E.G, skey[3]);
+  if (err)
+    {
+      point_free (&kG);
+      point_free (&sk.E.G);
+      return err;
+    }
+  sk.E.n = skey[4];
+  point_init (&sk.Q);
+  err = os2ec (&sk.Q, skey[5]);
+  if (err)
+    {
+      point_free (&kG);
+      point_free (&sk.E.G);
+      point_free (&sk.Q);
+      return err;
+    }
+  sk.d = skey[6];
 
-  int sign;
-  byte *hash_inp_buf;
-  byte hash_out_buf[32];
-  MD_HANDLE hash = md_open (8, 1);      /* algo SHA256 in secure mode */
+  ctx = _gcry_mpi_ec_p_internal_new (sk.E.p, sk.E.a);
 
-  unsigned int nbytes;
+  /* R = dkG */
+  point_init (&R);
+  _gcry_mpi_ec_mul_point (&R, sk.d, &kG, ctx);
 
-  hash_inp_buf = mpi_get_secure_buffer (input, &nbytes, &sign); /* convert gcry_mpi_t input to string */
+  point_free (&kG);
 
-  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);
+  /* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so:  */
+  {
+    gcry_mpi_t x, y;
 
-  md_digest (hash, 8, hash_out_buf, 32);
-  mpi_set_buffer (*output, hash_out_buf, 32, 0);        /*  convert 256 bit digest to MPI */
+    x = mpi_new (0);
+    y = mpi_new (0);
 
-  wipememory (hash_out_buf, sizeof hash_out_buf);       /*  burn temp value  */
-  md_close (hash);              /*  destroy and free hash state. */
+    if (_gcry_mpi_ec_get_affine (x, y, &R, ctx))
+      log_fatal ("ecdh: Failed to get affine coordinates\n");
 
-}
+    r = ec2os (x, y, sk.E.p);
+    mpi_free (x);
+    mpi_free (y);
+  }
 
-/****************
- * Encrypt input MPI.
- * Use AES256 algorithm.
- */
+  point_free (&R);
+  _gcry_mpi_ec_free (ctx);
+  point_free (&kG);
+  point_free (&sk.E.G);
+  point_free (&sk.Q);
 
-static void
-aes256_encrypting (gcry_mpi_t key, gcry_mpi_t input, gcry_mpi_t * output)
-{                               /*   */
+  if (!r)
+    return GPG_ERR_ENOMEM;
 
-  int sign;
-  byte *key_buf;
-  byte *cipher_buf;
+  /* Success.  */
 
-  unsigned int keylength;
-  unsigned int nbytes;
+  *result = r;
+
+  return 0;
+}
 
 
-  CIPHER_HANDLE cipher = cipher_open (9, CIPHER_MODE_CFB, 1);   /* algo AES256 CFB mode in secure memory */
-  cipher_setiv (cipher, NULL, 0);       /*  Zero IV */
+static unsigned int
+ecc_get_nbits (int algo, gcry_mpi_t *pkey)
+{
+  (void)algo;
 
-  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);
+  return mpi_get_nbits (pkey[0]);
+}
 
-  cipher_buf = mpi_get_secure_buffer (input, &nbytes, &sign);   /* convert MPI input to string */
 
-  cipher_encrypt (cipher, cipher_buf + 1, cipher_buf + 1, nbytes - 1);  /*  */
-  cipher_close (cipher);        /*  destroy and free cipher state. */
+/* See rsa.c for a description of this function.  */
+static gpg_err_code_t
+compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam)
+{
+#define N_COMPONENTS 6
+  static const char names[N_COMPONENTS+1] = "pabgnq";
+  gpg_err_code_t ec = 0;
+  gcry_sexp_t l1;
+  gcry_mpi_t values[N_COMPONENTS];
+  int 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);
-}
+  /* Clear the values for easier error cleanup.  */
+  for (idx=0; idx < N_COMPONENTS; idx++)
+    values[idx] = NULL;
 
-/****************
- * Decrypt input MPI.
- * Use AES256 algorithm.
- */
+  /* Fill values with all provided parameters.  */
+  for (idx=0; idx < N_COMPONENTS; idx++)
+    {
+      l1 = gcry_sexp_find_token (keyparam, names+idx, 1);
+      if (l1)
+        {
+          values[idx] = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+         gcry_sexp_release (l1);
+         if (!values[idx])
+            {
+              ec = GPG_ERR_INV_OBJ;
+              goto leave;
+            }
+       }
+    }
 
-static void
-aes256_decrypting (gcry_mpi_t key, gcry_mpi_t input, gcry_mpi_t * output)
-{                               /*   */
+  /* Check whether a curve parameter is available and use that to fill
+     in missing values.  */
+  l1 = gcry_sexp_find_token (keyparam, "curve", 5);
+  if (l1)
+    {
+      char *curve;
+      gcry_mpi_t tmpvalues[N_COMPONENTS];
 
-  int sign;
-  byte *key_buf;
-  byte *cipher_buf;
+      for (idx = 0; idx < N_COMPONENTS; idx++)
+        tmpvalues[idx] = NULL;
 
-  unsigned int keylength;
-  unsigned int nbytes;
+      curve = _gcry_sexp_nth_string (l1, 1);
+      gcry_sexp_release (l1);
+      if (!curve)
+        {
+          ec = GPG_ERR_INV_OBJ; /* Name missing or out of core. */
+          goto leave;
+        }
+      ec = ecc_get_param (curve, tmpvalues);
+      gcry_free (curve);
+      if (ec)
+        goto leave;
 
+      for (idx = 0; idx < N_COMPONENTS; idx++)
+        {
+          if (!values[idx])
+            values[idx] = tmpvalues[idx];
+          else
+            mpi_free (tmpvalues[idx]);
+        }
+    }
 
-  CIPHER_HANDLE cipher = cipher_open (9, CIPHER_MODE_CFB, 1);   /* algo AES256 CFB mode in secure memory */
-  cipher_setiv (cipher, NULL, 0);       /*  Zero IV */
+  /* 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])
+      {
+        ec = GPG_ERR_NO_OBJ;
+        goto leave;
+      }
+    else
+      _gcry_mpi_normalize (values[idx]);
 
-  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);
+  /* Hash them all.  */
+  for (idx = 0; idx < N_COMPONENTS; idx++)
+    {
+      char buf[30];
+      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], &rawmpilen, NULL);
+      if (!rawmpi)
+        {
+          ec = 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);
+      gcry_free (rawmpi);
+    }
 
-  cipher_decrypt (cipher, cipher_buf + 1, cipher_buf + 1, nbytes - 1);  /*  */
-  cipher_close (cipher);        /*  destroy and free cipher state. */
+ leave:
+  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 ec;
+#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)
+/* Helper to extract an MPI from key parameters.  */
+static gpg_err_code_t
+mpi_from_keyparam (gcry_mpi_t *r_a, gcry_sexp_t keyparam, const char *name)
 {
-  gpg_err_code_t err;
-  ECC_secret_key sk;
-
-  (void)algo;
-
-  /* Make an empty list of factors.  */
-  *retfactors = gcry_calloc ( 1, sizeof **retfactors );
-  if (!*retfactors)
-    return gpg_err_code_from_syserror ();
+  gcry_err_code_t ec = 0;
+  gcry_sexp_t l1;
 
-  err = generate_key (&sk, nbits);
-  if (err)
+  l1 = gcry_sexp_find_token (keyparam, name, 0);
+  if (l1)
     {
-      gcry_free (*retfactors);
-      *retfactors = NULL;
-      return err;
+      *r_a = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+      gcry_sexp_release (l1);
+      if (!*r_a)
+        ec = GPG_ERR_INV_OBJ;
     }
+  return ec;
+}
+
+/* Helper to extract a point from key parameters.  If no parameter
+   with NAME is found, the functions tries to find a non-encoded point
+   by appending ".x", ".y" and ".z" to NAME.  ".z" is in this case
+   optional and defaults to 1.  */
+static gpg_err_code_t
+point_from_keyparam (gcry_mpi_point_t *r_a,
+                     gcry_sexp_t keyparam, const char *name)
+{
+  gcry_err_code_t ec;
+  gcry_mpi_t a = NULL;
+  gcry_mpi_point_t point;
 
-  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;
+  ec = mpi_from_keyparam (&a, keyparam, name);
+  if (ec)
+    return ec;
 
-  if (DBG_CIPHER)
+  if (a)
     {
-      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]);
+      point = gcry_mpi_point_new (0);
+      ec = os2ec (point, a);
+      mpi_free (a);
+      if (ec)
+        {
+          gcry_mpi_point_release (point);
+          return ec;
+        }
     }
-
-  if (DBG_CIPHER)
+  else
     {
-      log_debug ("ECC key Generated.\n");
+      char *tmpname;
+      gcry_mpi_t x = NULL;
+      gcry_mpi_t y = NULL;
+      gcry_mpi_t z = NULL;
+
+      tmpname = gcry_malloc (strlen (name) + 2 + 1);
+      if (!tmpname)
+        return gpg_err_code_from_syserror ();
+      strcpy (stpcpy (tmpname, name), ".x");
+      ec = mpi_from_keyparam (&x, keyparam, tmpname);
+      if (ec)
+        {
+          gcry_free (tmpname);
+          return ec;
+        }
+      strcpy (stpcpy (tmpname, name), ".y");
+      ec = mpi_from_keyparam (&y, keyparam, tmpname);
+      if (ec)
+        {
+          mpi_free (x);
+          gcry_free (tmpname);
+          return ec;
+        }
+      strcpy (stpcpy (tmpname, name), ".z");
+      ec = mpi_from_keyparam (&z, keyparam, tmpname);
+      if (ec)
+        {
+          mpi_free (y);
+          mpi_free (x);
+          gcry_free (tmpname);
+          return ec;
+        }
+      if (!z)
+        z = mpi_set_ui (NULL, 1);
+      if (x && y)
+        point = gcry_mpi_point_snatch_set (NULL, x, y, z);
+      else
+        {
+          mpi_free (x);
+          mpi_free (y);
+          mpi_free (z);
+          point = NULL;
+        }
+      gcry_free (tmpname);
     }
+
+  if (point)
+    *r_a = point;
   return 0;
 }
 
 
-static gcry_err_code_t
-ecc_check_secret_key (int algo, gcry_mpi_t *skey)
+/* This function creates a new context for elliptic curve operations.
+   Either KEYPARAM or CURVENAME must be given.  If both are given and
+   KEYPARAM has no curve parameter CURVENAME is used to add missing
+   parameters.  On success 0 is returned and the new context stored at
+   R_CTX.  On error NULL is stored at R_CTX and an error code is
+   returned.  The context needs to be released using
+   gcry_ctx_release.  */
+gpg_err_code_t
+_gcry_mpi_ec_new (gcry_ctx_t *r_ctx,
+                  gcry_sexp_t keyparam, const char *curvename)
 {
-  ECC_secret_key sk;
-
-  (void)algo;
+  gpg_err_code_t errc;
+  gcry_ctx_t ctx = NULL;
+  gcry_mpi_t p = NULL;
+  gcry_mpi_t a = NULL;
+  gcry_mpi_t b = NULL;
+  gcry_mpi_point_t G = NULL;
+  gcry_mpi_t n = NULL;
+  gcry_mpi_point_t Q = NULL;
+  gcry_mpi_t d = NULL;
+  gcry_sexp_t l1;
+
+  *r_ctx = NULL;
+
+  if (keyparam)
+    {
+      errc = mpi_from_keyparam (&p, keyparam, "p");
+      if (errc)
+        goto leave;
+      errc = mpi_from_keyparam (&a, keyparam, "a");
+      if (errc)
+        goto leave;
+      errc = mpi_from_keyparam (&b, keyparam, "b");
+      if (errc)
+        goto leave;
+      errc = point_from_keyparam (&G, keyparam, "g");
+      if (errc)
+        goto leave;
+      errc = mpi_from_keyparam (&n, keyparam, "n");
+      if (errc)
+        goto leave;
+      errc = point_from_keyparam (&Q, keyparam, "q");
+      if (errc)
+        goto leave;
+      errc = mpi_from_keyparam (&d, keyparam, "d");
+      if (errc)
+        goto leave;
+    }
 
-  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)
+  /* Check whether a curve parameter is available and use that to fill
+     in missing values.  If no curve parameter is available try an
+     optional provided curvename.  If only the curvename has been
+     given use that one. */
+  if (keyparam)
+    l1 = gcry_sexp_find_token (keyparam, "curve", 5);
+  else
+    l1 = NULL;
+  if (l1 || curvename)
     {
-      log_debug ("ECC check secret key.\n");
+      char *name;
+      elliptic_curve_t *E;
+
+      if (l1)
+        {
+          name = _gcry_sexp_nth_string (l1, 1);
+          gcry_sexp_release (l1);
+          if (!name)
+            {
+              errc = GPG_ERR_INV_OBJ; /* Name missing or out of core. */
+              goto leave;
+            }
+        }
+      else
+        name = NULL;
+
+      E = gcry_calloc (1, sizeof *E);
+      if (!E)
+        {
+          errc = gpg_err_code_from_syserror ();
+          gcry_free (name);
+          goto leave;
+        }
+
+      errc = fill_in_curve (0, name? name : curvename, E, NULL);
+      gcry_free (name);
+      if (errc)
+        {
+          gcry_free (E);
+          goto leave;
+        }
+
+      if (!p)
+        {
+          p = E->p;
+          E->p = NULL;
+        }
+      if (!a)
+        {
+          a = E->a;
+          E->a = NULL;
+        }
+      if (!b)
+        {
+          b = E->b;
+          E->b = NULL;
+        }
+      if (!G)
+        {
+          G = gcry_mpi_point_snatch_set (NULL, E->G.x, E->G.y, E->G.z);
+          E->G.x = NULL;
+          E->G.y = NULL;
+          E->G.z = NULL;
+        }
+      if (!n)
+        {
+          n = E->n;
+          E->n = NULL;
+        }
+      curve_free (E);
+      gcry_free (E);
     }
-  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))
+  errc = _gcry_mpi_ec_p_new (&ctx, p, a);
+  if (!errc)
     {
-      if (DBG_CIPHER)
-        log_debug ("Bad check: Bad secret key.\n");
-      return GPG_ERR_BAD_SECKEY;
+      mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
+
+      if (b)
+        {
+          ec->b = b;
+          b = NULL;
+        }
+      if (G)
+        {
+          ec->G = G;
+          G = NULL;
+        }
+      if (n)
+        {
+          ec->n = n;
+          n = NULL;
+        }
+      if (Q)
+        {
+          ec->Q = Q;
+          Q = NULL;
+        }
+      if (d)
+        {
+          ec->d = d;
+          d = NULL;
+        }
+
+      *r_ctx = ctx;
     }
-  return 0;
+
+ leave:
+  mpi_free (p);
+  mpi_free (a);
+  mpi_free (b);
+  gcry_mpi_point_release (G);
+  mpi_free (n);
+  gcry_mpi_point_release (Q);
+  mpi_free (d);
+  return errc;
 }
 
 
-#if 0
-static int
-ecc_encrypt_FIXME (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, gcry_mpi_t * pkey)
+/* This is the wroker 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)
 {
-  ECC_public_key pk;
-  point R;
+  gpg_err_code_t rc;
+  gcry_mpi_t mpi_G = NULL;
+  gcry_mpi_t mpi_Q = NULL;
 
-  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 (!ec->p || !ec->a || !ec->b || !ec->G || !ec->n)
+    return GPG_ERR_BAD_CRYPT_CTX;
 
-  if (DBG_CIPHER)
+  if (mode == GCRY_PK_GET_SECKEY && !ec->d)
+    return GPG_ERR_NO_SECKEY;
+
+  /* Compute the public point if it is missing.  */
+  if (!ec->Q && ec->d)
     {
-      log_debug ("ECC encrypt.\n");
+      ec->Q = gcry_mpi_point_new (0);
+      _gcry_mpi_ec_mul_point (ec->Q, ec->d, ec->G, ec);
     }
-  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;
-}
 
-int
-ecc_decrypt_FIXME (int algo, gcry_mpi_t * result, gcry_mpi_t * data, gcry_mpi_t * skey)
-{
-  ECC_secret_key sk;
-  point R;
+  /* Encode G and Q.  */
+  mpi_G = _gcry_mpi_ec_ec2os (ec->G, ec);
+  if (!mpi_G)
+    {
+      rc = GPG_ERR_BROKEN_PUBKEY;
+      goto leave;
+    }
+  if (!ec->Q)
+    {
+      rc = GPG_ERR_BAD_CRYPT_CTX;
+      goto leave;
+    }
+  mpi_Q = _gcry_mpi_ec_ec2os (ec->Q, ec);
+  if (!mpi_Q)
+    {
+      rc = GPG_ERR_BROKEN_PUBKEY;
+      goto leave;
+    }
 
-  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;
+  /* Fixme: We should return a curve name instead of the parameters if
+     if know that they match a curve.  */
 
-  if (DBG_CIPHER)
+  if (ec->d && (!mode || mode == GCRY_PK_GET_SECKEY))
     {
-      log_debug ("ECC decrypt.\n");
+      /* Let's return a private key. */
+      rc = gpg_err_code
+        (gcry_sexp_build
+         (r_sexp, NULL,
+          "(private-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)(d%m)))",
+          ec->p, ec->a, ec->b, mpi_G, ec->n, mpi_Q, ec->d));
     }
-  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*/
+  else if (ec->Q)
+    {
+      /* Let's return a public key.  */
+      rc = gpg_err_code
+        (gcry_sexp_build
+         (r_sexp, NULL,
+          "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))",
+          ec->p, ec->a, ec->b, mpi_G, ec->n, mpi_Q));
+    }
+  else
+    rc = GPG_ERR_BAD_CRYPT_CTX;
 
-static gcry_err_code_t
-ecc_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey)
-{
-  gpg_err_code_t err;
-  ECC_secret_key sk;
+ leave:
+  mpi_free (mpi_Q);
+  mpi_free (mpi_G);
+  return rc;
+}
 
-  (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;
+\f
+/*
+     Self-test section.
+ */
 
-  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;
-}
 
-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)
+static gpg_err_code_t
+selftests_ecdsa (selftest_report_func_t report)
 {
-  ECC_public_key pk;
+  const char *what;
+  const char *errtxt;
 
-  (void)algo;
+  what = "low-level";
+  errtxt = NULL; /*selftest ();*/
+  if (errtxt)
+    goto failed;
 
-  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;
+  /* FIXME:  need more tests.  */
 
-  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]);
-}
+  return 0; /* Succeeded. */
 
+ failed:
+  if (report)
+    report ("pubkey", GCRY_PK_ECDSA, 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;
+  gpg_err_code_t ec;
 
-  if (DBG_CIPHER)
-    {
-      log_debug ("ECC get nbits.\n");
-    }
+  (void)extended;
 
-  if (DBG_CIPHER)
+  switch (algo)
     {
-      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]);
-    }
+    case GCRY_PK_ECDSA:
+      ec = selftests_ecdsa (report);
+      break;
+    default:
+      ec = GPG_ERR_PUBKEY_ALGO;
+      break;
 
-  return mpi_get_nbits (pkey[0]);
+    }
+  return ec;
 }
 
 
+
+\f
 static const char *ecdsa_names[] =
   {
     "ecdsa",
+    "ecc",
+    NULL,
+  };
+static const char *ecdh_names[] =
+  {
+    "ecdh",
+    "ecc",
     NULL,
   };
 
 gcry_pk_spec_t _gcry_pubkey_spec_ecdsa =
   {
-    "ECDSA", ecdsa_names, 
-    "pabxyznXYZ", "pabxyznXYZd", "", "rs", "pabxyznXYZ",
+    "ECDSA", ecdsa_names,
+    "pabgnq", "pabgnqd", "", "rs", "pabgnq",
     GCRY_PK_USAGE_SIGN,
     ecc_generate,
     ecc_check_secret_key,
@@ -2015,5 +2164,27 @@ gcry_pk_spec_t _gcry_pubkey_spec_ecdsa =
     ecc_get_nbits
   };
 
+gcry_pk_spec_t _gcry_pubkey_spec_ecdh =
+  {
+    "ECDH", ecdh_names,
+    "pabgnq", "pabgnqd", "se", "", "pabgnq",
+    GCRY_PK_USAGE_ENCR,
+    ecc_generate,
+    ecc_check_secret_key,
+    ecc_encrypt_raw,
+    ecc_decrypt_raw,
+    NULL,
+    NULL,
+    ecc_get_nbits
+  };
 
 
+pk_extra_spec_t _gcry_pubkey_extraspec_ecdsa =
+  {
+    run_selftests,
+    ecc_generate_ext,
+    compute_keygrip,
+    ecc_get_param,
+    ecc_get_curve,
+    ecc_get_param_sexp
+  };