Enable AMD64 SHA512 implementations for WIN64
[libgcrypt.git] / cipher / ecc.c
index bd4d253..2f5e401 100644 (file)
   verification algorithms.  The arithmetic functions have entirely
   been rewritten and moved to mpi/ec.c.
 
-  ECDH encrypt and decrypt code written by Andrey Jivsov,
+  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.
 
@@ -71,6 +68,7 @@ static const char *ecc_names[] =
     "ecdsa",
     "ecdh",
     "eddsa",
+    "gost",
     NULL,
   };
 
@@ -80,20 +78,10 @@ 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_ecdsa (gcry_mpi_t input, ECC_secret_key *skey,
-                                  gcry_mpi_t r, gcry_mpi_t s,
-                                  int flags, int hashalgo);
-static gpg_err_code_t verify_ecdsa (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);
+static void test_ecdh_only_keys (ECC_secret_key * sk, unsigned int nbits);
 static unsigned int ecc_get_nbits (gcry_sexp_t parms);
 
 
@@ -117,32 +105,6 @@ _gcry_register_pk_ecc_progress (void (*cb) (void *, const char *,
 
 
 \f
-
-/*
- * Solve the right side of the Weierstrass equation.
- */
-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. */
-}
-
-
 /* Standard version of the key generation.  */
 static gpg_err_code_t
 nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
@@ -153,7 +115,21 @@ nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
   point_init (&Q);
 
   /* Generate a secret.  */
-  sk->d = _gcry_dsa_gen_k (E->n, random_level);
+  if (ctx->dialect == ECC_DIALECT_ED25519)
+    {
+      char *rndbuf;
+
+      sk->d = mpi_snew (256);
+      rndbuf = _gcry_random_bytes_secure (32, random_level);
+      rndbuf[0] &= 0x7f;  /* Clear bit 255. */
+      rndbuf[0] |= 0x40;  /* Set bit 254.   */
+      rndbuf[31] &= 0xf8; /* Clear bits 2..0 so that d mod 8 == 0  */
+      _gcry_mpi_set_buffer (sk->d, rndbuf, 32, 0);
+      xfree (rndbuf);
+    }
+  else
+    sk->d = _gcry_dsa_gen_k (E->n, random_level);
+
 
   /* Compute Q.  */
   _gcry_mpi_ec_mul_point (&Q, sk->d, &E->G, ctx);
@@ -167,6 +143,7 @@ nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
   point_init (&sk->E.G);
   point_set (&sk->E.G, &E->G);
   sk->E.n = mpi_copy (E->n);
+  sk->E.h = mpi_copy (E->h);
   point_init (&sk->Q);
 
   /* We want the Q=(x,y) be a "compliant key" in terms of the
@@ -175,45 +152,68 @@ nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
    * 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, y, p_y;
-    const unsigned int pbits = mpi_get_nbits (E->p);
+   * possibilities without any loss of security.  Note that we don't
+   * do that for Ed25519 so that we do not violate the special
+   * construction of the secret key.  */
+  if (E->dialect == ECC_DIALECT_ED25519)
+    point_set (&sk->Q, &Q);
+  else
+    {
+      gcry_mpi_t x, y, negative;
+      const unsigned int pbits = mpi_get_nbits (E->p);
 
-    x = mpi_new (pbits);
-    y = mpi_new (pbits);
-    p_y = mpi_new (pbits);
+      x = mpi_new (pbits);
+      y = mpi_new (pbits);
+      negative = mpi_new (pbits);
 
-    if (_gcry_mpi_ec_get_affine (x, y, &Q, ctx))
-      log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q");
+      if (_gcry_mpi_ec_get_affine (x, y, &Q, ctx))
+        log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q");
 
-    mpi_sub (p_y, E->p, y);    /* p_y = p - y */
+      if (E->model == MPI_EC_WEIERSTRASS)
+        mpi_sub (negative, E->p, y);      /* negative = p - y */
+      else
+        mpi_sub (negative, E->p, x);      /* negative = p - x */
 
-    if (mpi_cmp (p_y, y) < 0)   /* p - y < p */
-      {
-        /* We need to end up with -Q; this assures that new Q's y is
-           the smallest one */
-        mpi_sub (sk->d, E->n, sk->d);   /* d = order - d */
-        gcry_mpi_point_snatch_set (&sk->Q, x, p_y, mpi_alloc_set_ui (1));
+      if (mpi_cmp (negative, y) < 0)   /* p - y < p */
+        {
+          /* We need to end up with -Q; this assures that new Q's y is
+             the smallest one */
+          mpi_sub (sk->d, E->n, sk->d);   /* d = order - d */
+          if (E->model == MPI_EC_WEIERSTRASS)
+            mpi_point_snatch_set (&sk->Q, x, negative,
+                                       mpi_alloc_set_ui (1));
+          else
+            mpi_point_snatch_set (&sk->Q, negative, y, mpi_alloc_set_ui (1));
 
-      if (DBG_CIPHER)
-        log_debug ("ecgen converted Q to a compliant point\n");
-      }
-    else /* p - y >= p */
-      {
-        /* No change is needed exactly 50% of the time: just copy. */
-        point_set (&sk->Q, &Q);
-        if (DBG_CIPHER)
-          log_debug ("ecgen didn't need to convert Q to a compliant point\n");
+          if (DBG_CIPHER)
+            log_debug ("ecgen converted Q to a compliant point\n");
+        }
+      else /* p - y >= p */
+        {
+          /* No change is needed exactly 50% of the time: just copy. */
+          point_set (&sk->Q, &Q);
+          if (DBG_CIPHER)
+            log_debug ("ecgen didn't need to convert Q to a compliant point\n");
+
+          mpi_free (negative);
+          if (E->model == MPI_EC_WEIERSTRASS)
+            mpi_free (x);
+          else
+            mpi_free (y);
+        }
 
-        mpi_free (p_y);
+      if (E->model == MPI_EC_WEIERSTRASS)
+        mpi_free (y);
+      else
         mpi_free (x);
-      }
-    mpi_free (y);
-  }
+    }
 
+  point_free (&Q);
   /* Now we can test our keys (this should never fail!).  */
-  test_keys (sk, nbits - 64);
+  if (sk->E.model != MPI_EC_MONTGOMERY)
+    test_keys (sk, nbits - 64);
+  else
+    test_ecdh_only_keys (sk, nbits - 64);
 
   return 0;
 }
@@ -245,12 +245,12 @@ test_keys (ECC_secret_key *sk, unsigned int nbits)
   point_init (&pk.Q);
   point_set (&pk.Q, &sk->Q);
 
-  gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
+  _gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
 
-  if (sign_ecdsa (test, sk, r, s, 0, 0) )
+  if (_gcry_ecc_ecdsa_sign (test, sk, r, s, 0, 0) )
     log_fatal ("ECDSA operation: sign failed\n");
 
-  if (verify_ecdsa (test, &pk, r, s))
+  if (_gcry_ecc_ecdsa_verify (test, &pk, r, s))
     {
       log_fatal ("ECDSA operation: sign, verify failed\n");
     }
@@ -270,962 +270,189 @@ test_keys (ECC_secret_key *sk, unsigned int nbits)
 }
 
 
-/*
- * To check the validity of the value, recalculate the correspondence
- * between the public value and the secret one.
- */
-static int
-check_secret_key (ECC_secret_key * sk)
-{
-  int rc = 1;
-  mpi_point_struct Q;
-  gcry_mpi_t y_2, y2;
-  gcry_mpi_t x1, x2;
-  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);
-  x1 = mpi_alloc (0);
-  x2 = 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;
-    }
-
-  ctx = _gcry_mpi_ec_p_internal_new (sk->E.model, sk->E.dialect,
-                                     sk->E.p, sk->E.a, sk->E.b);
-
-  _gcry_mpi_ec_mul_point (&Q, sk->E.n, &sk->E.G, ctx);
-  if (mpi_cmp_ui (Q.z, 0))
-    {
-      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 (_gcry_mpi_ec_get_affine (x1, y_2, &Q, ctx))
-    {
-      if (DBG_CIPHER)
-        log_debug ("Bad check: Q can not be a Point at Infinity!\n");
-      goto leave;
-    }
-
-  /* Fast path for loaded secret keys - Q is already in affine coordinates */
-  if (!mpi_cmp_ui (sk->Q.z, 1))
-    {
-      if (mpi_cmp (x1, sk->Q.x) || mpi_cmp (y_2, sk->Q.y))
-        {
-          if (DBG_CIPHER)
-            log_debug
-              ("Bad check: There is NO correspondence between 'd' and 'Q'!\n");
-          goto leave;
-        }
-    }
-  else
-    {
-      if (_gcry_mpi_ec_get_affine (x2, y2, &sk->Q, ctx))
-        {
-          if (DBG_CIPHER)
-            log_debug ("Bad check: Q can not be a Point at Infinity!\n");
-          goto leave;
-        }
-
-      if (mpi_cmp (x1, x2) || mpi_cmp (y_2, y2))
-        {
-          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 (x2);
-  mpi_free (x1);
-  mpi_free (y2);
-  mpi_free (y_2);
-  point_free (&Q);
-  return rc;
-}
-
-
-/* Compute an ECDSA signature.
- * Return the signature struct (r,s) from the message hash.  The caller
- * must have allocated R and S.
- */
-static gpg_err_code_t
-sign_ecdsa (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s,
-            int flags, int hashalgo)
-{
-  gpg_err_code_t err = 0;
-  int extraloops = 0;
-  gcry_mpi_t k, dr, sum, k_1, x;
-  mpi_point_struct I;
-  gcry_mpi_t hash;
-  const void *abuf;
-  unsigned int abits, qbits;
-  mpi_ec_t ctx;
-
-  if (DBG_CIPHER)
-    log_mpidump ("ecdsa sign hash  ", input );
-
-  qbits = mpi_get_nbits (skey->E.n);
-
-  /* Convert the INPUT into an MPI if needed.  */
-  if (mpi_is_opaque (input))
-    {
-      abuf = gcry_mpi_get_opaque (input, &abits);
-      err = gpg_err_code (gcry_mpi_scan (&hash, GCRYMPI_FMT_USG,
-                                         abuf, (abits+7)/8, NULL));
-      if (err)
-        return err;
-      if (abits > qbits)
-        gcry_mpi_rshift (hash, hash, abits - qbits);
-    }
-  else
-    hash = input;
-
-
-  k = NULL;
-  dr = mpi_alloc (0);
-  sum = mpi_alloc (0);
-  k_1 = mpi_alloc (0);
-  x = mpi_alloc (0);
-  point_init (&I);
-
-  ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect,
-                                     skey->E.p, skey->E.a, skey->E.b);
-
-  /* Two loops to avoid R or S are zero.  This is more of a joke than
-     a real demand because the probability of them being zero is less
-     than any hardware failure.  Some specs however require it.  */
-  do
-    {
-      do
-        {
-          mpi_free (k);
-          k = NULL;
-          if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo)
-            {
-              /* Use Pornin's method for deterministic DSA.  If this
-                 flag is set, it is expected that HASH is an opaque
-                 MPI with the to be signed hash.  That hash is also
-                 used as h1 from 3.2.a.  */
-              if (!mpi_is_opaque (input))
-                {
-                  err = GPG_ERR_CONFLICT;
-                  goto leave;
-                }
-
-              abuf = gcry_mpi_get_opaque (input, &abits);
-              err = _gcry_dsa_gen_rfc6979_k (&k, skey->E.n, skey->d,
-                                             abuf, (abits+7)/8,
-                                             hashalgo, extraloops);
-              if (err)
-                goto leave;
-              extraloops++;
-            }
-          else
-            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 */
-        }
-      while (!mpi_cmp_ui (r, 0));
-
-      mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n  */
-      mpi_addm (sum, hash, 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 */
-    }
-  while (!mpi_cmp_ui (s, 0));
-
-  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 (hash != input)
-    mpi_free (hash);
-
-  return err;
-}
-
-
-/* Verify an ECDSA signature.
- * Check if R and S verifies INPUT.
- */
-static gpg_err_code_t
-verify_ecdsa (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;
-  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);
-  point_init (&Q);
-  point_init (&Q1);
-  point_init (&Q2);
-
-  ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect,
-                                     pkey->E.p, pkey->E.a, pkey->E.b);
-
-  /* h  = s^(-1) (mod n) */
-  mpi_invm (h, s, pkey->E.n);
-  /* h1 = hash * s^(-1) (mod n) */
-  mpi_mulm (h1, input, h, pkey->E.n);
-  /* Q1 = [ hash * s^(-1) ]G  */
-  _gcry_mpi_ec_mul_point (&Q1, h1, &pkey->E.G, ctx);
-  /* h2 = r * s^(-1) (mod n) */
-  mpi_mulm (h2, r, h, pkey->E.n);
-  /* Q2 = [ r * s^(-1) ]Q */
-  _gcry_mpi_ec_mul_point (&Q2, h2, &pkey->Q, ctx);
-  /* Q  = ([hash * s^(-1)]G) + ([r * s^(-1)]Q) */
-  _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx);
-
-  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, NULL, &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 ("     r", r);
-          log_mpidump ("     s", s);
-          log_debug ("ecc verify: Not verified\n");
-        }
-      err = GPG_ERR_BAD_SIGNATURE;
-      goto leave;
-    }
-  if (DBG_CIPHER)
-    log_debug ("ecc verify: Accepted\n");
-
- leave:
-  _gcry_mpi_ec_free (ctx);
-  point_free (&Q2);
-  point_free (&Q1);
-  point_free (&Q);
-  mpi_free (x);
-  mpi_free (h2);
-  mpi_free (h1);
-  mpi_free (h);
-  return err;
-}
-
-
-\f
 static void
-reverse_buffer (unsigned char *buffer, unsigned int length)
-{
-  unsigned int tmp, i;
-
-  for (i=0; i < length/2; i++)
-    {
-      tmp = buffer[i];
-      buffer[i] = buffer[length-1-i];
-      buffer[length-1-i] = tmp;
-    }
-}
-
-
-/* Encode MPI using the EdDSA scheme.  MINLEN specifies the required
-   length of the buffer in bytes.  On success 0 is returned an a
-   malloced buffer with the encoded point is stored at R_BUFFER; the
-   length of this buffer is stored at R_BUFLEN.  */
-static gpg_err_code_t
-eddsa_encodempi (gcry_mpi_t mpi, unsigned int minlen,
-                 unsigned char **r_buffer, unsigned int *r_buflen)
-{
-  unsigned char *rawmpi;
-  unsigned int rawmpilen;
-
-  rawmpi = _gcry_mpi_get_buffer (mpi, minlen, &rawmpilen, NULL);
-  if (!rawmpi)
-    return gpg_err_code_from_syserror ();
-
-  *r_buffer = rawmpi;
-  *r_buflen = rawmpilen;
-  return 0;
-}
-
-
-/* Encode (X,Y) using the EdDSA scheme.  MINLEN is the required length
-   in bytes for the result.  On success 0 is returned and a malloced
-   buffer with the encoded point is stored at R_BUFFER; the length of
-   this buffer is stored at R_BUFLEN.  */
-static gpg_err_code_t
-eddsa_encode_x_y (gcry_mpi_t x, gcry_mpi_t y, unsigned int minlen,
-                  unsigned char **r_buffer, unsigned int *r_buflen)
-{
-  unsigned char *rawmpi;
-  unsigned int rawmpilen;
-
-  rawmpi = _gcry_mpi_get_buffer (y, minlen, &rawmpilen, NULL);
-  if (!rawmpi)
-    return gpg_err_code_from_syserror ();
-  if (mpi_test_bit (x, 0) && rawmpilen)
-    rawmpi[rawmpilen - 1] |= 0x80;  /* Set sign bit.  */
-
-  *r_buffer = rawmpi;
-  *r_buflen = rawmpilen;
-  return 0;
-}
-
-/* Encode POINT using the EdDSA scheme.  X and Y are either scratch
-   variables supplied by the caller or NULL.  CTX is the usual
-   context.  On success 0 is returned and a malloced buffer with the
-   encoded point is stored at R_BUFFER; the length of this buffer is
-   stored at R_BUFLEN.  */
-gpg_err_code_t
-_gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ec,
-                             gcry_mpi_t x_in, gcry_mpi_t y_in,
-                             unsigned char **r_buffer, unsigned int *r_buflen)
-{
-  gpg_err_code_t rc;
-  gcry_mpi_t x, y;
-
-  x = x_in? x_in : mpi_new (0);
-  y = y_in? y_in : mpi_new (0);
-
-  if (_gcry_mpi_ec_get_affine (x, y, point, ec))
-    {
-      log_error ("eddsa_encodepoint: Failed to get affine coordinates\n");
-      rc = GPG_ERR_INTERNAL;
-    }
-  else
-    rc = eddsa_encode_x_y (x, y, ec->nbits/8, r_buffer, r_buflen);
-
-  if (!x_in)
-    mpi_free (x);
-  if (!y_in)
-    mpi_free (y);
-  return rc;
-}
-
-
-/* Decode the EdDSA style encoded PK and set it into RESULT.  CTX is
-   the usual curve context.  If R_ENCPK is not NULL, the encoded PK is
-   stored at that address; this is a new copy to be released by the
-   caller.  In contrast to the supplied PK, this is not an MPI and
-   thus guarnateed to be properly padded.  R_ENCPKLEN received the
-   length of that encoded key.  */
-gpg_err_code_t
-_gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx, mpi_point_t result,
-                             unsigned char **r_encpk, unsigned int *r_encpklen)
-{
-  gpg_err_code_t rc;
-  unsigned char *rawmpi;
-  unsigned int rawmpilen;
-  gcry_mpi_t yy, t, x, p1, p2, p3;
-  int sign;
-
-  if (mpi_is_opaque (pk))
-    {
-      const unsigned char *buf;
-
-      buf = gcry_mpi_get_opaque (pk, &rawmpilen);
-      if (!buf)
-        return GPG_ERR_INV_OBJ;
-      rawmpilen = (rawmpilen + 7)/8;
-
-      /* First check whether the public key has been given in standard
-         uncompressed format.  No need to recover x in this case.
-         Detection is easy: The size of the buffer will be odd and the
-         first byte be 0x04.  */
-      if (rawmpilen > 1 && buf[0] == 0x04 && (rawmpilen%2))
-        {
-          gcry_mpi_t y;
-
-          rc = gcry_mpi_scan (&x, GCRYMPI_FMT_STD,
-                              buf+1, (rawmpilen-1)/2, NULL);
-          if (rc)
-            return rc;
-          rc = gcry_mpi_scan (&y, GCRYMPI_FMT_STD,
-                              buf+1+(rawmpilen-1)/2, (rawmpilen-1)/2, NULL);
-          if (rc)
-            {
-              mpi_free (x);
-              return rc;
-            }
-
-          if (r_encpk)
-            {
-              rc = eddsa_encode_x_y (x, y, ctx->nbits/8, r_encpk, r_encpklen);
-              if (rc)
-                {
-                  mpi_free (x);
-                  mpi_free (y);
-                  return rc;
-                }
-            }
-          mpi_snatch (result->x, x);
-          mpi_snatch (result->y, y);
-          mpi_set_ui (result->z, 1);
-          return 0;
-        }
-
-      /* EdDSA compressed point.  */
-      rawmpi = gcry_malloc (rawmpilen? rawmpilen:1);
-      if (!rawmpi)
-        return gpg_err_code_from_syserror ();
-      memcpy (rawmpi, buf, rawmpilen);
-      reverse_buffer (rawmpi, rawmpilen);
-    }
-  else
-    {
-      /* Note: Without using an opaque MPI it is not reliable possible
-         to find out whether the public key has been given in
-         uncompressed format.  Thus we expect EdDSA format here.  */
-      rawmpi = _gcry_mpi_get_buffer (pk, ctx->nbits/8, &rawmpilen, NULL);
-      if (!rawmpi)
-        return gpg_err_code_from_syserror ();
-    }
-
-  if (rawmpilen)
-    {
-      sign = !!(rawmpi[0] & 0x80);
-      rawmpi[0] &= 0x7f;
-    }
-  else
-    sign = 0;
-  _gcry_mpi_set_buffer (result->y, rawmpi, rawmpilen, 0);
-  if (r_encpk)
-    {
-      /* Revert to little endian.  */
-      if (sign && rawmpilen)
-        rawmpi[0] |= 0x80;
-      reverse_buffer (rawmpi, rawmpilen);
-      *r_encpk = rawmpi;
-      if (r_encpklen)
-        *r_encpklen = rawmpilen;
-    }
-  else
-    gcry_free (rawmpi);
-
-  /* Now recover X.  */
-  /* t = (y^2-1) · ((b*y^2+1)^{p-2} mod p) */
-  x = mpi_new (0);
-  yy = mpi_new (0);
-  mpi_mul (yy, result->y, result->y);
-  t = mpi_copy (yy);
-  mpi_mul (t, t, ctx->b);
-  mpi_add_ui (t, t, 1);
-  p2 = mpi_copy (ctx->p);
-  mpi_sub_ui (p2, p2, 2);
-  mpi_powm (t, t, p2, ctx->p);
-
-  mpi_sub_ui (yy, yy, 1);
-  mpi_mul (t, yy, t);
-
-  /* x = t^{(p+3)/8} mod p */
-  p3 = mpi_copy (ctx->p);
-  mpi_add_ui (p3, p3, 3);
-  mpi_fdiv_q (p3, p3, mpi_const (MPI_C_EIGHT));
-  mpi_powm (x, t, p3, ctx->p);
-
-  /* (x^2 - t) % p != 0 ? x = (x*(2^{(p-1)/4} mod p)) % p */
-  mpi_mul (yy, x, x);
-  mpi_subm (yy, yy, t, ctx->p);
-  if (mpi_cmp_ui (yy, 0))
-    {
-      p1 = mpi_copy (ctx->p);
-      mpi_sub_ui (p1, p1, 1);
-      mpi_fdiv_q (p1, p1, mpi_const (MPI_C_FOUR));
-      mpi_powm (yy, mpi_const (MPI_C_TWO), p1, ctx->p);
-      mpi_mulm (x, x, yy, ctx->p);
-    }
-  else
-    p1 = NULL;
-
-  /* is_odd(x) ? x = p-x */
-  if (mpi_test_bit (x, 0))
-    mpi_sub (x, ctx->p, x);
-
-  /* lowbit(x) != highbit(input) ?  x = p-x */
-  if (mpi_test_bit (x, 0) != sign)
-    mpi_sub (x, ctx->p, x);
-
-  mpi_set (result->x, x);
-  mpi_set_ui (result->z, 1);
-
-  gcry_mpi_release (x);
-  gcry_mpi_release (yy);
-  gcry_mpi_release (t);
-  gcry_mpi_release (p3);
-  gcry_mpi_release (p2);
-  gcry_mpi_release (p1);
-
-  return 0;
-}
-
-
-/* Ed25519 version of the key generation.  */
-static gpg_err_code_t
-eddsa_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
-                    gcry_random_level_t random_level)
+test_ecdh_only_keys (ECC_secret_key *sk, unsigned int nbits)
 {
-  gpg_err_code_t rc;
-  int b = 256/8;             /* The only size we currently support.  */
-  gcry_mpi_t a, x, y;
-  mpi_point_struct Q;
-  char *dbuf;
-  size_t dlen;
-  gcry_buffer_t hvec[1];
-  unsigned char *hash_d = NULL;
-
-  point_init (&Q);
-  memset (hvec, 0, sizeof hvec);
-
-  a = mpi_snew (0);
-  x = mpi_new (0);
-  y = mpi_new (0);
-
-  /* Generate a secret.  */
-  hash_d = gcry_malloc_secure (2*b);
-  if (!hash_d)
-    {
-      rc = gpg_error_from_syserror ();
-      goto leave;
-    }
-  dlen = b;
-  dbuf = gcry_random_bytes_secure (dlen, random_level);
-
-  /* Compute the A value.  */
-  hvec[0].data = dbuf;
-  hvec[0].len = dlen;
-  rc = _gcry_md_hash_buffers (GCRY_MD_SHA512, 0, hash_d, hvec, 1);
-  if (rc)
-    goto leave;
-  sk->d = _gcry_mpi_set_opaque (NULL, dbuf, dlen*8);
-  dbuf = NULL;
-  reverse_buffer (hash_d, 32);  /* Only the first half of the hash.  */
-  hash_d[0] = (hash_d[0] & 0x7f) | 0x40;
-  hash_d[31] &= 0xf8;
-  _gcry_mpi_set_buffer (a, hash_d, 32, 0);
-  gcry_free (hash_d); hash_d = NULL;
-  /* log_printmpi ("ecgen         a", a); */
-
-  /* Compute Q.  */
-  _gcry_mpi_ec_mul_point (&Q, a, &E->G, ctx);
-  if (DBG_CIPHER)
-    log_printpnt ("ecgen      pk", &Q, ctx);
-
-  /* Copy the stuff to the key structures. */
-  sk->E.model = E->model;
-  sk->E.dialect = E->dialect;
-  sk->E.p = mpi_copy (E->p);
-  sk->E.a = mpi_copy (E->a);
-  sk->E.b = mpi_copy (E->b);
-  point_init (&sk->E.G);
-  point_set (&sk->E.G, &E->G);
-  sk->E.n = mpi_copy (E->n);
-  point_init (&sk->Q);
-  point_set (&sk->Q, &Q);
-
- leave:
-  gcry_mpi_release (a);
-  gcry_mpi_release (x);
-  gcry_mpi_release (y);
-  gcry_free (hash_d);
-  return rc;
-}
-
-
-/* Compute an EdDSA signature. See:
- *   [ed25519] 23pp. (PDF) Daniel J. Bernstein, Niels Duif, Tanja
- *   Lange, Peter Schwabe, Bo-Yin Yang. High-speed high-security
- *   signatures.  Journal of Cryptographic Engineering 2 (2012), 77-89.
- *   Document ID: a1a62a2f76d23f65d622484ddd09caf8.
- *   URL: http://cr.yp.to/papers.html#ed25519. Date: 2011.09.26.
- *
- * Despite that this function requires the specification of a hash
- * algorithm, we only support what has been specified by the paper.
- * This may change in the future.  Note that we don't check the used
- * curve; the user is responsible to use Ed25519.
- *
- * Return the signature struct (r,s) from the message hash.  The caller
- * must have allocated R_R and S.
- */
-static gpg_err_code_t
-sign_eddsa (gcry_mpi_t input, ECC_secret_key *skey,
-            gcry_mpi_t r_r, gcry_mpi_t s, int hashalgo, gcry_mpi_t pk)
-{
-  int rc;
-  mpi_ec_t ctx = NULL;
-  int b;
-  unsigned int tmp;
-  unsigned char *digest;
-  gcry_buffer_t hvec[3];
-  const void *mbuf;
-  size_t mlen;
-  unsigned char *rawmpi = NULL;
-  unsigned int rawmpilen;
-  unsigned char *encpk = NULL; /* Encoded public key.  */
-  unsigned int encpklen;
-  mpi_point_struct I;          /* Intermediate value.  */
-  mpi_point_struct Q;          /* Public key.  */
-  gcry_mpi_t a, x, y, r;
-
-  memset (hvec, 0, sizeof hvec);
-
-  if (!mpi_is_opaque (input))
-    return GPG_ERR_INV_DATA;
-  if (hashalgo != GCRY_MD_SHA512)
-    return GPG_ERR_DIGEST_ALGO;
-
-  /* Initialize some helpers.  */
-  point_init (&I);
-  point_init (&Q);
-  a = mpi_snew (0);
-  x = mpi_new (0);
-  y = mpi_new (0);
-  r = mpi_new (0);
-  ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect,
-                                     skey->E.p, skey->E.a, skey->E.b);
-  b = (ctx->nbits+7)/8;
-  if (b != 256/8)
-    return GPG_ERR_INTERNAL; /* We only support 256 bit. */
+  ECC_public_key pk;
+  gcry_mpi_t test;
+  mpi_point_struct R_;
+  gcry_mpi_t x0, x1;
+  mpi_ec_t ec;
 
-  digest = gcry_calloc_secure (2, b);
-  if (!digest)
-    {
-      rc = gpg_err_code_from_syserror ();
-      goto leave;
-    }
+  if (DBG_CIPHER)
+    log_debug ("Testing key.\n");
 
-  /* Hash the secret key.  We clear DIGEST so we can use it as input
-     to left pad the key with zeroes for hashing.  */
-  rawmpi = _gcry_mpi_get_buffer (skey->d, 0, &rawmpilen, NULL);
-  if (!rawmpi)
-    {
-      rc = gpg_err_code_from_syserror ();
-      goto leave;
-    }
-  hvec[0].data = digest;
-  hvec[0].off = 0;
-  hvec[0].len = b > rawmpilen? b - rawmpilen : 0;
-  hvec[1].data = rawmpi;
-  hvec[1].off = 0;
-  hvec[1].len = rawmpilen;
-  rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2);
-  gcry_free (rawmpi); rawmpi = NULL;
-  if (rc)
-    goto leave;
+  point_init (&R_);
 
-  /* Compute the A value (this modifies DIGEST).  */
-  reverse_buffer (digest, 32);  /* Only the first half of the hash.  */
-  digest[0] = (digest[0] & 0x7f) | 0x40;
-  digest[31] &= 0xf8;
-  _gcry_mpi_set_buffer (a, digest, 32, 0);
+  pk.E = _gcry_ecc_curve_copy (sk->E);
+  point_init (&pk.Q);
+  point_set (&pk.Q, &sk->Q);
 
-  /* Compute the public key if it has not been supplied as optional
-     parameter.  */
-  if (pk)
+  if (sk->E.dialect == ECC_DIALECT_ED25519)
     {
-      rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q,  &encpk, &encpklen);
-      if (rc)
-        goto leave;
-      if (DBG_CIPHER)
-        log_printhex ("* e_pk", encpk, encpklen);
-      if (!_gcry_mpi_ec_curve_point (&Q, ctx))
-        {
-          rc = GPG_ERR_BROKEN_PUBKEY;
-          goto leave;
-        }
+      char *rndbuf;
+
+      test = mpi_new (256);
+      rndbuf = _gcry_random_bytes (32, GCRY_WEAK_RANDOM);
+      rndbuf[0] &= 0x7f;  /* Clear bit 255. */
+      rndbuf[0] |= 0x40;  /* Set bit 254.   */
+      rndbuf[31] &= 0xf8; /* Clear bits 2..0 so that d mod 8 == 0  */
+      _gcry_mpi_set_buffer (test, rndbuf, 32, 0);
+      xfree (rndbuf);
     }
   else
     {
-      _gcry_mpi_ec_mul_point (&Q, a, &skey->E.G, ctx);
-      rc = _gcry_ecc_eddsa_encodepoint (&Q, ctx, x, y, &encpk, &encpklen);
-      if (rc)
-        goto leave;
-      if (DBG_CIPHER)
-        log_printhex ("  e_pk", encpk, encpklen);
+      test = mpi_new (nbits);
+      _gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
     }
 
-  /* Compute R.  */
-  mbuf = gcry_mpi_get_opaque (input, &tmp);
-  mlen = (tmp +7)/8;
-  if (DBG_CIPHER)
-    log_printhex ("     m", mbuf, mlen);
-
-  hvec[0].data = digest;
-  hvec[0].off  = 32;
-  hvec[0].len  = 32;
-  hvec[1].data = (char*)mbuf;
-  hvec[1].len  = mlen;
-  rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2);
-  if (rc)
-    goto leave;
-  reverse_buffer (digest, 64);
-  if (DBG_CIPHER)
-    log_printhex ("     r", digest, 64);
-  _gcry_mpi_set_buffer (r, digest, 64, 0);
-  _gcry_mpi_ec_mul_point (&I, r, &skey->E.G, ctx);
-  if (DBG_CIPHER)
-    log_printpnt ("   r", &I, ctx);
+  ec = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect, 0,
+                                    pk.E.p, pk.E.a, pk.E.b);
+  x0 = mpi_new (0);
+  x1 = mpi_new (0);
 
-  /* Convert R into affine coordinates and apply encoding.  */
-  rc = _gcry_ecc_eddsa_encodepoint (&I, ctx, x, y, &rawmpi, &rawmpilen);
-  if (rc)
-    goto leave;
-  if (DBG_CIPHER)
-    log_printhex ("   e_r", rawmpi, rawmpilen);
-
-  /* S = r + a * H(encodepoint(R) + encodepoint(pk) + m) mod n  */
-  hvec[0].data = rawmpi;  /* (this is R) */
-  hvec[0].off  = 0;
-  hvec[0].len  = rawmpilen;
-  hvec[1].data = encpk;
-  hvec[1].off  = 0;
-  hvec[1].len  = encpklen;
-  hvec[2].data = (char*)mbuf;
-  hvec[2].off  = 0;
-  hvec[2].len  = mlen;
-  rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3);
-  if (rc)
-    goto leave;
+  /* R_ = hkQ  <=>  R_ = hkdG  */
+  _gcry_mpi_ec_mul_point (&R_, test, &pk.Q, ec);
+  if (sk->E.dialect != ECC_DIALECT_ED25519)
+    _gcry_mpi_ec_mul_point (&R_, ec->h, &R_, ec);
+  if (_gcry_mpi_ec_get_affine (x0, NULL, &R_, ec))
+    log_fatal ("ecdh: Failed to get affine coordinates for hkQ\n");
 
-  /* No more need for RAWMPI thus we now transfer it to R_R.  */
-  gcry_mpi_set_opaque (r_r, rawmpi, rawmpilen*8);
-  rawmpi = NULL;
+  _gcry_mpi_ec_mul_point (&R_, test, &pk.E.G, ec);
+  _gcry_mpi_ec_mul_point (&R_, sk->d, &R_, ec);
+  /* R_ = hdkG */
+  if (sk->E.dialect != ECC_DIALECT_ED25519)
+    _gcry_mpi_ec_mul_point (&R_, ec->h, &R_, ec);
 
-  reverse_buffer (digest, 64);
-  if (DBG_CIPHER)
-    log_printhex (" H(R+)", digest, 64);
-  _gcry_mpi_set_buffer (s, digest, 64, 0);
-  mpi_mulm (s, s, a, skey->E.n);
-  mpi_addm (s, s, r, skey->E.n);
-  rc = eddsa_encodempi (s, b, &rawmpi, &rawmpilen);
-  if (rc)
-    goto leave;
-  if (DBG_CIPHER)
-    log_printhex ("   e_s", rawmpi, rawmpilen);
-  gcry_mpi_set_opaque (s, rawmpi, rawmpilen*8);
-  rawmpi = NULL;
+  if (_gcry_mpi_ec_get_affine (x1, NULL, &R_, ec))
+    log_fatal ("ecdh: Failed to get affine coordinates for hdkG\n");
 
-  rc = 0;
+  if (mpi_cmp (x0, x1))
+    {
+      log_fatal ("ECDH test failed.\n");
+    }
 
- leave:
-  gcry_mpi_release (a);
-  gcry_mpi_release (x);
-  gcry_mpi_release (y);
-  gcry_mpi_release (r);
-  gcry_free (digest);
-  _gcry_mpi_ec_free (ctx);
-  point_free (&I);
-  point_free (&Q);
-  gcry_free (encpk);
-  gcry_free (rawmpi);
-  return rc;
+  mpi_free (x0);
+  mpi_free (x1);
+  _gcry_mpi_ec_free (ec);
+
+  point_free (&pk.Q);
+  _gcry_ecc_curve_free (&pk.E);
+
+  point_free (&R_);
+  mpi_free (test);
 }
 
 
-/* Verify an EdDSA signature.  See sign_eddsa for the reference.
- * Check if R_IN and S_IN verifies INPUT.  PKEY has the curve
- * parameters and PK is the EdDSA style encoded public key.
+/*
+ * To check the validity of the value, recalculate the correspondence
+ * between the public value and the secret one.
  */
-static gpg_err_code_t
-verify_eddsa (gcry_mpi_t input, ECC_public_key *pkey,
-              gcry_mpi_t r_in, gcry_mpi_t s_in, int hashalgo, gcry_mpi_t pk)
+static int
+check_secret_key (ECC_secret_key *sk, mpi_ec_t ec, int flags)
 {
-  int rc;
-  mpi_ec_t ctx = NULL;
-  int b;
-  unsigned int tmp;
-  mpi_point_struct Q;          /* Public key.  */
-  unsigned char *encpk = NULL; /* Encoded public key.  */
-  unsigned int encpklen;
-  const void *mbuf, *rbuf;
-  unsigned char *tbuf = NULL;
-  size_t mlen, rlen;
-  unsigned int tlen;
-  unsigned char digest[64];
-  gcry_buffer_t hvec[3];
-  gcry_mpi_t h, s;
-  mpi_point_struct Ia, Ib;
-
-  if (!mpi_is_opaque (input) || !mpi_is_opaque (r_in) || !mpi_is_opaque (s_in))
-    return GPG_ERR_INV_DATA;
-  if (hashalgo != GCRY_MD_SHA512)
-    return GPG_ERR_DIGEST_ALGO;
+  int rc = 1;
+  mpi_point_struct Q;
+  gcry_mpi_t x1, y1;
+  gcry_mpi_t x2 = NULL;
+  gcry_mpi_t y2 = NULL;
 
   point_init (&Q);
-  point_init (&Ia);
-  point_init (&Ib);
-  h = mpi_new (0);
-  s = mpi_new (0);
-
-  ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect,
-                                     pkey->E.p, pkey->E.a, pkey->E.b);
-  b = ctx->nbits/8;
-  if (b != 256/8)
-    return GPG_ERR_INTERNAL; /* We only support 256 bit. */
-
-  /* Decode and check the public key.  */
-  rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q, &encpk, &encpklen);
-  if (rc)
-    goto leave;
-  if (!_gcry_mpi_ec_curve_point (&Q, ctx))
+  x1 = mpi_new (0);
+  if (ec->model == MPI_EC_MONTGOMERY)
+    y1 = NULL;
+  else
+    y1 = mpi_new (0);
+
+  /* G in E(F_p) */
+  if (!_gcry_mpi_ec_curve_point (&sk->E.G, ec))
     {
-      rc = GPG_ERR_BROKEN_PUBKEY;
+      if (DBG_CIPHER)
+        log_debug ("Bad check: Point 'G' does not belong to curve 'E'!\n");
       goto leave;
     }
-  if (DBG_CIPHER)
-    log_printhex ("  e_pk", encpk, encpklen);
-  if (encpklen != b)
+
+  /* G != PaI */
+  if (!mpi_cmp_ui (sk->E.G.z, 0))
     {
-      rc = GPG_ERR_INV_LENGTH;
+      if (DBG_CIPHER)
+        log_debug ("Bad check: 'G' cannot be Point at Infinity!\n");
       goto leave;
     }
 
-  /* Convert the other input parameters.  */
-  mbuf = gcry_mpi_get_opaque (input, &tmp);
-  mlen = (tmp +7)/8;
-  if (DBG_CIPHER)
-    log_printhex ("     m", mbuf, mlen);
-  rbuf = gcry_mpi_get_opaque (r_in, &tmp);
-  rlen = (tmp +7)/8;
-  if (DBG_CIPHER)
-    log_printhex ("     r", rbuf, rlen);
-  if (rlen != b)
+  /* Check order of curve.  */
+  if (sk->E.dialect != ECC_DIALECT_ED25519)
     {
-      rc = GPG_ERR_INV_LENGTH;
-      goto leave;
+      _gcry_mpi_ec_mul_point (&Q, sk->E.n, &sk->E.G, ec);
+      if (mpi_cmp_ui (Q.z, 0))
+        {
+          if (DBG_CIPHER)
+            log_debug ("check_secret_key: E is not a curve of order n\n");
+          goto leave;
+        }
     }
 
-  /* h = H(encodepoint(R) + encodepoint(pk) + m)  */
-  hvec[0].data = (char*)rbuf;
-  hvec[0].off  = 0;
-  hvec[0].len  = rlen;
-  hvec[1].data = encpk;
-  hvec[1].off  = 0;
-  hvec[1].len  = encpklen;
-  hvec[2].data = (char*)mbuf;
-  hvec[2].off  = 0;
-  hvec[2].len  = mlen;
-  rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3);
-  if (rc)
-    goto leave;
-  reverse_buffer (digest, 64);
-  if (DBG_CIPHER)
-    log_printhex (" H(R+)", digest, 64);
-  _gcry_mpi_set_buffer (h, digest, 64, 0);
-
-  /* According to the paper the best way for verification is:
-         encodepoint(sG - h·Q) = encodepoint(r)
-     because we don't need to decode R. */
-  {
-    void *sbuf;
-    unsigned int slen;
-
-    sbuf = _gcry_mpi_get_opaque_copy (s_in, &tmp);
-    slen = (tmp +7)/8;
-    reverse_buffer (sbuf, slen);
-    if (DBG_CIPHER)
-      log_printhex ("     s", sbuf, slen);
-    _gcry_mpi_set_buffer (s, sbuf, slen, 0);
-    gcry_free (sbuf);
-    if (slen != b)
-      {
-        rc = GPG_ERR_INV_LENGTH;
-        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;
+    }
 
-  _gcry_mpi_ec_mul_point (&Ia, s, &pkey->E.G, ctx);
-  _gcry_mpi_ec_mul_point (&Ib, h, &Q, ctx);
-  _gcry_mpi_neg (Ib.x, Ib.x);
-  _gcry_mpi_ec_add_points (&Ia, &Ia, &Ib, ctx);
-  rc = _gcry_ecc_eddsa_encodepoint (&Ia, ctx, s, h, &tbuf, &tlen);
-  if (rc)
-    goto leave;
-  if (tlen != rlen || memcmp (tbuf, rbuf, tlen))
+  /* pubkey = [d]G over E */
+  if (!_gcry_ecc_compute_public (&Q, ec, &sk->E.G, sk->d))
+    {
+      if (DBG_CIPHER)
+        log_debug ("Bad check: computation of dG failed\n");
+      goto leave;
+    }
+  if (_gcry_mpi_ec_get_affine (x1, y1, &Q, ec))
     {
       if (DBG_CIPHER)
-        log_debug ("eddsa verify: Not verified\n");
-      rc = GPG_ERR_BAD_SIGNATURE;
+        log_debug ("Bad check: Q can not be a Point at Infinity!\n");
       goto leave;
     }
 
-  if (DBG_CIPHER)
-    log_debug ("eddsa verify: Accepted\n");
-  rc = 0;
+  if ((flags & PUBKEY_FLAG_EDDSA))
+    ; /* Fixme: EdDSA is special.  */
+  else if (!mpi_cmp_ui (sk->Q.z, 1))
+    {
+      /* Fast path if Q is already in affine coordinates.  */
+      if (mpi_cmp (x1, sk->Q.x) || (!y1 && mpi_cmp (y1, sk->Q.y)))
+        {
+          if (DBG_CIPHER)
+            log_debug
+              ("Bad check: There is NO correspondence between 'd' and 'Q'!\n");
+          goto leave;
+        }
+    }
+  else
+    {
+      x2 = mpi_new (0);
+      y2 = mpi_new (0);
+      if (_gcry_mpi_ec_get_affine (x2, y2, &sk->Q, ec))
+        {
+          if (DBG_CIPHER)
+            log_debug ("Bad check: Q can not be a Point at Infinity!\n");
+          goto leave;
+        }
+
+      if (mpi_cmp (x1, x2) || mpi_cmp (y1, y2))
+        {
+          if (DBG_CIPHER)
+            log_debug
+              ("Bad check: There is NO correspondence between 'd' and 'Q'!\n");
+          goto leave;
+        }
+    }
+  rc = 0; /* Okay.  */
 
  leave:
-  gcry_free (encpk);
-  gcry_free (tbuf);
-  _gcry_mpi_ec_free (ctx);
-  gcry_mpi_release (s);
-  gcry_mpi_release (h);
-  point_free (&Ia);
-  point_free (&Ib);
+  mpi_free (x2);
+  mpi_free (x1);
+  mpi_free (y1);
+  mpi_free (y2);
   point_free (&Q);
   return rc;
 }
@@ -1247,13 +474,14 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
   gcry_mpi_t y = NULL;
   char *curve_name = NULL;
   gcry_sexp_t l1;
-  int transient_key = 0;
   gcry_random_level_t random_level;
   mpi_ec_t ctx = NULL;
   gcry_sexp_t curve_info = NULL;
+  gcry_sexp_t curve_flags = NULL;
   gcry_mpi_t base = NULL;
   gcry_mpi_t public = NULL;
   gcry_mpi_t secret = NULL;
+  int flags = 0;
 
   memset (&E, 0, sizeof E);
   memset (&sk, 0, sizeof sk);
@@ -1263,21 +491,31 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
     return rc;
 
   /* Parse the optional "curve" parameter. */
-  l1 = gcry_sexp_find_token (genparms, "curve", 0);
+  l1 = sexp_find_token (genparms, "curve", 0);
   if (l1)
     {
       curve_name = _gcry_sexp_nth_string (l1, 1);
-      gcry_sexp_release (l1);
+      sexp_release (l1);
       if (!curve_name)
         return GPG_ERR_INV_OBJ; /* No curve name or value too large. */
     }
 
-  /* Parse the optional transient-key flag.  */
-  l1 = gcry_sexp_find_token (genparms, "transient-key", 0);
+  /* Parse the optional flags list.  */
+  l1 = sexp_find_token (genparms, "flags", 0);
+  if (l1)
+    {
+      rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL);
+      sexp_release (l1);
+      if (rc)
+        goto leave;
+    }
+
+  /* Parse the deprecated optional transient-key flag.  */
+  l1 = sexp_find_token (genparms, "transient-key", 0);
   if (l1)
     {
-      transient_key = 1;
-      gcry_sexp_release (l1);
+      flags |= PUBKEY_FLAG_TRANSIENT_KEY;
+      sexp_release (l1);
     }
 
   /* NBITS is required if no curve name has been given.  */
@@ -1285,7 +523,7 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
     return GPG_ERR_NO_OBJ; /* No NBITS parameter. */
 
   rc = _gcry_ecc_fill_in_curve (nbits, curve_name, &E, &nbits);
-  gcry_free (curve_name); curve_name = NULL;
+  xfree (curve_name); curve_name = NULL;
   if (rc)
     goto leave;
 
@@ -1300,26 +538,23 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
       log_printmpi ("ecgen curve   a", E.a);
       log_printmpi ("ecgen curve   b", E.b);
       log_printmpi ("ecgen curve   n", E.n);
+      log_printmpi ("ecgen curve   h", E.h);
       log_printpnt ("ecgen curve G", &E.G, NULL);
     }
 
-  random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM;
-  ctx = _gcry_mpi_ec_p_internal_new (E.model, E.dialect, E.p, E.a, E.b);
+  if ((flags & PUBKEY_FLAG_TRANSIENT_KEY))
+    random_level = GCRY_STRONG_RANDOM;
+  else
+    random_level = GCRY_VERY_STRONG_RANDOM;
+
+  ctx = _gcry_mpi_ec_p_internal_new (E.model, E.dialect, 0, E.p, E.a, E.b);
   x = mpi_new (0);
   y = mpi_new (0);
 
-  switch (E.dialect)
-    {
-    case ECC_DIALECT_STANDARD:
-      rc = nist_generate_key (&sk, &E, ctx, random_level, nbits);
-      break;
-    case ECC_DIALECT_ED25519:
-      rc = eddsa_generate_key (&sk, &E, ctx, random_level);
-      break;
-    default:
-      rc = GPG_ERR_INTERNAL;
-      break;
-    }
+  if ((flags & PUBKEY_FLAG_EDDSA))
+    rc = _gcry_ecc_eddsa_genkey (&sk, &E, ctx, random_level);
+  else
+    rc = nist_generate_key (&sk, &E, ctx, random_level, nbits);
   if (rc)
     goto leave;
 
@@ -1327,16 +562,18 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
   if (_gcry_mpi_ec_get_affine (x, y, &sk.E.G, ctx))
     log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "G");
   base = _gcry_ecc_ec2os (x, y, sk.E.p);
-  if (sk.E.dialect == ECC_DIALECT_ED25519)
+  if (sk.E.dialect == ECC_DIALECT_ED25519 && !(flags & PUBKEY_FLAG_NOCOMP))
     {
       unsigned char *encpk;
       unsigned int encpklen;
 
-      rc = _gcry_ecc_eddsa_encodepoint (&sk.Q, ctx, x, y, &encpk, &encpklen);
+      rc = _gcry_ecc_eddsa_encodepoint (&sk.Q, ctx, x, y,
+                                        !!(flags & PUBKEY_FLAG_COMP),
+                                        &encpk, &encpklen);
       if (rc)
         return rc;
       public = mpi_new (0);
-      gcry_mpi_set_opaque (public, encpk, encpklen*8);
+      mpi_set_opaque (public, encpk, encpklen*8);
       encpk = NULL;
     }
   else
@@ -1348,22 +585,48 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
   secret = sk.d; sk.d = NULL;
   if (E.name)
     {
-      rc = gcry_sexp_build (&curve_info, NULL, "(curve %s)", E.name);
+      rc = sexp_build (&curve_info, NULL, "(curve %s)", E.name);
       if (rc)
         goto leave;
     }
 
-  rc = gcry_sexp_build (r_skey, NULL,
-                        "(key-data"
-                        " (public-key"
-                        "  (ecc%S(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))"
-                        " (private-key"
-                        "  (ecc%S(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)(d%m)))"
-                        " )",
-                        curve_info,
-                        sk.E.p, sk.E.a, sk.E.b, base, sk.E.n, public,
-                        curve_info,
-                        sk.E.p, sk.E.a, sk.E.b, base, sk.E.n, public, secret);
+  if ((flags & PUBKEY_FLAG_PARAM) || (flags & PUBKEY_FLAG_EDDSA))
+    {
+      rc = sexp_build
+        (&curve_flags, NULL,
+         ((flags & PUBKEY_FLAG_PARAM) && (flags & PUBKEY_FLAG_EDDSA))?
+         "(flags param eddsa)" :
+         ((flags & PUBKEY_FLAG_PARAM))?
+         "(flags param)" :
+         "(flags eddsa)");
+      if (rc)
+        goto leave;
+    }
+
+  if ((flags & PUBKEY_FLAG_PARAM) && E.name)
+    rc = sexp_build (r_skey, NULL,
+                     "(key-data"
+                     " (public-key"
+                     "  (ecc%S%S(p%m)(a%m)(b%m)(g%m)(n%m)(h%m)(q%m)))"
+                     " (private-key"
+                     "  (ecc%S%S(p%m)(a%m)(b%m)(g%m)(n%m)(h%m)(q%m)(d%m)))"
+                     " )",
+                     curve_info, curve_flags,
+                     sk.E.p, sk.E.a, sk.E.b, base, sk.E.n, sk.E.h, public,
+                     curve_info, curve_flags,
+                     sk.E.p, sk.E.a, sk.E.b, base, sk.E.n, sk.E.h, public, secret);
+  else
+    rc = sexp_build (r_skey, NULL,
+                     "(key-data"
+                     " (public-key"
+                     "  (ecc%S%S(q%m)))"
+                     " (private-key"
+                     "  (ecc%S%S(q%m)(d%m)))"
+                     " )",
+                     curve_info, curve_flags,
+                     public,
+                     curve_info, curve_flags,
+                     public, secret);
   if (rc)
     goto leave;
 
@@ -1374,8 +637,11 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
       log_printmpi ("ecgen result  b", sk.E.b);
       log_printmpi ("ecgen result  G", base);
       log_printmpi ("ecgen result  n", sk.E.n);
+      log_printmpi ("ecgen result  h", sk.E.h);
       log_printmpi ("ecgen result  Q", public);
       log_printmpi ("ecgen result  d", secret);
+      if ((flags & PUBKEY_FLAG_EDDSA))
+        log_debug ("ecgen result  using Ed25519+EdDSA\n");
     }
 
  leave:
@@ -1391,7 +657,8 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
   mpi_free (x);
   mpi_free (y);
   _gcry_mpi_ec_free (ctx);
-  gcry_sexp_release (curve_info);
+  sexp_release (curve_flags);
+  sexp_release (curve_info);
   return rc;
 }
 
@@ -1401,47 +668,69 @@ ecc_check_secret_key (gcry_sexp_t keyparms)
 {
   gcry_err_code_t rc;
   gcry_sexp_t l1 = NULL;
+  int flags = 0;
   char *curvename = NULL;
   gcry_mpi_t mpi_g = NULL;
   gcry_mpi_t mpi_q = NULL;
   ECC_secret_key sk;
+  mpi_ec_t ec = NULL;
 
   memset (&sk, 0, sizeof sk);
 
-  /*
-   * Extract the key.
-   */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?/q?+d",
-                                   &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
-                                   &mpi_q, &sk.d, NULL);
-  if (rc)
-    goto leave;
-  if (mpi_g)
+  /* Look for flags. */
+  l1 = sexp_find_token (keyparms, "flags", 0);
+  if (l1)
     {
-      point_init (&sk.E.G);
-      rc = _gcry_ecc_os2ec (&sk.E.G, mpi_g);
+      rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL);
       if (rc)
         goto leave;
     }
+
+  /* Extract the parameters.  */
+  if ((flags & PUBKEY_FLAG_PARAM))
+    rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?h?/q?+d",
+                             &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
+                             &sk.E.h, &mpi_q, &sk.d, NULL);
+  else
+    rc = sexp_extract_param (keyparms, NULL, "/q?+d",
+                             &mpi_q, &sk.d, NULL);
+  if (rc)
+    goto leave;
+
   /* Add missing parameters using the optional curve parameter.  */
-  gcry_sexp_release (l1);
-  l1 = gcry_sexp_find_token (keyparms, "curve", 5);
+  sexp_release (l1);
+  l1 = sexp_find_token (keyparms, "curve", 5);
   if (l1)
     {
-      curvename = gcry_sexp_nth_string (l1, 1);
+      curvename = sexp_nth_string (l1, 1);
       if (curvename)
         {
-          rc = _gcry_ecc_fill_in_curve (0, curvename, &sk.E, NULL);
+          rc = _gcry_ecc_update_curve_param (curvename,
+                                             &sk.E.model, &sk.E.dialect,
+                                             &sk.E.p, &sk.E.a, &sk.E.b,
+                                             &mpi_g, &sk.E.n, &sk.E.h);
           if (rc)
             return rc;
         }
     }
+  if (mpi_g)
+    {
+      point_init (&sk.E.G);
+      rc = _gcry_ecc_os2ec (&sk.E.G, mpi_g);
+      if (rc)
+        goto leave;
+    }
+
   /* Guess required fields if a curve parameter has not been given.
      FIXME: This is a crude hacks.  We need to fix that.  */
   if (!curvename)
     {
-      sk.E.model = MPI_EC_WEIERSTRASS;
-      sk.E.dialect = ECC_DIALECT_STANDARD;
+      sk.E.model = ((flags & PUBKEY_FLAG_EDDSA)
+               ? MPI_EC_EDWARDS
+               : MPI_EC_WEIERSTRASS);
+      sk.E.dialect = ((flags & PUBKEY_FLAG_EDDSA)
+                      ? ECC_DIALECT_ED25519
+                      : ECC_DIALECT_STANDARD);
     }
   if (DBG_CIPHER)
     {
@@ -1455,45 +744,54 @@ ecc_check_secret_key (gcry_sexp_t keyparms)
       log_printmpi ("ecc_testkey   b", sk.E.b);
       log_printpnt ("ecc_testkey g",   &sk.E.G, NULL);
       log_printmpi ("ecc_testkey   n", sk.E.n);
+      log_printmpi ("ecc_testkey   h", sk.E.h);
       log_printmpi ("ecc_testkey   q", mpi_q);
       if (!fips_mode ())
         log_printmpi ("ecc_testkey   d", sk.d);
     }
-  if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.d)
+  if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.E.h || !sk.d)
     {
       rc = GPG_ERR_NO_OBJ;
       goto leave;
     }
 
+  ec = _gcry_mpi_ec_p_internal_new (sk.E.model, sk.E.dialect, 0,
+                                    sk.E.p, sk.E.a, sk.E.b);
+
   if (mpi_q)
     {
       point_init (&sk.Q);
-      rc = _gcry_ecc_os2ec (&sk.Q, mpi_q);
+      if (ec->dialect == ECC_DIALECT_ED25519)
+        rc = _gcry_ecc_eddsa_decodepoint (mpi_q, ec, &sk.Q, NULL, NULL);
+      else
+        rc = _gcry_ecc_os2ec (&sk.Q, mpi_q);
       if (rc)
         goto leave;
     }
   else
     {
-      /* The current test requires Q.  */
+      /* The secret key test requires Q.  */
       rc = GPG_ERR_NO_OBJ;
       goto leave;
     }
 
-  if (check_secret_key (&sk))
+  if (check_secret_key (&sk, ec, flags))
     rc = GPG_ERR_BAD_SECKEY;
 
  leave:
-  gcry_mpi_release (sk.E.p);
-  gcry_mpi_release (sk.E.a);
-  gcry_mpi_release (sk.E.b);
-  gcry_mpi_release (mpi_g);
+  _gcry_mpi_ec_free (ec);
+  _gcry_mpi_release (sk.E.p);
+  _gcry_mpi_release (sk.E.a);
+  _gcry_mpi_release (sk.E.b);
+  _gcry_mpi_release (mpi_g);
   point_free (&sk.E.G);
-  gcry_mpi_release (sk.E.n);
-  gcry_mpi_release (mpi_q);
+  _gcry_mpi_release (sk.E.n);
+  _gcry_mpi_release (sk.E.h);
+  _gcry_mpi_release (mpi_q);
   point_free (&sk.Q);
-  gcry_mpi_release (sk.d);
-  gcry_free (curvename);
-  gcry_sexp_release (l1);
+  _gcry_mpi_release (sk.d);
+  xfree (curvename);
+  sexp_release (l1);
   if (DBG_CIPHER)
     log_debug ("ecc_testkey   => %s\n", gpg_strerror (rc));
   return rc;
@@ -1528,9 +826,13 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   /*
    * Extract the key.
    */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?/q?+d",
-                                   &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
-                                   &mpi_q, &sk.d, NULL);
+  if ((ctx.flags & PUBKEY_FLAG_PARAM))
+    rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?h?/q?+d",
+                             &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
+                             &sk.E.h, &mpi_q, &sk.d, NULL);
+  else
+    rc = sexp_extract_param (keyparms, NULL, "/q?+d",
+                             &mpi_q, &sk.d, NULL);
   if (rc)
     goto leave;
   if (mpi_g)
@@ -1541,11 +843,11 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
         goto leave;
     }
   /* Add missing parameters using the optional curve parameter.  */
-  gcry_sexp_release (l1);
-  l1 = gcry_sexp_find_token (keyparms, "curve", 5);
+  sexp_release (l1);
+  l1 = sexp_find_token (keyparms, "curve", 5);
   if (l1)
     {
-      curvename = gcry_sexp_nth_string (l1, 1);
+      curvename = sexp_nth_string (l1, 1);
       if (curvename)
         {
           rc = _gcry_ecc_fill_in_curve (0, curvename, &sk.E, NULL);
@@ -1558,7 +860,7 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   if (!curvename)
     {
       sk.E.model = ((ctx.flags & PUBKEY_FLAG_EDDSA)
-                    ? MPI_EC_TWISTEDEDWARDS
+                    ? MPI_EC_EDWARDS
                     : MPI_EC_WEIERSTRASS);
       sk.E.dialect = ((ctx.flags & PUBKEY_FLAG_EDDSA)
                       ? ECC_DIALECT_ED25519
@@ -1566,9 +868,10 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
     }
   if (DBG_CIPHER)
     {
-      log_debug ("ecc_sign   info: %s/%s\n",
+      log_debug ("ecc_sign   info: %s/%s%s\n",
                  _gcry_ecc_model2str (sk.E.model),
-                 _gcry_ecc_dialect2str (sk.E.dialect));
+                 _gcry_ecc_dialect2str (sk.E.dialect),
+                 (ctx.flags & PUBKEY_FLAG_EDDSA)? "+EdDSA":"");
       if (sk.E.name)
         log_debug  ("ecc_sign   name: %s\n", sk.E.name);
       log_printmpi ("ecc_sign      p", sk.E.p);
@@ -1576,51 +879,61 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
       log_printmpi ("ecc_sign      b", sk.E.b);
       log_printpnt ("ecc_sign    g",   &sk.E.G, NULL);
       log_printmpi ("ecc_sign      n", sk.E.n);
+      log_printmpi ("ecc_sign      h", sk.E.h);
       log_printmpi ("ecc_sign      q", mpi_q);
       if (!fips_mode ())
         log_printmpi ("ecc_sign      d", sk.d);
     }
-  if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.d)
+  if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.E.h || !sk.d)
     {
       rc = GPG_ERR_NO_OBJ;
       goto leave;
     }
 
 
-  sig_r = gcry_mpi_new (0);
-  sig_s = gcry_mpi_new (0);
+  sig_r = mpi_new (0);
+  sig_s = mpi_new (0);
   if ((ctx.flags & PUBKEY_FLAG_EDDSA))
     {
       /* EdDSA requires the public key.  */
-      rc = sign_eddsa (data, &sk, sig_r, sig_s, ctx.hash_algo, mpi_q);
+      rc = _gcry_ecc_eddsa_sign (data, &sk, sig_r, sig_s, ctx.hash_algo, mpi_q);
       if (!rc)
-        rc = gcry_sexp_build (r_sig, NULL,
-                              "(sig-val(eddsa(r%M)(s%M)))", sig_r, sig_s);
+        rc = sexp_build (r_sig, NULL,
+                         "(sig-val(eddsa(r%M)(s%M)))", sig_r, sig_s);
+    }
+  else if ((ctx.flags & PUBKEY_FLAG_GOST))
+    {
+      rc = _gcry_ecc_gost_sign (data, &sk, sig_r, sig_s);
+      if (!rc)
+        rc = sexp_build (r_sig, NULL,
+                         "(sig-val(gost(r%M)(s%M)))", sig_r, sig_s);
     }
   else
     {
-      rc = sign_ecdsa (data, &sk, sig_r, sig_s, ctx.flags, ctx.hash_algo);
+      rc = _gcry_ecc_ecdsa_sign (data, &sk, sig_r, sig_s,
+                                 ctx.flags, ctx.hash_algo);
       if (!rc)
-        rc = gcry_sexp_build (r_sig, NULL,
-                              "(sig-val(ecdsa(r%M)(s%M)))", sig_r, sig_s);
+        rc = sexp_build (r_sig, NULL,
+                         "(sig-val(ecdsa(r%M)(s%M)))", sig_r, sig_s);
     }
 
 
  leave:
-  gcry_mpi_release (sk.E.p);
-  gcry_mpi_release (sk.E.a);
-  gcry_mpi_release (sk.E.b);
-  gcry_mpi_release (mpi_g);
+  _gcry_mpi_release (sk.E.p);
+  _gcry_mpi_release (sk.E.a);
+  _gcry_mpi_release (sk.E.b);
+  _gcry_mpi_release (mpi_g);
   point_free (&sk.E.G);
-  gcry_mpi_release (sk.E.n);
-  gcry_mpi_release (mpi_q);
+  _gcry_mpi_release (sk.E.n);
+  _gcry_mpi_release (sk.E.h);
+  _gcry_mpi_release (mpi_q);
   point_free (&sk.Q);
-  gcry_mpi_release (sk.d);
-  gcry_mpi_release (sig_r);
-  gcry_mpi_release (sig_s);
-  gcry_free (curvename);
-  gcry_mpi_release (data);
-  gcry_sexp_release (l1);
+  _gcry_mpi_release (sk.d);
+  _gcry_mpi_release (sig_r);
+  _gcry_mpi_release (sig_s);
+  xfree (curvename);
+  _gcry_mpi_release (data);
+  sexp_release (l1);
   _gcry_pk_util_free_encoding_ctx (&ctx);
   if (DBG_CIPHER)
     log_debug ("ecc_sign      => %s\n", gpg_strerror (rc));
@@ -1660,9 +973,8 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
   rc = _gcry_pk_util_preparse_sigval (s_sig, ecc_names, &l1, &sigflags);
   if (rc)
     goto leave;
-  rc = _gcry_pk_util_extract_mpis (l1,
-                                   (sigflags & PUBKEY_FLAG_EDDSA)? "/rs":"rs",
-                                   &sig_r, &sig_s, NULL);
+  rc = sexp_extract_param (l1, NULL, (sigflags & PUBKEY_FLAG_EDDSA)? "/rs":"rs",
+                           &sig_r, &sig_s, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -1680,9 +992,13 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
   /*
    * Extract the key.
    */
-  rc = _gcry_pk_util_extract_mpis (s_keyparms, "-p?a?b?g?n?/q?",
-                                   &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n,
-                                   &mpi_q, NULL);
+  if ((ctx.flags & PUBKEY_FLAG_PARAM))
+    rc = sexp_extract_param (s_keyparms, NULL, "-p?a?b?g?n?h?/q",
+                             &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n,
+                             &pk.E.n, &mpi_q, NULL);
+  else
+    rc = sexp_extract_param (s_keyparms, NULL, "/q",
+                             &mpi_q, NULL);
   if (rc)
     goto leave;
   if (mpi_g)
@@ -1693,11 +1009,11 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
         goto leave;
     }
   /* Add missing parameters using the optional curve parameter.  */
-  gcry_sexp_release (l1);
-  l1 = gcry_sexp_find_token (s_keyparms, "curve", 5);
+  sexp_release (l1);
+  l1 = sexp_find_token (s_keyparms, "curve", 5);
   if (l1)
     {
-      curvename = gcry_sexp_nth_string (l1, 1);
+      curvename = sexp_nth_string (l1, 1);
       if (curvename)
         {
           rc = _gcry_ecc_fill_in_curve (0, curvename, &pk.E, NULL);
@@ -1710,7 +1026,7 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
   if (!curvename)
     {
       pk.E.model = ((sigflags & PUBKEY_FLAG_EDDSA)
-                    ? MPI_EC_TWISTEDEDWARDS
+                    ? MPI_EC_EDWARDS
                     : MPI_EC_WEIERSTRASS);
       pk.E.dialect = ((sigflags & PUBKEY_FLAG_EDDSA)
                       ? ECC_DIALECT_ED25519
@@ -1719,9 +1035,10 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
 
   if (DBG_CIPHER)
     {
-      log_debug ("ecc_verify info: %s/%s\n",
+      log_debug ("ecc_verify info: %s/%s%s\n",
                  _gcry_ecc_model2str (pk.E.model),
-                 _gcry_ecc_dialect2str (pk.E.dialect));
+                 _gcry_ecc_dialect2str (pk.E.dialect),
+                 (sigflags & PUBKEY_FLAG_EDDSA)? "+EdDSA":"");
       if (pk.E.name)
         log_debug  ("ecc_verify name: %s\n", pk.E.name);
       log_printmpi ("ecc_verify    p", pk.E.p);
@@ -1729,9 +1046,10 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
       log_printmpi ("ecc_verify    b", pk.E.b);
       log_printpnt ("ecc_verify  g",   &pk.E.G, NULL);
       log_printmpi ("ecc_verify    n", pk.E.n);
+      log_printmpi ("ecc_verify    h", pk.E.h);
       log_printmpi ("ecc_verify    q", mpi_q);
     }
-  if (!pk.E.p || !pk.E.a || !pk.E.b || !pk.E.G.x || !pk.E.n || !mpi_q)
+  if (!pk.E.p || !pk.E.a || !pk.E.b || !pk.E.G.x || !pk.E.n || !pk.E.h || !mpi_q)
     {
       rc = GPG_ERR_NO_OBJ;
       goto leave;
@@ -1743,15 +1061,40 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
    */
   if ((sigflags & PUBKEY_FLAG_EDDSA))
     {
-      rc = verify_eddsa (data, &pk, sig_r, sig_s, ctx.hash_algo, mpi_q);
+      rc = _gcry_ecc_eddsa_verify (data, &pk, sig_r, sig_s,
+                                   ctx.hash_algo, mpi_q);
     }
-  else
+  else if ((sigflags & PUBKEY_FLAG_GOST))
     {
       point_init (&pk.Q);
       rc = _gcry_ecc_os2ec (&pk.Q, mpi_q);
       if (rc)
         goto leave;
 
+      rc = _gcry_ecc_gost_verify (data, &pk, sig_r, sig_s);
+    }
+  else
+    {
+      point_init (&pk.Q);
+      if (pk.E.dialect == ECC_DIALECT_ED25519)
+        {
+          mpi_ec_t ec;
+
+          /* Fixme: Factor the curve context setup out of eddsa_verify
+             and ecdsa_verify. So that we don't do it twice.  */
+          ec = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect, 0,
+                                            pk.E.p, pk.E.a, pk.E.b);
+
+          rc = _gcry_ecc_eddsa_decodepoint (mpi_q, ec, &pk.Q, NULL, NULL);
+          _gcry_mpi_ec_free (ec);
+        }
+      else
+        {
+          rc = _gcry_ecc_os2ec (&pk.Q, mpi_q);
+        }
+      if (rc)
+        goto leave;
+
       if (mpi_is_opaque (data))
         {
           const void *abuf;
@@ -1760,36 +1103,36 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
 
           qbits = mpi_get_nbits (pk.E.n);
 
-          abuf = gcry_mpi_get_opaque (data, &abits);
-          rc = gpg_err_code (gcry_mpi_scan (&a, GCRYMPI_FMT_USG,
-                                            abuf, (abits+7)/8, NULL));
+          abuf = mpi_get_opaque (data, &abits);
+          rc = _gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, (abits+7)/8, NULL);
           if (!rc)
             {
               if (abits > qbits)
-                gcry_mpi_rshift (a, a, abits - qbits);
+                mpi_rshift (a, a, abits - qbits);
 
-              rc = verify_ecdsa (a, &pk, sig_r, sig_s);
-              gcry_mpi_release (a);
+              rc = _gcry_ecc_ecdsa_verify (a, &pk, sig_r, sig_s);
+              _gcry_mpi_release (a);
             }
         }
       else
-        rc = verify_ecdsa (data, &pk, sig_r, sig_s);
+        rc = _gcry_ecc_ecdsa_verify (data, &pk, sig_r, sig_s);
     }
 
  leave:
-  gcry_mpi_release (pk.E.p);
-  gcry_mpi_release (pk.E.a);
-  gcry_mpi_release (pk.E.b);
-  gcry_mpi_release (mpi_g);
+  _gcry_mpi_release (pk.E.p);
+  _gcry_mpi_release (pk.E.a);
+  _gcry_mpi_release (pk.E.b);
+  _gcry_mpi_release (mpi_g);
   point_free (&pk.E.G);
-  gcry_mpi_release (pk.E.n);
-  gcry_mpi_release (mpi_q);
+  _gcry_mpi_release (pk.E.n);
+  _gcry_mpi_release (pk.E.h);
+  _gcry_mpi_release (mpi_q);
   point_free (&pk.Q);
-  gcry_mpi_release (data);
-  gcry_mpi_release (sig_r);
-  gcry_mpi_release (sig_s);
-  gcry_free (curvename);
-  gcry_sexp_release (l1);
+  _gcry_mpi_release (data);
+  _gcry_mpi_release (sig_r);
+  _gcry_mpi_release (sig_s);
+  xfree (curvename);
+  sexp_release (l1);
   _gcry_pk_util_free_encoding_ctx (&ctx);
   if (DBG_CIPHER)
     log_debug ("ecc_verify    => %s\n", rc?gpg_strerror (rc):"Good");
@@ -1862,9 +1205,9 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   /*
    * Extract the key.
    */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?+q",
-                                   &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n,
-                                   &mpi_q, NULL);
+  rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?h?+q",
+                           &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n, &pk.E.h,
+                           &mpi_q, NULL);
   if (rc)
     goto leave;
   if (mpi_g)
@@ -1875,11 +1218,11 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
         goto leave;
     }
   /* Add missing parameters using the optional curve parameter.  */
-  gcry_sexp_release (l1);
-  l1 = gcry_sexp_find_token (keyparms, "curve", 5);
+  sexp_release (l1);
+  l1 = sexp_find_token (keyparms, "curve", 5);
   if (l1)
     {
-      curvename = gcry_sexp_nth_string (l1, 1);
+      curvename = sexp_nth_string (l1, 1);
       if (curvename)
         {
           rc = _gcry_ecc_fill_in_curve (0, curvename, &pk.E, NULL);
@@ -1906,9 +1249,10 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
       log_printmpi ("ecc_encrypt    b", pk.E.b);
       log_printpnt ("ecc_encrypt  g",   &pk.E.G, NULL);
       log_printmpi ("ecc_encrypt    n", pk.E.n);
+      log_printmpi ("ecc_encrypt    h", pk.E.h);
       log_printmpi ("ecc_encrypt    q", mpi_q);
     }
-  if (!pk.E.p || !pk.E.a || !pk.E.b || !pk.E.G.x || !pk.E.n || !mpi_q)
+  if (!pk.E.p || !pk.E.a || !pk.E.b || !pk.E.G.x || !pk.E.n || !pk.E.h || !mpi_q)
     {
       rc = GPG_ERR_NO_OBJ;
       goto leave;
@@ -1924,7 +1268,7 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
     }
 
   /* Compute the encrypted value.  */
-  ec = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect,
+  ec = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect, 0,
                                     pk.E.p, pk.E.a, pk.E.b);
 
   /* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so */
@@ -1957,22 +1301,22 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
     point_free (&R);
   }
 
-  rc = gcry_sexp_build (r_ciph, NULL, "(enc-val(ecdh(s%m)(e%m)))",
-                        mpi_s, mpi_e);
+  rc = sexp_build (r_ciph, NULL, "(enc-val(ecdh(s%m)(e%m)))", mpi_s, mpi_e);
 
  leave:
-  gcry_mpi_release (pk.E.p);
-  gcry_mpi_release (pk.E.a);
-  gcry_mpi_release (pk.E.b);
-  gcry_mpi_release (mpi_g);
+  _gcry_mpi_release (pk.E.p);
+  _gcry_mpi_release (pk.E.a);
+  _gcry_mpi_release (pk.E.b);
+  _gcry_mpi_release (mpi_g);
   point_free (&pk.E.G);
-  gcry_mpi_release (pk.E.n);
-  gcry_mpi_release (mpi_q);
+  _gcry_mpi_release (pk.E.n);
+  _gcry_mpi_release (pk.E.h);
+  _gcry_mpi_release (mpi_q);
   point_free (&pk.Q);
-  gcry_mpi_release (data);
-  gcry_mpi_release (mpi_s);
-  gcry_mpi_release (mpi_e);
-  gcry_free (curvename);
+  _gcry_mpi_release (data);
+  _gcry_mpi_release (mpi_s);
+  _gcry_mpi_release (mpi_e);
+  xfree (curvename);
   _gcry_mpi_ec_free (ec);
   _gcry_pk_util_free_encoding_ctx (&ctx);
   if (DBG_CIPHER)
@@ -2016,7 +1360,7 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   rc = _gcry_pk_util_preparse_encval (s_data, ecc_names, &l1, &ctx);
   if (rc)
     goto leave;
-  rc = _gcry_pk_util_extract_mpis (l1, "e", &data_e, NULL);
+  rc = sexp_extract_param (l1, NULL, "e", &data_e, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -2030,9 +1374,9 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   /*
    * Extract the key.
    */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?+d",
-                                   &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
-                                   &sk.d, NULL);
+  rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?h?+d",
+                           &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
+                           &sk.E.h, &sk.d, NULL);
   if (rc)
     goto leave;
   if (mpi_g)
@@ -2043,11 +1387,11 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
         goto leave;
     }
   /* Add missing parameters using the optional curve parameter.  */
-  gcry_sexp_release (l1);
-  l1 = gcry_sexp_find_token (keyparms, "curve", 5);
+  sexp_release (l1);
+  l1 = sexp_find_token (keyparms, "curve", 5);
   if (l1)
     {
-      curvename = gcry_sexp_nth_string (l1, 1);
+      curvename = sexp_nth_string (l1, 1);
       if (curvename)
         {
           rc = _gcry_ecc_fill_in_curve (0, curvename, &sk.E, NULL);
@@ -2073,10 +1417,11 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
       log_printmpi ("ecc_decrypt    b", sk.E.b);
       log_printpnt ("ecc_decrypt  g",   &sk.E.G, NULL);
       log_printmpi ("ecc_decrypt    n", sk.E.n);
+      log_printmpi ("ecc_decrypt    h", sk.E.h);
       if (!fips_mode ())
         log_printmpi ("ecc_decrypt    d", sk.d);
     }
-  if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.d)
+  if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.E.h || !sk.d)
     {
       rc = GPG_ERR_NO_OBJ;
       goto leave;
@@ -2093,7 +1438,7 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
       return rc;
     }
 
-  ec = _gcry_mpi_ec_p_internal_new (sk.E.model, sk.E.dialect,
+  ec = _gcry_mpi_ec_p_internal_new (sk.E.model, sk.E.dialect, 0,
                                     sk.E.p, sk.E.a, sk.E.b);
 
   /* R = dkG */
@@ -2121,22 +1466,23 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
     log_printmpi ("ecc_decrypt  res", r);
 
   if (!rc)
-    rc = gcry_sexp_build (r_plain, NULL, "(value %m)", r);
+    rc = sexp_build (r_plain, NULL, "(value %m)", r);
 
  leave:
   point_free (&R);
   point_free (&kG);
-  gcry_mpi_release (r);
-  gcry_mpi_release (sk.E.p);
-  gcry_mpi_release (sk.E.a);
-  gcry_mpi_release (sk.E.b);
-  gcry_mpi_release (mpi_g);
+  _gcry_mpi_release (r);
+  _gcry_mpi_release (sk.E.p);
+  _gcry_mpi_release (sk.E.a);
+  _gcry_mpi_release (sk.E.b);
+  _gcry_mpi_release (mpi_g);
   point_free (&sk.E.G);
-  gcry_mpi_release (sk.E.n);
-  gcry_mpi_release (sk.d);
-  gcry_mpi_release (data_e);
-  gcry_free (curvename);
-  gcry_sexp_release (l1);
+  _gcry_mpi_release (sk.E.n);
+  _gcry_mpi_release (sk.E.h);
+  _gcry_mpi_release (sk.d);
+  _gcry_mpi_release (data_e);
+  xfree (curvename);
+  sexp_release (l1);
   _gcry_mpi_ec_free (ec);
   _gcry_pk_util_free_encoding_ctx (&ctx);
   if (DBG_CIPHER)
@@ -2168,30 +1514,30 @@ ecc_get_nbits (gcry_sexp_t parms)
   unsigned int nbits = 0;
   char *curve;
 
-  l1 = gcry_sexp_find_token (parms, "p", 1);
+  l1 = sexp_find_token (parms, "p", 1);
   if (!l1)
     { /* Parameter P not found - check whether we have "curve".  */
-      l1 = gcry_sexp_find_token (parms, "curve", 5);
+      l1 = sexp_find_token (parms, "curve", 5);
       if (!l1)
         return 0; /* Neither P nor CURVE found.  */
 
-      curve = _gcry_sexp_nth_string (l1, 1);
-      gcry_sexp_release (l1);
+      curve = sexp_nth_string (l1, 1);
+      sexp_release (l1);
       if (!curve)
         return 0;  /* No curve name given (or out of core). */
 
       if (_gcry_ecc_fill_in_curve (0, curve, NULL, &nbits))
         nbits = 0;
-      gcry_free (curve);
+      xfree (curve);
     }
   else
     {
-      p = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
-      gcry_sexp_release (l1);
+      p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+      sexp_release (l1);
       if (p)
         {
           nbits = mpi_get_nbits (p);
-          gcry_mpi_release (p);
+          _gcry_mpi_release (p);
         }
     }
   return nbits;
@@ -2200,65 +1546,87 @@ ecc_get_nbits (gcry_sexp_t parms)
 
 /* 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)
+compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparms)
 {
-#define N_COMPONENTS 6
-  static const char names[N_COMPONENTS+1] = "pabgnq";
-  gpg_err_code_t ec = 0;
+#define N_COMPONENTS 7
+  static const char names[N_COMPONENTS] = "pabgnhq";
+  gpg_err_code_t rc;
   gcry_sexp_t l1;
   gcry_mpi_t values[N_COMPONENTS];
   int idx;
+  char *curvename = NULL;
+  int flags = 0;
+  enum gcry_mpi_ec_models model = 0;
+  enum ecc_dialects dialect = 0;
 
-  /* Clear the values for easier error cleanup.  */
+  /* Clear the values first.  */
   for (idx=0; idx < N_COMPONENTS; idx++)
     values[idx] = NULL;
 
-  /* Fill values with all provided parameters.  */
-  for (idx=0; idx < N_COMPONENTS; idx++)
+
+  /* Look for flags. */
+  l1 = sexp_find_token (keyparms, "flags", 0);
+  if (l1)
     {
-      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;
-            }
-       }
+      rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL);
+      if (rc)
+        goto leave;
+    }
+
+  /* Extract the parameters.  */
+  if ((flags & PUBKEY_FLAG_PARAM))
+    {
+      if ((flags & PUBKEY_FLAG_EDDSA))
+        rc = sexp_extract_param (keyparms, NULL, "p?a?b?g?n?h?/q",
+                                 &values[0], &values[1], &values[2],
+                                 &values[3], &values[4], &values[5],
+                                 &values[6], NULL);
+      else
+        rc = sexp_extract_param (keyparms, NULL, "p?a?b?g?n?h?q",
+                                 &values[0], &values[1], &values[2],
+                                 &values[3], &values[4], &values[5],
+                                 &values[6], NULL);
+    }
+  else
+    {
+      if ((flags & PUBKEY_FLAG_EDDSA))
+        rc = sexp_extract_param (keyparms, NULL, "/q",
+                                 &values[6], NULL);
+      else
+        rc = sexp_extract_param (keyparms, NULL, "q",
+                                 &values[6], NULL);
     }
+  if (rc)
+    goto leave;
 
   /* Check whether a curve parameter is available and use that to fill
      in missing values.  */
-  l1 = gcry_sexp_find_token (keyparam, "curve", 5);
+  sexp_release (l1);
+  l1 = sexp_find_token (keyparms, "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)
+      curvename = sexp_nth_string (l1, 1);
+      if (curvename)
         {
-          ec = GPG_ERR_INV_OBJ; /* Name missing or out of core. */
-          goto leave;
+          rc = _gcry_ecc_update_curve_param (curvename,
+                                             &model, &dialect,
+                                             &values[0], &values[1], &values[2],
+                                             &values[3], &values[4], &values[5]);
+          if (rc)
+            goto leave;
         }
-      ec = _gcry_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]);
-        }
+  /* Guess required fields if a curve parameter has not been given.
+     FIXME: This is a crude hacks.  We need to fix that.  */
+  if (!curvename)
+    {
+      model = ((flags & PUBKEY_FLAG_EDDSA)
+               ? MPI_EC_EDWARDS
+               : MPI_EC_WEIERSTRASS);
+      dialect = ((flags & PUBKEY_FLAG_EDDSA)
+                 ? ECC_DIALECT_ED25519
+                 : ECC_DIALECT_STANDARD);
     }
 
   /* Check that all parameters are known and normalize all MPIs (that
@@ -2267,37 +1635,73 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam)
   for (idx = 0; idx < N_COMPONENTS; idx++)
     if (!values[idx])
       {
-        ec = GPG_ERR_NO_OBJ;
+        rc = GPG_ERR_NO_OBJ;
         goto leave;
       }
     else
       _gcry_mpi_normalize (values[idx]);
 
+  /* Uncompress the public key with the exception of EdDSA where
+     compression is the default and we thus compute the keygrip using
+     the compressed version.  Because we don't support any non-eddsa
+     compression, the only thing we need to do is to compress
+     EdDSA.  */
+  if ((flags & PUBKEY_FLAG_EDDSA))
+    {
+      if (dialect == ECC_DIALECT_ED25519)
+        rc = _gcry_ecc_eddsa_ensure_compact (values[6], 256);
+      else
+        rc = GPG_ERR_NOT_IMPLEMENTED;
+      if (rc)
+        goto leave;
+    }
+
   /* Hash them all.  */
   for (idx = 0; idx < N_COMPONENTS; idx++)
     {
       char buf[30];
-      unsigned char *rawmpi;
-      unsigned int rawmpilen;
 
-      rawmpi = _gcry_mpi_get_buffer (values[idx], 0, &rawmpilen, NULL);
-      if (!rawmpi)
+      if (idx == 5)
+        continue;               /* Skip cofactor. */
+
+      if (mpi_is_opaque (values[idx]))
         {
-          ec = gpg_err_code_from_syserror ();
-          goto leave;
+          const unsigned char *raw;
+          unsigned int n;
+
+          raw = mpi_get_opaque (values[idx], &n);
+          n = (n + 7)/8;
+          snprintf (buf, sizeof buf, "(1:%c%u:", names[idx], n);
+          _gcry_md_write (md, buf, strlen (buf));
+          _gcry_md_write (md, raw, n);
+          _gcry_md_write (md, ")", 1);
+        }
+      else
+        {
+          unsigned char *rawmpi;
+          unsigned int rawmpilen;
+
+          rawmpi = _gcry_mpi_get_buffer (values[idx], 0, &rawmpilen, NULL);
+          if (!rawmpi)
+            {
+              rc = gpg_err_code_from_syserror ();
+              goto leave;
+            }
+          snprintf (buf, sizeof buf, "(1:%c%u:", names[idx], rawmpilen);
+          _gcry_md_write (md, buf, strlen (buf));
+          _gcry_md_write (md, rawmpi, rawmpilen);
+          _gcry_md_write (md, ")", 1);
+          xfree (rawmpi);
         }
-      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);
     }
 
  leave:
+  xfree (curvename);
+  sexp_release (l1);
   for (idx = 0; idx < N_COMPONENTS; idx++)
     _gcry_mpi_release (values[idx]);
 
-  return ec;
+  return rc;
 #undef N_COMPONENTS
 }
 
@@ -2317,7 +1721,7 @@ _gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, mpi_ec_t ec)
   gcry_mpi_t mpi_G = NULL;
   gcry_mpi_t mpi_Q = NULL;
 
-  if (!ec->p || !ec->a || !ec->b || !ec->G || !ec->n)
+  if (!ec->p || !ec->a || !ec->b || !ec->G || !ec->n || !ec->h)
     return GPG_ERR_BAD_CRYPT_CTX;
 
   if (mode == GCRY_PK_GET_SECKEY && !ec->d)
@@ -2325,7 +1729,7 @@ _gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, mpi_ec_t ec)
 
   /* Compute the public point if it is missing.  */
   if (!ec->Q && ec->d)
-    ec->Q = _gcry_ecc_compute_public (NULL, ec);
+    ec->Q = _gcry_ecc_compute_public (NULL, ec, NULL, NULL);
 
   /* Encode G and Q.  */
   mpi_G = _gcry_mpi_ec_ec2os (ec->G, ec);
@@ -2345,11 +1749,11 @@ _gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, mpi_ec_t ec)
       unsigned char *encpk;
       unsigned int encpklen;
 
-      rc = _gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL,
+      rc = _gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL, 0,
                                         &encpk, &encpklen);
       if (rc)
         goto leave;
-      mpi_Q = gcry_mpi_set_opaque (NULL, encpk, encpklen*8);
+      mpi_Q = mpi_set_opaque (NULL, encpk, encpklen*8);
       encpk = NULL;
     }
   else
@@ -2368,18 +1772,16 @@ _gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, mpi_ec_t ec)
   if (ec->d && (!mode || mode == GCRY_PK_GET_SECKEY))
     {
       /* Let's return a private key. */
-      rc = 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);
+      rc = sexp_build (r_sexp, NULL,
+                       "(private-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(h%m)(q%m)(d%m)))",
+                       ec->p, ec->a, ec->b, mpi_G, ec->n, ec->h, mpi_Q, ec->d);
     }
   else if (ec->Q)
     {
       /* Let's return a public key.  */
-      rc = 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);
+      rc = sexp_build (r_sexp, NULL,
+                       "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(h%m)(q%m)))",
+                       ec->p, ec->a, ec->b, mpi_G, ec->n, ec->h, mpi_Q);
     }
   else
     rc = GPG_ERR_BAD_CRYPT_CTX;
@@ -2439,7 +1841,7 @@ gcry_pk_spec_t _gcry_pubkey_spec_ecc =
     GCRY_PK_ECC, { 0, 0 },
     (GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR),
     "ECC", ecc_names,
-    "pabgnq", "pabgnqd", "sw", "rs", "pabgnq",
+    "pabgnhq", "pabgnhqd", "sw", "rs", "pabgnhq",
     ecc_generate,
     ecc_check_secret_key,
     ecc_encrypt_raw,
@@ -2449,7 +1851,6 @@ gcry_pk_spec_t _gcry_pubkey_spec_ecc =
     ecc_get_nbits,
     run_selftests,
     compute_keygrip,
-    _gcry_ecc_get_param,
     _gcry_ecc_get_curve,
     _gcry_ecc_get_param_sexp
   };