Add crypto hash SM3.
[libgcrypt.git] / cipher / ecc-eddsa.c
index 72103e9..813e030 100644 (file)
@@ -1,5 +1,5 @@
 /* ecc-eddsa.c  -  Elliptic Curve EdDSA signatures
- * Copyright (C) 2013 g10 Code GmbH
+ * Copyright (C) 2013, 2014 g10 Code GmbH
  *
  * This file is part of Libgcrypt.
  *
@@ -46,6 +46,20 @@ reverse_buffer (unsigned char *buffer, unsigned int length)
 }
 
 
+/* Helper to scan a hex string. */
+static gcry_mpi_t
+scanval (const char *string)
+{
+  gpg_err_code_t rc;
+  gcry_mpi_t val;
+
+  rc = _gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
+  if (rc)
+    log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (rc));
+  return val;
+}
+
+
 \f
 /* Encode MPI using the EdDSA scheme.  MINLEN specifies the required
    length of the buffer in bytes.  On success 0 is returned an a
@@ -69,35 +83,42 @@ eddsa_encodempi (gcry_mpi_t mpi, unsigned int minlen,
 
 
 /* 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.  */
+   in bytes for the result.  If WITH_PREFIX is set the returned buffer
+   is prefixed with a 0x40 byte.  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,
+                  int with_prefix,
                   unsigned char **r_buffer, unsigned int *r_buflen)
 {
   unsigned char *rawmpi;
   unsigned int rawmpilen;
+  int off = with_prefix? 1:0;
 
-  rawmpi = _gcry_mpi_get_buffer (y, minlen, &rawmpilen, NULL);
+  rawmpi = _gcry_mpi_get_buffer_extra (y, minlen, off?-1:0, &rawmpilen, NULL);
   if (!rawmpi)
     return gpg_err_code_from_syserror ();
   if (mpi_test_bit (x, 0) && rawmpilen)
-    rawmpi[rawmpilen - 1] |= 0x80;  /* Set sign bit.  */
+    rawmpi[off + rawmpilen - 1] |= 0x80;  /* Set sign bit.  */
+  if (off)
+    rawmpi[0] = 0x40;
 
   *r_buffer = rawmpi;
-  *r_buflen = rawmpilen;
+  *r_buflen = rawmpilen + off;
   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.  */
+   context.  If WITH_PREFIX is set the returned buffer is prefixed
+   with a 0x40 byte.  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,
+                             int with_prefix,
                              unsigned char **r_buffer, unsigned int *r_buflen)
 {
   gpg_err_code_t rc;
@@ -112,7 +133,7 @@ _gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ec,
       rc = GPG_ERR_INTERNAL;
     }
   else
-    rc = eddsa_encode_x_y (x, y, ec->nbits/8, r_buffer, r_buflen);
+    rc = eddsa_encode_x_y (x, y, ec->nbits/8, with_prefix, r_buffer, r_buflen);
 
   if (!x_in)
     mpi_free (x);
@@ -122,11 +143,149 @@ _gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ec,
 }
 
 
+/* Make sure that the opaque MPI VALUE is in compact EdDSA format.
+   This function updates MPI if needed.  */
+gpg_err_code_t
+_gcry_ecc_eddsa_ensure_compact (gcry_mpi_t value, unsigned int nbits)
+{
+  gpg_err_code_t rc;
+  const unsigned char *buf;
+  unsigned int rawmpilen;
+  gcry_mpi_t x, y;
+  unsigned char *enc;
+  unsigned int enclen;
+
+  if (!mpi_is_opaque (value))
+    return GPG_ERR_INV_OBJ;
+  buf = mpi_get_opaque (value, &rawmpilen);
+  if (!buf)
+    return GPG_ERR_INV_OBJ;
+  rawmpilen = (rawmpilen + 7)/8;
+
+  if (rawmpilen > 1 && (rawmpilen%2))
+    {
+      if (buf[0] == 0x04)
+        {
+          /* Buffer is in SEC1 uncompressed format.  Extract y and
+             compress.  */
+          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;
+            }
+
+          rc = eddsa_encode_x_y (x, y, nbits/8, 0, &enc, &enclen);
+          mpi_free (x);
+          mpi_free (y);
+          if (rc)
+            return rc;
+
+          mpi_set_opaque (value, enc, 8*enclen);
+        }
+      else if (buf[0] == 0x40)
+        {
+          /* Buffer is compressed but with our SEC1 alike compression
+             indicator.  Remove that byte.  FIXME: We should write and
+             use a function to manipulate an opaque MPI in place. */
+          if (!_gcry_mpi_set_opaque_copy (value, buf + 1, (rawmpilen - 1)*8))
+            return gpg_err_code_from_syserror ();
+        }
+    }
+
+  return 0;
+}
+
+
+/* Recover X from Y and SIGN (which actually is a parity bit).  */
+gpg_err_code_t
+_gcry_ecc_eddsa_recover_x (gcry_mpi_t x, gcry_mpi_t y, int sign, mpi_ec_t ec)
+{
+  gpg_err_code_t rc = 0;
+  gcry_mpi_t u, v, v3, t;
+  static gcry_mpi_t p58, seven;
+
+  if (ec->dialect != ECC_DIALECT_ED25519)
+    return GPG_ERR_NOT_IMPLEMENTED;
+
+  if (!p58)
+    p58 = scanval ("0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+                   "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD");
+  if (!seven)
+    seven = mpi_set_ui (NULL, 7);
+
+  u   = mpi_new (0);
+  v   = mpi_new (0);
+  v3  = mpi_new (0);
+  t   = mpi_new (0);
+
+  /* Compute u and v */
+  /* u = y^2    */
+  mpi_mulm (u, y, y, ec->p);
+  /* v = b*y^2   */
+  mpi_mulm (v, ec->b, u, ec->p);
+  /* u = y^2-1  */
+  mpi_sub_ui (u, u, 1);
+  /* v = b*y^2+1 */
+  mpi_add_ui (v, v, 1);
+
+  /* Compute sqrt(u/v) */
+  /* v3 = v^3 */
+  mpi_powm (v3, v, mpi_const (MPI_C_THREE), ec->p);
+  /* t = v3 * v3 * u * v = u * v^7 */
+  mpi_powm (t, v, seven, ec->p);
+  mpi_mulm (t, t, u, ec->p);
+  /* t = t^((p-5)/8) = (u * v^7)^((p-5)/8)  */
+  mpi_powm (t, t, p58, ec->p);
+  /* x = t * u * v^3 = (u * v^3) * (u * v^7)^((p-5)/8) */
+  mpi_mulm (t, t, u, ec->p);
+  mpi_mulm (x, t, v3, ec->p);
+
+  /* Adjust if needed.  */
+  /* t = v * x^2  */
+  mpi_mulm (t, x, x, ec->p);
+  mpi_mulm (t, t, v, ec->p);
+  /* -t == u ? x = x * sqrt(-1) */
+  mpi_sub (t, ec->p, t);
+  if (!mpi_cmp (t, u))
+    {
+      static gcry_mpi_t m1;  /* Fixme: this is not thread-safe.  */
+      if (!m1)
+        m1 = scanval ("2B8324804FC1DF0B2B4D00993DFBD7A7"
+                      "2F431806AD2FE478C4EE1B274A0EA0B0");
+      mpi_mulm (x, x, m1, ec->p);
+      /* t = v * x^2  */
+      mpi_mulm (t, x, x, ec->p);
+      mpi_mulm (t, t, v, ec->p);
+      /* -t == u ? x = x * sqrt(-1) */
+      mpi_sub (t, ec->p, t);
+      if (!mpi_cmp (t, u))
+        rc = GPG_ERR_INV_OBJ;
+    }
+
+  /* Choose the desired square root according to parity */
+  if (mpi_test_bit (x, 0) != !!sign)
+    mpi_sub (x, ec->p, x);
+
+  mpi_free (t);
+  mpi_free (v3);
+  mpi_free (v);
+  mpi_free (u);
+
+  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
+   thus guaranteed to be properly padded.  R_ENCPKLEN receives 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,
@@ -135,56 +294,69 @@ _gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx, mpi_point_t result,
   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);
+      buf = 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))
+      /* Handle compression prefixes.  The size of the buffer will be
+         odd in this case.  */
+      if (rawmpilen > 1 && (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)
+          /* First check whether the public key has been given in
+             standard uncompressed format (SEC1).  No need to recover
+             x in this case.  */
+          if (buf[0] == 0x04)
             {
-              mpi_free (x);
-              return rc;
-            }
+              gcry_mpi_t x, y;
 
-          if (r_encpk)
-            {
-              rc = eddsa_encode_x_y (x, y, ctx->nbits/8, r_encpk, r_encpklen);
+              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);
-                  mpi_free (y);
                   return rc;
                 }
+
+              if (r_encpk)
+                {
+                  rc = eddsa_encode_x_y (x, y, ctx->nbits/8, 0,
+                                         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;
+            }
+
+          /* Check whether the public key has been prefixed with a 0x40
+             byte to explicitly indicate compressed format using a SEC1
+             alike prefix byte.  This is a Libgcrypt extension.  */
+          if (buf[0] == 0x40)
+            {
+              rawmpilen--;
+              buf++;
             }
-          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);
+      rawmpi = xtrymalloc (rawmpilen? rawmpilen:1);
       if (!rawmpi)
         return gpg_err_code_from_syserror ();
       memcpy (rawmpi, buf, rawmpilen);
@@ -194,7 +366,7 @@ _gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx, mpi_point_t result,
     {
       /* 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.  */
+         uncompressed format.  Thus we expect native EdDSA format.  */
       rawmpi = _gcry_mpi_get_buffer (pk, ctx->nbits/8, &rawmpilen, NULL);
       if (!rawmpi)
         return gpg_err_code_from_syserror ();
@@ -219,74 +391,102 @@ _gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx, mpi_point_t result,
         *r_encpklen = rawmpilen;
     }
   else
-    gcry_free (rawmpi);
+    xfree (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;
+  rc = _gcry_ecc_eddsa_recover_x (result->x, result->y, sign, ctx);
+  mpi_set_ui (result->z, 1);
 
-  /* is_odd(x) ? x = p-x */
-  if (mpi_test_bit (x, 0))
-    mpi_sub (x, ctx->p, x);
+  return rc;
+}
 
-  /* 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);
+/* Compute the A value as used by EdDSA.  The caller needs to provide
+   the context EC and the actual secret D as an MPI.  The function
+   returns a newly allocated 64 byte buffer at r_digest; the first 32
+   bytes represent the A value.  NULL is returned on error and NULL
+   stored at R_DIGEST.  */
+gpg_err_code_t
+_gcry_ecc_eddsa_compute_h_d (unsigned char **r_digest,
+                             gcry_mpi_t d, mpi_ec_t ec)
+{
+  gpg_err_code_t rc;
+  unsigned char *rawmpi = NULL;
+  unsigned int rawmpilen;
+  unsigned char *digest;
+  gcry_buffer_t hvec[2];
+  int hashalgo, b;
+
+  *r_digest = NULL;
+
+  hashalgo = GCRY_MD_SHA512;
+  if (hashalgo != GCRY_MD_SHA512)
+    return GPG_ERR_DIGEST_ALGO;
+
+  b = (ec->nbits+7)/8;
+  if (b != 256/8)
+    return GPG_ERR_INTERNAL; /* We only support 256 bit. */
+
+  /* Note that we clear DIGEST so we can use it as input to left pad
+     the key with zeroes for hashing.  */
+  digest = xtrycalloc_secure (2, b);
+  if (!digest)
+    return gpg_err_code_from_syserror ();
+
+  memset (hvec, 0, sizeof hvec);
 
-  gcry_mpi_release (x);
-  gcry_mpi_release (yy);
-  gcry_mpi_release (t);
-  gcry_mpi_release (p3);
-  gcry_mpi_release (p2);
-  gcry_mpi_release (p1);
+  rawmpi = _gcry_mpi_get_buffer (d, 0, &rawmpilen, NULL);
+  if (!rawmpi)
+    {
+      xfree (digest);
+      return gpg_err_code_from_syserror ();
+    }
+
+  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);
+  xfree (rawmpi);
+  if (rc)
+    {
+      xfree (digest);
+      return rc;
+    }
+
+  /* Compute the A value.  */
+  reverse_buffer (digest, 32);  /* Only the first half of the hash.  */
+  digest[0]   = (digest[0] & 0x7f) | 0x40;
+  digest[31] &= 0xf8;
 
+  *r_digest = digest;
   return 0;
 }
 
 
-/* Ed25519 version of the key generation.  */
+/**
+ * _gcry_ecc_eddsa_genkey - EdDSA version of the key generation.
+ *
+ * @sk:  A struct to receive the secret key.
+ * @E:   Parameters of the curve.
+ * @ctx: Elliptic curve computation context.
+ * @flags: Flags controlling aspects of the creation.
+ *
+ * Return: An error code.
+ *
+ * The only @flags bit used by this function is %PUBKEY_FLAG_TRANSIENT
+ * to use a faster RNG.
+ */
 gpg_err_code_t
 _gcry_ecc_eddsa_genkey (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
-                        gcry_random_level_t random_level)
+                        int flags)
 {
   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;
+  gcry_random_level_t random_level;
   char *dbuf;
   size_t dlen;
   gcry_buffer_t hvec[1];
@@ -295,19 +495,24 @@ _gcry_ecc_eddsa_genkey (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
   point_init (&Q);
   memset (hvec, 0, sizeof hvec);
 
+  if ((flags & PUBKEY_FLAG_TRANSIENT_KEY))
+    random_level = GCRY_STRONG_RANDOM;
+  else
+    random_level = GCRY_VERY_STRONG_RANDOM;
+
   a = mpi_snew (0);
   x = mpi_new (0);
   y = mpi_new (0);
 
   /* Generate a secret.  */
-  hash_d = gcry_malloc_secure (2*b);
+  hash_d = xtrymalloc_secure (2*b);
   if (!hash_d)
     {
-      rc = gpg_error_from_syserror ();
+      rc = gpg_err_code_from_syserror ();
       goto leave;
     }
   dlen = b;
-  dbuf = gcry_random_bytes_secure (dlen, random_level);
+  dbuf = _gcry_random_bytes_secure (dlen, random_level);
 
   /* Compute the A value.  */
   hvec[0].data = dbuf;
@@ -321,7 +526,7 @@ _gcry_ecc_eddsa_genkey (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
   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;
+  xfree (hash_d); hash_d = NULL;
   /* log_printmpi ("ecgen         a", a); */
 
   /* Compute Q.  */
@@ -338,14 +543,16 @@ _gcry_ecc_eddsa_genkey (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);
   point_set (&sk->Q, &Q);
 
  leave:
-  gcry_mpi_release (a);
-  gcry_mpi_release (x);
-  gcry_mpi_release (y);
-  gcry_free (hash_d);
+  point_free (&Q);
+  _gcry_mpi_release (a);
+  _gcry_mpi_release (x);
+  _gcry_mpi_release (y);
+  xfree (hash_d);
   return rc;
 }
 
@@ -373,7 +580,7 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, ECC_secret_key *skey,
   mpi_ec_t ctx = NULL;
   int b;
   unsigned int tmp;
-  unsigned char *digest;
+  unsigned char *digest = NULL;
   gcry_buffer_t hvec[3];
   const void *mbuf;
   size_t mlen;
@@ -389,8 +596,6 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, ECC_secret_key *skey,
 
   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);
@@ -398,43 +603,18 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, ECC_secret_key *skey,
   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,
+  r = mpi_snew (0);
+  ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect, 0,
                                      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. */
-
-  digest = gcry_calloc_secure (2, b);
-  if (!digest)
-    {
-      rc = gpg_err_code_from_syserror ();
-      goto leave;
-    }
+  if (b != 256/8) {
+    rc = GPG_ERR_INTERNAL; /* We only support 256 bit. */
+    goto leave;
+  }
 
-  /* 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;
+  rc = _gcry_ecc_eddsa_compute_h_d (&digest, skey->d, ctx);
   if (rc)
     goto leave;
-
-  /* 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);
 
   /* Compute the public key if it has not been supplied as optional
@@ -455,7 +635,7 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, ECC_secret_key *skey,
   else
     {
       _gcry_mpi_ec_mul_point (&Q, a, &skey->E.G, ctx);
-      rc = _gcry_ecc_eddsa_encodepoint (&Q, ctx, x, y, &encpk, &encpklen);
+      rc = _gcry_ecc_eddsa_encodepoint (&Q, ctx, x, y, 0, &encpk, &encpklen);
       if (rc)
         goto leave;
       if (DBG_CIPHER)
@@ -463,7 +643,7 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, ECC_secret_key *skey,
     }
 
   /* Compute R.  */
-  mbuf = gcry_mpi_get_opaque (input, &tmp);
+  mbuf = mpi_get_opaque (input, &tmp);
   mlen = (tmp +7)/8;
   if (DBG_CIPHER)
     log_printhex ("     m", mbuf, mlen);
@@ -485,7 +665,7 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, ECC_secret_key *skey,
     log_printpnt ("   r", &I, ctx);
 
   /* Convert R into affine coordinates and apply encoding.  */
-  rc = _gcry_ecc_eddsa_encodepoint (&I, ctx, x, y, &rawmpi, &rawmpilen);
+  rc = _gcry_ecc_eddsa_encodepoint (&I, ctx, x, y, 0, &rawmpi, &rawmpilen);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -506,7 +686,7 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, ECC_secret_key *skey,
     goto leave;
 
   /* No more need for RAWMPI thus we now transfer it to R_R.  */
-  gcry_mpi_set_opaque (r_r, rawmpi, rawmpilen*8);
+  mpi_set_opaque (r_r, rawmpi, rawmpilen*8);
   rawmpi = NULL;
 
   reverse_buffer (digest, 64);
@@ -520,22 +700,22 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, ECC_secret_key *skey,
     goto leave;
   if (DBG_CIPHER)
     log_printhex ("   e_s", rawmpi, rawmpilen);
-  gcry_mpi_set_opaque (s, rawmpi, rawmpilen*8);
+  mpi_set_opaque (s, rawmpi, rawmpilen*8);
   rawmpi = NULL;
 
   rc = 0;
 
  leave:
-  gcry_mpi_release (a);
-  gcry_mpi_release (x);
-  gcry_mpi_release (y);
-  gcry_mpi_release (r);
-  gcry_free (digest);
+  _gcry_mpi_release (a);
+  _gcry_mpi_release (x);
+  _gcry_mpi_release (y);
+  _gcry_mpi_release (r);
+  xfree (digest);
   _gcry_mpi_ec_free (ctx);
   point_free (&I);
   point_free (&Q);
-  gcry_free (encpk);
-  gcry_free (rawmpi);
+  xfree (encpk);
+  xfree (rawmpi);
   return rc;
 }
 
@@ -576,7 +756,7 @@ _gcry_ecc_eddsa_verify (gcry_mpi_t input, ECC_public_key *pkey,
   h = mpi_new (0);
   s = mpi_new (0);
 
-  ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect,
+  ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect, 0,
                                      pkey->E.p, pkey->E.a, pkey->E.b);
   b = ctx->nbits/8;
   if (b != 256/8)
@@ -600,11 +780,11 @@ _gcry_ecc_eddsa_verify (gcry_mpi_t input, ECC_public_key *pkey,
     }
 
   /* Convert the other input parameters.  */
-  mbuf = gcry_mpi_get_opaque (input, &tmp);
+  mbuf = 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);
+  rbuf = mpi_get_opaque (r_in, &tmp);
   rlen = (tmp +7)/8;
   if (DBG_CIPHER)
     log_printhex ("     r", rbuf, rlen);
@@ -645,7 +825,7 @@ _gcry_ecc_eddsa_verify (gcry_mpi_t input, ECC_public_key *pkey,
     if (DBG_CIPHER)
       log_printhex ("     s", sbuf, slen);
     _gcry_mpi_set_buffer (s, sbuf, slen, 0);
-    gcry_free (sbuf);
+    xfree (sbuf);
     if (slen != b)
       {
         rc = GPG_ERR_INV_LENGTH;
@@ -655,9 +835,9 @@ _gcry_ecc_eddsa_verify (gcry_mpi_t input, ECC_public_key *pkey,
 
   _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_sub (Ib.x, ctx->p, Ib.x);
   _gcry_mpi_ec_add_points (&Ia, &Ia, &Ib, ctx);
-  rc = _gcry_ecc_eddsa_encodepoint (&Ia, ctx, s, h, &tbuf, &tlen);
+  rc = _gcry_ecc_eddsa_encodepoint (&Ia, ctx, s, h, 0, &tbuf, &tlen);
   if (rc)
     goto leave;
   if (tlen != rlen || memcmp (tbuf, rbuf, tlen))
@@ -669,11 +849,11 @@ _gcry_ecc_eddsa_verify (gcry_mpi_t input, ECC_public_key *pkey,
   rc = 0;
 
  leave:
-  gcry_free (encpk);
-  gcry_free (tbuf);
+  xfree (encpk);
+  xfree (tbuf);
   _gcry_mpi_ec_free (ctx);
-  gcry_mpi_release (s);
-  gcry_mpi_release (h);
+  _gcry_mpi_release (s);
+  _gcry_mpi_release (h);
   point_free (&Ia);
   point_free (&Ib);
   point_free (&Q);