ecc: Fix a minor flaw in the generation of K.
[libgcrypt.git] / cipher / ecc.c
index b2e0847..63ee2d0 100644 (file)
-/* ecc.c  -  ECElGamal Public Key encryption & ECDSA signature algorithm
- *     Copyright (C) 2004, 2005, 2006 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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/>.
  */
 
-/* This code is a based on the 
- * Patch 0.1.6 for the gnupg 1.4.x branch
- * as retrieved on 2007-03-21 from
- * http://www.calcurco.cat/eccGnuPG/src/gnupg-1.4.6-ecc0.2.0beta1.diff.bz2
- *
- * Written by 
- *  Sergi Blanch i Torne <d4372211 at alumnes.eup.udl.es>, 
- *  Ramiro Moreno Chiral <ramiro at eup.udl.es>
- * Maintainers
- *  Sergi Blanch i Torne
- *  Ramiro Moreno Chiral
- *  Mikael Mylnikov (mmr)
- */
+/* This 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,
+*/
+
+
+/* TODO:
+
+  - If we support point compression we need to uncompress before
+    computing the keygrip
+
+  - 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:
- *  genBigPoint(): 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 "types.h"
-#include "util.h"
+#include <errno.h>
+
+#include "g10lib.h"
 #include "mpi.h"
 #include "cipher.h"
-#include "ecc.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
-
-typedef struct {
-        MPI x_;
-        MPI y_;
-        MPI z_;
-} point; //Point representation in projective coordinates.
-
-typedef struct {
-        MPI p_;
-        MPI a_,b_;
-        //MPI Gx,Gy,Gz;
-        point G;
-        MPI n_;
-        //MPI h_; =1                    //!! We will need to change this value in 2-isogeny
-} ellipticCurve;//doubtful name         //!!
-
-typedef struct {
-        ellipticCurve E;
-        point Q;        /*Q=[d]G*/
-} ECC_public_key;//Q
-
-typedef struct {
-        ellipticCurve E;
-        point Q;        /*Q=[d]G*/
-        MPI d;
-} ECC_secret_key;//d
-
-
-static MPI gen_k( MPI p, int secure );
-
-static void generateCurve(unsigned nbits, ellipticCurve *ECC_curve);//choice a curve of the rank
-
-static void generateKey(ECC_secret_key *sk, unsigned nbits , MPI **factors );//Generate de cryptosystem setup.
-static void testKeys( ECC_secret_key *sk, unsigned nbits );//verify correct skey
-static int check_secret_key( ECC_secret_key *sk );//check the validity of the value
-static void doEncrypt(MPI input, ECC_public_key *pkey, point *R, MPI c);
-static MPI decrypt(MPI output, ECC_secret_key *skey, point R, MPI c);
-static void sign(MPI input, ECC_secret_key *skey, MPI *r, MPI *s);
-static int verify(MPI input, ECC_public_key *pkey, MPI r, MPI s);
-
-static int genBigPoint(MPI *prime, ellipticCurve *base, point *G, unsigned nbits);//return -1 if it isn't possible
-static point genPoint(MPI prime, ellipticCurve base);//random point over an Elliptic curve
-static MPI existSquareRoot(MPI integer, MPI modulus);//return true or false
-static void Lucas(MPI n, MPI p_, MPI q_, MPI k, MPI V_n, MPI Q_0);
-
-static int PointAtInfinity(point Query);//return true(1), false(0), or error(-1) for an invalid point
-
-static void escalarMult(MPI escalar, point *P, point *R, ellipticCurve *base);//return R=escalarP
-static void sumPoints(point *P0, point *P1, point *P2, ellipticCurve *base);//P2=P0+P1
-static void duplicatePoint(point *P, point *R, ellipticCurve *base);//R=2P
-static void invertPoint(point *P, ellipticCurve *base);//P=-P
-
-static point point_copy(point P);
-static void point_free(point *P);
-static int point_affine(point *P, MPI x, MPI y, ellipticCurve *base);//turn an projective coordinate to affine, return 0 (1 if error).
-static ellipticCurve curve_copy(ellipticCurve E);
-static void curve_free(ellipticCurve *E);
-static MPI gen_bit();
-static MPI gen_y_2(MPI x, ellipticCurve *base);
-
-//Function for IFP ECElGamal Weakness.
-static void sha256_hashing(MPI input, MPI *output);//Compute a hash
-static void aes256_encrypting(MPI key, MPI input, MPI *output);//Encrypt simmetricaly
-static void aes256_decrypting(MPI key, MPI input, MPI *output);//Decrypt simmetricaly
-
-static void (*progress_cb) ( void *, int );
+#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 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;
+  mpi_point_struct Q; /* Q = [d]G  */
+} ECC_public_key;
+
+typedef struct
+{
+  elliptic_curve_t E;
+  mpi_point_struct Q;
+  gcry_mpi_t d;
+} ECC_secret_key;
+
+
+/* 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.  */
+  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, 1,
+      "0xfffffffffffffffffffffffffffffffeffffffffffffffff",
+      "0xfffffffffffffffffffffffffffffffefffffffffffffffc",
+      "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
+      "0xffffffffffffffffffffffff99def836146bc9b1b4d22831",
+
+      "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
+      "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"
+    },
+    {
+      "NIST P-224", 224, 1,
+      "0xffffffffffffffffffffffffffffffff000000000000000000000001",
+      "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe",
+      "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
+      "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" ,
+
+      "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
+      "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"
+    },
+    {
+      "NIST P-256", 256, 1,
+      "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
+      "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc",
+      "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
+      "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
+
+      "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
+      "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
+    },
+    {
+      "NIST P-384", 384, 1,
+      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
+      "ffffffff0000000000000000ffffffff",
+      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
+      "ffffffff0000000000000000fffffffc",
+      "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a"
+      "c656398d8a2ed19d2a85c8edd3ec2aef",
+      "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf"
+      "581a0db248b0a77aecec196accc52973",
+
+      "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38"
+      "5502f25dbf55296c3a545e3872760ab7",
+      "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0"
+      "0a60b1ce1d7e819d7a431d7c90ea0e5f"
+    },
+    {
+      "NIST P-521", 521, 1,
+      "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+      "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+      "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+      "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc",
+      "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10"
+      "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
+      "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+      "ffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409",
+
+      "0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3d"
+      "baa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
+      "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e6"
+      "62c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"
+    },
+
+    { "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 }
+  };
+
+
+/* Registered progress function and its callback value. */
+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 void test_keys (ECC_secret_key * sk, unsigned int nbits);
+static int check_secret_key (ECC_secret_key * sk);
+static gpg_err_code_t sign (gcry_mpi_t input, ECC_secret_key *skey,
+                            gcry_mpi_t r, gcry_mpi_t s);
+static gpg_err_code_t verify (gcry_mpi_t input, ECC_public_key *pkey,
+                              gcry_mpi_t r, gcry_mpi_t s);
+
+
+static gcry_mpi_t gen_y_2 (gcry_mpi_t x, elliptic_curve_t * base);
+
+
+
+\f
+void
+_gcry_register_pk_ecc_progress (void (*cb) (void *, const char *,
+                                            int, int, int),
+                                void *cb_data)
+{
+  progress_cb = cb;
+  progress_cb_data = cb_data;
+}
+
+/* static void */
+/* progress (int c) */
+/* { */
+/*   if (progress_cb) */
+/*     progress_cb (progress_cb_data, "pk_ecc", c, 0, 0); */
+/* } */
+
+
+\f
+
+/* Set the value from S into D.  */
 static void
-progress( int c )
+point_set (mpi_point_t d, mpi_point_t s)
 {
-    if ( progress_cb )
-       progress_cb ( progress_cb_data, c );
-    else
-       fputc( c, stderr );
+  mpi_set (d->x, s->x);
+  mpi_set (d->y, s->y);
+  mpi_set (d->z, s->z);
 }
 
-/****************
- * At the begging was the same than elgamal.c
- * but mmr improve it.
- * Generate a random secret scalar k with an order of p
- * Moreover it do NOT use Wiener's table.
+
+/*
+ * Release a curve object.
  */
-static MPI
-gen_k( MPI p, int secure ){
-
-    MPI k = mpi_alloc_secure( 0 );
-    unsigned int nbits = mpi_get_nbits(p);
-    unsigned int nbytes;
-
-    nbytes = (nbits+7)/8;
-    if( DBG_CIPHER )
-       log_debug("choosing a random k of %u bits\n", nbits);
-    char *c = get_random_bits( nbits, secure, 1 );
-    mpi_set_buffer( k, c, nbytes, 0 );
-    xfree(c);
-    mpi_fdiv_r(k,k, p);//simple module: k=k (mod p)
-    if( DBG_CIPHER )
-       progress('\n');
-
-    return k;
+static void
+curve_free (elliptic_curve_t *E)
+{
+  mpi_free (E->p); E->p = NULL;
+  mpi_free (E->a); E->a = NULL;
+  mpi_free (E->b);  E->b = NULL;
+  point_free (&E->G);
+  mpi_free (E->n);  E->n = NULL;
 }
 
-/****************
- * Generate de cryptosystem setup.
- * At this time it fix the values to the ones which NIST recomend.
- * The subgroup generator point is in another function: 'genBigPoint'.
+
+/*
+ * Return a copy of a curve object.
  */
-static void
-generateCurve(unsigned nbits, ellipticCurve *ECC_curve){
-
-        ellipticCurve E;
-        //point *G;
-
-        if( nbits == 192 ){//NIST P-192
-                E.p_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.p_,\
-                        "0xfffffffffffffffffffffffffffffffeffffffffffffffff"))
-                        log_fatal("ECC operation: Curve assigments failed(p)\n");
-                else    ECC_curve->p_ = mpi_copy(E.p_);
-                E.a_ =mpi_alloc((2/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.a_,\
-                       "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC"))//"-0x3"))
-                        log_fatal("ECC operation: Curve assigments failed(a)\n");
-                else    ECC_curve->a_ = mpi_copy(E.a_);
-                E.b_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.b_,\
-                        "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1"))
-                        log_fatal("ECC operation: Curve assigments failed(b)\n");
-                else    ECC_curve->b_ = mpi_copy(E.b_);
-                E.n_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.n_,\
-                        "0xffffffffffffffffffffffff99def836146bc9b1b4d22831"))
-                        log_fatal("ECC operation: Curve assigments failed(n)\n");
-                else    ECC_curve->n_ = mpi_copy(E.n_);
-        }
-        else if( nbits == 224 ){//NIST P-224
-               E.p_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.p_,\
-                        "0xffffffffffffffffffffffffffffffff000000000000000000000001"))
-                        log_fatal("ECC operation: Curve assigments failed(p)\n");
-               else    ECC_curve->p_ = mpi_copy(E.p_);
-               E.a_ =mpi_alloc((2/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.a_,\
-                       "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE"))//"-0x3"))
-                        log_fatal("ECC operation: Curve assigments failed(a)\n");
-               else    ECC_curve->a_ = mpi_copy(E.a_);
-               E.b_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.b_,\
-                        "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4"))
-                        log_fatal("ECC operation: Curve assigments failed(b)\n");
-               else    ECC_curve->b_ = mpi_copy(E.b_);
-               E.n_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.n_,\
-                        "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d"))
-                        log_fatal("ECC operation: Curve assigments failed(n)\n");
-               else    ECC_curve->n_ = mpi_copy(E.n_);
-        }
-        else if( nbits == 256 ){//NIST P-256
-               E.p_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.p_,\
-                        "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"))
-                        log_fatal("ECC operation: Curve assigments failed(p)\n");
-               else    ECC_curve->p_ = mpi_copy(E.p_);
-               E.a_ =mpi_alloc((2/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.a_,\
-                       "0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"))//"-0x3"))
-                        log_fatal("ECC operation: Curve assigments failed(a)\n");
-               else    ECC_curve->a_ = mpi_copy(E.a_);
-               E.b_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.b_,\
-                        "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"))
-                        log_fatal("ECC operation: Curve assigments failed(b)\n");
-               else    ECC_curve->b_ = mpi_copy(E.b_);
-               E.n_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.n_,\
-                        "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"))
-                        log_fatal("ECC operation: Curve assigments failed(n)\n");
-               else    ECC_curve->n_ = mpi_copy(E.n_);
-        }
-        else if( nbits == 384 ){//NIST P-384
-               E.p_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.p_,\
-                        "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff"))
-                       log_fatal("ECC operation: Curve assigments failed(p)\n");
-               else    ECC_curve->p_ = mpi_copy(E.p_);
-               E.a_ =mpi_alloc((2/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.a_,\
-                       "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC"))//"-0x3"))
-                        log_fatal("ECC operation: Curve assigments failed(a)\n");
-               else    ECC_curve->a_ = mpi_copy(E.a_);
-               E.b_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.b_,\
-                        "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef"))
-                        log_fatal("ECC operation: Curve assigments failed(b)\n");
-               else    ECC_curve->b_ = mpi_copy(E.b_);
-               E.n_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.n_,\
-                        "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973"))
-                        log_fatal("ECC operation: Curve assigments failed(n)\n");
-               else    ECC_curve->n_ = mpi_copy(E.n_);
-        }
-        else if( nbits == 521 ){//NIST P-521
-               E.p_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.p_,\
-                        "0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
-                        log_fatal("ECC operation: Curve assigments failed(p)\n");
-               else    ECC_curve->p_ = mpi_copy(E.p_);
-               E.a_ =mpi_alloc((2/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.a_,\
-                       "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC"))//"-0x3"))
-                        log_fatal("ECC operation: Curve assigments failed(a)\n");
-               else    ECC_curve->a_ = mpi_copy(E.a_);
-               E.b_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.b_,\
-                        "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00"))
-                        log_fatal("ECC operation: Curve assigments failed(b)\n");
-               else    ECC_curve->b_ = mpi_copy(E.b_);
-               E.n_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
-                if (mpi_fromstr(E.n_,\
-                        "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409"))
-                        log_fatal("ECC operation: Curve assigments failed(n)\n");
-               else    ECC_curve->n_ = mpi_copy(E.n_);
-        }
-        else{
-                log_fatal("ECC operation: Curve generation failed\n");
-        }
-        if( DBG_CIPHER ){
-               progress('\n');
-               log_mpidump("generation  p= ", ECC_curve->p_ );
-               log_mpidump("generation  a= ", ECC_curve->a_ );
-               log_mpidump("generation  b= ", ECC_curve->b_ );
-               log_mpidump("generation  n= ", ECC_curve->n_ );
-        }
-        if ( genBigPoint(&ECC_curve->n_, ECC_curve, &ECC_curve->G, nbits) == -1){
-                log_fatal("ECC operation: Point generation failed\n");
-        }
-        if( DBG_CIPHER ) {
-               log_mpidump("generation  Gx= ", ECC_curve->G.x_ );
-               log_mpidump("generation  Gy= ", ECC_curve->G.y_ );
-               log_mpidump("generation  Gz= ", ECC_curve->G.z_ );
-                log_info("Setup generated\n");
-               progress('\n');
-        }
+static elliptic_curve_t
+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);
+  point_init (&R.G);
+  point_set (&R.G, &E.G);
+  R.n = mpi_copy (E.n);
+
+  return R;
 }
 
+
+/* 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;
+}
+
+
+
+\f
+
 /****************
- * Fisrt obtain the setup.
- * Over the finite field randomize an scalar secret value, and calculat de public point.
- * 
- *        !! What about the **ret_factors !!  //!!
+ * Solve the right side of the equation that defines a curve.
  */
-static void
-generateKey(ECC_secret_key *sk, unsigned nbits , MPI **ret_factors ){
+static gcry_mpi_t
+gen_y_2 (gcry_mpi_t x, elliptic_curve_t *base)
+{
+  gcry_mpi_t three, x_3, axb, y;
+
+  three = mpi_alloc_set_ui (3);
+  x_3 = mpi_new (0);
+  axb = mpi_new (0);
+  y   = mpi_new (0);
+
+  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_free (x_3);
+  mpi_free (axb);
+  mpi_free (three);
+  return y; /* The quadratic value of the coordinate if it exist. */
+}
+
 
-        ellipticCurve E;
-        MPI d;
-        point Q,G;
+/* 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)
+        {
+          for (aliasno = 0; curve_aliases[aliasno].name; aliasno++)
+            if (!strcmp (name, curve_aliases[aliasno].other))
+              break;
+          if (curve_aliases[aliasno].name)
+            {
+              for (idx = 0; domain_parms[idx].desc; idx++)
+                if (!strcmp (curve_aliases[aliasno].name,
+                             domain_parms[idx].desc))
+                  {
+                    resname = domain_parms[idx].desc;
+                    break;
+                  }
+            }
+        }
+    }
+  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;
+}
 
-        generateCurve(nbits,&E);
 
-       d = mpi_alloc_secure(nbits/BITS_PER_MPI_LIMB);
-        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);
+/*
+ * 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, 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;
+
+  *r_usedcurve = NULL;
+
+  err = fill_in_curve (nbits, name, &E, &nbits);
+  if (err)
+    return err;
+
+  if (DBG_CIPHER)
+    {
+      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);
+    }
 
-        escalarMult(d,&E.G,&Q,&E);
+  random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM;
+  d = _gcry_dsa_gen_k (E.n, random_level);
+
+  /* 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);
+
+  /* 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);
+
+    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 */
+
+    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);
+  }
+
+  /* We also return copies of G and Q in affine coordinates if
+     requested.  */
+  if (g_x && g_y)
+    {
+      if (_gcry_mpi_ec_get_affine (g_x, g_y, &sk->E.G, ctx))
+        log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "G");
+    }
+  if (q_x && q_y)
+    {
+      if (_gcry_mpi_ec_get_affine (q_x, q_y, &sk->Q, ctx))
+        log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q");
+    }
+  _gcry_mpi_ec_free (ctx);
 
-        /* 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);
+  point_free (&Q);
+  mpi_free (d);
 
-        /* now we can test our keys (this should never fail!) */
-        testKeys( sk, nbits - 64 );
+  *r_usedcurve = E.name;
+  curve_free (&E);
 
-        point_free(&Q);
-        mpi_free(d);
-        curve_free(&E);
+  /* Now we can test our keys (this should never fail!).  */
+  test_keys (sk, nbits - 64);
+
+  return 0;
 }
 
-/****************
+
+/*
  * To verify correct skey it use a random information.
- * First, encrypt and decrypt this dummy value, 
+ * First, encrypt and decrypt this dummy value,
  * test if the information is recuperated.
  * Second, test with the sign and verify functions.
  */
 static void
-testKeys( ECC_secret_key *sk, unsigned nbits ){
-
-        ECC_public_key pk;
-        MPI test = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
-        point R_;
-        MPI c = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
-        MPI out = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
-        MPI r = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
-        MPI s = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
-
-        if( DBG_CIPHER )log_info("Testing key.\n");
-
-        pk.E = curve_copy(sk->E);
-        pk.E.G = point_copy(sk->E.G);
-        pk.Q = point_copy(sk->Q);
-
-        /*mpi_set_bytes( test, nbits, get_random_byte, 0 );*/
-        {      char *p = get_random_bits( nbits, 0, 0 );
-               mpi_set_buffer( test, p, (nbits+7)/8, 0 );
-               xfree(p);
-        }
+test_keys (ECC_secret_key *sk, unsigned int nbits)
+{
+  ECC_public_key pk;
+  gcry_mpi_t test = mpi_new (nbits);
+  mpi_point_struct R_;
+  gcry_mpi_t c = mpi_new (nbits);
+  gcry_mpi_t out = mpi_new (nbits);
+  gcry_mpi_t r = mpi_new (nbits);
+  gcry_mpi_t s = mpi_new (nbits);
 
-        doEncrypt(test,&pk,&R_,c);
+  if (DBG_CIPHER)
+    log_debug ("Testing key.\n");
 
-        out = decrypt(out,sk,R_,c);
+  point_init (&R_);
 
-        if( mpi_cmp( test, out ) )//test!=out
-               log_fatal("ECELG operation: encrypt, decrypt failed\n");
-        if( DBG_CIPHER )log_info("ECELG operation: encrypt, decrypt ok.\n");
+  pk.E = curve_copy (sk->E);
+  point_init (&pk.Q);
+  point_set (&pk.Q, &sk->Q);
 
-        sign(test,sk,&r,&s);
+  gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
 
-        if( !verify(test,&pk,r,s) ){
-               log_fatal("ECDSA operation: sign, verify failed\n");}
+  if (sign (test, sk, r, s) )
+    log_fatal ("ECDSA operation: sign failed\n");
 
-        if( DBG_CIPHER )log_info("ECDSA operation: sign, verify ok.\n");
+  if (verify (test, &pk, r, s))
+    {
+      log_fatal ("ECDSA operation: sign, verify failed\n");
+    }
+
+  if (DBG_CIPHER)
+    log_debug ("ECDSA operation: sign, verify ok.\n");
+
+  point_free (&pk.Q);
+  curve_free (&pk.E);
 
-        mpi_free(s);
-        mpi_free(r);
-        mpi_free(out);
-        mpi_free(c);
-        point_free(&R_);
-        mpi_free(test);
+  point_free (&R_);
+  mpi_free (s);
+  mpi_free (r);
+  mpi_free (out);
+  mpi_free (c);
+  mpi_free (test);
 }
 
-/****************
+
+/*
  * To check the validity of the value, recalculate the correspondence
- * between the public value and de secret one.
+ * between the public value and the secret one.
  */
 static int
-check_secret_key( ECC_secret_key *sk ){
-
-        point Q;
-        MPI y_2,y2 = mpi_alloc(0);
-
-        //?primarity test of 'p'
-        // (...) //!!
-        //G in E(F_p)
-        y_2 = gen_y_2(sk->E.G.x_,&sk->E);// y^2=x^3+a*x+b
-        mpi_mulm(y2,sk->E.G.y_,sk->E.G.y_,sk->E.p_);// y^2=y*y
-        if (mpi_cmp(y_2,y2)){
-                if( DBG_CIPHER )log_info("Bad check: Point 'G' does not belong to curve 'E'!\n");
-                return (1);
-        }
-        //G != PaI
-        if (PointAtInfinity(sk->E.G)){
-                if( DBG_CIPHER )log_info("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
-        escalarMult(sk->E.n_,&sk->E.G,&Q,&sk->E);
-        if (!PointAtInfinity(Q)){
-                if( DBG_CIPHER )log_info("Bad check: 'E' is not curve of order 'n'!\n");
-                return (1);
-        }
-        //pubkey cannot be PaI
-        if (PointAtInfinity(sk->Q)){
-                if( DBG_CIPHER )log_info("Bad check: Q can not be a Point at Infinity!\n");
-                return (1);
-        }
-        //pubkey = [d]G over E
-        escalarMult(sk->d,&sk->E.G,&Q,&sk->E);
-        if ((Q.x_ == sk->Q.x_) && (Q.y_ == sk->Q.y_) && (Q.z_ == sk->Q.z_)){
-                if( DBG_CIPHER )log_info("Bad check: There is NO correspondence between 'd' and 'Q'!\n");
-                return (1);
-        }
-        point_free(&Q);
-        return (0);
-}
+check_secret_key (ECC_secret_key * sk)
+{
+  int rc = 1;
+  mpi_point_struct Q;
+  gcry_mpi_t y_2, y2;
+  mpi_ec_t ctx = NULL;
+
+  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;
+    }
+  /* 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;
+    }
 
-/****************
- * Encrypt a number and obtain and struct (R,c)
- */
-static void
-doEncrypt(MPI input, ECC_public_key *pkey, point *R, MPI c){
-
-        MPI k,p,x,y;
-        point P,Q,G;
-        ellipticCurve E;
-
-        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_info("Encrypting: Cannot turn to affine.\n");}
-        }
-        //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);
+  ctx = _gcry_mpi_ec_p_internal_new (sk->E.p, sk->E.a);
 
-        if( DBG_CIPHER ){log_debug("doEncrypt: end.\n");}
+  _gcry_mpi_ec_mul_point (&Q, sk->E.n, &sk->E.G, ctx);
+  if (mpi_cmp_ui (Q.z, 0))
+    {
+      if (DBG_CIPHER)
+        log_debug ("check_secret_key: E is not a curve of order n\n");
+      goto leave;
+    }
+  /* 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.  */
+
+ leave:
+  _gcry_mpi_ec_free (ctx);
+  mpi_free (y2);
+  mpi_free (y_2);
+  point_free (&Q);
+  return rc;
 }
 
-/****************
- * Undo the ciphertext
+
+/*
+ * Return the signature struct (r,s) from the message hash.  The caller
+ * must have allocated R and S.
  */
-static MPI
-decrypt(MPI output, ECC_secret_key *skey, point R, MPI c){
-
-        MPI p,inv,x,y;
-        point P,Q;
-        ellipticCurve E;
-
-        p = mpi_copy(skey->E.p_);
-        inv = mpi_alloc(0);
-        x = mpi_alloc(0);
-        y = mpi_alloc(0);
-        Q = point_copy(skey->Q);
-        E = curve_copy(skey->E);
-
-        escalarMult(skey->d,&R,&P,&E);//P=[d]R
-        //That is like: mpi_fdiv_q(output,c,Q.x_);
-       //IFP weakness//mpi_invm(inv,Q.x_,p);//inv=Q{_x}^-1 (mod p)
-       //IFP weakness//mpi_mulm(output,c,inv,p);//output=c*inv (mod p)
-        //MMR Use affine conversion befor extract x-coordinate
-        if (point_affine(&P,x,y,&E)){//Q cannot turn to affine coordinate
-                if( DBG_CIPHER ){log_info("Encrypting: Cannot turn to affine.\n");}
+static gpg_err_code_t
+sign (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s)
+{
+  gpg_err_code_t err = 0;
+  gcry_mpi_t k, dr, sum, k_1, x;
+  mpi_point_struct I;
+  mpi_ec_t ctx;
+
+  if (DBG_CIPHER)
+    log_mpidump ("ecdsa sign hash  ", input );
+
+  k = NULL;
+  dr = mpi_alloc (0);
+  sum = mpi_alloc (0);
+  k_1 = mpi_alloc (0);
+  x = mpi_alloc (0);
+  point_init (&I);
+
+  mpi_set_ui (s, 0);
+  mpi_set_ui (r, 0);
+
+  ctx = _gcry_mpi_ec_p_internal_new (skey->E.p, skey->E.a);
+
+  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 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 */
         }
-        sha256_hashing(x,&x);
-        aes256_decrypting(x,c,&output);
+      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_mpidump ("ecdsa sign result r ", r);
+      log_mpidump ("ecdsa sign result s ", s);
+    }
+
+ 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);
 
-        if( DBG_CIPHER ){log_debug("decrypt: end.\n");}
-        return (output);
+  return err;
 }
 
-/****************
- * Return the signature struct (r,s) from the message hash.
+
+/*
+ * Check if R and S verifies INPUT.
  */
-static void
-sign(MPI input, ECC_secret_key *skey, MPI *r, MPI *s){
-
-        MPI k,i,dr,sum,k_1,x,y;
-        point G,I;
-        ellipticCurve E;
-
-        k = mpi_alloc(0); i = mpi_alloc(0); 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);
-        *r = mpi_alloc(0);
-        *s = mpi_alloc(0);
-
-        while (!mpi_cmp_ui(*s,0)){//s==0
-               while (!mpi_cmp_ui(*r,0)){//r==0
-                        k = gen_k( E.p_, 1 );
-                        escalarMult(k,&G,&I,&E);//I=[k]G
-                        if (point_affine(&I,x,y,&E)){//I cannot turn to affine coordinate
-                              if( DBG_CIPHER ){log_info("Sign: Cannot turn to affine. Cannot complete sign.\n");}
-                        }
-                        i = mpi_copy(x);//i=I_x
-                        mpi_fdiv_r(*r,i,E.n_);//simple module: 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)
+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;
+  mpi_point_struct Q, Q1, Q2;
+  mpi_ec_t ctx;
+
+  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.  */
+
+  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");
         }
-       if( DBG_CIPHER ){log_debug("Sign: end\n");}
-        mpi_free(y);
-        mpi_free(x);
-        mpi_free(k_1);
-        mpi_free(sum);
-        mpi_free(dr);
-        mpi_free(i);
-        mpi_free(k);
+      err = GPG_ERR_BAD_SIGNATURE;
+      goto leave;
+    }
+  if (DBG_CIPHER)
+    log_debug ("ecc verify: Accepted\n");
+
+ 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;
 }
 
-/****************
- * Check if the struct (r,s) is for the hash value that it have.
- */
-static int
-verify(MPI input, ECC_public_key *pkey, MPI r, MPI s){
-
-        MPI r_,s_,h,h1,h2,i,x,y;
-        point Q,Q1,Q2,G;
-        ellipticCurve E;
-
-        r_ = mpi_alloc(0); s_ = mpi_alloc(0); h = mpi_alloc(0); h1 = mpi_alloc(0); h2 = mpi_alloc(0); x = mpi_alloc(0); y = mpi_alloc(0);
-        G = point_copy(pkey->E.G);
-        E = curve_copy(pkey->E);
-        
-        mpi_fdiv_r(r_,r,pkey->E.n_);//simple module
-        mpi_fdiv_r(s_,s,pkey->E.n_);//simple module
-
-        //check if the input parameters are valid.
-        if ( mpi_cmp(r_,r) || mpi_cmp(s_,s)) {//r_!=r || s_!=s
-                if( DBG_CIPHER ){log_info("Verification: No valid values.\n");}
-                return 0; //not valid values.
-        }
 
-        mpi_invm(h,s,E.n_);//h=s^(-1) (mod n)
-        mpi_mulm(h1,input,h,E.n_);//h1=hash*s^(-1) (mod n)
-        escalarMult(h1,&G,&Q1,&E);//Q1=[hash*s^(-1)]G
-        mpi_mulm(h2,r,h,E.n_);//h2=r*s^(-1) (mod n)
-        escalarMult(h2,&pkey->Q,&Q2,&E);//Q2=[r*s^(-1)]Q
-        sumPoints(&Q1,&Q2,&Q,&E);//Q=([hash*s^(-1)]G)+([r*s^(-1)]Q)
+\f
+/*********************************************
+ **************  interface  ******************
+ *********************************************/
+static gcry_mpi_t
+ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p)
+{
+  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));
+    }
 
-        if (PointAtInfinity(Q)){
-                if( DBG_CIPHER ){log_info("Verification: Rejected.\n");}
-                return 0;//rejected
-        }
-       if (point_affine(&Q,x,y,&E)){//Q cannot turn to affine coordinate
-               if( DBG_CIPHER ){log_info("Verification: Cannot turn to affine. Rejected.\n");}
-               return 0;//rejected
-        }
-        i = mpi_copy(x);//Give the x_coordinate
-        mpi_fdiv_r(i,i,E.n_);//simple module
+  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 (!mpi_cmp(i,r)){//i==r => Return 0 (distance between them).
-                if( DBG_CIPHER ){log_info("Verification: Accepted.\n");}
-                return 1;//accepted
-        }
-        if( DBG_CIPHER ){log_info("Verification: Not verified.\n");}
-        return 0;
+  return result;
 }
 
-/****************
- * A point of order 'n' is needed to generate a ciclic subgroup.
- * Over this ciclic subgroup it's defined the ECDLP.
- * Now it use a fix values from NIST FIPS PUB 186-2.
- */
-static int
-genBigPoint(MPI *prime, ellipticCurve *base, point *G, unsigned nbits){
-  ///*estandard nist
-        if( nbits == 192 ){//NIST P-192
-                G->x_ = mpi_alloc(mpi_get_nlimbs(base->n_));
-                if (mpi_fromstr(G->x_,\
-                        "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012"))
-                        log_fatal("Generator operation: Point assigments failed(x)\n");
-                G->y_ = mpi_alloc(mpi_get_nlimbs(base->n_));
-                if (mpi_fromstr(G->y_,\
-                        "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"))
-                        log_fatal("Generator operation: Point assigments failed(y)\n");
-                G->z_ = mpi_alloc_set_ui(1);
-        }
-        else if( nbits == 224 ){//NIST P-224
-                G->x_ = mpi_alloc(mpi_get_nlimbs(base->n_));
-                if (mpi_fromstr(G->x_,\
-                        "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21"))
-                        log_fatal("Generator operation: Point assigments failed(x)\n");
-                G->y_ = mpi_alloc(mpi_get_nlimbs(base->n_));
-                if (mpi_fromstr(G->y_,\
-                        "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"))
-                        log_fatal("Generator operation: Point assigments failed(y)\n");
-                G->z_ = mpi_alloc_set_ui(1);
-        }
-        else if( nbits == 256 ){//NIST P-256
-                G->x_ = mpi_alloc(mpi_get_nlimbs(base->n_));
-                if (mpi_fromstr(G->x_,\
-                        "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"))
-                        log_fatal("Generator operation: Point assigments failed(x)\n");
-                G->y_ = mpi_alloc(mpi_get_nlimbs(base->n_));
-                if (mpi_fromstr(G->y_,\
-                        "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"))
-                        log_fatal("Generator operation: Point assigments failed(y)\n");
-                G->z_ = mpi_alloc_set_ui(1);
-        }
-        else if( nbits == 384 ){//NIST P-384
-                G->x_ = mpi_alloc(mpi_get_nlimbs(base->n_));
-                if (mpi_fromstr(G->x_,\
-                        "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7"))
-                        log_fatal("Generator operation: Point assigments failed(x)\n");
-                G->y_ = mpi_alloc(mpi_get_nlimbs(base->n_));
-                if (mpi_fromstr(G->y_,\
-                        "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f"))
-                        log_fatal("Generator operation: Point assigments failed(y)\n");
-                G->z_ = mpi_alloc_set_ui(1);
-        }
-        else if( nbits == 521 ){//NIST P-521
-                G->x_ = mpi_alloc(mpi_get_nlimbs(base->n_));
-                if (mpi_fromstr(G->x_,\
-                        "0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66"))
-                        log_fatal("Generator operation: Point assigments failed(x)\n");
-                G->y_ = mpi_alloc(mpi_get_nlimbs(base->n_));
-                if (mpi_fromstr(G->y_,\
-                        "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"))
-                        log_fatal("Generator operation: Point assigments failed(y)\n");
-                G->z_ = mpi_alloc_set_ui(1);
-        }
-  //end Estandard nist
-  /*Randomize G
-        unsigned int i=0;
-        MPI one;
-        point 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_MPI )log_info("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_MPI )log_info("Big point generated.\n");
-        if( DBG_MPI ){
-                log_mpidump("Gx=",G->x_);log_mpidump("Gy=",G->y_);log_mpidump("Gz=",G->z_);
-        }
-        return 0;
-  *///end aleatoritzar G
-        return 0;
+
+/* 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 result;
 }
 
-/****************
- * Generate a random point over an Elliptic curve 
- * is the first step to find a random ciclic subgroup
- * generator.
- *
- *        !! At this moment it isn't used !!  //!!
- */
-static point
-genPoint(MPI prime, ellipticCurve base){
-
-        unsigned int i=0;
-        MPI x,y_2,y;
-        MPI one, one_neg,bit;
-        point P;
-
-        x = mpi_alloc(mpi_get_nlimbs(base.p_));
-        y_2 = mpi_alloc(mpi_get_nlimbs(base.p_));
-        y = mpi_alloc(mpi_get_nlimbs(base.p_));
-        one = mpi_alloc_set_ui(1);
-        one_neg = mpi_alloc(mpi_get_nlimbs(one));
-        mpi_invm(one_neg,one,base.p_);
-
-        if( DBG_MPI )log_info("Generating a normal point.\n");
-        do{
-               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_);
-        }
-        if( DBG_MPI )log_info("Normal point generated.\n");
 
-        P.x_ = mpi_copy(x);
-        P.y_ = mpi_copy(y);
-        P.z_ = mpi_copy(one);
+/* 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)
+{
+  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)
+    {
+      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(bit);
-        mpi_free(one_neg);
-        mpi_free(one);
-        mpi_free(y);
-        mpi_free(y_2);
-        mpi_free(x);
+  mpi_free (x);
+  mpi_free (y);
 
-        return(P);
+  return 0;
 }
 
-/****************
- * Find, if it exist, the square root of one integer module a big prime.
- * Return the square root or 0 if it is not found.
- */
-static MPI
-existSquareRoot(MPI integer, MPI modulus){
-
-        unsigned long int i=0;
-        MPI one,two,three,four,five,eight;
-        MPI k,r,z,k1;
-        MPI t1,t2,t3,t4;
-
-        one = mpi_alloc_set_ui(1);
-        two = mpi_alloc_set_ui(2);
-        three = mpi_alloc_set_ui(3);
-        four = mpi_alloc_set_ui(4);
-        five = mpi_alloc_set_ui(5);
-        eight = mpi_alloc_set_ui(8);
-        k = mpi_alloc(mpi_get_nlimbs(modulus));
-        r = mpi_alloc(mpi_get_nlimbs(modulus));
-        z = mpi_alloc(mpi_get_nlimbs(modulus));
-        k1 = mpi_alloc(mpi_get_nlimbs(modulus));
-        t1 = mpi_alloc(mpi_get_nlimbs(modulus));
-        t2 = mpi_alloc(mpi_get_nlimbs(modulus));
-        t3 = mpi_alloc(mpi_get_nlimbs(modulus));
-        t4 = mpi_alloc(mpi_get_nlimbs(modulus));
-
-        if( DBG_MPI )log_mpidump("?exist Square Root of ",integer);
-
-        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_MPI ){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_MPI ){log_mpidump("z=",z);}
-                return z;//value found
+
+/* 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)
+{
+  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;
+
+  (void)algo;
+  (void)evalue;
+
+  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. */
         }
-        if (mpi_cmp(r,one)){//p=1 (mod 8)
-                while(i<0xFF){//while not find z after 256 iterations*/
-                        if( DBG_MPI )log_info("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_MPI ){log_mpidump("z=",z);}
-                                return z;//value found
-                        }
-                        if (t4>mpi_alloc_set_ui(1) && t4<t3){
-                                if( DBG_MPI )log_info("Rejected.\n");
-                                return (0);             //NULL
-                        }
-                        if( DBG_MPI )log_info("Another loop.\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);
         }
-        if( DBG_MPI )log_info("iterations limit.\n");
-        return (0);//because this algorithm not always finish.
-}
+    }
 
-/****************
- * Formal definition:
- * V_0=2;V_1=p
- * V_k=(p*V_(k-1))-(q*V_(k-2)) for k>=2
- */
-static void
-Lucas(MPI n, MPI p_, MPI q_, MPI k, MPI V_n, MPI Q_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)
+    {
+      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]);
+    }
 
-        MPI v0,v1,q0,q1;
-        MPI t1,t2;
-        unsigned int r,i;
+  return 0;
+}
 
-        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);
 
-        if( DBG_MPI ){log_info("Generating lucas sequence.\n");log_mpidump("k=",k);}
+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);
+}
 
-        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_MPI ){
-                        log_info("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_MPI ){
-                log_info("Lucas sequence generated.\n");
-                log_mpidump("V_n=",V_n);
-                log_mpidump("Q_0=",Q_0);
-        }
+
+/* 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;
+  mpi_ec_t ctx;
+  gcry_mpi_t g_x, g_y;
+
+  err = fill_in_curve (0, name, &E, &nbits);
+  if (err)
+    return err;
+
+  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);
+
+  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;
+
+  mpi_free (g_x);
+  mpi_free (g_y);
+
+  return 0;
 }
 
-/****************
- * 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.
- */
-static int
-PointAtInfinity(point Query){
 
-        if( DBG_MPI ){log_info("?is a Point at Infinity.\n");}
+/* Return the parameters of the curve NAME as an S-expression.  */
+static gcry_sexp_t
+ecc_get_param_sexp (const char *name)
+{
+  gcry_mpi_t pkey[6];
+  gcry_sexp_t result;
+  int i;
 
-        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
-                        if( DBG_MPI )log_info("True:It is a Point at Infinite.\n");
-                        return (1); //true
-                }
-                if( DBG_MPI )log_info("Error:It isn't an elliptic curve valid point.\n");
-                return (-1); //
-        }
-        if( DBG_MPI ){log_info("False:It isn't a Point at Infinity.\n");}
-        return (0); //it is a valid curve point, but it isn't the point at infinity
-}
+  if (ecc_get_param (name, pkey))
+    return NULL;
 
-/****************
- * The modular power used without EC, 
- * is this function over EC.
- */
-static void
-escalarMult(MPI escalar, point *P, point *R, ellipticCurve *base){
-
-        MPI one,two,three;
-        MPI p;
-        MPI xx,yy,zz,x1,y1,z1,z2,z3,k,h;//it could use less memory!!!!
-        unsigned int i,loops;
-        point P1,P2,P1_;
-
-        x1 = mpi_alloc(mpi_get_nlimbs(P->x_));
-        y1 = mpi_alloc(mpi_get_nlimbs(P->y_));
-        z2 = mpi_alloc(mpi_get_nlimbs(P->z_));
-        z3 = mpi_alloc(mpi_get_nlimbs(P->z_));
-        h = mpi_alloc(mpi_get_nlimbs(P->z_));
-
-        if( DBG_MPI )log_info("Calculating an scalar Multiple.\n");
-
-        one = mpi_alloc_set_ui(1);
-        two = mpi_alloc_set_ui(2);
-        three = mpi_alloc_set_ui(3);
-        p = mpi_copy(base->p_);
-
-        if ( !mpi_cmp_ui(escalar,0) || mpi_cmp_ui(P->z_,0)){//n=0 | Z=0 => [1:1:0]
-                R->x_ = mpi_copy(one);
-                R->y_ = mpi_copy(one);
-                R->z_ = mpi_alloc(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 {
-                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
-        R->x_ = mpi_copy(xx);
-        R->y_ = mpi_copy(yy);
-        R->z_ = mpi_copy(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
-                duplicatePoint(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);
-                        sumPoints(&P2,&P1,R,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);
-                        invertPoint(&P1_,base);
-                        sumPoints(&P2,&P1_,R,base);//R=P2+P1_ over the base elliptic curve
-                }
-                i--;
-        }
-        if( DBG_MPI )log_info("Scalar Multiple calculated.\n");
-
-       point_free(&P1);
-       point_free(&P2);
-        point_free(&P1_);
-       mpi_free(h);
-        mpi_free(k);
-        mpi_free(z3);
-        mpi_free(z2);
-        mpi_free(z1);
-        mpi_free(y1);
-        mpi_free(x1);
-        mpi_free(zz);
-        mpi_free(yy);
-        mpi_free(xx);
-        mpi_free(p);
-        mpi_free(three);
-        mpi_free(two);
-        mpi_free(one);
+  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;
+
+  for (i=0; pkey[i]; i++)
+    gcry_mpi_release (pkey[i]);
+
+  return result;
 }
 
-/****************
- * Point addition is the group operation.
- */
-static void
-sumPoints(point *P0, point *P1, point *P2, ellipticCurve *base){
-
-        MPI one,two;
-        MPI p;
-        MPI t1,t2,t3,t4,t5,t6,t7;
-
-        one = mpi_alloc_set_ui(1);
-        two = mpi_alloc_set_ui(2);
-        p = mpi_copy(base->p_);
-        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));
-
-        if( DBG_MPI )log_info("Add two points.\n");
-
-        if ((!mpi_cmp(P1->x_,P0->x_)) && (!mpi_cmp(P1->y_,P0->y_)) && (!mpi_cmp(P1->z_,P0->z_))){// P1=P0
-                duplicatePoint(P0,P2,base);
-        }
-        else if (PointAtInfinity(*P0)){//(!mpi_cmp_ui(P0->y_,0) || !mpi_cmp_ui(P0->z_,0)){// P2=0+P1=P1
-                P2->x_ = mpi_copy(P1->x_);
-                P2->y_ = mpi_copy(P1->y_);
-                P2->z_ = mpi_copy(P1->z_);
-        }
-        else if (PointAtInfinity(*P1)){//(!mpi_cmp_ui(P1->y_,0) || !mpi_cmp_ui(P1->z_,0)){// P2=P0+0=P0
-                P2->x_ = mpi_copy(P0->x_);
-                P2->y_ = mpi_copy(P0->y_);
-                P2->z_ = mpi_copy(P0->z_);
+
+/* 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 (r_nbits)
+    *r_nbits = 0;
+
+  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;
         }
-        else {
-                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
-                        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 have an special mean.
-                                if( DBG_MPI )log_info("Point Addition: [0:0:0]!\n");
-                                P2->x_ = mpi_copy(mpi_alloc_set_ui(0));
-                                P2->y_ = mpi_copy(mpi_alloc_set_ui(0));
-                                P2->z_ = mpi_copy(mpi_alloc_set_ui(0));
-                        }
-                        else {//return (1:1:0)
-                                if( DBG_MPI )log_info("Point Addition: [1:1:0]!\n");
-                                P2->x_ = mpi_copy(one);
-                                P2->y_ = mpi_copy(one);
-                                P2->z_ = mpi_copy(mpi_alloc_set_ui(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
+      return result;
+    }
+
+  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)
+    {
+      point_free (&E.G);
+      return NULL;
+    }
+  E.n = pkey[4];
+
+  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_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
-
-                        P2->x_ = mpi_copy(t1);
-                        P2->y_ = mpi_copy(t2);
-                        P2->z_ = mpi_copy(t3);
+                    }
                 }
+            }
         }
-        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);
-}
+      mpi_free (tmp);
+    }
 
-/****************
- * Scalar multiplication of one point, with the integer fixed to 2.
- */
-static void
-duplicatePoint(point *P, point *R, ellipticCurve *base){
-
-        MPI one,two,three,four,eight;
-        MPI p,p_3,a;
-        MPI t1,t2,t3,t4,t5,t6,t7;
-        MPI aux;
-
-        one = mpi_alloc_set_ui(1);
-        two = mpi_alloc_set_ui(2);
-        three = mpi_alloc_set_ui(3);
-        four = mpi_alloc_set_ui(4);
-        eight = mpi_alloc_set_ui(8);
-        p = mpi_copy(base->p_);
-        p_3 = mpi_alloc(mpi_get_nlimbs(p));
-        mpi_sub_ui(p_3,p,3);
-        a = mpi_copy(base->a_);
-        t1 = mpi_alloc(mpi_get_nlimbs(p));
-        t2 = mpi_alloc(mpi_get_nlimbs(p));
-        t3 = mpi_alloc(mpi_get_nlimbs(p));
-        t4 = mpi_alloc(mpi_get_nlimbs(p));
-        t5 = mpi_alloc(mpi_get_nlimbs(p));
-        t6 = mpi_alloc(mpi_get_nlimbs(p));
-        t7 = mpi_alloc(mpi_get_nlimbs(p));
-        aux= mpi_alloc(mpi_get_nlimbs(p));
-
-        if( DBG_MPI ){log_info("Duplicate a point.\n");}
-
-        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]
-                if( DBG_MPI ){log_info("t2==0 | t3==0\n");}
-                R->x_ = mpi_copy(one);
-                R->y_ = mpi_copy(one);
-                R->z_ = mpi_copy(mpi_alloc_set_ui(0));
-        }
-        else{
-                mpi_fdiv_r(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
-                }
-                if( DBG_MPI ){log_info("t2!=0 & t3!=0\n");}
-                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
-
-                R->x_ = mpi_copy(t1);
-                R->y_ = mpi_copy(t2);
-                R->z_ = mpi_copy(t3);
-        }
-        if( DBG_MPI ){log_info("Duplicated point.\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);
+  point_free (&E.G);
 
+  return result;
 }
 
-/****************
- * The point inversion over F_p
- * is a simple modular inversion
- * of the Y coordinate.
- */
-static void
-invertPoint(point *P, ellipticCurve *base){
 
-        mpi_subm(P->y_,base->p_,P->y_,base->p_);//y=p-y mod p
-}
+static gcry_err_code_t
+ecc_check_secret_key (int algo, gcry_mpi_t *skey)
+{
+  gpg_err_code_t err;
+  ECC_secret_key sk;
+
+  (void)algo;
+
+  /* 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)
+    {
+      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 (&sk.E.G);
+      point_free (&sk.Q);
+      return err;
+    }
 
-/****************
- * Auxiliar function to made easy a struct copy.
- */
-static point
-point_copy(point P){
-        point R;
+  sk.d = skey[6];
 
-        R.x_ = mpi_copy(P.x_);
-        R.y_ = mpi_copy(P.y_);
-        R.z_ = mpi_copy(P.z_);
+  if (check_secret_key (&sk))
+    {
+      point_free (&sk.E.G);
+      point_free (&sk.Q);
+      return GPG_ERR_BAD_SECKEY;
+    }
+  point_free (&sk.E.G);
+  point_free (&sk.Q);
+  return 0;
+}
 
-        return R;
+
+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;
+
+  (void)algo;
+
+  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;
+    }
+  sk.E.n = skey[4];
+  /* Note: We don't have any need for Q here.  */
+  sk.d = skey[6];
+
+  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.  */
+    }
+  point_free (&sk.E.G);
+  return err;
 }
 
-/****************
- * Made easy the free memory for a point struct.
- */
-static void
-point_free(point *P){
 
-        mpi_free(P->x_);
-        mpi_free(P->y_);
-        mpi_free(P->z_);
+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;
+
+  (void)algo;
+  (void)cmp;
+  (void)opaquev;
+
+  if (!data[0] || !data[1] || !hash || !pkey[0] || !pkey[1] || !pkey[2]
+      || !pkey[3] || !pkey[4] || !pkey[5] )
+    return GPG_ERR_BAD_MPI;
+
+  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;
+    }
+
+  err = verify (hash, &pk, data[0], data[1]);
+
+  point_free (&pk.E.G);
+  point_free (&pk.Q);
+  return err;
 }
 
-/****************
- * Turn a projective coordinate to affine, return 0 (or 1 in error case).
- * Needed to verify a signature.
+
+/* 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
  *
- * y_coordinate it is never used, we could do without it. //!!
+ * 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 int 
-point_affine(point *P, MPI x, MPI y, ellipticCurve *base){
+static gcry_err_code_t
+ecc_encrypt_raw (int algo, gcry_mpi_t *resarr, gcry_mpi_t k,
+                 gcry_mpi_t *pkey, int flags)
+{
+  ECC_public_key pk;
+  mpi_ec_t ctx;
+  gcry_mpi_t result[2];
+  int err;
+
+  (void)algo;
+  (void)flags;
+
+  if (!k
+      || !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] || !pkey[4] || !pkey[5])
+    return GPG_ERR_BAD_MPI;
+
+  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;
+    }
 
-        //MPI z;
-        MPI z1,z2,z3;
+  ctx = _gcry_mpi_ec_p_internal_new (pk.E.p, pk.E.a);
 
-        z1 = mpi_alloc(0);
-        z2 = mpi_alloc(0);
-        z3 = mpi_alloc(0);
+  /* 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;
 
-        if (PointAtInfinity(*P)){
-                if( DBG_CIPHER )log_info("Affine: Point at Infinity does NOT exist in the affine plane!\n");
-                return 1;
-       }
+    x = mpi_new (0);
+    y = mpi_new (0);
 
-        mpi_invm(z1,P->z_,base->p_);    //      z1 =Z^{-1} (mod p)
-        mpi_mulm(z2,z1,z1,base->p_);    //      z2 =Z^(-2) (mod p)
-        mpi_mulm(z3,z2,z1,base->p_);    //      z3 =Z^(-3) (mod p)
-        mpi_mulm(x,P->x_,z2,base->p_);
-        mpi_mulm(y,P->y_,z3,base->p_);
+    point_init (&R);
 
-        mpi_free(z1);
-        mpi_free(z2);
-        mpi_free(z3);
-        return 0;
-}
+    /* R = kQ  <=>  R = kdG  */
+    _gcry_mpi_ec_mul_point (&R, k, &pk.Q, ctx);
 
-/****************
- * Auxiliar function to made easy a struct copy.
- */
-static ellipticCurve
-curve_copy(ellipticCurve E){
+    if (_gcry_mpi_ec_get_affine (x, y, &R, ctx))
+      log_fatal ("ecdh: Failed to get affine coordinates for kdG\n");
 
-        ellipticCurve R;
+    result[0] = ec2os (x, y, pk.E.p);
 
-        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 = kG */
+    _gcry_mpi_ec_mul_point (&R, k, &pk.E.G, ctx);
 
-        return R;
-}
+    if (_gcry_mpi_ec_get_affine (x, y, &R, ctx))
+      log_fatal ("ecdh: Failed to get affine coordinates for kG\n");
 
-/****************
- * Made easy the free memory for a setup struct.
- */
-static void
-curve_free(ellipticCurve *E){
-        mpi_free(E->p_);
-        mpi_free(E->a_);
-        mpi_free(E->b_);
-        point_free(&E->G);
-        mpi_free(E->n_);
-}
+    result[1] = ec2os (x, y, pk.E.p);
 
-/****************
- * Boolean generator to choose between to coordinates.
- */
-static MPI
-gen_bit(){
+    mpi_free (x);
+    mpi_free (y);
 
-        MPI aux = mpi_alloc_set_ui(0);
+    point_free (&R);
+  }
 
-        //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(...)
+  _gcry_mpi_ec_free (ctx);
+  point_free (&pk.E.G);
+  point_free (&pk.Q);
+
+  if (!result[0] || !result[1])
+    {
+      mpi_free (result[0]);
+      mpi_free (result[1]);
+      return GPG_ERR_ENOMEM;
+    }
 
-        return aux;//b;
+  /* Success.  */
+  resarr[0] = result[0];
+  resarr[1] = result[1];
+
+  return 0;
 }
 
-/****************
- * Solve the right side of the equation that define a curve.
+/*  input:
+ *     data[0] : a point kG (ephemeral public key)
+ *   output:
+ *     resaddr[0] : shared point kdG
+ *
+ *  see ecc_encrypt_raw for details.
  */
-static MPI
-gen_y_2(MPI x, ellipticCurve *base){
-
-        MPI three;
-        MPI x_3,ax,axb,y;
-        MPI a,b,p;
+static gcry_err_code_t
+ecc_decrypt_raw (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
+                 gcry_mpi_t *skey, int flags)
+{
+  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;
+
+  (void)algo;
+  (void)flags;
+
+  *result = NULL;
+
+  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;
+    }
 
-        three = mpi_alloc_set_ui(3);
-        a = mpi_copy(base->a_);
-        b = mpi_copy(base->b_),
-        p = mpi_copy(base->p_);
-        x_3 = mpi_alloc(mpi_get_nlimbs(p));
-        ax = mpi_alloc(mpi_get_nlimbs(p));
-        axb = mpi_alloc(mpi_get_nlimbs(p));
-        y = mpi_alloc(mpi_get_nlimbs(p));
 
-        if( DBG_MPI )log_info("solving an elliptic equation.\n");
+  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];
 
-        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
+  ctx = _gcry_mpi_ec_p_internal_new (sk.E.p, sk.E.a);
 
-        if( DBG_MPI )log_info("solved.\n");
+  /* R = dkG */
+  point_init (&R);
+  _gcry_mpi_ec_mul_point (&R, sk.d, &kG, ctx);
 
-        return y;//the quadratic value of the coordinate if it exist.
-}
+  point_free (&kG);
 
-//Function to solve an IFP ECElGamal weakness:
-// sha256_hashing()
-// aes256_encrypting()
-// aes356_decrypting()
+  /* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so:  */
+  {
+    gcry_mpi_t x, y;
 
-/****************
- * Compute 256 bit hash value from input MPI.
- * Use SHA256 Algorithm.
- */
-static void 
-sha256_hashing(MPI input, MPI *output){ // 
+    x = mpi_new (0);
+    y = mpi_new (0);
 
-        int sign;
-        byte *hash_inp_buf; 
-        byte hash_out_buf[32]; 
-        MD_HANDLE hash = md_open(8,1);//algo SHA256 in secure mode
+    if (_gcry_mpi_ec_get_affine (x, y, &R, ctx))
+      log_fatal ("ecdh: Failed to get affine coordinates\n");
 
-        unsigned int nbytes;
+    r = ec2os (x, y, sk.E.p);
+    mpi_free (x);
+    mpi_free (y);
+  }
 
-        hash_inp_buf = mpi_get_secure_buffer( input, &nbytes, &sign );//convert MPI input to string
+  point_free (&R);
+  _gcry_mpi_ec_free (ctx);
+  point_free (&kG);
+  point_free (&sk.E.G);
+  point_free (&sk.Q);
 
-        md_write( hash, hash_inp_buf, nbytes );//hashing input string
-        wipememory( hash_inp_buf, sizeof hash_inp_buf ); // burn temp value 
-        xfree(hash_inp_buf);
+  if (!r)
+    return GPG_ERR_ENOMEM;
 
-        md_digest(hash, 8, hash_out_buf, 32);
-        mpi_set_buffer( *output, hash_out_buf, 32, 0 );// convert 256 bit digest to MPI
+  /* Success.  */
 
-        wipememory( hash_out_buf, sizeof hash_out_buf ); // burn temp value 
-        md_close(hash);// destroy and free hash state.
+  *result = r;
 
+  return 0;
 }
 
-/****************
- * Encrypt input MPI.
- * Use AES256 algorithm.
- */
-
-static void 
-aes256_encrypting(MPI key, MPI input, MPI *output){ // 
 
-        int sign;
-        byte *key_buf; 
-        byte *cipher_buf; 
+static unsigned int
+ecc_get_nbits (int algo, gcry_mpi_t *pkey)
+{
+  (void)algo;
 
-        unsigned int keylength;
-        unsigned int nbytes;
+  return mpi_get_nbits (pkey[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
+/* 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;
+
+  /* Clear the values for easier error cleanup.  */
+  for (idx=0; idx < N_COMPONENTS; idx++)
+    values[idx] = NULL;
+
+  /* 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;
+            }
+       }
+    }
 
-        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);
+  /* 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];
+
+      for (idx = 0; idx < N_COMPONENTS; idx++)
+        tmpvalues[idx] = NULL;
+
+      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_buf = mpi_get_secure_buffer( input, &nbytes, &sign );//convert MPI input to string
+  /* 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]);
+
+  /* Hash them all.  */
+  for (idx = 0; idx < N_COMPONENTS; idx++)
+    {
+      char buf[30];
+      unsigned char *rawmpi;
+      unsigned int rawmpilen;
+
+      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_encrypt( 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
 }
 
-/****************
- * Decrypt input MPI.
- * Use AES256 algorithm.
+
+\f
+/*
+   Low-level API helper functions.
  */
 
-static void 
-aes256_decrypting(MPI key, MPI input, MPI *output){ // 
+/* 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)
+{
+  gcry_err_code_t ec = 0;
+  gcry_sexp_t l1;
+
+  l1 = gcry_sexp_find_token (keyparam, name, 0);
+  if (l1)
+    {
+      *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;
+}
 
-        int sign;
-        byte *key_buf; 
-        byte *cipher_buf; 
+/* 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;
+
+  ec = mpi_from_keyparam (&a, keyparam, name);
+  if (ec)
+    return ec;
+
+  if (a)
+    {
+      point = gcry_mpi_point_new (0);
+      ec = os2ec (point, a);
+      mpi_free (a);
+      if (ec)
+        {
+          gcry_mpi_point_release (point);
+          return ec;
+        }
+    }
+  else
+    {
+      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);
+    }
 
-        unsigned int keylength;
-        unsigned int nbytes;
+  if (point)
+    *r_a = point;
+  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
+/* 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)
+{
+  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;
+    }
 
-        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);
 
-        cipher_buf = mpi_get_secure_buffer( input, &nbytes, &sign );//convert MPI input to string;
+  /* 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)
+    {
+      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;
+        }
 
-        cipher_decrypt( cipher, cipher_buf+1, cipher_buf+1, nbytes-1 );//
-        cipher_close(cipher);// destroy and free cipher state.
+      errc = fill_in_curve (0, name? name : curvename, E, NULL);
+      gcry_free (name);
+      if (errc)
+        {
+          gcry_free (E);
+          goto leave;
+        }
 
-        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);
-}
-//End of IFP ECElGamal weakness functions.
+      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);
+    }
 
-/*********************************************
- **************  interface  ******************
- *********************************************/
-int
-ecc_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
-{
+  errc = _gcry_mpi_ec_p_new (&ctx, p, a);
+  if (!errc)
+    {
+      mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
 
-        ECC_secret_key sk;
-
-        if( !is_ECC(algo) )
-               return G10ERR_PUBKEY_ALGO;
-
-        generateKey( &sk, nbits, retfactors );
-
-        skey[0] = sk.E.p_;
-        skey[1] = sk.E.a_;
-        skey[2] = sk.E.b_;
-        skey[3] = sk.E.G.x_;
-        skey[4] = sk.E.G.y_;
-        skey[5] = sk.E.G.z_;
-        skey[6] = sk.E.n_;
-        skey[7] = sk.Q.x_;
-        skey[8] = sk.Q.y_;
-        skey[9] = sk.Q.z_;
-        skey[10] = sk.d;
-
-        if( DBG_CIPHER ) {
-               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]);
+      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;
+    }
 
-       if( DBG_CIPHER ){log_info("ECC key Generated.\n");}
-        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;
 }
 
 
-int
-ecc_check_secret_key( int algo, MPI *skey )
+/* 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_secret_key sk;
-
-        if( !is_ECC(algo) )
-               return G10ERR_PUBKEY_ALGO;
-        if(!skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] || !skey[5] || !skey[6] || !skey[7] || !skey[8] || !skey[9] || !skey[10])
-               return G10ERR_BAD_MPI;
-
-        if( DBG_CIPHER ){log_info("ECC check secret key.\n");}
-        sk.E.p_ = skey[0];
-        sk.E.a_ = skey[1];
-        sk.E.b_ = skey[2];
-        sk.E.G.x_ = skey[3];
-        sk.E.G.y_ = skey[4];
-        sk.E.G.z_ = skey[5];
-        sk.E.n_ = skey[6];
-        sk.Q.x_ = skey[7];
-        sk.Q.y_ = skey[8];
-        sk.Q.z_ = skey[9];
-        sk.d = skey[10];
-
-        if( check_secret_key(&sk)){
-                if( DBG_CIPHER )log_info("Bad check: Bad secret key.\n");
-                return G10ERR_BAD_SECKEY;
-        }
-        return 0;
-}
+  gpg_err_code_t rc;
+  gcry_mpi_t mpi_G = NULL;
+  gcry_mpi_t mpi_Q = NULL;
 
+  if (!ec->p || !ec->a || !ec->b || !ec->G || !ec->n)
+    return GPG_ERR_BAD_CRYPT_CTX;
 
+  if (mode == GCRY_PK_GET_SECKEY && !ec->d)
+    return GPG_ERR_NO_SECKEY;
 
-int
-ecc_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
-{
-        ECC_public_key pk;
-        point R;
-
-        if( algo != PUBKEY_ALGO_ECC && algo != PUBKEY_ALGO_ECC_E )
-                return G10ERR_PUBKEY_ALGO;
-        if( !data || !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] || !pkey[4] || !pkey[5] || !pkey[6] || !pkey[7] || !pkey[8] || !pkey[9])
-               return G10ERR_BAD_MPI;
-
-        if( DBG_CIPHER ){log_info("ECC encrypt.\n");}
-        pk.E.p_ = pkey[0];
-        pk.E.a_ = pkey[1];
-        pk.E.b_ = pkey[2];
-        pk.E.G.x_ = pkey[3];
-        pk.E.G.y_ = pkey[4];
-        pk.E.G.z_ = pkey[5];
-        pk.E.n_ = pkey[6];
-        pk.Q.x_ = pkey[7];
-        pk.Q.y_ = pkey[8];
-        pk.Q.z_ = pkey[9];
-
-        R.x_ = resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.Q.x_ ) );
-        R.y_ = resarr[1] = mpi_alloc( mpi_get_nlimbs( pk.Q.y_ ) );
-        R.z_ = resarr[2] = mpi_alloc( mpi_get_nlimbs( pk.Q.z_ ) );
-        resarr[3] = mpi_alloc( mpi_get_nlimbs( pk.E.p_ ) );
-
-        doEncrypt(data, &pk, &R, resarr[3]);
-
-       resarr[0] = mpi_copy(R.x_);
-       resarr[1] = mpi_copy(R.y_);
-       resarr[2] = mpi_copy(R.z_);
-        return 0;
-}
+  /* Compute the public point if it is missing.  */
+  if (!ec->Q && ec->d)
+    {
+      ec->Q = gcry_mpi_point_new (0);
+      _gcry_mpi_ec_mul_point (ec->Q, ec->d, ec->G, ec);
+    }
 
-int
-ecc_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
-{
-        ECC_secret_key sk;
-        point R;
-
-        if( algo != PUBKEY_ALGO_ECC && algo != PUBKEY_ALGO_ECC_E )
-                return G10ERR_PUBKEY_ALGO;
-        if( !data[0] || !data[1] || !data[2] || !data[3] || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] || !skey[5] || !skey[6] || !skey[7] || !skey[8] || !skey[9] || !skey[10])
-               return G10ERR_BAD_MPI;
-
-        if( DBG_CIPHER ){log_info("ECC decrypt.\n");}
-        R.x_ = data[0];
-        R.y_ = data[1];
-        R.z_ = data[2];
-        sk.E.p_ = skey[0];
-        sk.E.a_ = skey[1];
-        sk.E.b_ = skey[2];
-        sk.E.G.x_ = skey[3];
-        sk.E.G.y_ = skey[4];
-        sk.E.G.z_ = skey[5];
-        sk.E.n_ = skey[6];
-        sk.Q.x_ = skey[7];
-        sk.Q.y_ = skey[8];
-        sk.Q.z_ = skey[9];
-        sk.d = skey[10];
-
-        *result = mpi_alloc_secure( mpi_get_nlimbs( sk.E.p_ ) );
-        *result = decrypt( *result, &sk, R, data[3]);
-        return 0;
-}
+  /* 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;
+    }
 
-int
-ecc_sign( int algo, MPI *resarr, MPI data, MPI *skey )
-{
-        ECC_secret_key sk;
-
-        if( algo != PUBKEY_ALGO_ECC && algo != PUBKEY_ALGO_ECC_S )
-                return G10ERR_PUBKEY_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 G10ERR_BAD_MPI;
-
-        sk.E.p_ = skey[0];
-        sk.E.a_ = skey[1];
-        sk.E.b_ = skey[2];
-        sk.E.G.x_ = skey[3];
-        sk.E.G.y_ = skey[4];
-        sk.E.G.z_ = skey[5];
-        sk.E.n_ = skey[6];
-        sk.Q.x_ = skey[7];
-        sk.Q.y_ = skey[8];
-        sk.Q.z_ = skey[9];
-        sk.d = skey[10];
-
-        resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.E.p_ ) );
-        resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.E.p_ ) );
-        sign( data, &sk, &resarr[0], &resarr[1]);
-        return 0;
-}
+  /* Fixme: We should return a curve name instead of the parameters if
+     if know that they match a curve.  */
+
+  if (ec->d && (!mode || mode == GCRY_PK_GET_SECKEY))
+    {
+      /* 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));
+    }
+  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;
 
-int
-ecc_verify( int algo, MPI hash, MPI *data, MPI *pkey )
-{
-        ECC_public_key pk;
-
-        if( algo != PUBKEY_ALGO_ECC && algo != PUBKEY_ALGO_ECC_S )
-                return G10ERR_PUBKEY_ALGO;
-        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 G10ERR_BAD_MPI;
-
-        if( DBG_CIPHER ){log_info("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];
-
-        if( !verify( hash, &pk, data[0], data[1]) )
-               return G10ERR_BAD_SIGN;
-        return 0;
+ leave:
+  mpi_free (mpi_Q);
+  mpi_free (mpi_G);
+  return rc;
 }
 
 
+\f
+/*
+     Self-test section.
+ */
+
 
-unsigned int
-ecc_get_nbits( int algo, MPI *pkey )
+static gpg_err_code_t
+selftests_ecdsa (selftest_report_func_t report)
 {
-        if ( !is_ECC(algo) ){
-                return 0;
-        }
-        if( DBG_CIPHER ){log_info("ECC get nbits.\n");}
-
-        if( DBG_CIPHER ) {
-               progress('\n');
-
-               log_mpidump("[ecc]  p= ", pkey[0]);
-               log_mpidump("[ecc]  a= ", pkey[1]);
-               log_mpidump("[ecc]  b= ", pkey[2]);
-               log_mpidump("[ecc]  Gx= ", pkey[3]);
-               log_mpidump("[ecc]  Gy= ", pkey[4]);
-               log_mpidump("[ecc]  Gz= ", pkey[5]);
-               log_mpidump("[ecc]  n= ", pkey[6]);
-               log_mpidump("[ecc]  Qx= ", pkey[7]);
-               log_mpidump("[ecc]  Qy= ", pkey[8]);
-               log_mpidump("[ecc]  Qz= ", pkey[9]);
-        }
+  const char *what;
+  const char *errtxt;
+
+  what = "low-level";
+  errtxt = NULL; /*selftest ();*/
+  if (errtxt)
+    goto failed;
+
+  /* FIXME:  need more tests.  */
 
-        return mpi_get_nbits( pkey[0] );
+  return 0; /* Succeeded. */
+
+ failed:
+  if (report)
+    report ("pubkey", GCRY_PK_ECDSA, what, errtxt);
+  return GPG_ERR_SELFTEST_FAILED;
 }
 
-const char *
-ecc_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig, int *use )
+
+/* 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)
 {
-    *npkey = 10;
-    *nskey = 11;
-    *nenc = 4;
-    *nsig = 2;
-
-    if( DBG_CIPHER ){log_info("ECC get info.\n");}
-    switch( algo ) {
-      case PUBKEY_ALGO_ECC:
-        *use = PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC;
-        return "ECC";
-      case PUBKEY_ALGO_ECC_S:
-        *use = PUBKEY_USAGE_SIG;
-        return "ECDSA";
-      case PUBKEY_ALGO_ECC_E:
-        *use = PUBKEY_USAGE_ENC;
-        return "ECELG";
-      default: *use = 0; return NULL;
+  gpg_err_code_t ec;
+
+  (void)extended;
+
+  switch (algo)
+    {
+    case GCRY_PK_ECDSA:
+      ec = selftests_ecdsa (report);
+      break;
+    default:
+      ec = GPG_ERR_PUBKEY_ALGO;
+      break;
+
     }
+  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,
+    "pabgnq", "pabgnqd", "", "rs", "pabgnq",
+    GCRY_PK_USAGE_SIGN,
+    ecc_generate,
+    ecc_check_secret_key,
+    NULL,
+    NULL,
+    ecc_sign,
+    ecc_verify,
+    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
+  };