Enable AMD64 SHA512 implementations for WIN64
[libgcrypt.git] / cipher / ecc.c
index a7de254..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.
 
@@ -84,6 +81,7 @@ static void *progress_cb_data;
 \f
 /* Local prototypes. */
 static void test_keys (ECC_secret_key * sk, unsigned int nbits);
+static void test_ecdh_only_keys (ECC_secret_key * sk, unsigned int nbits);
 static unsigned int ecc_get_nbits (gcry_sexp_t parms);
 
 
@@ -127,7 +125,7 @@ nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
       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);
-      gcry_free (rndbuf);
+      xfree (rndbuf);
     }
   else
     sk->d = _gcry_dsa_gen_k (E->n, random_level);
@@ -145,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
@@ -211,7 +210,10 @@ nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
 
   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;
 }
@@ -268,6 +270,80 @@ test_keys (ECC_secret_key *sk, unsigned int nbits)
 }
 
 
+static void
+test_ecdh_only_keys (ECC_secret_key *sk, unsigned int nbits)
+{
+  ECC_public_key pk;
+  gcry_mpi_t test;
+  mpi_point_struct R_;
+  gcry_mpi_t x0, x1;
+  mpi_ec_t ec;
+
+  if (DBG_CIPHER)
+    log_debug ("Testing key.\n");
+
+  point_init (&R_);
+
+  pk.E = _gcry_ecc_curve_copy (sk->E);
+  point_init (&pk.Q);
+  point_set (&pk.Q, &sk->Q);
+
+  if (sk->E.dialect == ECC_DIALECT_ED25519)
+    {
+      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
+    {
+      test = mpi_new (nbits);
+      _gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
+    }
+
+  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);
+
+  /* R_ = hkQ  <=>  R_ = hkdG  */
+  _gcry_mpi_ec_mul_point (&R_, test, &pk.Q, ec);
+  if (sk->E.dialect != ECC_DIALECT_ED25519)
+    _gcry_mpi_ec_mul_point (&R_, ec->h, &R_, ec);
+  if (_gcry_mpi_ec_get_affine (x0, NULL, &R_, ec))
+    log_fatal ("ecdh: Failed to get affine coordinates for hkQ\n");
+
+  _gcry_mpi_ec_mul_point (&R_, test, &pk.E.G, ec);
+  _gcry_mpi_ec_mul_point (&R_, sk->d, &R_, ec);
+  /* R_ = hdkG */
+  if (sk->E.dialect != ECC_DIALECT_ED25519)
+    _gcry_mpi_ec_mul_point (&R_, ec->h, &R_, ec);
+
+  if (_gcry_mpi_ec_get_affine (x1, NULL, &R_, ec))
+    log_fatal ("ecdh: Failed to get affine coordinates for hdkG\n");
+
+  if (mpi_cmp (x0, x1))
+    {
+      log_fatal ("ECDH test failed.\n");
+    }
+
+  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);
+}
+
+
 /*
  * To check the validity of the value, recalculate the correspondence
  * between the public value and the secret one.
@@ -283,7 +359,10 @@ check_secret_key (ECC_secret_key *sk, mpi_ec_t ec, int flags)
 
   point_init (&Q);
   x1 = mpi_new (0);
-  y1 = 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))
@@ -340,7 +419,7 @@ check_secret_key (ECC_secret_key *sk, mpi_ec_t ec, int flags)
   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) || mpi_cmp (y1, sk->Q.y))
+      if (mpi_cmp (x1, sk->Q.x) || (!y1 && mpi_cmp (y1, sk->Q.y)))
         {
           if (DBG_CIPHER)
             log_debug
@@ -444,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;
 
@@ -459,6 +538,7 @@ 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);
     }
 
@@ -487,7 +567,9 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
       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);
@@ -525,14 +607,14 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
     rc = sexp_build (r_skey, NULL,
                      "(key-data"
                      " (public-key"
-                     "  (ecc%S%S(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))"
+                     "  (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)(q%m)(d%m)))"
+                     "  (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, public,
+                     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, public, secret);
+                     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"
@@ -555,6 +637,7 @@ 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))
@@ -605,9 +688,9 @@ ecc_check_secret_key (gcry_sexp_t keyparms)
 
   /* Extract the parameters.  */
   if ((flags & PUBKEY_FLAG_PARAM))
-    rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?/q?+d",
+    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,
-                             &mpi_q, &sk.d, NULL);
+                             &sk.E.h, &mpi_q, &sk.d, NULL);
   else
     rc = sexp_extract_param (keyparms, NULL, "/q?+d",
                              &mpi_q, &sk.d, NULL);
@@ -625,7 +708,7 @@ ecc_check_secret_key (gcry_sexp_t keyparms)
           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);
+                                             &mpi_g, &sk.E.n, &sk.E.h);
           if (rc)
             return rc;
         }
@@ -643,7 +726,7 @@ ecc_check_secret_key (gcry_sexp_t keyparms)
   if (!curvename)
     {
       sk.E.model = ((flags & PUBKEY_FLAG_EDDSA)
-               ? MPI_EC_TWISTEDEDWARDS
+               ? MPI_EC_EDWARDS
                : MPI_EC_WEIERSTRASS);
       sk.E.dialect = ((flags & PUBKEY_FLAG_EDDSA)
                       ? ECC_DIALECT_ED25519
@@ -661,11 +744,12 @@ 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;
@@ -702,10 +786,11 @@ ecc_check_secret_key (gcry_sexp_t keyparms)
   _gcry_mpi_release (mpi_g);
   point_free (&sk.E.G);
   _gcry_mpi_release (sk.E.n);
+  _gcry_mpi_release (sk.E.h);
   _gcry_mpi_release (mpi_q);
   point_free (&sk.Q);
   _gcry_mpi_release (sk.d);
-  gcry_free (curvename);
+  xfree (curvename);
   sexp_release (l1);
   if (DBG_CIPHER)
     log_debug ("ecc_testkey   => %s\n", gpg_strerror (rc));
@@ -742,9 +827,9 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
    * Extract the key.
    */
   if ((ctx.flags & PUBKEY_FLAG_PARAM))
-    rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?/q?+d",
+    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,
-                             &mpi_q, &sk.d, NULL);
+                             &sk.E.h, &mpi_q, &sk.d, NULL);
   else
     rc = sexp_extract_param (keyparms, NULL, "/q?+d",
                              &mpi_q, &sk.d, NULL);
@@ -775,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
@@ -794,11 +879,12 @@ 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;
@@ -839,12 +925,13 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   _gcry_mpi_release (mpi_g);
   point_free (&sk.E.G);
   _gcry_mpi_release (sk.E.n);
+  _gcry_mpi_release (sk.E.h);
   _gcry_mpi_release (mpi_q);
   point_free (&sk.Q);
   _gcry_mpi_release (sk.d);
   _gcry_mpi_release (sig_r);
   _gcry_mpi_release (sig_s);
-  gcry_free (curvename);
+  xfree (curvename);
   _gcry_mpi_release (data);
   sexp_release (l1);
   _gcry_pk_util_free_encoding_ctx (&ctx);
@@ -906,9 +993,9 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
    * Extract the key.
    */
   if ((ctx.flags & PUBKEY_FLAG_PARAM))
-    rc = sexp_extract_param (s_keyparms, NULL, "-p?a?b?g?n?/q",
+    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,
-                             &mpi_q, NULL);
+                             &pk.E.n, &mpi_q, NULL);
   else
     rc = sexp_extract_param (s_keyparms, NULL, "/q",
                              &mpi_q, NULL);
@@ -939,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
@@ -959,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;
@@ -1037,12 +1125,13 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
   _gcry_mpi_release (mpi_g);
   point_free (&pk.E.G);
   _gcry_mpi_release (pk.E.n);
+  _gcry_mpi_release (pk.E.h);
   _gcry_mpi_release (mpi_q);
   point_free (&pk.Q);
   _gcry_mpi_release (data);
   _gcry_mpi_release (sig_r);
   _gcry_mpi_release (sig_s);
-  gcry_free (curvename);
+  xfree (curvename);
   sexp_release (l1);
   _gcry_pk_util_free_encoding_ctx (&ctx);
   if (DBG_CIPHER)
@@ -1116,8 +1205,8 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   /*
    * Extract the key.
    */
-  rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?+q",
-                           &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n,
+  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;
@@ -1160,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;
@@ -1220,12 +1310,13 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   _gcry_mpi_release (mpi_g);
   point_free (&pk.E.G);
   _gcry_mpi_release (pk.E.n);
+  _gcry_mpi_release (pk.E.h);
   _gcry_mpi_release (mpi_q);
   point_free (&pk.Q);
   _gcry_mpi_release (data);
   _gcry_mpi_release (mpi_s);
   _gcry_mpi_release (mpi_e);
-  gcry_free (curvename);
+  xfree (curvename);
   _gcry_mpi_ec_free (ec);
   _gcry_pk_util_free_encoding_ctx (&ctx);
   if (DBG_CIPHER)
@@ -1283,9 +1374,9 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   /*
    * Extract the key.
    */
-  rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?+d",
+  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.d, NULL);
+                           &sk.E.h, &sk.d, NULL);
   if (rc)
     goto leave;
   if (mpi_g)
@@ -1326,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;
@@ -1386,9 +1478,10 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   _gcry_mpi_release (mpi_g);
   point_free (&sk.E.G);
   _gcry_mpi_release (sk.E.n);
+  _gcry_mpi_release (sk.E.h);
   _gcry_mpi_release (sk.d);
   _gcry_mpi_release (data_e);
-  _gcry_free (curvename);
+  xfree (curvename);
   sexp_release (l1);
   _gcry_mpi_ec_free (ec);
   _gcry_pk_util_free_encoding_ctx (&ctx);
@@ -1435,7 +1528,7 @@ ecc_get_nbits (gcry_sexp_t parms)
 
       if (_gcry_ecc_fill_in_curve (0, curve, NULL, &nbits))
         nbits = 0;
-      gcry_free (curve);
+      xfree (curve);
     }
   else
     {
@@ -1455,8 +1548,8 @@ ecc_get_nbits (gcry_sexp_t parms)
 static gpg_err_code_t
 compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparms)
 {
-#define N_COMPONENTS 6
-  static const char names[N_COMPONENTS+1] = "pabgnq";
+#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];
@@ -1484,24 +1577,24 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparms)
   if ((flags & PUBKEY_FLAG_PARAM))
     {
       if ((flags & PUBKEY_FLAG_EDDSA))
-        rc = sexp_extract_param (keyparms, NULL, "p?a?b?g?n?/q",
+        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],
-                                 NULL);
+                                 &values[6], NULL);
       else
-        rc = sexp_extract_param (keyparms, NULL, "p?a?b?g?n?q",
+        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],
-                                 NULL);
+                                 &values[6], NULL);
     }
   else
     {
       if ((flags & PUBKEY_FLAG_EDDSA))
         rc = sexp_extract_param (keyparms, NULL, "/q",
-                                 &values[5], NULL);
+                                 &values[6], NULL);
       else
         rc = sexp_extract_param (keyparms, NULL, "q",
-                                 &values[5], NULL);
+                                 &values[6], NULL);
     }
   if (rc)
     goto leave;
@@ -1518,9 +1611,9 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparms)
           rc = _gcry_ecc_update_curve_param (curvename,
                                              &model, &dialect,
                                              &values[0], &values[1], &values[2],
-                                             &values[3], &values[4]);
+                                             &values[3], &values[4], &values[5]);
           if (rc)
-            return rc;
+            goto leave;
         }
     }
 
@@ -1529,7 +1622,7 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparms)
   if (!curvename)
     {
       model = ((flags & PUBKEY_FLAG_EDDSA)
-               ? MPI_EC_TWISTEDEDWARDS
+               ? MPI_EC_EDWARDS
                : MPI_EC_WEIERSTRASS);
       dialect = ((flags & PUBKEY_FLAG_EDDSA)
                  ? ECC_DIALECT_ED25519
@@ -1556,7 +1649,7 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparms)
   if ((flags & PUBKEY_FLAG_EDDSA))
     {
       if (dialect == ECC_DIALECT_ED25519)
-        rc = _gcry_ecc_eddsa_ensure_compact (values[5], 256);
+        rc = _gcry_ecc_eddsa_ensure_compact (values[6], 256);
       else
         rc = GPG_ERR_NOT_IMPLEMENTED;
       if (rc)
@@ -1568,6 +1661,9 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparms)
     {
       char buf[30];
 
+      if (idx == 5)
+        continue;               /* Skip cofactor. */
+
       if (mpi_is_opaque (values[idx]))
         {
           const unsigned char *raw;
@@ -1595,12 +1691,12 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparms)
           _gcry_md_write (md, buf, strlen (buf));
           _gcry_md_write (md, rawmpi, rawmpilen);
           _gcry_md_write (md, ")", 1);
-          gcry_free (rawmpi);
+          xfree (rawmpi);
         }
     }
 
  leave:
-  gcry_free (curvename);
+  xfree (curvename);
   sexp_release (l1);
   for (idx = 0; idx < N_COMPONENTS; idx++)
     _gcry_mpi_release (values[idx]);
@@ -1625,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)
@@ -1653,7 +1749,7 @@ _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;
@@ -1677,15 +1773,15 @@ _gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, mpi_ec_t ec)
     {
       /* Let's return a private key. */
       rc = sexp_build (r_sexp, NULL,
-                       "(private-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)(d%m)))",
-                       ec->p, ec->a, ec->b, mpi_G, ec->n, mpi_Q, ec->d);
+                       "(private-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(h%m)(q%m)(d%m)))",
+                       ec->p, ec->a, ec->b, mpi_G, ec->n, ec->h, mpi_Q, ec->d);
     }
   else if (ec->Q)
     {
       /* Let's return a public key.  */
       rc = sexp_build (r_sexp, NULL,
-                       "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))",
-                       ec->p, ec->a, ec->b, mpi_G, ec->n, mpi_Q);
+                       "(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;
@@ -1745,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,
@@ -1755,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
   };