[git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-273-g1c6660d

by Werner Koch cvs at cvs.gnupg.org
Wed Sep 25 18:48:22 CEST 2013


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU crypto library".

The branch, master has been updated
       via  1c6660debdbf1e4c3e80074c846a3e3097f214bb (commit)
       via  9b7c49971588edf6acfc74bfb797eb79d19cb350 (commit)
       via  d6683d2a6065986a9198d2d2eaa02c005b68cea4 (commit)
       via  9a4447ccd1b90bcd701941e80a7f484a1825fcea (commit)
       via  64a7d347847d606eb5f4c156e24ba060271b8f6b (commit)
      from  1f5f4452e5bca105ec2197a4facbf9778e7dc31e (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 1c6660debdbf1e4c3e80074c846a3e3097f214bb
Author: Werner Koch <wk at gnupg.org>
Date:   Sat Sep 7 10:06:46 2013 +0200

    mpi: Change not yet used _gcry_mpi_set_opaque_copy.
    
    * mpi/mpiutil.c (_gcry_mpi_set_opaque_copy): Change prototype.
    (_gcry_mpi_get_opaque_copy): Take care of gcry_malloc failure.

diff --git a/mpi/mpiutil.c b/mpi/mpiutil.c
index 3855dc4..c9e6b31 100644
--- a/mpi/mpiutil.c
+++ b/mpi/mpiutil.c
@@ -283,13 +283,15 @@ gcry_mpi_set_opaque( gcry_mpi_t a, void *p, unsigned int nbits )
 
 
 gcry_mpi_t
-_gcry_mpi_set_opaque_copy (gcry_mpi_t a, void *p, unsigned int nbits)
+_gcry_mpi_set_opaque_copy (gcry_mpi_t a, const void *p, unsigned int nbits)
 {
   void *d;
   unsigned int n;
 
   n = (nbits+7)/8;
   d = gcry_is_secure (p)? gcry_malloc_secure (n) : gcry_malloc (n);
+  if (!d)
+    return NULL;
   memcpy (d, p, n);
   return gcry_mpi_set_opaque (a, d, nbits);
 }
@@ -318,7 +320,8 @@ _gcry_mpi_get_opaque_copy (gcry_mpi_t a, unsigned int *nbits)
     return NULL;
   n = (*nbits+7)/8;
   d = gcry_is_secure (s)? gcry_malloc_secure (n) : gcry_malloc (n);
-  memcpy (d, s, n);
+  if (d)
+    memcpy (d, s, n);
   return d;
 }
 
diff --git a/src/mpi.h b/src/mpi.h
index 279c485..780d5eb 100644
--- a/src/mpi.h
+++ b/src/mpi.h
@@ -135,7 +135,7 @@ void _gcry_mpi_swap( gcry_mpi_t a, gcry_mpi_t b);
 gcry_mpi_t _gcry_mpi_new (unsigned int nbits);
 gcry_mpi_t _gcry_mpi_snew (unsigned int nbits);
 gcry_mpi_t _gcry_mpi_set_opaque_copy (gcry_mpi_t a,
-                                      void *p, unsigned int nbits);
+                                      const void *p, unsigned int nbits);
 void *_gcry_mpi_get_opaque_copy (gcry_mpi_t a, unsigned int *nbits);
 int _gcry_mpi_is_neg (gcry_mpi_t a);
 void _gcry_mpi_neg (gcry_mpi_t w, gcry_mpi_t u);

commit 9b7c49971588edf6acfc74bfb797eb79d19cb350
Author: Werner Koch <wk at gnupg.org>
Date:   Sat Sep 7 10:06:46 2013 +0200

    sexp: Improve printing of data with a leading zero.
    
    * src/sexp.c (suitable_encoding): Detect leading zero byte.

diff --git a/src/sexp.c b/src/sexp.c
index 54d0c4a..6a2a9be 100644
--- a/src/sexp.c
+++ b/src/sexp.c
@@ -1725,6 +1725,8 @@ suitable_encoding (const unsigned char *buffer, size_t length)
   if (*buffer & 0x80)
     return 0; /* If the MSB is set we assume that buffer represents a
                  negative number.  */
+  if (!*buffer)
+    return 0; /* Starting with a zero is pretty much a binary string.  */
 
   for (s=buffer; length; s++, length--)
     {

commit d6683d2a6065986a9198d2d2eaa02c005b68cea4
Author: Werner Koch <wk at gnupg.org>
Date:   Sat Sep 7 10:06:46 2013 +0200

    ecc: Allow the name "q at eddsa" to get/set the public key.
    
    * cipher/ecc-curves.c (_gcry_ecc_get_mpi): Support "q at eddsa".
    (_gcry_ecc_set_mpi): Support "q".
    * cipher/ecc.c (eddsa_encodepoint): Rename to ...
    (_gcry_ecc_eddsa_encodepoint): this and make global.  Remove arg
    MINLEN and take from context.
    (eddsa_decodepoint): Rename to
    (_gcry_ecc_eddsa_decodepoint): this and make global. Remove arg LEN
    and take from context.
    (sign_eddsa, verify_eddsa): Take B from context.
    (ecc_sign, ecc_verify): Add hack to set DIALECT.
    (_gcry_pk_ecc_get_sexp): Use _gcry_ecc_compute_public.  Handle EdDSA.
    * src/ec-context.h (mpi_ec_ctx_s): Add field NBITS.
    * mpi/ec.c (ec_p_init): Init NBITS.
    * tests/t-mpi-point.c (test_curve): Add Ed25519.
    (sample_ed25519_q): New.
    (context_param): Check new sample key.
    (hex2buffer, hex2mpiopa): New.
    (cmp_mpihex): Take care of opaque MPIs.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/cipher/ecc-common.h b/cipher/ecc-common.h
index 031994a..cdb1362 100644
--- a/cipher/ecc-common.h
+++ b/cipher/ecc-common.h
@@ -84,5 +84,15 @@ gcry_error_t _gcry_ecc_os2ec (mpi_point_t result, gcry_mpi_t value);
 
 mpi_point_t  _gcry_ecc_compute_public (mpi_point_t Q, mpi_ec_t ec);
 
+/*-- ecc.c --*/
+gpg_err_code_t _gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ctx,
+                                            gcry_mpi_t x, gcry_mpi_t y,
+                                            unsigned char **r_buffer,
+                                            unsigned int *r_buflen);
+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);
+
 
 #endif /*GCRY_ECC_COMMON_H*/
diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c
index e6a993f..7447340 100644
--- a/cipher/ecc-curves.c
+++ b/cipher/ecc-curves.c
@@ -812,6 +812,9 @@ _gcry_ecc_get_param_sexp (const char *name)
 gcry_mpi_t
 _gcry_ecc_get_mpi (const char *name, mpi_ec_t ec, int copy)
 {
+  if (!*name)
+    return NULL;
+
   if (!strcmp (name, "p") && ec->p)
     return mpi_is_const (ec->p) && !copy? ec->p : mpi_copy (ec->p);
   if (!strcmp (name, "a") && ec->a)
@@ -833,17 +836,35 @@ _gcry_ecc_get_mpi (const char *name, mpi_ec_t ec, int copy)
   if (!strcmp (name, "q.y") && ec->Q && ec->Q->y)
     return mpi_is_const (ec->G->y) && !copy? ec->Q->y : mpi_copy (ec->Q->y);
 
-  /* If a point has been requested, return it in standard encoding.  */
+  /* If the base point has been requested, return it in standard
+     encoding.  */
   if (!strcmp (name, "g") && ec->G)
     return _gcry_mpi_ec_ec2os (ec->G, ec);
-  if (!strcmp (name, "q"))
+
+  /* If the public key has been requested, return it by default in
+     standard uncompressed encoding or if requested in other
+     encodings.  */
+  if (*name == 'q' && (!name[1] || name[1] == '@'))
     {
       /* If only the private key is given, compute the public key.  */
       if (!ec->Q)
         ec->Q = _gcry_ecc_compute_public (NULL, ec);
 
-      if (ec->Q)
+      if (!ec->Q)
+        return NULL;
+
+      if (name[1] != '@')
         return _gcry_mpi_ec_ec2os (ec->Q, ec);
+
+      if (!strcmp (name+2, "eddsa") && ec->model == MPI_EC_TWISTEDEDWARDS)
+        {
+          unsigned char *encpk;
+          unsigned int encpklen;
+
+          if (!_gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL,
+                                            &encpk, &encpklen))
+            return gcry_mpi_set_opaque (NULL, encpk, encpklen*8);
+        }
     }
 
   return NULL;
@@ -874,7 +895,11 @@ _gcry_ecc_get_point (const char *name, mpi_ec_t ec)
 gpg_err_code_t
 _gcry_ecc_set_mpi (const char *name, gcry_mpi_t newvalue, mpi_ec_t ec)
 {
-  if (!strcmp (name, "p"))
+  gpg_err_code_t rc = 0;
+
+  if (!*name)
+    ;
+  else if (!strcmp (name, "p"))
     {
       mpi_free (ec->p);
       ec->p = mpi_copy (newvalue);
@@ -896,15 +921,40 @@ _gcry_ecc_set_mpi (const char *name, gcry_mpi_t newvalue, mpi_ec_t ec)
       mpi_free (ec->n);
       ec->n = mpi_copy (newvalue);
     }
+  else if (*name == 'q' && (!name[1] || name[1] == '@'))
+    {
+      if (newvalue)
+        {
+          if (!ec->Q)
+            ec->Q = gcry_mpi_point_new (0);
+          if (ec->dialect == ECC_DIALECT_ED25519)
+            rc = _gcry_ecc_eddsa_decodepoint (newvalue, ec, ec->Q, NULL, NULL);
+          else
+            rc = _gcry_ecc_os2ec (ec->Q, newvalue);
+        }
+      if (rc || !newvalue)
+        {
+          gcry_mpi_point_release (ec->Q);
+          ec->Q = NULL;
+        }
+      /* Note: We assume that Q matches d and thus do not reset d.  */
+    }
   else if (!strcmp (name, "d"))
     {
       mpi_free (ec->d);
       ec->d = mpi_copy (newvalue);
+      if (ec->d)
+        {
+          /* We need to reset the public key because it may not
+             anymore match.  */
+          gcry_mpi_point_release (ec->Q);
+          ec->Q = NULL;
+        }
     }
   else
-    return GPG_ERR_UNKNOWN_NAME;
+   rc = GPG_ERR_UNKNOWN_NAME;
 
-  return 0;
+  return rc;
 }
 
 
diff --git a/cipher/ecc.c b/cipher/ecc.c
index 0b89ec2..abd501f 100644
--- a/cipher/ecc.c
+++ b/cipher/ecc.c
@@ -626,36 +626,47 @@ eddsa_encode_x_y (gcry_mpi_t x, gcry_mpi_t y, unsigned int minlen,
   return 0;
 }
 
-/* Encode POINT using the EdDSA scheme.  X and Y are scratch variables
-   supplied by the caller and CTX is the usual context.  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_encodepoint (mpi_point_t point, unsigned int minlen, mpi_ec_t ctx,
-                   gcry_mpi_t x, gcry_mpi_t y,
-                   unsigned char **r_buffer, unsigned int *r_buflen)
+/* 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)
 {
-  if (_gcry_mpi_ec_get_affine (x, y, point, ctx))
+  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");
-      return GPG_ERR_INTERNAL;
+      rc = GPG_ERR_INTERNAL;
     }
-  return eddsa_encode_x_y (x, y, minlen, r_buffer, r_buflen);
+  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.  LEN is
-   the expected length in bytes of the encoded key and CTX 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.  */
-static gpg_err_code_t
-eddsa_decodepoint (gcry_mpi_t pk, unsigned int len, mpi_ec_t ctx,
-                   mpi_point_t result,
-                   unsigned char **r_encpk, unsigned int *r_encpklen)
+/* 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;
@@ -694,7 +705,7 @@ eddsa_decodepoint (gcry_mpi_t pk, unsigned int len, mpi_ec_t ctx,
 
           if (r_encpk)
             {
-              rc = eddsa_encode_x_y (x, y, len, r_encpk, r_encpklen);
+              rc = eddsa_encode_x_y (x, y, ctx->nbits/8, r_encpk, r_encpklen);
               if (rc)
                 {
                   mpi_free (x);
@@ -720,7 +731,7 @@ eddsa_decodepoint (gcry_mpi_t pk, unsigned int len, mpi_ec_t ctx,
       /* 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, len, &rawmpilen, NULL);
+      rawmpi = _gcry_mpi_get_buffer (pk, ctx->nbits/8, &rawmpilen, NULL);
       if (!rawmpi)
         return gpg_err_code_from_syserror ();
     }
@@ -896,7 +907,7 @@ sign_eddsa (gcry_mpi_t input, ECC_secret_key *skey,
 {
   int rc;
   mpi_ec_t ctx = NULL;
-  int b = 256/8;             /* The only size we currently support.  */
+  int b;
   unsigned int tmp;
   unsigned char hash_d[64];  /* Fixme: malloc in secure memory */
   unsigned char digest[64];
@@ -927,6 +938,10 @@ sign_eddsa (gcry_mpi_t input, ECC_secret_key *skey,
   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/8;
+  if (b != 256/8)
+    return GPG_ERR_INTERNAL; /* We only support 256 bit. */
+
 
   /* Hash the secret key.  We clear DIGEST so we can use it to left
      pad the key with zeroes for hashing.  */
@@ -959,7 +974,7 @@ sign_eddsa (gcry_mpi_t input, ECC_secret_key *skey,
      parameter.  */
   if (pk)
     {
-      rc = eddsa_decodepoint (pk, b, ctx, &Q,  &encpk, &encpklen);
+      rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q,  &encpk, &encpklen);
       if (rc)
         goto leave;
       if (DBG_CIPHER)
@@ -973,7 +988,7 @@ sign_eddsa (gcry_mpi_t input, ECC_secret_key *skey,
   else
     {
       _gcry_mpi_ec_mul_point (&Q, a, &skey->E.G, ctx);
-      rc = eddsa_encodepoint (&Q, b, ctx, x, y, &encpk, &encpklen);
+      rc = _gcry_ecc_eddsa_encodepoint (&Q, ctx, x, y, &encpk, &encpklen);
       if (rc)
         goto leave;
       if (DBG_CIPHER)
@@ -1003,7 +1018,7 @@ sign_eddsa (gcry_mpi_t input, ECC_secret_key *skey,
     log_printpnt ("   r", &I, ctx);
 
   /* Convert R into affine coordinates and apply encoding.  */
-  rc = eddsa_encodepoint (&I, b, ctx, x, y, &rawmpi, &rawmpilen);
+  rc = _gcry_ecc_eddsa_encodepoint (&I, ctx, x, y, &rawmpi, &rawmpilen);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -1067,7 +1082,7 @@ verify_eddsa (gcry_mpi_t input, ECC_public_key *pkey,
 {
   int rc;
   mpi_ec_t ctx = NULL;
-  int b = 256/8;               /* The only size we currently support.  */
+  int b;
   unsigned int tmp;
   mpi_point_struct Q;          /* Public key.  */
   unsigned char *encpk = NULL; /* Encoded public key.  */
@@ -1094,9 +1109,12 @@ verify_eddsa (gcry_mpi_t input, ECC_public_key *pkey,
 
   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 = eddsa_decodepoint (pk, b, ctx, &Q, &encpk, &encpklen);
+  rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q, &encpk, &encpklen);
   if (rc)
     goto leave;
   if (!_gcry_mpi_ec_curve_point (&Q, ctx))
@@ -1170,7 +1188,7 @@ verify_eddsa (gcry_mpi_t input, ECC_public_key *pkey,
   _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 = eddsa_encodepoint (&Ia, b, ctx, s, h, &tbuf, &tlen);
+  rc = _gcry_ecc_eddsa_encodepoint (&Ia, ctx, s, h, &tbuf, &tlen);
   if (rc)
     goto leave;
   if (tlen != rlen || memcmp (tbuf, rbuf, tlen))
@@ -1301,7 +1319,7 @@ ecc_generate (int algo, unsigned int nbits, unsigned long evalue,
       unsigned char *encpk;
       unsigned int encpklen;
 
-      rc = eddsa_encodepoint (&sk.Q, 256/8, ctx, x, y, &encpk, &encpklen);
+      rc = _gcry_ecc_eddsa_encodepoint (&sk.Q, ctx, x, y, &encpk, &encpklen);
       if (rc)
         return rc;
       public = mpi_new (0);
@@ -1443,9 +1461,15 @@ ecc_sign (int algo, gcry_sexp_t *r_result, gcry_mpi_t data, gcry_mpi_t *skey,
       || !skey[6] )
     return GPG_ERR_BAD_MPI;
 
+  /* FIXME: The setting of model and dialect are crude hacks.  We will
+     fix that by moving the s-expression parsing from pubkey.c to
+     here.  */
   sk.E.model = ((flags & PUBKEY_FLAG_EDDSA)
                 ? MPI_EC_TWISTEDEDWARDS
                 : MPI_EC_WEIERSTRASS);
+  sk.E.dialect = ((flags & PUBKEY_FLAG_EDDSA)
+                  ? ECC_DIALECT_ED25519
+                  : ECC_DIALECT_STANDARD);
   sk.E.p = skey[0];
   sk.E.a = skey[1];
   sk.E.b = skey[2];
@@ -1525,9 +1549,15 @@ ecc_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
       || !pkey[3] || !pkey[4] || !pkey[5] )
     return GPG_ERR_BAD_MPI;
 
+  /* FIXME: The setting of model and dialect are crude hacks.  We will
+     fix that by moving the s-expression parsing from pubkey.c to
+     here.  */
   pk.E.model = ((flags & PUBKEY_FLAG_EDDSA)
                 ? MPI_EC_TWISTEDEDWARDS
                 : MPI_EC_WEIERSTRASS);
+  pk.E.dialect = ((flags & PUBKEY_FLAG_EDDSA)
+                  ? ECC_DIALECT_ED25519
+                  : ECC_DIALECT_STANDARD);
   pk.E.p = pkey[0];
   pk.E.a = pkey[1];
   pk.E.b = pkey[2];
@@ -1922,7 +1952,7 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam)
    Low-level API helper functions.
  */
 
-/* This is the wroker function for gcry_pubkey_get_sexp for ECC
+/* This is the worker function for gcry_pubkey_get_sexp for ECC
    algorithms.  Note that the caller has already stored NULL at
    R_SEXP.  */
 gpg_err_code_t
@@ -1940,10 +1970,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_mpi_point_new (0);
-      _gcry_mpi_ec_mul_point (ec->Q, ec->d, ec->G, ec);
-    }
+    ec->Q = _gcry_ecc_compute_public (NULL, ec);
 
   /* Encode G and Q.  */
   mpi_G = _gcry_mpi_ec_ec2os (ec->G, ec);
@@ -1957,7 +1984,23 @@ _gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, mpi_ec_t ec)
       rc = GPG_ERR_BAD_CRYPT_CTX;
       goto leave;
     }
-  mpi_Q = _gcry_mpi_ec_ec2os (ec->Q, ec);
+
+  if (ec->dialect == ECC_DIALECT_ED25519)
+    {
+      unsigned char *encpk;
+      unsigned int encpklen;
+
+      rc = _gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL,
+                                        &encpk, &encpklen);
+      if (rc)
+        goto leave;
+      mpi_Q = gcry_mpi_set_opaque (NULL, encpk, encpklen*8);
+      encpk = NULL;
+    }
+  else
+    {
+      mpi_Q = _gcry_mpi_ec_ec2os (ec->Q, ec);
+    }
   if (!mpi_Q)
     {
       rc = GPG_ERR_BROKEN_PUBKEY;
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 5d1be8d..0590a26 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -4182,10 +4182,16 @@ modified, it is suggested to pass @code{1} to @var{copy}, so that the
 function guarantees that a modifiable copy of the MPI is returned.  If
 @code{0} is used for @var{copy}, this function may return a constant
 flagged MPI.  In any case @code{gcry_mpi_release} needs to be called
-to release the result.  For valid names @ref{ecc_keyparam}.  If a
-point parameter is requested it is returned as an uncompressed encoded
-point.  If the public key @code{q} is requested but only the private
-key @code{d} is available, @code{q} will be recomputed on the fly.
+to release the result.  For valid names @ref{ecc_keyparam}.  If the
+public key @code{q} is requested but only the private key @code{d} is
+available, @code{q} will be recomputed on the fly.  If a point
+parameter is requested it is returned as an uncompressed
+encoded point unless these special names are used:
+ at table @var
+ at item q@@eddsa
+Return an EdDSA style compressed point.  This is only supported for
+Twisted Edwards curves.
+ at end table
 @end deftypefun
 
 @deftypefun gcry_mpi_point_t gcry_mpi_ec_get_point ( @
diff --git a/mpi/ec.c b/mpi/ec.c
index 883d8f6..c6d0fc8 100644
--- a/mpi/ec.c
+++ b/mpi/ec.c
@@ -436,6 +436,10 @@ ec_p_init (mpi_ec_t ctx, enum gcry_mpi_ec_models model,
 
   ctx->model = model;
   ctx->dialect = dialect;
+  if (dialect == ECC_DIALECT_ED25519)
+    ctx->nbits = 256;
+  else
+    ctx->nbits = mpi_get_nbits (p);
   ctx->p = mpi_copy (p);
   ctx->a = mpi_copy (a);
   if (b && model == MPI_EC_TWISTEDEDWARDS)
diff --git a/src/ec-context.h b/src/ec-context.h
index fdfbc0a..8dce7a7 100644
--- a/src/ec-context.h
+++ b/src/ec-context.h
@@ -27,6 +27,8 @@ struct mpi_ec_ctx_s
 
   enum ecc_dialects dialect;     /* The ECC dialect used with the curve.  */
 
+  unsigned int nbits;            /* Number of bits.  */
+
   /* Domain parameters.  Note that they may not all be set and if set
      the MPIs may be flaged as constant. */
   gcry_mpi_t p;         /* Prime specifying the field GF(p).  */
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 62c9721..5f49edc 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -726,7 +726,7 @@ void gcry_mpi_set_flag (gcry_mpi_t a, enum gcry_mpi_flag flag);
    currently useless as no flags are allowed. */
 void gcry_mpi_clear_flag (gcry_mpi_t a, enum gcry_mpi_flag flag);
 
-/* Return true when the FLAG is set for A. */
+/* Return true if the FLAG is set for A. */
 int gcry_mpi_get_flag (gcry_mpi_t a, enum gcry_mpi_flag flag);
 
 /* Private function - do not use.  */
diff --git a/tests/t-mpi-point.c b/tests/t-mpi-point.c
index 6683189..0641779 100644
--- a/tests/t-mpi-point.c
+++ b/tests/t-mpi-point.c
@@ -36,6 +36,14 @@ static int debug;
 static int error_count;
 
 
+#define my_isascii(c) (!((c) & 0x80))
+#define digitp(p)   (*(p) >= '0' && *(p) <= '9')
+#define hexdigitp(a) (digitp (a)                     \
+                      || (*(a) >= 'A' && *(a) <= 'F')  \
+                      || (*(a) >= 'a' && *(a) <= 'f'))
+#define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
+                     *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
+#define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
 #define xmalloc(a)    gcry_xmalloc ((a))
 #define xcalloc(a,b)  gcry_xcalloc ((a),(b))
 #define xfree(a)      gcry_free ((a))
@@ -113,6 +121,15 @@ static struct
       "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e6"
       "62c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"
     },
+    {
+      "Ed25519",
+      "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
+      "-0x01",
+      "-0x98412DFC9311D490018C7338BF8688861767FF8FF5B2BEBE27548A14B235EC8FEDA4",
+      "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED",
+      "0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A",
+      "0x6666666666666666666666666666666666666666666666666666666666666658"
+    },
     { NULL, NULL, NULL, NULL, NULL }
   };
 
@@ -127,6 +144,20 @@ static const char sample_p256_q_y[] =
   "00E86525E38CCECFF3FB8D152CC6334F70D23A525175C1BCBDDE6E023B2228770E";
 
 
+/* A sample public key for Ed25519.  */
+static const char sample_ed25519_q[] =
+  "04"
+  "55d0e09a2b9d34292297e08d60d0f620c513d47253187c24b12786bd777645ce"
+  "1a5107f7681a02af2523a6daf372e10e3a0764c9d3fe4bd5b70ab18201985ad7";
+static const char sample_ed25519_q_x[] =
+  "55d0e09a2b9d34292297e08d60d0f620c513d47253187c24b12786bd777645ce";
+static const char sample_ed25519_q_y[] =
+  "1a5107f7681a02af2523a6daf372e10e3a0764c9d3fe4bd5b70ab18201985ad7";
+static const char sample_ed25519_q_eddsa[] =
+  "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a";
+static const char sample_ed25519_d[] =
+  "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60";
+
 
 static void
 show (const char *format, ...)
@@ -241,7 +272,49 @@ hex2mpi (const char *string)
 
   err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
   if (err)
-    die ("hex2mpi '%s' failed: %s\n", gpg_strerror (err));
+    die ("hex2mpi '%s' failed: %s\n", string, gpg_strerror (err));
+  return val;
+}
+
+
+/* Convert STRING consisting of hex characters into its binary
+   representation and return it as an allocated buffer. The valid
+   length of the buffer is returned at R_LENGTH.  The string is
+   delimited by end of string.  The function returns NULL on
+   error.  */
+static void *
+hex2buffer (const char *string, size_t *r_length)
+{
+  const char *s;
+  unsigned char *buffer;
+  size_t length;
+
+  buffer = xmalloc (strlen(string)/2+1);
+  length = 0;
+  for (s=string; *s; s +=2 )
+    {
+      if (!hexdigitp (s) || !hexdigitp (s+1))
+        return NULL;           /* Invalid hex digits. */
+      ((unsigned char*)buffer)[length++] = xtoi_2 (s);
+    }
+  *r_length = length;
+  return buffer;
+}
+
+
+static gcry_mpi_t
+hex2mpiopa (const char *string)
+{
+  char *buffer;
+  size_t buflen;
+  gcry_mpi_t val;
+
+  buffer = hex2buffer (string, &buflen);
+  if (!buffer)
+    die ("hex2mpiopa '%s' failed: parser error\n", string);
+  val = gcry_mpi_set_opaque (NULL, buffer, buflen*8);
+  if (!buffer)
+    die ("hex2mpiopa '%s' failed: set_opaque error%s\n", string);
   return val;
 }
 
@@ -253,7 +326,10 @@ cmp_mpihex (gcry_mpi_t a, const char *b)
   gcry_mpi_t bval;
   int res;
 
-  bval = hex2mpi (b);
+  if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
+    bval = hex2mpiopa (b);
+  else
+    bval = hex2mpi (b);
   res = gcry_mpi_cmp (a, bval);
   gcry_mpi_release (bval);
   return res;
@@ -459,7 +535,7 @@ context_param (void)
   gpg_error_t err;
   int idx;
   gcry_ctx_t ctx = NULL;
-  gcry_mpi_t q;
+  gcry_mpi_t q, d;
   gcry_sexp_t keyparam;
 
   wherestr = "context_param";
@@ -492,13 +568,11 @@ context_param (void)
         continue;
 
     }
-  gcry_ctx_release (ctx);
-
 
-  show ("checking sample public key\n");
+  show ("checking sample public key (nistp256)\n");
   q = hex2mpi (sample_p256_q);
   err = gcry_sexp_build (&keyparam, NULL,
-                        "(public-key(ecdsa(curve %s)(q %m)))",
+                        "(public-key(ecc(curve %s)(q %m)))",
                         "NIST P-256", q);
   if (err)
     die ("gcry_sexp_build failed: %s\n", gpg_strerror (err));
@@ -511,18 +585,112 @@ context_param (void)
   /*   fail ("gcry_pk_testkey failed for sample public key: %s\n", */
   /*         gpg_strerror (err)); */
 
+  gcry_ctx_release (ctx);
   err = gcry_mpi_ec_new (&ctx, keyparam, NULL);
   if (err)
-    fail ("gcry_mpi_ec_new failed for sample public key: %s\n",
+    fail ("gcry_mpi_ec_new failed for sample public key (nistp256): %s\n",
           gpg_strerror (err));
   else
     {
       gcry_sexp_t sexp;
 
-      get_and_cmp_mpi ("q", sample_p256_q, "NIST P-256", ctx);
-      get_and_cmp_point ("q", sample_p256_q_x, sample_p256_q_y, "NIST P-256",
+      get_and_cmp_mpi ("q", sample_p256_q, "nistp256", ctx);
+      get_and_cmp_point ("q", sample_p256_q_x, sample_p256_q_y, "nistp256",
                          ctx);
 
+      /* Delete Q.  */
+      err = gcry_mpi_ec_set_mpi ("q", NULL, ctx);
+      if (err)
+        fail ("clearing Q for nistp256 failed: %s\n", gpg_strerror (err));
+      if (gcry_mpi_ec_get_mpi ("q", ctx, 0))
+        fail ("clearing Q for nistp256 did not work\n");
+
+      /* Set Q again.  */
+      q = hex2mpi (sample_p256_q);
+      err = gcry_mpi_ec_set_mpi ("q", q, ctx);
+      if (err)
+        fail ("setting Q for nistp256 failed: %s\n", gpg_strerror (err));
+      get_and_cmp_mpi ("q", sample_p256_q, "nistp256(2)", ctx);
+
+      /* Get as s-expression.  */
+      err = gcry_pubkey_get_sexp (&sexp, 0, ctx);
+      if (err)
+        fail ("gcry_pubkey_get_sexp(0) failed: %s\n", gpg_strerror (err));
+      else if (debug)
+        print_sexp ("Result of gcry_pubkey_get_sexp (0):\n", sexp);
+      gcry_sexp_release (sexp);
+
+      err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_PUBKEY, ctx);
+      if (err)
+        fail ("gcry_pubkey_get_sexp(GET_PUBKEY) failed: %s\n",
+              gpg_strerror (err));
+      else if (debug)
+        print_sexp ("Result of gcry_pubkey_get_sexp (GET_PUBKEY):\n", sexp);
+      gcry_sexp_release (sexp);
+
+      err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_SECKEY, ctx);
+      if (gpg_err_code (err) != GPG_ERR_NO_SECKEY)
+        fail ("gcry_pubkey_get_sexp(GET_SECKEY) returned wrong error: %s\n",
+              gpg_strerror (err));
+      gcry_sexp_release (sexp);
+    }
+
+  show ("checking sample public key (Ed25519)\n");
+  q = hex2mpi (sample_ed25519_q);
+  gcry_sexp_release (keyparam);
+  err = gcry_sexp_build (&keyparam, NULL,
+                        "(public-key(ecc(curve %s)(q %m)))",
+                        "Ed25519", q);
+  if (err)
+    die ("gcry_sexp_build failed: %s\n", gpg_strerror (err));
+  gcry_mpi_release (q);
+
+  /* We can't call gcry_pk_testkey because it is only implemented for
+     private keys.  */
+  /* err = gcry_pk_testkey (keyparam); */
+  /* if (err) */
+  /*   fail ("gcry_pk_testkey failed for sample public key: %s\n", */
+  /*         gpg_strerror (err)); */
+
+  gcry_ctx_release (ctx);
+  err = gcry_mpi_ec_new (&ctx, keyparam, NULL);
+  if (err)
+    fail ("gcry_mpi_ec_new failed for sample public key: %s\n",
+          gpg_strerror (err));
+  else
+    {
+      gcry_sexp_t sexp;
+
+      get_and_cmp_mpi ("q", sample_ed25519_q, "Ed25519", ctx);
+      get_and_cmp_point ("q", sample_ed25519_q_x, sample_ed25519_q_y,
+                         "Ed25519", ctx);
+      get_and_cmp_mpi ("q at eddsa", sample_ed25519_q_eddsa, "Ed25519", ctx);
+
+      /* Delete Q by setting d and the clearing d.  The clearing is
+         required so that we can check whether Q has been cleared and
+         because further tests only expect a public key. */
+      d = hex2mpi (sample_ed25519_d);
+      err = gcry_mpi_ec_set_mpi ("d", d, ctx);
+      if (err)
+        fail ("setting d for Ed25519 failed: %s\n", gpg_strerror (err));
+      gcry_mpi_release (d);
+      err = gcry_mpi_ec_set_mpi ("d", NULL, ctx);
+      if (err)
+        fail ("setting d for Ed25519 failed(2): %s\n", gpg_strerror (err));
+      if (gcry_mpi_ec_get_mpi ("q", ctx, 0))
+        fail ("setting d for Ed25519 did not reset Q\n");
+
+      /* Set Q again.  We need to use an opaque MPI here because
+         sample_ed25519_q is in uncompressed format which can only be
+         auto-detected if passed opaque.  */
+      q = hex2mpiopa (sample_ed25519_q);
+      err = gcry_mpi_ec_set_mpi ("q", q, ctx);
+      if (err)
+        fail ("setting Q for Ed25519 failed: %s\n", gpg_strerror (err));
+      gcry_mpi_release (q);
+      get_and_cmp_mpi ("q", sample_ed25519_q, "Ed25519(2)", ctx);
+
+      /* Get as s-expression.  */
       err = gcry_pubkey_get_sexp (&sexp, 0, ctx);
       if (err)
         fail ("gcry_pubkey_get_sexp(0) failed: %s\n", gpg_strerror (err));
@@ -544,9 +712,9 @@ context_param (void)
               gpg_strerror (err));
       gcry_sexp_release (sexp);
 
-      gcry_ctx_release (ctx);
     }
 
+  gcry_ctx_release (ctx);
   gcry_sexp_release (keyparam);
 }
 
@@ -730,7 +898,7 @@ basic_ec_math_simplified (void)
     print_sexp ("Result of gcry_pubkey_get_sexp (GET_PUBKEY):\n", sexp);
   gcry_sexp_release (sexp);
 
-  /* Does get_sexp return the public key if after d has been deleted?  */
+  /* Does get_sexp return the public key after d has been deleted?  */
   err = gcry_mpi_ec_set_mpi ("d", NULL, ctx);
   if (err)
     die ("gcry_mpi_ec_set_mpi(d=NULL) failed\n");

commit 9a4447ccd1b90bcd701941e80a7f484a1825fcea
Author: Werner Koch <wk at gnupg.org>
Date:   Sat Sep 7 10:06:46 2013 +0200

    mpicalc: Add statement to compute the number of bits.
    
    * src/mpicalc.c (do_nbits): New.
    (main): Add statement 'b'.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/mpicalc.c b/src/mpicalc.c
index 762d7c8..dd85227 100644
--- a/src/mpicalc.c
+++ b/src/mpicalc.c
@@ -238,6 +238,20 @@ do_rshift (void)
 }
 
 
+static void
+do_nbits (void)
+{
+  unsigned int n;
+
+  if (stackidx < 1)
+    {
+      fputs ("stack underflow\n", stderr);
+      return;
+    }
+  n = mpi_get_nbits (stack[stackidx - 1]);
+  mpi_set_ui (stack[stackidx - 1], n);
+}
+
 
 static int
 my_getc (void)
@@ -279,6 +293,7 @@ print_help (void)
          "i   remove item   [0] := [1]                {-1}\n"
          "d   dup item      [-1] := [0]               {+1}\n"
          "r   reverse       [0] := [1], [1] := [0]    {0}\n"
+         "b   # of bits     [0] := nbits([0])         {0}\n"
          "c   clear stack\n"
          "p   print top item\n"
          "f   print the stack\n"
@@ -381,7 +396,7 @@ main (int argc, char **argv)
 		      do_add ();
 		    }
 		  break;
-		case '-':
+                case '-':
 		  if ((c = my_getc ()) == '-')
 		    do_dec ();
 		  else if (isdigit (c) || (c >= 'A' && c <= 'F'))
@@ -454,6 +469,9 @@ main (int argc, char **argv)
                       stack[stackidx-2] = tmp;
 		    }
 		  break;
+                case 'b':
+                  do_nbits ();
+                  break;
 		case 'c':
 		  for (i = 0; i < stackidx; i++)
                     {

commit 64a7d347847d606eb5f4c156e24ba060271b8f6b
Author: Werner Koch <wk at gnupg.org>
Date:   Sat Sep 7 10:06:46 2013 +0200

    ecc: Refactor low-level access functions.
    
    * mpi/ec.c (point_copy): Move to cipher/ecc-curves.c.
    (ec_get_reset): Rename to _gcry_mpi_ec_get_reset and make global.
    (_gcry_mpi_ec_get_mpi): Factor most code out to _gcry_ecc_get_mpi.
    (_gcry_mpi_ec_get_point): Factor most code out to _gcry_ecc_get_point.
    (_gcry_mpi_ec_set_mpi): Factor most code out to _gcry_ecc_set_mpi.
    (_gcry_mpi_ec_set_point): Factor most code out to _gcry_ecc_set_point.
    * cipher/ecc-curves.c (_gcry_ecc_get_mpi): New.
    (_gcry_ecc_get_point, _gcry_ecc_set_mpi, _gcry_ecc_set_point): New.
    * cipher/ecc-misc.c (_gcry_ecc_compute_public): New.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/cipher/ecc-common.h b/cipher/ecc-common.h
index e806059..031994a 100644
--- a/cipher/ecc-common.h
+++ b/cipher/ecc-common.h
@@ -82,5 +82,7 @@ const char *_gcry_ecc_dialect2str (enum ecc_dialects dialect);
 gcry_mpi_t   _gcry_ecc_ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p);
 gcry_error_t _gcry_ecc_os2ec (mpi_point_t result, gcry_mpi_t value);
 
+mpi_point_t  _gcry_ecc_compute_public (mpi_point_t Q, mpi_ec_t ec);
+
 
 #endif /*GCRY_ECC_COMMON_H*/
diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c
index 49c0959..e6a993f 100644
--- a/cipher/ecc-curves.c
+++ b/cipher/ecc-curves.c
@@ -270,6 +270,23 @@ static const ecc_domain_parms_t domain_parms[] =
 
 
 
+/* Return a copy of POINT.  */
+static gcry_mpi_point_t
+point_copy (gcry_mpi_point_t point)
+{
+  gcry_mpi_point_t newpoint;
+
+  if (point)
+    {
+      newpoint = gcry_mpi_point_new (0);
+      point_set (newpoint, point);
+    }
+  else
+    newpoint = NULL;
+  return newpoint;
+}
+
+
 /* Helper to scan a hex string. */
 static gcry_mpi_t
 scanval (const char *string)
@@ -787,3 +804,126 @@ _gcry_ecc_get_param_sexp (const char *name)
 
   return result;
 }
+
+
+/* Return an MPI (or opaque MPI) described by NAME and the context EC.
+   If COPY is true a copy is returned, if not a const MPI may be
+   returned.  In any case mpi_free must be used.  */
+gcry_mpi_t
+_gcry_ecc_get_mpi (const char *name, mpi_ec_t ec, int copy)
+{
+  if (!strcmp (name, "p") && ec->p)
+    return mpi_is_const (ec->p) && !copy? ec->p : mpi_copy (ec->p);
+  if (!strcmp (name, "a") && ec->a)
+    return mpi_is_const (ec->a) && !copy? ec->a : mpi_copy (ec->a);
+  if (!strcmp (name, "b") && ec->b)
+    return mpi_is_const (ec->b) && !copy? ec->b : mpi_copy (ec->b);
+  if (!strcmp (name, "n") && ec->n)
+    return mpi_is_const (ec->n) && !copy? ec->n : mpi_copy (ec->n);
+  if (!strcmp (name, "d") && ec->d)
+    return mpi_is_const (ec->d) && !copy? ec->d : mpi_copy (ec->d);
+
+  /* Return a requested point coordinate.  */
+  if (!strcmp (name, "g.x") && ec->G && ec->G->x)
+    return mpi_is_const (ec->G->x) && !copy? ec->G->x : mpi_copy (ec->G->x);
+  if (!strcmp (name, "g.y") && ec->G && ec->G->y)
+    return mpi_is_const (ec->G->y) && !copy? ec->G->y : mpi_copy (ec->G->y);
+  if (!strcmp (name, "q.x") && ec->Q && ec->Q->x)
+    return mpi_is_const (ec->Q->x) && !copy? ec->Q->x : mpi_copy (ec->Q->x);
+  if (!strcmp (name, "q.y") && ec->Q && ec->Q->y)
+    return mpi_is_const (ec->G->y) && !copy? ec->Q->y : mpi_copy (ec->Q->y);
+
+  /* If a point has been requested, return it in standard encoding.  */
+  if (!strcmp (name, "g") && ec->G)
+    return _gcry_mpi_ec_ec2os (ec->G, ec);
+  if (!strcmp (name, "q"))
+    {
+      /* If only the private key is given, compute the public key.  */
+      if (!ec->Q)
+        ec->Q = _gcry_ecc_compute_public (NULL, ec);
+
+      if (ec->Q)
+        return _gcry_mpi_ec_ec2os (ec->Q, ec);
+    }
+
+  return NULL;
+}
+
+
+/* Return a point described by NAME and the context EC.  */
+gcry_mpi_point_t
+_gcry_ecc_get_point (const char *name, mpi_ec_t ec)
+{
+  if (!strcmp (name, "g") && ec->G)
+    return point_copy (ec->G);
+  if (!strcmp (name, "q"))
+    {
+      /* If only the private key is given, compute the public key.  */
+      if (!ec->Q)
+        ec->Q = _gcry_ecc_compute_public (NULL, ec);
+
+      if (ec->Q)
+        return point_copy (ec->Q);
+    }
+
+  return NULL;
+}
+
+
+/* Store the MPI NEWVALUE into the context EC under NAME. */
+gpg_err_code_t
+_gcry_ecc_set_mpi (const char *name, gcry_mpi_t newvalue, mpi_ec_t ec)
+{
+  if (!strcmp (name, "p"))
+    {
+      mpi_free (ec->p);
+      ec->p = mpi_copy (newvalue);
+      _gcry_mpi_ec_get_reset (ec);
+    }
+  else if (!strcmp (name, "a"))
+    {
+      mpi_free (ec->a);
+      ec->a = mpi_copy (newvalue);
+      _gcry_mpi_ec_get_reset (ec);
+    }
+  else if (!strcmp (name, "b"))
+    {
+      mpi_free (ec->b);
+      ec->b = mpi_copy (newvalue);
+    }
+  else if (!strcmp (name, "n"))
+    {
+      mpi_free (ec->n);
+      ec->n = mpi_copy (newvalue);
+    }
+  else if (!strcmp (name, "d"))
+    {
+      mpi_free (ec->d);
+      ec->d = mpi_copy (newvalue);
+    }
+  else
+    return GPG_ERR_UNKNOWN_NAME;
+
+  return 0;
+}
+
+
+/* Store the point NEWVALUE into the context EC under NAME.  */
+gpg_err_code_t
+_gcry_ecc_set_point (const char *name, gcry_mpi_point_t newvalue, mpi_ec_t ec)
+{
+  if (!strcmp (name, "g"))
+    {
+      gcry_mpi_point_release (ec->G);
+      ec->G = point_copy (newvalue);
+    }
+  else if (!strcmp (name, "q"))
+    {
+      gcry_mpi_point_release (ec->Q);
+      ec->Q = point_copy (newvalue);
+    }
+  else
+    return GPG_ERR_UNKNOWN_NAME;
+
+  return 0;
+}
diff --git a/cipher/ecc-misc.c b/cipher/ecc-misc.c
index f8db81a..1dc0480 100644
--- a/cipher/ecc-misc.c
+++ b/cipher/ecc-misc.c
@@ -232,3 +232,24 @@ _gcry_ecc_os2ec (mpi_point_t result, gcry_mpi_t value)
 
   return 0;
 }
+
+
+/* Compute the public key from the the context EC.  Obviously a
+   requirement is that the secret key is available in EC.  On success
+   Q is returned; on error NULL.  If Q is NULL a newly allocated pint
+   is returned.  */
+mpi_point_t
+_gcry_ecc_compute_public (mpi_point_t Q, mpi_ec_t ec)
+{
+  if (!ec->d || !ec->G || !ec->p || !ec->a)
+    return NULL;
+  if (ec->model == MPI_EC_TWISTEDEDWARDS && !ec->b)
+    return NULL;
+
+  if (!Q)
+    Q = gcry_mpi_point_new (0);
+  if (!Q)
+    return NULL;
+  _gcry_mpi_ec_mul_point (Q, ec->d, ec->G, ec);
+  return Q;
+}
diff --git a/mpi/ec.c b/mpi/ec.c
index e52facd..883d8f6 100644
--- a/mpi/ec.c
+++ b/mpi/ec.c
@@ -132,23 +132,6 @@ point_set (mpi_point_t d, mpi_point_t s)
 }
 
 
-/* Return a copy of POINT.  */
-static gcry_mpi_point_t
-point_copy (gcry_mpi_point_t point)
-{
-  gcry_mpi_point_t newpoint;
-
-  if (point)
-    {
-      newpoint = gcry_mpi_point_new (0);
-      point_set (newpoint, point);
-    }
-  else
-    newpoint = NULL;
-  return newpoint;
-}
-
-
 /* Set the projective coordinates from POINT into X, Y, and Z.  If a
    coordinate is not required, X, Y, or Z may be passed as NULL.  */
 void
@@ -396,8 +379,8 @@ ec_invm (gcry_mpi_t x, gcry_mpi_t a, mpi_ec_t ctx)
 
 
 /* Force recomputation of all helper variables.  */
-static void
-ec_get_reset (mpi_ec_t ec)
+void
+_gcry_mpi_ec_get_reset (mpi_ec_t ec)
 {
   ec->t.valid.a_is_pminus3 = 0;
   ec->t.valid.two_inv_p = 0;
@@ -458,7 +441,7 @@ ec_p_init (mpi_ec_t ctx, enum gcry_mpi_ec_models model,
   if (b && model == MPI_EC_TWISTEDEDWARDS)
     ctx->b = mpi_copy (b);
 
-  ec_get_reset (ctx);
+  _gcry_mpi_ec_get_reset (ctx);
 
   /* Allocate scratch variables.  */
   for (i=0; i< DIM(ctx->t.scratch); i++)
@@ -590,44 +573,7 @@ _gcry_mpi_ec_get_mpi (const char *name, gcry_ctx_t ctx, int copy)
 {
   mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
 
-  if (!strcmp (name, "p") && ec->p)
-    return mpi_is_const (ec->p) && !copy? ec->p : mpi_copy (ec->p);
-  if (!strcmp (name, "a") && ec->a)
-    return mpi_is_const (ec->a) && !copy? ec->a : mpi_copy (ec->a);
-  if (!strcmp (name, "b") && ec->b)
-    return mpi_is_const (ec->b) && !copy? ec->b : mpi_copy (ec->b);
-  if (!strcmp (name, "n") && ec->n)
-    return mpi_is_const (ec->n) && !copy? ec->n : mpi_copy (ec->n);
-  if (!strcmp (name, "d") && ec->d)
-    return mpi_is_const (ec->d) && !copy? ec->d : mpi_copy (ec->d);
-
-  /* Return a requested point coordinate.  */
-  if (!strcmp (name, "g.x") && ec->G && ec->G->x)
-    return mpi_is_const (ec->G->x) && !copy? ec->G->x : mpi_copy (ec->G->x);
-  if (!strcmp (name, "g.y") && ec->G && ec->G->y)
-    return mpi_is_const (ec->G->y) && !copy? ec->G->y : mpi_copy (ec->G->y);
-  if (!strcmp (name, "q.x") && ec->Q && ec->Q->x)
-    return mpi_is_const (ec->Q->x) && !copy? ec->Q->x : mpi_copy (ec->Q->x);
-  if (!strcmp (name, "q.y") && ec->Q && ec->Q->y)
-    return mpi_is_const (ec->G->y) && !copy? ec->Q->y : mpi_copy (ec->Q->y);
-
-  /* If a point has been requested, return it in standard encoding.  */
-  if (!strcmp (name, "g") && ec->G)
-    return _gcry_mpi_ec_ec2os (ec->G, ec);
-  if (!strcmp (name, "q"))
-    {
-      /* If only the private key is given, compute the public key.  */
-      if (!ec->Q && ec->d && ec->G && ec->p && ec->a)
-        {
-          ec->Q = gcry_mpi_point_new (0);
-          _gcry_mpi_ec_mul_point (ec->Q, ec->d, ec->G, ec);
-        }
-
-      if (ec->Q)
-        return _gcry_mpi_ec_ec2os (ec->Q, ec);
-    }
-
-  return NULL;
+  return _gcry_ecc_get_mpi (name, ec, copy);
 }
 
 
@@ -638,22 +584,7 @@ _gcry_mpi_ec_get_point (const char *name, gcry_ctx_t ctx, int copy)
 
   (void)copy;  /* Not used.  */
 
-  if (!strcmp (name, "g") && ec->G)
-    return point_copy (ec->G);
-  if (!strcmp (name, "q"))
-    {
-      /* If only the private key is given, compute the public key.  */
-      if (!ec->Q && ec->d && ec->G && ec->p && ec->a)
-        {
-          ec->Q = gcry_mpi_point_new (0);
-          _gcry_mpi_ec_mul_point (ec->Q, ec->d, ec->G, ec);
-        }
-
-      if (ec->Q)
-        return point_copy (ec->Q);
-    }
-
-  return NULL;
+  return _gcry_ecc_get_point (name, ec);
 }
 
 
@@ -663,37 +594,7 @@ _gcry_mpi_ec_set_mpi (const char *name, gcry_mpi_t newvalue,
 {
   mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
 
-  if (!strcmp (name, "p"))
-    {
-      mpi_free (ec->p);
-      ec->p = mpi_copy (newvalue);
-      ec_get_reset (ec);
-    }
-  else if (!strcmp (name, "a"))
-    {
-      mpi_free (ec->a);
-      ec->a = mpi_copy (newvalue);
-      ec_get_reset (ec);
-    }
-  else if (!strcmp (name, "b"))
-    {
-      mpi_free (ec->b);
-      ec->b = mpi_copy (newvalue);
-    }
-  else if (!strcmp (name, "n"))
-    {
-      mpi_free (ec->n);
-      ec->n = mpi_copy (newvalue);
-    }
-  else if (!strcmp (name, "d"))
-    {
-      mpi_free (ec->d);
-      ec->d = mpi_copy (newvalue);
-    }
-  else
-    return GPG_ERR_UNKNOWN_NAME;
-
-  return 0;
+  return _gcry_ecc_set_mpi (name, newvalue, ec);
 }
 
 
@@ -703,20 +604,7 @@ _gcry_mpi_ec_set_point (const char *name, gcry_mpi_point_t newvalue,
 {
   mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
 
-  if (!strcmp (name, "g"))
-    {
-      gcry_mpi_point_release (ec->G);
-      ec->G = point_copy (newvalue);
-    }
-  else if (!strcmp (name, "q"))
-    {
-      gcry_mpi_point_release (ec->Q);
-      ec->Q = point_copy (newvalue);
-    }
-  else
-    return GPG_ERR_UNKNOWN_NAME;
-
-  return 0;
+  return _gcry_ecc_set_point (name, newvalue, ec);
 }
 
 
diff --git a/src/ec-context.h b/src/ec-context.h
index f2ad19b..fdfbc0a 100644
--- a/src/ec-context.h
+++ b/src/ec-context.h
@@ -62,5 +62,20 @@ struct mpi_ec_ctx_s
 };
 
 
+/*-- mpi/ec.c --*/
+void _gcry_mpi_ec_get_reset (mpi_ec_t ec);
+
+
+/*-- cipher/ecc-curves.c --*/
+gpg_err_code_t   _gcry_mpi_ec_new (gcry_ctx_t *r_ctx,
+                                   gcry_sexp_t keyparam, const char *curvename);
+
+gcry_mpi_t       _gcry_ecc_get_mpi (const char *name, mpi_ec_t ec, int copy);
+gcry_mpi_point_t _gcry_ecc_get_point (const char *name, mpi_ec_t ec);
+gpg_err_code_t   _gcry_ecc_set_mpi (const char *name,
+                                    gcry_mpi_t newvalue, mpi_ec_t ec);
+gpg_err_code_t   _gcry_ecc_set_point (const char *name,
+                                      gcry_mpi_point_t newvalue, mpi_ec_t ec);
+
 
 #endif /*GCRY_EC_CONTEXT_H*/
diff --git a/src/mpi.h b/src/mpi.h
index 3466951..279c485 100644
--- a/src/mpi.h
+++ b/src/mpi.h
@@ -333,8 +333,6 @@ int  _gcry_mpi_ec_curve_point (gcry_mpi_point_t point, mpi_ec_t ctx);
 
 gcry_mpi_t _gcry_mpi_ec_ec2os (gcry_mpi_point_t point, mpi_ec_t ectx);
 
-gpg_err_code_t _gcry_mpi_ec_new (gcry_ctx_t *r_ctx,
-                                 gcry_sexp_t keyparam, const char *curvename);
 gcry_mpi_t _gcry_mpi_ec_get_mpi (const char *name, gcry_ctx_t ctx, int copy);
 gcry_mpi_point_t _gcry_mpi_ec_get_point (const char *name,
                                          gcry_ctx_t ctx, int copy);

-----------------------------------------------------------------------

Summary of changes:
 cipher/ecc-common.h |   12 +++
 cipher/ecc-curves.c |  190 ++++++++++++++++++++++++++++++++++++++++++++++++++
 cipher/ecc-misc.c   |   21 ++++++
 cipher/ecc.c        |  121 ++++++++++++++++++++++----------
 doc/gcrypt.texi     |   14 +++-
 mpi/ec.c            |  130 +++-------------------------------
 mpi/mpiutil.c       |    7 ++-
 src/ec-context.h    |   17 +++++
 src/gcrypt.h.in     |    2 +-
 src/mpi.h           |    4 +-
 src/mpicalc.c       |   20 +++++-
 src/sexp.c          |    2 +
 tests/t-mpi-point.c |  192 +++++++++++++++++++++++++++++++++++++++++++++++---
 13 files changed, 551 insertions(+), 181 deletions(-)


hooks/post-receive
-- 
The GNU crypto library
http://git.gnupg.org


_______________________________________________
Gnupg-commits mailing list
Gnupg-commits at gnupg.org
http://lists.gnupg.org/mailman/listinfo/gnupg-commits




More information about the Gcrypt-devel mailing list