[git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-96-g229f321

by Werner Koch cvs at cvs.gnupg.org
Fri Mar 15 15:08:58 CET 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  229f3219f80c9369ed9624242c0436ae6d293201 (commit)
       via  e005629bd7bebb3e13945645c6e1230b44ab16a2 (commit)
       via  1fecae98ee7e0fa49b29f98efa6817ca121ed98a (commit)
      from  5e743bc72e3fee3d550d0d7ae98596b7de6b46f8 (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 229f3219f80c9369ed9624242c0436ae6d293201
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Mar 15 14:43:19 2013 +0100

    mpi: Add functions to manipulate an EC context.
    
    * src/gcrypt.h.in (gcry_mpi_ec_p_new): Remove.
    (gcry_mpi_ec_new): New.
    (gcry_mpi_ec_get_mpi): New.
    (gcry_mpi_ec_get_point): New.
    (gcry_mpi_ec_set_mpi): New.
    (gcry_mpi_ec_set_point): New.
    * src/visibility.c (gcry_mpi_ec_p_new): Remove.
    * mpi/ec.c (_gcry_mpi_ec_p_new): Make it an internal function and
    change to return an error code.
    (_gcry_mpi_ec_get_mpi): New.
    (_gcry_mpi_ec_get_point): New.
    (_gcry_mpi_ec_set_mpi): New.
    (_gcry_mpi_ec_set_point): New.
    * src/mpi.h: Add new prototypes.
    * src/ec-context.h: New.
    * mpi/ec.c: Include that header.
    (mpi_ec_ctx_s): Move to ec-context.h, add new fields, and put some
    fields into an inner struct.
    (point_copy): New.
    * cipher/ecc.c (fill_in_curve): Allow passing NULL for R_NBITS.
    (mpi_from_keyparam, point_from_keyparam): New.
    (_gcry_mpi_ec_new): New.
    
    * tests/t-mpi-point.c (test-curve): New.
    (ec_p_new): New.  Use it instead of the removed gcry_mpi_ec_p_new.
    (get_and_cmp_mpi, get_and_cmp_point): New.
    (context_param): New test.
    (basic_ec_math_simplified): New test.
    (main): Call new tests.
    
    * src/context.c (_gcry_ctx_get_pointer): Check for a NULL CTX.
    --
    
    gcry_mpi_ec_p_new() was a specialized version of the more general new
    gcry_mpi_ec_new().  It was added to master only a few days ago, thus
    there should be no problem to remove it.  A replacement can easily be
    written (cf. t-mpi-point.c).
    
    Note that gcry_mpi_ec_set_mpi and gcry_mpi_ec_set_point have not yet
    been tested.

diff --git a/NEWS b/NEWS
index c0a7e8e..429f666 100644
--- a/NEWS
+++ b/NEWS
@@ -46,7 +46,12 @@ Noteworthy changes in version 1.6.0 (unreleased)
  gcry_mpi_point_snatch_set       NEW.
  gcry_ctx_t                      NEW.
  gcry_ctx_release                NEW.
- gcry_mpi_ec_p_new               NEW.
+ gcry_mpi_ec_new                 NEW.
+ gcry_mpi_ec_get_mpi             NEW.
+ gcry_mpi_ec_get_point           NEW.
+ gcry_mpi_ec_set_mpi             NEW.
+ gcry_mpi_ec_set_point           NEW.
+ gcry_mpi_ec_get_affine          NEW.
  gcry_mpi_ec_dup                 NEW.
  gcry_mpi_ec_add                 NEW.
  gcry_mpi_ec_mul                 NEW.
diff --git a/cipher/ecc.c b/cipher/ecc.c
index 4efbef4..c95a57a 100644
--- a/cipher/ecc.c
+++ b/cipher/ecc.c
@@ -46,6 +46,12 @@
 
   - In mpi/ec.c we use mpi_powm for x^2 mod p: Either implement a
     special case in mpi_powm or check whether mpi_mulm is faster.
+
+  - Split this up into several files.  For example the curve
+    management and gcry_mpi_ec_new are independent of the actual ECDSA
+    implementation.  This will also help to support optimized versions
+    of some curves.
+
 */
 
 
@@ -53,10 +59,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 
 #include "g10lib.h"
 #include "mpi.h"
 #include "cipher.h"
+#include "context.h"
+#include "ec-context.h"
 
 /* Definition of a curve.  */
 typedef struct
@@ -440,8 +449,8 @@ gen_k (gcry_mpi_t p, int security_level)
 
 /* Generate the crypto system setup.  This function takes the NAME of
    a curve or the desired number of bits and stores at R_CURVE the
-   parameters of the named curve or those of a suitable curve.  The
-   chosen number of bits is stored on R_NBITS.  */
+   parameters of the named curve or those of a suitable curve.  If
+   R_NBITS is not NULL, the chosen number of bits is stored there.  */
 static gpg_err_code_t
 fill_in_curve (unsigned int nbits, const char *name,
                elliptic_curve_t *curve, unsigned int *r_nbits)
@@ -491,7 +500,8 @@ fill_in_curve (unsigned int nbits, const char *name,
   if (fips_mode () && !domain_parms[idx].fips )
     return GPG_ERR_NOT_SUPPORTED;
 
-  *r_nbits = domain_parms[idx].nbits;
+  if (r_nbits)
+    *r_nbits = domain_parms[idx].nbits;
   curve->p = scanval (domain_parms[idx].p);
   curve->a = scanval (domain_parms[idx].a);
   curve->b = scanval (domain_parms[idx].b);
@@ -1689,6 +1699,277 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam)
 }
 
 
+

+/*
+   Low-level API helper functions.
+ */
+
+/* Helper to extract an MPI from key parameters.  */
+static gpg_err_code_t
+mpi_from_keyparam (gcry_mpi_t *r_a, gcry_sexp_t keyparam, const char *name)
+{
+  gcry_err_code_t ec = 0;
+  gcry_sexp_t l1;
+
+  l1 = gcry_sexp_find_token (keyparam, name, 0);
+  if (l1)
+    {
+      *r_a = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+      gcry_sexp_release (l1);
+      if (!*r_a)
+        ec = GPG_ERR_INV_OBJ;
+    }
+  return ec;
+}
+
+/* Helper to extract a point from key parameters.  If no parameter
+   with NAME is found, the functions tries to find a non-encoded point
+   by appending ".x", ".y" and ".z" to NAME.  ".z" is in this case
+   optional and defaults to 1.  */
+static gpg_err_code_t
+point_from_keyparam (gcry_mpi_point_t *r_a,
+                     gcry_sexp_t keyparam, const char *name)
+{
+  gcry_err_code_t ec;
+  gcry_mpi_t a = NULL;
+  gcry_mpi_point_t point;
+
+  ec = mpi_from_keyparam (&a, keyparam, name);
+  if (ec)
+    return ec;
+
+  if (a)
+    {
+      point = gcry_mpi_point_new (0);
+      ec = os2ec (point, a);
+      if (ec)
+        {
+          gcry_mpi_point_release (point);
+          mpi_free (a);
+          return ec;
+        }
+    }
+  else
+    {
+      char *tmpname;
+      gcry_mpi_t x = NULL;
+      gcry_mpi_t y = NULL;
+      gcry_mpi_t z = NULL;
+
+      tmpname = gcry_malloc (strlen (name) + 2 + 1);
+      if (!tmpname)
+        return gpg_err_code_from_syserror ();
+      strcpy (stpcpy (tmpname, name), ".x");
+      ec = mpi_from_keyparam (&x, keyparam, tmpname);
+      if (ec)
+        {
+          gcry_free (tmpname);
+          return ec;
+        }
+      strcpy (stpcpy (tmpname, name), ".y");
+      ec = mpi_from_keyparam (&y, keyparam, tmpname);
+      if (ec)
+        {
+          mpi_free (x);
+          gcry_free (tmpname);
+          return ec;
+        }
+      strcpy (stpcpy (tmpname, name), ".z");
+      ec = mpi_from_keyparam (&z, keyparam, tmpname);
+      if (ec)
+        {
+          mpi_free (y);
+          mpi_free (x);
+          gcry_free (tmpname);
+          return ec;
+        }
+      if (!z)
+        z = mpi_set_ui (NULL, 1);
+      if (x && y)
+        point = gcry_mpi_point_snatch_set (NULL, x, y, z);
+      else
+        {
+          mpi_free (x);
+          mpi_free (y);
+          mpi_free (z);
+          point = NULL;
+        }
+      gcry_free (tmpname);
+    }
+
+  if (point)
+    *r_a = point;
+  return 0;
+}
+
+
+/* This function creates a new context for elliptic curve operations.
+   Either KEYPARAM or CURVENAME must be given.  If both are given and
+   KEYPARAM has no curve parameter CURVENAME is used to add missing
+   parameters.  On success 0 is returned and the new context stored at
+   R_CTX.  On error NULL is stored at R_CTX and an error code is
+   returned.  The context needs to be released using
+   gcry_ctx_release.  */
+gpg_err_code_t
+_gcry_mpi_ec_new (gcry_ctx_t *r_ctx,
+                  gcry_sexp_t keyparam, const char *curvename)
+{
+  gpg_err_code_t errc;
+  gcry_ctx_t ctx = NULL;
+  gcry_mpi_t p = NULL;
+  gcry_mpi_t a = NULL;
+  gcry_mpi_t b = NULL;
+  gcry_mpi_point_t G = NULL;
+  gcry_mpi_t n = NULL;
+  gcry_mpi_point_t Q = NULL;
+  gcry_mpi_t d = NULL;
+  gcry_sexp_t l1;
+
+  *r_ctx = NULL;
+
+  if (keyparam)
+    {
+      errc = mpi_from_keyparam (&p, keyparam, "p");
+      if (errc)
+        goto leave;
+      errc = mpi_from_keyparam (&a, keyparam, "a");
+      if (errc)
+        goto leave;
+      errc = mpi_from_keyparam (&b, keyparam, "b");
+      if (errc)
+        goto leave;
+      errc = point_from_keyparam (&G, keyparam, "G");
+      if (errc)
+        goto leave;
+      errc = mpi_from_keyparam (&n, keyparam, "n");
+      if (errc)
+        goto leave;
+      errc = point_from_keyparam (&Q, keyparam, "Q");
+      if (errc)
+        goto leave;
+      errc = mpi_from_keyparam (&d, keyparam, "d");
+      if (errc)
+        goto leave;
+    }
+
+
+  /* Check whether a curve parameter is available and use that to fill
+     in missing values.  If no curve parameter is available try an
+     optional provided curvename.  If only the curvename has been
+     given use that one. */
+  if (keyparam)
+    l1 = gcry_sexp_find_token (keyparam, "curve", 5);
+  else
+    l1 = NULL;
+  if (l1 || curvename)
+    {
+      char *name;
+      elliptic_curve_t *E;
+
+      if (l1)
+        {
+          name = _gcry_sexp_nth_string (l1, 1);
+          gcry_sexp_release (l1);
+          if (!name)
+            {
+              errc = GPG_ERR_INV_OBJ; /* Name missing or out of core. */
+              goto leave;
+            }
+        }
+      else
+        name = NULL;
+
+      E = gcry_calloc (1, sizeof *E);
+      if (!E)
+        {
+          errc = gpg_err_code_from_syserror ();
+          gcry_free (name);
+          goto leave;
+        }
+
+      errc = fill_in_curve (0, name? name : curvename, E, NULL);
+      gcry_free (name);
+      if (errc)
+        {
+          gcry_free (E);
+          goto leave;
+        }
+
+      if (!p)
+        {
+          p = E->p;
+          E->p = NULL;
+        }
+      if (!a)
+        {
+          a = E->a;
+          E->a = NULL;
+        }
+      if (!b)
+        {
+          b = E->b;
+          E->b = NULL;
+        }
+      if (!G)
+        {
+          G = gcry_mpi_point_snatch_set (NULL, E->G.x, E->G.y, E->G.z);
+          E->G.x = NULL;
+          E->G.y = NULL;
+          E->G.z = NULL;
+        }
+      if (!n)
+        {
+          n = E->n;
+          E->n = NULL;
+        }
+      curve_free (E);
+      gcry_free (E);
+    }
+
+  errc = _gcry_mpi_ec_p_new (&ctx, p, a);
+  if (!errc)
+    {
+      mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
+
+      if (b)
+        {
+          ec->b = b;
+          b = NULL;
+        }
+      if (G)
+        {
+          ec->G = G;
+          G = NULL;
+        }
+      if (n)
+        {
+          ec->n = n;
+          n = NULL;
+        }
+      if (Q)
+        {
+          ec->Q = Q;
+          Q = NULL;
+        }
+      if (d)
+        {
+          ec->d = d;
+          d = NULL;
+        }
+
+      *r_ctx = ctx;
+    }
+
+ leave:
+  mpi_free (p);
+  mpi_free (a);
+  mpi_free (b);
+  gcry_mpi_point_release (G);
+  mpi_free (n);
+  gcry_mpi_point_release (Q);
+  mpi_free (d);
+  return errc;
+}
 
 
 

diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index a56d527..4d48eb4 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -2058,6 +2058,7 @@ and no @var{x-mpi}.
 @node ECC key parameters
 @subsection ECC key parameters
 
+ at anchor{ecc_keyparam}
 @noindent
 An ECC private key is described by this S-expression:
 
@@ -2084,7 +2085,7 @@ Base point @math{g}.
 @item n-mpi
 Order of @math{g}
 @item q-point
-The point representing the public key @math{Q = dP}.
+The point representing the public key @math{Q = dG}.
 @item d-mpi
 The private key @math{d}
 @end table
@@ -3919,16 +3920,71 @@ some extra memory allocations and copies.  Returns @var{point} or the
 newly allocated point object.
 @end deftypefun
 
- at anchor{gcry_mpi_ec_p_new}
- at deftypefun gcry_ctx_t gcry_mpi_ec_p_new (@w{gcry_mpi_t @var{p}}, @
- @w{gcry_mpi_t @var{a}}
+ at anchor{gcry_mpi_ec_new}
+ at deftypefun gpg_error_t gcry_mpi_ec_p_new (@w{gpg_ctx_t *@var{r_ctx}}, @
+ @w{gcry_sexp_t @var{keyparam}}, @w{const char *@var{curvename}})
 
-Allocate a new context for elliptic curve operations based on the
-field GF(p).  @var{p} is the prime specifying this field, @var{a} is
-the first coefficient of the Weierstrass equation.  The function
-returns a context object which eventually needs to be released using
- at ref{gcry_ctx_release}.  On error this function returns @code{NULL}
-and sets @code{errno}.
+Allocate a new context for elliptic curve operations.  If
+ at var{keyparam} is given it specifies the parameters of the curve
+(@pxref{ecc_keyparam}).  If @var{curvename} is given in addition to
+ at var{keyparam} and the key parameters do not include a named curve
+reference, the string @var{curvename} is used to fill in missing
+parameters.  If only @var{curvename} is given, the context is
+initialized for this named curve.
+
+If a parameter specifying a point (e.g. @code{g} or @code{q}) is not
+found, the parser looks for a non-encoded point by appending
+ at code{.x}, @code{.y}, and @code{.z} to the parameter name and looking
+them all up to create a point.  A parameter with the suffix @code{.z}
+is optional and defaults to 1.
+
+On success the function returns 0 and stores the new context object at
+ at var{r_ctx}; this object eventually needs to be released
+(@pxref{gcry_ctx_release}).  On error the function stores @code{NULL} at
+ at var{r_ctx} and returns an error code.
+ at end deftypefun
+
+ at deftypefun gcry_mpi_t gcry_mpi_ec_get_mpi ( @
+ @w{const char *@var{name}}, @w{gcry_ctx_t @var{ctx}}, @w{int @var{copy}})
+
+Return the MPI with @var{name} from the context @var{ctx}.  If not
+found @code{NULL} is returned.  If the returned MPI may later be
+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
+ at 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}.
+ at end deftypefun
+
+ at deftypefun gcry_mpi_point_t gcry_mpi_ec_get_point ( @
+ @w{const char *@var{name}}, @w{gcry_ctx_t @var{ctx}}, @w{int @var{copy}})
+
+Return the point with @var{name} from the context @var{ctx}.  If not
+found @code{NULL} is returned.  If the returned MPI may later be
+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
+ at code{0} is used for @var{copy}, this function may return a constant
+flagged point.  In any case @code{gcry_mpi_point_release} needs to be
+called to release the result.
+ at end deftypefun
+
+ at deftypefun gpg_error_t gcry_mpi_ec_set_mpi ( @
+ @w{const char *@var{name}}, @w{gcry_mpi_t @var{newvalue}}, @
+ @w{gcry_ctx_t @var{ctx}})
+
+Store the MPI @var{newvalue} at @var{name} into the context @var{ctx}.
+On success @code{0} is returned; on error an error code.  Valid names
+are the MPI parameters of an elliptic curve (@pxref{ecc_keyparam}).
+ at end deftypefun
+
+ at deftypefun gpg_error_t gcry_mpi_ec_set_point ( @
+ @w{const char *@var{name}}, @w{gcry_mpi_point_t @var{newvalue}}, @
+ @w{gcry_ctx_t @var{ctx}})
+
+Store the point @var{newvalue} at @var{name} into the context
+ at var{ctx}.  On success @code{0} is returned; on error an error code.
+Valid names are the point parameters of an elliptic curve
+(@pxref{ecc_keyparam}).
 @end deftypefun
 
 @deftypefun int gcry_mpi_ec_get_affine ( @
@@ -3938,9 +3994,9 @@ and sets @code{errno}.
 Compute the affine coordinates from the projective coordinates in
 @var{point} and store them into @var{x} and @var{y}.  If one
 coordinate is not required, @code{NULL} may be passed to @var{x} or
- at var{y}.  @var{ctx} is the context object which for example may have
-been created using @ref{gcry_mpi_ec_p_new}. Returns 0 on success or
-not 0 if @var{point} is at infinity.
+ at var{y}.  @var{ctx} is the context object which has been created using
+ at code{gcry_mpi_ec_new}. Returns 0 on success or not 0 if @var{point}
+is at infinity.
 @end deftypefun
 
 @deftypefun void gcry_mpi_ec_dup ( @
diff --git a/mpi/ec.c b/mpi/ec.c
index 7f310ea..9a6868b 100644
--- a/mpi/ec.c
+++ b/mpi/ec.c
@@ -27,37 +27,13 @@
 #include "longlong.h"
 #include "g10lib.h"
 #include "context.h"
+#include "ec-context.h"
 
 
 #define point_init(a)  _gcry_mpi_point_init ((a))
 #define point_free(a)  _gcry_mpi_point_free_parts ((a))
 
 
-/* Object to represent a point in projective coordinates. */
-/* Currently defined in mpi.h */
-
-/* This context is used with all our EC functions. */
-struct mpi_ec_ctx_s
-{
-  /* Domain parameters.  */
-  gcry_mpi_t p;   /* Prime specifying the field GF(p).  */
-  gcry_mpi_t a;   /* First coefficient of the Weierstrass equation.  */
-
-  int a_is_pminus3;  /* True if A = P - 3. */
-
-  gcry_mpi_t two_inv_p;
-
-  /* Scratch variables.  */
-  gcry_mpi_t scratch[11];
-
-  /* Helper for fast reduction.  */
-/*   int nist_nbits; /\* If this is a NIST curve, the number of bits.  *\/ */
-/*   gcry_mpi_t s[10]; */
-/*   gcry_mpi_t c; */
-
-};
-
-
 /* Create a new point option.  NBITS gives the size in bits of one
    coordinate; it is only used to pre-allocate some resources and
    might also be passed as 0 to use a default value.  */
@@ -116,6 +92,24 @@ point_set (mpi_point_t d, mpi_point_t s)
   mpi_set (d->z, s->z);
 }
 
+
+/* 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
@@ -353,27 +347,22 @@ ec_p_init (mpi_ec_t ctx, gcry_mpi_t p, gcry_mpi_t a)
   int i;
   gcry_mpi_t tmp;
 
-  mpi_normalize (p);
-  mpi_normalize (a);
-
-  /* Fixme: Do we want to check some constraints? e.g.
-     a < p
-  */
+  /* Fixme: Do we want to check some constraints? e.g.  a < p  */
 
   ctx->p = mpi_copy (p);
   ctx->a = mpi_copy (a);
 
   tmp = mpi_alloc_like (ctx->p);
   mpi_sub_ui (tmp, ctx->p, 3);
-  ctx->a_is_pminus3 = !mpi_cmp (ctx->a, tmp);
+  ctx->t.a_is_pminus3 = !mpi_cmp (ctx->a, tmp);
   mpi_free (tmp);
 
-  ctx->two_inv_p = mpi_alloc (0);
-  ec_invm (ctx->two_inv_p, mpi_const (MPI_C_TWO), ctx);
+  ctx->t.two_inv_p = mpi_alloc (0);
+  ec_invm (ctx->t.two_inv_p, mpi_const (MPI_C_TWO), ctx);
 
   /* Allocate scratch variables.  */
-  for (i=0; i< DIM(ctx->scratch); i++)
-    ctx->scratch[i] = mpi_alloc_like (ctx->p);
+  for (i=0; i< DIM(ctx->t.scratch); i++)
+    ctx->t.scratch[i] = mpi_alloc_like (ctx->p);
 
   /* Prepare for fast reduction.  */
   /* FIXME: need a test for NIST values.  However it does not gain us
@@ -401,13 +390,22 @@ ec_deinit (void *opaque)
   mpi_ec_t ctx = opaque;
   int i;
 
+  /* Domain parameter.  */
   mpi_free (ctx->p);
   mpi_free (ctx->a);
+  mpi_free (ctx->b);
+  gcry_mpi_point_release (ctx->G);
+  mpi_free (ctx->n);
+
+  /* The key.  */
+  gcry_mpi_point_release (ctx->Q);
+  mpi_free (ctx->d);
 
-  mpi_free (ctx->two_inv_p);
+  /* Private data of ec.c.  */
+  mpi_free (ctx->t.two_inv_p);
 
-  for (i=0; i< DIM(ctx->scratch); i++)
-    mpi_free (ctx->scratch[i]);
+  for (i=0; i< DIM(ctx->t.scratch); i++)
+    mpi_free (ctx->t.scratch[i]);
 
 /*   if (ctx->nist_nbits == 192) */
 /*     { */
@@ -455,28 +453,128 @@ _gcry_mpi_ec_free (mpi_ec_t ctx)
 
 /* This function returns a new context for elliptic curve operations
    based on the field GF(p).  P is the prime specifying this field, A
-   is the first coefficient.  This function is part of the public API.
-   On error this function returns NULL and sets ERRNO.
-   The context needs to be released using gcry_ctx_release.  */
-gcry_ctx_t
-gcry_mpi_ec_p_new (gcry_mpi_t p, gcry_mpi_t a)
+   is the first coefficient.  On success the new context is stored at
+   R_CTX and 0 is returned; on error NULL is stored at R_CTX and an
+   error code is returned.  The context needs to be released using
+   gcry_ctx_release.  This is an internal fucntions.  */
+gpg_err_code_t
+_gcry_mpi_ec_p_new (gcry_ctx_t *r_ctx, gcry_mpi_t p, gcry_mpi_t a)
 {
   gcry_ctx_t ctx;
   mpi_ec_t ec;
 
+  *r_ctx = NULL;
   if (!p || !a || !mpi_cmp_ui (a, 0))
-    {
-      gpg_err_set_errno (EINVAL);
-      return NULL;
-    }
+    return GPG_ERR_EINVAL;
 
   ctx = _gcry_ctx_alloc (CONTEXT_TYPE_EC, sizeof *ec, ec_deinit);
   if (!ctx)
-    return NULL;
+    return gpg_err_code_from_syserror ();
   ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
   ec_p_init (ec, p, a);
 
-  return ctx;
+  *r_ctx = ctx;
+  return 0;
+}
+
+gcry_mpi_t
+_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);
+  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);
+
+  return NULL;
+}
+
+
+gcry_mpi_point_t
+_gcry_mpi_ec_get_point (const char *name, gcry_ctx_t ctx, int copy)
+{
+  mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
+
+  (void)copy;  /* Not used.  */
+
+  if (!strcmp (name, "g") && ec->G)
+    return point_copy (ec->G);
+  if (!strcmp (name, "q") && ec->Q)
+    return point_copy (ec->Q);
+
+  return NULL;
+}
+
+
+gpg_err_code_t
+_gcry_mpi_ec_set_mpi (const char *name, gcry_mpi_t newvalue,
+                      gcry_ctx_t ctx)
+{
+  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);
+    }
+  else if (!strcmp (name, "a"))
+    {
+      mpi_free (ec->a);
+      ec->a = mpi_copy (newvalue);
+    }
+  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;
+}
+
+
+gpg_err_code_t
+_gcry_mpi_ec_set_point (const char *name, gcry_mpi_point_t newvalue,
+                        gcry_ctx_t ctx)
+{
+  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;
 }
 
 
@@ -523,12 +621,12 @@ _gcry_mpi_ec_dup_point (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx)
 #define x3 (result->x)
 #define y3 (result->y)
 #define z3 (result->z)
-#define t1 (ctx->scratch[0])
-#define t2 (ctx->scratch[1])
-#define t3 (ctx->scratch[2])
-#define l1 (ctx->scratch[3])
-#define l2 (ctx->scratch[4])
-#define l3 (ctx->scratch[5])
+#define t1 (ctx->t.scratch[0])
+#define t2 (ctx->t.scratch[1])
+#define t3 (ctx->t.scratch[2])
+#define l1 (ctx->t.scratch[3])
+#define l2 (ctx->t.scratch[4])
+#define l3 (ctx->t.scratch[5])
 
   if (!mpi_cmp_ui (point->y, 0) || !mpi_cmp_ui (point->z, 0))
     {
@@ -539,7 +637,7 @@ _gcry_mpi_ec_dup_point (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx)
     }
   else
     {
-      if (ctx->a_is_pminus3)  /* Use the faster case.  */
+      if (ctx->t.a_is_pminus3)  /* Use the faster case.  */
         {
           /* L1 = 3(X - Z^2)(X + Z^2) */
           /*                          T1: used for Z^2. */
@@ -615,17 +713,17 @@ _gcry_mpi_ec_add_points (mpi_point_t result,
 #define x3 (result->x)
 #define y3 (result->y)
 #define z3 (result->z)
-#define l1 (ctx->scratch[0])
-#define l2 (ctx->scratch[1])
-#define l3 (ctx->scratch[2])
-#define l4 (ctx->scratch[3])
-#define l5 (ctx->scratch[4])
-#define l6 (ctx->scratch[5])
-#define l7 (ctx->scratch[6])
-#define l8 (ctx->scratch[7])
-#define l9 (ctx->scratch[8])
-#define t1 (ctx->scratch[9])
-#define t2 (ctx->scratch[10])
+#define l1 (ctx->t.scratch[0])
+#define l2 (ctx->t.scratch[1])
+#define l3 (ctx->t.scratch[2])
+#define l4 (ctx->t.scratch[3])
+#define l5 (ctx->t.scratch[4])
+#define l6 (ctx->t.scratch[5])
+#define l7 (ctx->t.scratch[6])
+#define l8 (ctx->t.scratch[7])
+#define l9 (ctx->t.scratch[8])
+#define t1 (ctx->t.scratch[9])
+#define t2 (ctx->t.scratch[10])
 
   if ( (!mpi_cmp (x1, x2)) && (!mpi_cmp (y1, y2)) && (!mpi_cmp (z1, z2)) )
     {
@@ -715,7 +813,7 @@ _gcry_mpi_ec_add_points (mpi_point_t result,
           ec_powm (t1, l3, mpi_const (MPI_C_THREE), ctx); /* fixme: Use saved value*/
           ec_mulm (t1, t1, l8, ctx);
           ec_subm (y3, l9, t1, ctx);
-          ec_mulm (y3, y3, ctx->two_inv_p, ctx);
+          ec_mulm (y3, y3, ctx->t.two_inv_p, ctx);
         }
     }
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 1869ad3..713e616 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -60,6 +60,7 @@ libgcrypt_la_SOURCES = g10lib.h visibility.c visibility.h types.h \
 	stdmem.c stdmem.h secmem.c secmem.h \
 	mpi.h missing-string.c module.c fips.c \
 	hmac256.c hmac256.h context.c context.h \
+	ec-context.h \
 	ath.h ath.c
 
 EXTRA_libgcrypt_la_SOURCES = hwf-x86.c
diff --git a/src/context.c b/src/context.c
index ae991c5..2c02c9c 100644
--- a/src/context.c
+++ b/src/context.c
@@ -86,7 +86,7 @@ _gcry_ctx_alloc (int type, size_t length, void (*deinit)(void*))
 void *
 _gcry_ctx_get_pointer (gcry_ctx_t ctx, int type)
 {
-  if (memcmp (ctx->magic, CTX_MAGIC, CTX_MAGIC_LEN))
+  if (!ctx || memcmp (ctx->magic, CTX_MAGIC, CTX_MAGIC_LEN))
     log_fatal ("bad pointer %p passed to _gcry_ctx_get_pointer\n", ctx);
   if (ctx->type != type)
     log_fatal ("wrong context type %d request for context %p of type %d\n",
diff --git a/src/ec-context.h b/src/ec-context.h
new file mode 100644
index 0000000..88742bf
--- /dev/null
+++ b/src/ec-context.h
@@ -0,0 +1,57 @@
+/* ec-context.h - Private definitions for CONTEXT_TYPE_EC.
+ * Copyright (C) 2013  g10 Code GmbH
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser general Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GCRY_EC_CONTEXT_H
+#define GCRY_EC_CONTEXT_H
+
+/* This context is used with all our EC functions. */
+struct mpi_ec_ctx_s
+{
+  /* 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).  */
+  gcry_mpi_t a;         /* First coefficient of the Weierstrass equation.  */
+  gcry_mpi_t b;         /* Second coefficient of the Weierstrass equation.  */
+  gcry_mpi_point_t G;   /* Base point (generator).  */
+  gcry_mpi_t n;         /* Order of G.  */
+
+  /* The actual key.  May not be set.  */
+  gcry_mpi_point_t Q;   /* Public key.   */
+  gcry_mpi_t d;         /* Private key.  */
+
+
+  /* This structure is private to mpi/ec.c! */
+  struct {
+    int a_is_pminus3;  /* True if A = P - 3. */
+
+    gcry_mpi_t two_inv_p;
+
+    /* Scratch variables.  */
+    gcry_mpi_t scratch[11];
+
+    /* Helper for fast reduction.  */
+    /*   int nist_nbits; /\* If this is a NIST curve, the # of bits.  *\/ */
+    /*   gcry_mpi_t s[10]; */
+    /*   gcry_mpi_t c; */
+  } t;
+};
+
+
+
+#endif /*GCRY_EC_CONTEXT_H*/
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index eb9a11d..ad4da04 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -606,9 +606,24 @@ gcry_mpi_point_t gcry_mpi_point_snatch_set (gcry_mpi_point_t point,
                                             gcry_mpi_t z);
 
 /* Allocate a new context for elliptic curve operations based on the
-   field GF(p).  P is the prime specifying this field, A is the first
-   coefficient.  Returns NULL on error.  */
-gcry_ctx_t gcry_mpi_ec_p_new (gcry_mpi_t p, gcry_mpi_t a);
+   parameters given by KEYPARAM or using CURVENAME.  */
+gpg_error_t gcry_mpi_ec_new (gcry_ctx_t *r_ctx,
+                             gcry_sexp_t keyparam, const char *curvename);
+
+/* Get a named MPI from an elliptic curve context.  */
+gcry_mpi_t gcry_mpi_ec_get_mpi (const char *name, gcry_ctx_t ctx, int copy);
+
+/* Get a named point from an elliptic curve context.  */
+gcry_mpi_point_t gcry_mpi_ec_get_point (const char *name,
+                                        gcry_ctx_t ctx, int copy);
+
+/* Store a named MPI into an elliptic curve context.  */
+gpg_error_t gcry_mpi_ec_set_mpi (const char *name, gcry_mpi_t newvalue,
+                                 gcry_ctx_t ctx);
+
+/* Store a named point into an elliptic curve context.  */
+gpg_error_t gcry_mpi_ec_set_point (const char *name, gcry_mpi_point_t newvalue,
+                                   gcry_ctx_t ctx);
 
 /* Store the affine coordinates of POINT into X and Y.  */
 int gcry_mpi_ec_get_affine (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_point_t point,
diff --git a/src/libgcrypt.def b/src/libgcrypt.def
index 611f10f..061c7e3 100644
--- a/src/libgcrypt.def
+++ b/src/libgcrypt.def
@@ -223,8 +223,12 @@ EXPORTS
 
       gcry_ctx_release          @202
 
-      gcry_mpi_ec_p_new         @203
-      gcry_mpi_ec_get_affine    @204
-      gcry_mpi_ec_dup           @205
-      gcry_mpi_ec_add           @206
-      gcry_mpi_ec_mul           @207
+      gcry_mpi_ec_new           @203
+      gcry_mpi_ec_get_mpi       @204
+      gcry_mpi_ec_get_point     @205
+      gcry_mpi_ec_set_mpi       @206
+      gcry_mpi_ec_set_point     @207
+      gcry_mpi_ec_get_affine    @208
+      gcry_mpi_ec_dup           @209
+      gcry_mpi_ec_add           @210
+      gcry_mpi_ec_mul           @211
diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers
index 4a375b2..65959d3 100644
--- a/src/libgcrypt.vers
+++ b/src/libgcrypt.vers
@@ -90,7 +90,9 @@ GCRYPT_1.6 {
     gcry_mpi_point_new; gcry_mpi_point_release;
     gcry_mpi_point_get; gcry_mpi_point_snatch_get;
     gcry_mpi_point_set; gcry_mpi_point_snatch_set;
-    gcry_mpi_ec_p_new;
+    gcry_mpi_ec_new;
+    gcry_mpi_ec_get_mpi; gcry_mpi_ec_get_point;
+    gcry_mpi_ec_set_mpi; gcry_mpi_ec_set_point;
     gcry_mpi_ec_get_affine;
     gcry_mpi_ec_dup; gcry_mpi_ec_add; gcry_mpi_ec_mul;
 
diff --git a/src/mpi.h b/src/mpi.h
index 9c22141..b727d5f 100644
--- a/src/mpi.h
+++ b/src/mpi.h
@@ -289,6 +289,19 @@ void _gcry_mpi_ec_mul_point (mpi_point_t result,
                              gcry_mpi_t scalar, mpi_point_t point,
                              mpi_ec_t ctx);
 
+gpg_err_code_t _gcry_mpi_ec_p_new (gcry_ctx_t *r_ctx,
+                                   gcry_mpi_t p, gcry_mpi_t a);
+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);
+gpg_err_code_t _gcry_mpi_ec_set_mpi (const char *name, gcry_mpi_t newvalue,
+                                     gcry_ctx_t ctx);
+gpg_err_code_t _gcry_mpi_ec_set_point (const char *name,
+                                       gcry_mpi_point_t newvalue,
+                                       gcry_ctx_t ctx);
+
 
 
 #endif /*G10_MPI_H*/
diff --git a/src/visibility.c b/src/visibility.c
index 5c3216d..ed68b86 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -461,10 +461,36 @@ gcry_mpi_point_snatch_set (gcry_mpi_point_t point,
   return _gcry_mpi_point_snatch_set (point, x, y, z);
 }
 
-gcry_ctx_t
-gcry_mpi_ec_p_new (gcry_mpi_t p, gcry_mpi_t a)
+gpg_error_t
+gcry_mpi_ec_new (gcry_ctx_t *r_ctx,
+                 gcry_sexp_t keyparam, const char *curvename)
+{
+  return gpg_error (_gcry_mpi_ec_new (r_ctx, keyparam, curvename));
+}
+
+gcry_mpi_t
+gcry_mpi_ec_get_mpi (const char *name, gcry_ctx_t ctx, int copy)
+{
+  return _gcry_mpi_ec_get_mpi (name, ctx, copy);
+}
+
+gcry_mpi_point_t
+gcry_mpi_ec_get_point (const char *name, gcry_ctx_t ctx, int copy)
+{
+  return _gcry_mpi_ec_get_point (name, ctx, copy);
+}
+
+gpg_error_t
+gcry_mpi_ec_set_mpi (const char *name, gcry_mpi_t newvalue, gcry_ctx_t ctx)
+{
+  return gpg_error (_gcry_mpi_ec_set_mpi (name, newvalue, ctx));
+}
+
+gpg_error_t
+gcry_mpi_ec_set_point (const char *name, gcry_mpi_point_t newvalue,
+                        gcry_ctx_t ctx)
 {
-  return _gcry_mpi_ec_p_new (p, a);
+  return gpg_error (_gcry_mpi_ec_set_point (name, newvalue, ctx));
 }
 
 int
diff --git a/src/visibility.h b/src/visibility.h
index 90c6ad1..031537a 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -154,7 +154,6 @@
 #define gcry_mpi_copy               _gcry_mpi_copy
 #define gcry_mpi_div                _gcry_mpi_div
 #define gcry_mpi_dump               _gcry_mpi_dump
-#define gcry_mpi_ec_p_new           _gcry_mpi_ec_p_new
 #define gcry_mpi_gcd                _gcry_mpi_gcd
 #define gcry_mpi_get_flag           _gcry_mpi_get_flag
 #define gcry_mpi_get_nbits          _gcry_mpi_get_nbits
@@ -370,7 +369,6 @@ gcry_err_code_t gcry_md_get (gcry_md_hd_t hd, int algo,
 #undef gcry_mpi_copy
 #undef gcry_mpi_div
 #undef gcry_mpi_dump
-#undef gcry_mpi_ec_p_new
 #undef gcry_mpi_gcd
 #undef gcry_mpi_get_flag
 #undef gcry_mpi_get_nbits
@@ -550,7 +548,11 @@ MARK_VISIBLEX(gcry_mpi_ec_add)
 MARK_VISIBLEX(gcry_mpi_ec_dup)
 MARK_VISIBLEX(gcry_mpi_ec_get_affine)
 MARK_VISIBLEX(gcry_mpi_ec_mul)
-MARK_VISIBLE (gcry_mpi_ec_p_new)
+MARK_VISIBLEX(gcry_mpi_ec_new)
+MARK_VISIBLEX(gcry_mpi_ec_get_mpi)
+MARK_VISIBLEX(gcry_mpi_ec_get_point)
+MARK_VISIBLEX(gcry_mpi_ec_set_mpi)
+MARK_VISIBLEX(gcry_mpi_ec_set_point)
 MARK_VISIBLE (gcry_mpi_gcd)
 MARK_VISIBLE (gcry_mpi_get_flag)
 MARK_VISIBLE (gcry_mpi_get_nbits)
diff --git a/tests/t-mpi-point.c b/tests/t-mpi-point.c
index 8714d38..31df12b 100644
--- a/tests/t-mpi-point.c
+++ b/tests/t-mpi-point.c
@@ -41,6 +41,84 @@ static int error_count;
 #define xfree(a)      gcry_free ((a))
 #define pass() do { ; } while (0)
 
+
+static struct
+{
+  const char *desc;           /* Description of the curve.  */
+  const char *p;              /* Order of the prime field.  */
+  const char *a, *b;          /* The coefficients. */
+  const char *n;              /* The order of the base point.  */
+  const char *g_x, *g_y;      /* Base point.  */
+} test_curve[] =
+  {
+    {
+      "NIST P-192",
+      "0xfffffffffffffffffffffffffffffffeffffffffffffffff",
+      "0xfffffffffffffffffffffffffffffffefffffffffffffffc",
+      "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
+      "0xffffffffffffffffffffffff99def836146bc9b1b4d22831",
+
+      "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
+      "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"
+    },
+    {
+      "NIST P-224",
+      "0xffffffffffffffffffffffffffffffff000000000000000000000001",
+      "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe",
+      "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
+      "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" ,
+
+      "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
+      "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"
+    },
+    {
+      "NIST P-256",
+      "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
+      "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc",
+      "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
+      "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
+
+      "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
+      "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
+    },
+    {
+      "NIST P-384",
+      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
+      "ffffffff0000000000000000ffffffff",
+      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
+      "ffffffff0000000000000000fffffffc",
+      "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a"
+      "c656398d8a2ed19d2a85c8edd3ec2aef",
+      "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf"
+      "581a0db248b0a77aecec196accc52973",
+
+      "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38"
+      "5502f25dbf55296c3a545e3872760ab7",
+      "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0"
+      "0a60b1ce1d7e819d7a431d7c90ea0e5f"
+    },
+    {
+      "NIST P-521",
+      "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+      "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+      "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+      "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc",
+      "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10"
+      "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
+      "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+      "ffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409",
+
+      "0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3d"
+      "baa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
+      "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e6"
+      "62c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"
+    },
+    { NULL, NULL, NULL, NULL, NULL }
+  };
+
+
+
+
 static void
 show (const char *format, ...)
 {
@@ -131,6 +209,30 @@ cmp_mpihex (gcry_mpi_t a, const char *b)
 }
 
 
+/* Wrapper to emulate the libgcrypt internal EC context allocation
+   function.  */
+static gpg_error_t
+ec_p_new (gcry_ctx_t *r_ctx, gcry_mpi_t p, gcry_mpi_t a)
+{
+  gpg_error_t err;
+  gcry_sexp_t sexp;
+
+  if (p && a)
+    err = gcry_sexp_build (&sexp, NULL, "(ecdsa (p %m)(a %m))", p, a);
+  else if (p)
+    err = gcry_sexp_build (&sexp, NULL, "(ecdsa (p %m))", p);
+  else if (a)
+    err = gcry_sexp_build (&sexp, NULL, "(ecdsa (a %m))", a);
+  else
+    err = gcry_sexp_build (&sexp, NULL, "(ecdsa)");
+  if (err)
+    return err;
+  err = gcry_mpi_ec_new (r_ctx, sexp, NULL);
+  gcry_sexp_release (sexp);
+  return err;
+}
+
+
 

 static void
 set_get_point (void)
@@ -189,6 +291,7 @@ set_get_point (void)
 static void
 context_alloc (void)
 {
+  gpg_error_t err;
   gcry_ctx_t ctx;
   gcry_mpi_t p, a;
 
@@ -197,40 +300,153 @@ context_alloc (void)
 
   p = gcry_mpi_set_ui (NULL, 1);
   a = gcry_mpi_set_ui (NULL, 1);
-  ctx = gcry_mpi_ec_p_new (p, a);
-  if (!ctx)
-    die ("gcry_mpi_ec_p_new returned an error: %s\n",
-         gpg_strerror (gpg_error_from_syserror ()));
+  err = ec_p_new (&ctx, p, a);
+  if (err)
+    die ("ec_p_new returned an error: %s\n", gpg_strerror (err));
   gcry_mpi_release (p);
   gcry_mpi_release (a);
   gcry_ctx_release (ctx);
 
   p = gcry_mpi_set_ui (NULL, 0);
   a = gcry_mpi_set_ui (NULL, 0);
-  ctx = gcry_mpi_ec_p_new (p, a);
-  if (ctx || gpg_err_code_from_syserror () != GPG_ERR_EINVAL)
-    fail ("gcry_mpi_ec_p_new: bad parameter detection failed (1)\n");
+  err = ec_p_new (&ctx, p, a);
+  if (!err || gpg_err_code (err) != GPG_ERR_EINVAL)
+    fail ("ec_p_new: bad parameter detection failed (1)\n");
 
   gcry_mpi_set_ui (p, 1);
-  ctx = gcry_mpi_ec_p_new (p, a);
-  if (ctx || gpg_err_code_from_syserror () != GPG_ERR_EINVAL)
-    fail ("gcry_mpi_ec_p_new: bad parameter detection failed (2)\n");
+  err = ec_p_new (&ctx, p, a);
+  if (!err || gpg_err_code (err) != GPG_ERR_EINVAL)
+    fail ("ec_p_new: bad parameter detection failed (2)\n");
 
   gcry_mpi_release (p);
   p = NULL;
-  ctx = gcry_mpi_ec_p_new (p, a);
-  if (ctx || gpg_err_code_from_syserror () != GPG_ERR_EINVAL)
-    fail ("gcry_mpi_ec_p_new: bad parameter detection failed (3)\n");
+  err = ec_p_new (&ctx, p, a);
+  if (!err || gpg_err_code (err) != GPG_ERR_EINVAL)
+    fail ("ec_p_new: bad parameter detection failed (3)\n");
 
   gcry_mpi_release (a);
   a = NULL;
-  ctx = gcry_mpi_ec_p_new (p, a);
-  if (ctx || gpg_err_code_from_syserror () != GPG_ERR_EINVAL)
-    fail ("gcry_mpi_ec_p_new: bad parameter detection failed (4)\n");
+  err = ec_p_new (&ctx, p, a);
+  if (!err || gpg_err_code (err) != GPG_ERR_EINVAL)
+    fail ("ec_p_new: bad parameter detection failed (4)\n");
+
+}
+
+
+static int
+get_and_cmp_mpi (const char *name, const char *mpistring, const char *desc,
+                 gcry_ctx_t ctx)
+{
+  gcry_mpi_t mpi;
+
+  mpi = gcry_mpi_ec_get_mpi (name, ctx, 1);
+  if (!mpi)
+    {
+      fail ("error getting parameter '%s' of curve '%s'\n", name, desc);
+      return 1;
+    }
+  if (cmp_mpihex (mpi, mpistring))
+    {
+      fail ("parameter '%s' of curve '%s' does not match\n", name, desc);
+      gcry_mpi_release (mpi);
+      return 1;
+    }
+  gcry_mpi_release (mpi);
+  return 0;
+}
+
+
+static int
+get_and_cmp_point (const char *name,
+                   const char *mpi_x_string, const char *mpi_y_string,
+                   const char *desc, gcry_ctx_t ctx)
+{
+  gcry_mpi_point_t point;
+  gcry_mpi_t x, y, z;
+  int result = 0;
+
+  point = gcry_mpi_ec_get_point (name, ctx, 1);
+  if (!point)
+    {
+      fail ("error getting point parameter '%s' of curve '%s'\n", name, desc);
+      return 1;
+    }
+
+  x = gcry_mpi_new (0);
+  y = gcry_mpi_new (0);
+  z = gcry_mpi_new (0);
+  gcry_mpi_point_snatch_get (x, y, z, point);
+  if (cmp_mpihex (x, mpi_x_string))
+    {
+      fail ("x coordinate of '%s' of curve '%s' does not match\n", name, desc);
+      result = 1;
+    }
+  if (cmp_mpihex (y, mpi_y_string))
+    {
+      fail ("y coordinate of '%s' of curve '%s' does not match\n", name, desc);
+      result = 1;
+    }
+  if (cmp_mpihex (z, "01"))
+    {
+      fail ("z coordinate of '%s' of curve '%s' is not 1\n", name, desc);
+      result = 1;
+    }
+  gcry_mpi_release (x);
+  gcry_mpi_release (y);
+  gcry_mpi_release (z);
+  return result;
+}
+
+
+static void
+context_param (void)
+{
+  gpg_error_t err;
+  int idx;
+  gcry_ctx_t ctx = NULL;
+
+  wherestr = "context_param";
+
+  for (idx=0; test_curve[idx].desc; idx++)
+    {
+      show ("checking curve '%s'\n", test_curve[idx].desc);
+      gcry_ctx_release (ctx);
+      err = gcry_mpi_ec_new (&ctx, NULL, test_curve[idx].desc);
+      if (err)
+        {
+          fail ("can't create context for curve '%s': %s\n",
+                test_curve[idx].desc, gpg_strerror (err));
+          continue;
+        }
+      if (get_and_cmp_mpi ("p", test_curve[idx].p, test_curve[idx].desc, ctx))
+        continue;
+      if (get_and_cmp_mpi ("a", test_curve[idx].a, test_curve[idx].desc, ctx))
+        continue;
+      if (get_and_cmp_mpi ("b", test_curve[idx].b, test_curve[idx].desc, ctx))
+        continue;
+      if (get_and_cmp_mpi ("g.x",test_curve[idx].g_x, test_curve[idx].desc,ctx))
+        continue;
+      if (get_and_cmp_mpi ("g.y",test_curve[idx].g_y, test_curve[idx].desc,ctx))
+        continue;
+      if (get_and_cmp_mpi ("n", test_curve[idx].n, test_curve[idx].desc, ctx))
+        continue;
+      if (get_and_cmp_point ("g", test_curve[idx].g_x, test_curve[idx].g_y,
+                             test_curve[idx].desc, ctx))
+        continue;
+
+    }
+  gcry_ctx_release (ctx);
+
+  /* FIXME: Add tests for Q and d.  */
+
+  /* FIXME: Add test sor the set functions.  */
+
 
 }
 
 
+
+
 /* Create a new point from (X,Y,Z) given as hex strings.  */
 gcry_mpi_point_t
 make_point (const char *x, const char *y, const char *z)
@@ -244,9 +460,13 @@ make_point (const char *x, const char *y, const char *z)
 }
 
 
+/* This tests checks that the low-level EC API yields the same result
+   as using the high level API.  The values have been taken from a
+   test run using the high level API.  */
 static void
 basic_ec_math (void)
 {
+  gpg_error_t err;
   gcry_ctx_t ctx;
   gcry_mpi_t P, A;
   gcry_mpi_point_t G, Q;
@@ -264,7 +484,9 @@ basic_ec_math (void)
   d = hex2mpi ("D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D");
   Q = gcry_mpi_point_new (0);
 
-  ctx = gcry_mpi_ec_p_new (P, A);
+  err = ec_p_new (&ctx, P, A);
+  if (err)
+    die ("ec_p_new failed: %s\n", gpg_strerror (err));
   gcry_mpi_ec_mul (Q, d, G, ctx);
 
   x = gcry_mpi_new (0);
@@ -304,6 +526,66 @@ basic_ec_math (void)
 }
 
 
+/* This is the same as basic_ec_math but uses more advanced
+   features.  */
+static void
+basic_ec_math_simplified (void)
+{
+  gpg_error_t err;
+  gcry_ctx_t ctx;
+  gcry_mpi_point_t G, Q;
+  gcry_mpi_t d;
+  gcry_mpi_t x, y, z;
+
+  wherestr = "set_get_point";
+  show ("checking basic math functions for EC (variant)\n");
+
+  d = hex2mpi ("D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D");
+  Q = gcry_mpi_point_new (0);
+
+  err = gcry_mpi_ec_new (&ctx, NULL, "NIST P-192");
+  if (err)
+    die ("gcry_mpi_ec_new failed: %s\n", gpg_strerror (err));
+  G = gcry_mpi_ec_get_point ("g", ctx, 1);
+  if (!G)
+    die ("gcry_mpi_ec_get_point(G) failed\n");
+  gcry_mpi_ec_mul (Q, d, G, ctx);
+
+  x = gcry_mpi_new (0);
+  y = gcry_mpi_new (0);
+  z = gcry_mpi_new (0);
+  gcry_mpi_point_get (x, y, z, Q);
+  if (cmp_mpihex (x, "222D9EC717C89D047E0898C9185B033CD11C0A981EE6DC66")
+      || cmp_mpihex (y, "605DE0A82D70D3E0F84A127D0739ED33D657DF0D054BFDE8")
+      || cmp_mpihex (z, "00B06B519071BC536999AC8F2D3934B3C1FC9EACCD0A31F88F"))
+    fail ("computed public key does not match\n");
+  if (debug)
+    {
+      print_mpi ("Q.x", x);
+      print_mpi ("Q.y", y);
+      print_mpi ("Q.z", z);
+    }
+
+  if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
+    fail ("failed to get affine coordinates\n");
+  if (cmp_mpihex (x, "008532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE")
+      || cmp_mpihex (y, "00C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966"))
+    fail ("computed affine coordinates of public key do not match\n");
+  if (debug)
+    {
+      print_mpi ("q.x", x);
+      print_mpi ("q.y", y);
+    }
+
+  gcry_mpi_release (z);
+  gcry_mpi_release (y);
+  gcry_mpi_release (x);
+  gcry_mpi_point_release (Q);
+  gcry_mpi_release (d);
+  gcry_mpi_point_release (G);
+}
+
+
 int
 main (int argc, char **argv)
 {
@@ -324,7 +606,9 @@ main (int argc, char **argv)
 
   set_get_point ();
   context_alloc ();
+  context_param ();
   basic_ec_math ();
+  basic_ec_math_simplified ();
 
   show ("All tests completed. Errors: %d\n", error_count);
   return error_count ? 1 : 0;

commit e005629bd7bebb3e13945645c6e1230b44ab16a2
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Mar 13 15:08:33 2013 +0100

    Add GCRYMPI_FLAG_CONST and make use constants.
    
    * src/gcrypt.h.in (GCRYMPI_FLAG_CONST): New.
    * src/mpi.h (mpi_is_const, mpi_const): New.
    (enum gcry_mpi_constants, MPI_NUMBER_OF_CONSTANTS): New.
    * mpi/mpiutil.c (_gcry_mpi_init): New.
    (constants): New.
    (_gcry_mpi_free): Do not release a constant flagged MPI.
    (gcry_mpi_copy): Clear the const and immutable flags.
    (gcry_mpi_set_flag, gcry_mpi_clear_flag, gcry_mpi_get_flag): Support
    GCRYMPI_FLAG_CONST.
    (_gcry_mpi_const): New.
    * src/global.c (global_init): Call _gcry_mpi_init.
    * mpi/ec.c (mpi_ec_ctx_s): Remove fields one, two, three, four, and
    eight.  Change all users to call mpi_const() instead.
    
    * src/mpiutils.c (gcry_mpi_set_opaque): Check the immutable flag.
    --
    
    Allocating the trivial constants newly for every EC context is a waste
    of memory and cpu cycles.  We instead provide a simple mechanism to
    internally support such constants.  Using a new flag in THE API also
    allows to mark an arbitrary MPI as constant.  The drawback of the
    constants is the their memory will never be deallocated.  However,
    that is what constants are about.

diff --git a/NEWS b/NEWS
index 3a4ca4c..c0a7e8e 100644
--- a/NEWS
+++ b/NEWS
@@ -51,6 +51,7 @@ Noteworthy changes in version 1.6.0 (unreleased)
  gcry_mpi_ec_add                 NEW.
  gcry_mpi_ec_mul                 NEW.
  GCRYMPI_FLAG_IMMUTABLE          NEW.
+ GCRYMPI_FLAG_CONST              NEW.
 
 
 Noteworthy changes in version 1.5.0 (2011-06-29)
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index bfc825d..a56d527 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -3571,7 +3571,8 @@ confidential data like private key parameters.
 
 @deftypefun gcry_mpi_t gcry_mpi_copy (@w{const gcry_mpi_t @var{a}})
 
-Create a new MPI as the exact copy of @var{a}.
+Create a new MPI as the exact copy of @var{a} but with the constant
+and immutable flags cleared.
 @end deftypefun
 
 
@@ -4008,20 +4009,29 @@ cleared.
 If this flag is set, the MPI is marked as immutable.  Setting or
 changing the value of that MPI is ignored and an error message is
 logged.  The flag is sometimes useful for debugging.
+ at item GCRYMPI_FLAG_CONST
+If this flag is set, the MPI is marked as a constant and as immutable
+Setting or changing the value of that MPI is ignored and an error
+message is logged.  Such an MPI will never be deallocated and may thus
+be used without copying.  Note that using gcry_mpi_copy will return a
+copy of that constant with this and the immutable flag cleared.
 @end table
 
 @deftypefun void gcry_mpi_set_flag (@w{gcry_mpi_t @var{a}}, @
  @w{enum gcry_mpi_flag @var{flag}})
 
 Set the @var{flag} for the MPI @var{a}.  The only allowed flags are
- at code{GCRYMPI_FLAG_SECURE} and @code{GCRYMPI_FLAG_IMMUTABLE}.
+ at code{GCRYMPI_FLAG_SECURE}, @code{GCRYMPI_FLAG_IMMUTABLE}, and
+ at code{GCRYMPI_FLAG_CONST}.
 @end deftypefun
 
 @deftypefun void gcry_mpi_clear_flag (@w{gcry_mpi_t @var{a}}, @
  @w{enum gcry_mpi_flag @var{flag}})
 
 Clear @var{flag} for the multi-precision-integers @var{a}.  The only
-allowed flag is @code{GCRYMPI_FLAG_IMMUTABLE}.
+allowed flag is @code{GCRYMPI_FLAG_IMMUTABLE} but only if
+ at code{GCRYMPI_FLAG_CONST} is not set.  If @code{GCRYMPI_FLAG_CONST} is
+set, clearing @code{GCRYMPI_FLAG_IMMUTABLE} will simply be ignored.
 @end deftypefun
 o
 @deftypefun int gcry_mpi_get_flag (@w{gcry_mpi_t @var{a}}, @
diff --git a/mpi/ec.c b/mpi/ec.c
index e85ec04..7f310ea 100644
--- a/mpi/ec.c
+++ b/mpi/ec.c
@@ -45,12 +45,6 @@ struct mpi_ec_ctx_s
 
   int a_is_pminus3;  /* True if A = P - 3. */
 
-  /* Some often used constants.  */
-  gcry_mpi_t one;
-  gcry_mpi_t two;
-  gcry_mpi_t three;
-  gcry_mpi_t four;
-  gcry_mpi_t eight;
   gcry_mpi_t two_inv_p;
 
   /* Scratch variables.  */
@@ -374,15 +368,8 @@ ec_p_init (mpi_ec_t ctx, gcry_mpi_t p, gcry_mpi_t a)
   ctx->a_is_pminus3 = !mpi_cmp (ctx->a, tmp);
   mpi_free (tmp);
 
-
-  /* Allocate constants.  */
-  ctx->one   = mpi_alloc_set_ui (1);
-  ctx->two   = mpi_alloc_set_ui (2);
-  ctx->three = mpi_alloc_set_ui (3);
-  ctx->four  = mpi_alloc_set_ui (4);
-  ctx->eight = mpi_alloc_set_ui (8);
   ctx->two_inv_p = mpi_alloc (0);
-  ec_invm (ctx->two_inv_p, ctx->two, ctx);
+  ec_invm (ctx->two_inv_p, mpi_const (MPI_C_TWO), ctx);
 
   /* Allocate scratch variables.  */
   for (i=0; i< DIM(ctx->scratch); i++)
@@ -417,12 +404,6 @@ ec_deinit (void *opaque)
   mpi_free (ctx->p);
   mpi_free (ctx->a);
 
-  mpi_free (ctx->one);
-  mpi_free (ctx->two);
-  mpi_free (ctx->three);
-  mpi_free (ctx->four);
-  mpi_free (ctx->eight);
-
   mpi_free (ctx->two_inv_p);
 
   for (i=0; i< DIM(ctx->scratch); i++)
@@ -563,9 +544,9 @@ _gcry_mpi_ec_dup_point (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx)
           /* L1 = 3(X - Z^2)(X + Z^2) */
           /*                          T1: used for Z^2. */
           /*                          T2: used for the right term.  */
-          ec_powm (t1, point->z, ctx->two, ctx);
+          ec_powm (t1, point->z, mpi_const (MPI_C_TWO), ctx);
           ec_subm (l1, point->x, t1, ctx);
-          ec_mulm (l1, l1, ctx->three, ctx);
+          ec_mulm (l1, l1, mpi_const (MPI_C_THREE), ctx);
           ec_addm (t2, point->x, t1, ctx);
           ec_mulm (l1, l1, t2, ctx);
         }
@@ -573,32 +554,32 @@ _gcry_mpi_ec_dup_point (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx)
         {
           /* L1 = 3X^2 + aZ^4 */
           /*                          T1: used for aZ^4. */
-          ec_powm (l1, point->x, ctx->two, ctx);
-          ec_mulm (l1, l1, ctx->three, ctx);
-          ec_powm (t1, point->z, ctx->four, ctx);
+          ec_powm (l1, point->x, mpi_const (MPI_C_TWO), ctx);
+          ec_mulm (l1, l1, mpi_const (MPI_C_THREE), ctx);
+          ec_powm (t1, point->z, mpi_const (MPI_C_FOUR), ctx);
           ec_mulm (t1, t1, ctx->a, ctx);
           ec_addm (l1, l1, t1, ctx);
         }
       /* Z3 = 2YZ */
       ec_mulm (z3, point->y, point->z, ctx);
-      ec_mulm (z3, z3, ctx->two, ctx);
+      ec_mulm (z3, z3, mpi_const (MPI_C_TWO), ctx);
 
       /* L2 = 4XY^2 */
       /*                              T2: used for Y2; required later. */
-      ec_powm (t2, point->y, ctx->two, ctx);
+      ec_powm (t2, point->y, mpi_const (MPI_C_TWO), ctx);
       ec_mulm (l2, t2, point->x, ctx);
-      ec_mulm (l2, l2, ctx->four, ctx);
+      ec_mulm (l2, l2, mpi_const (MPI_C_FOUR), ctx);
 
       /* X3 = L1^2 - 2L2 */
       /*                              T1: used for L2^2. */
-      ec_powm (x3, l1, ctx->two, ctx);
-      ec_mulm (t1, l2, ctx->two, ctx);
+      ec_powm (x3, l1, mpi_const (MPI_C_TWO), ctx);
+      ec_mulm (t1, l2, mpi_const (MPI_C_TWO), ctx);
       ec_subm (x3, x3, t1, ctx);
 
       /* L3 = 8Y^4 */
       /*                              T2: taken from above. */
-      ec_powm (t2, t2, ctx->two, ctx);
-      ec_mulm (l3, t2, ctx->eight, ctx);
+      ec_powm (t2, t2, mpi_const (MPI_C_TWO), ctx);
+      ec_mulm (l3, t2, mpi_const (MPI_C_EIGHT), ctx);
 
       /* Y3 = L1(L2 - X3) - L3 */
       ec_subm (y3, l2, x3, ctx);
@@ -676,23 +657,23 @@ _gcry_mpi_ec_add_points (mpi_point_t result,
         mpi_set (l1, x1);
       else
         {
-          ec_powm (l1, z2, ctx->two, ctx);
+          ec_powm (l1, z2, mpi_const (MPI_C_TWO), ctx);
           ec_mulm (l1, l1, x1, ctx);
         }
       if (z1_is_one)
         mpi_set (l2, x1);
       else
         {
-          ec_powm (l2, z1, ctx->two, ctx);
+          ec_powm (l2, z1, mpi_const (MPI_C_TWO), ctx);
           ec_mulm (l2, l2, x2, ctx);
         }
       /* l3 = l1 - l2 */
       ec_subm (l3, l1, l2, ctx);
       /* l4 = y1 z2^3  */
-      ec_powm (l4, z2, ctx->three, ctx);
+      ec_powm (l4, z2, mpi_const (MPI_C_THREE), ctx);
       ec_mulm (l4, l4, y1, ctx);
       /* l5 = y2 z1^3  */
-      ec_powm (l5, z1, ctx->three, ctx);
+      ec_powm (l5, z1, mpi_const (MPI_C_THREE), ctx);
       ec_mulm (l5, l5, y2, ctx);
       /* l6 = l4 - l5  */
       ec_subm (l6, l4, l5, ctx);
@@ -722,16 +703,16 @@ _gcry_mpi_ec_add_points (mpi_point_t result,
           ec_mulm (z3, z1, z2, ctx);
           ec_mulm (z3, z3, l3, ctx);
           /* x3 = l6^2 - l7 l3^2  */
-          ec_powm (t1, l6, ctx->two, ctx);
-          ec_powm (t2, l3, ctx->two, ctx);
+          ec_powm (t1, l6, mpi_const (MPI_C_TWO), ctx);
+          ec_powm (t2, l3, mpi_const (MPI_C_TWO), ctx);
           ec_mulm (t2, t2, l7, ctx);
           ec_subm (x3, t1, t2, ctx);
           /* l9 = l7 l3^2 - 2 x3  */
-          ec_mulm (t1, x3, ctx->two, ctx);
+          ec_mulm (t1, x3, mpi_const (MPI_C_TWO), ctx);
           ec_subm (l9, t2, t1, ctx);
           /* y3 = (l9 l6 - l8 l3^3)/2  */
           ec_mulm (l9, l9, l6, ctx);
-          ec_powm (t1, l3, ctx->three, ctx); /* fixme: Use saved value*/
+          ec_powm (t1, l3, mpi_const (MPI_C_THREE), ctx); /* fixme: Use saved value*/
           ec_mulm (t1, t1, l8, ctx);
           ec_subm (y3, l9, t1, ctx);
           ec_mulm (y3, y3, ctx->two_inv_p, ctx);
@@ -824,9 +805,9 @@ _gcry_mpi_ec_mul_point (mpi_point_t result,
       mpi_free (z2);
       mpi_free (z3);
     }
-  z1 = mpi_copy (ctx->one);
+  z1 = mpi_copy (mpi_const (MPI_C_ONE));
 
-  mpi_mul (h, k, ctx->three); /* h = 3k */
+  mpi_mul (h, k, mpi_const (MPI_C_THREE)); /* h = 3k */
   loops = mpi_get_nbits (h);
 
   mpi_set (result->x, point->x);
diff --git a/mpi/mpiutil.c b/mpi/mpiutil.c
index 64a2f7e..cff15b7 100644
--- a/mpi/mpiutil.c
+++ b/mpi/mpiutil.c
@@ -28,6 +28,10 @@
 #include "mpi-internal.h"
 #include "mod-source-info.h"
 
+/* Constatns allocated right away at strtartup.  */
+static gcry_mpi_t constants[MPI_NUMBER_OF_CONSTANTS];
+
+
 
 const char *
 _gcry_mpi_get_hw_config (void)
@@ -36,6 +40,34 @@ _gcry_mpi_get_hw_config (void)
 }
 
 
+/* Initialize the MPI subsystem.  This is called early and allows to
+   do some initialization without taking care of threading issues.  */
+gcry_err_code_t
+_gcry_mpi_init (void)
+{
+  int idx;
+  unsigned long value;
+
+  for (idx=0; idx < MPI_NUMBER_OF_CONSTANTS; idx++)
+    {
+      switch (idx)
+        {
+        case MPI_C_ZERO:  value = 0; break;
+        case MPI_C_ONE:   value = 1; break;
+        case MPI_C_TWO:   value = 2; break;
+        case MPI_C_THREE: value = 3; break;
+        case MPI_C_FOUR:  value = 4; break;
+        case MPI_C_EIGHT: value = 8; break;
+        default: log_bug ("invalid mpi_const selector %d\n", idx);
+        }
+      constants[idx] = mpi_alloc_set_ui (value);
+      constants[idx]->flags = (16|32);
+    }
+
+  return 0;
+}
+
+
 /****************
  * Note:  It was a bad idea to use the number of limbs to allocate
  *	  because on a alpha the limbs are large but we normally need
@@ -178,6 +210,8 @@ _gcry_mpi_free( gcry_mpi_t a )
 {
   if (!a )
     return;
+  if ((a->flags & 32))
+    return; /* Never release a constant. */
   if ((a->flags & 4))
     gcry_free( a->d );
   else
@@ -195,7 +229,7 @@ _gcry_mpi_free( gcry_mpi_t a )
 void
 _gcry_mpi_immutable_failed (void)
 {
-  log_info ("Warning: trying to change immutable MPI\n");
+  log_info ("Warning: trying to change an immutable MPI\n");
 }
 
 
@@ -226,6 +260,12 @@ gcry_mpi_set_opaque( gcry_mpi_t a, void *p, unsigned int nbits )
   if (!a)
     a = mpi_alloc(0);
 
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return a;
+    }
+
   if( a->flags & 4 )
     gcry_free( a->d );
   else
@@ -266,6 +306,7 @@ gcry_mpi_copy( gcry_mpi_t a )
 				     : gcry_xmalloc( (a->sign+7)/8 );
 	memcpy( p, a->d, (a->sign+7)/8 );
 	b = gcry_mpi_set_opaque( NULL, p, a->sign );
+        b->flags &= ~(16|32); /* Reset the immutable and constant flags.  */
     }
     else if( a ) {
 	b = mpi_is_secure(a)? mpi_alloc_secure( a->nlimbs )
@@ -273,6 +314,7 @@ gcry_mpi_copy( gcry_mpi_t a )
 	b->nlimbs = a->nlimbs;
 	b->sign = a->sign;
 	b->flags  = a->flags;
+        b->flags &= ~(16|32); /* Reset the immutable and constant flags.  */
 	for(i=0; i < b->nlimbs; i++ )
 	    b->d[i] = a->d[i];
     }
@@ -478,24 +520,30 @@ gcry_mpi_randomize( gcry_mpi_t w,
 
 
 void
-gcry_mpi_set_flag( gcry_mpi_t a, enum gcry_mpi_flag flag )
+gcry_mpi_set_flag (gcry_mpi_t a, enum gcry_mpi_flag flag)
 {
-    switch( flag ) {
-      case GCRYMPI_FLAG_SECURE: mpi_set_secure(a); break;
-      case GCRYMPI_FLAG_IMMUTABLE:  a->flags |= 16; break;
-      case GCRYMPI_FLAG_OPAQUE:
-      default: log_bug("invalid flag value\n");
+  switch (flag)
+    {
+    case GCRYMPI_FLAG_SECURE:     mpi_set_secure(a); break;
+    case GCRYMPI_FLAG_CONST:      a->flags |= (16|32); break;
+    case GCRYMPI_FLAG_IMMUTABLE:  a->flags |= 16; break;
+    case GCRYMPI_FLAG_OPAQUE:
+    default: log_bug("invalid flag value\n");
     }
 }
 
 void
-gcry_mpi_clear_flag( gcry_mpi_t a, enum gcry_mpi_flag flag )
+gcry_mpi_clear_flag (gcry_mpi_t a, enum gcry_mpi_flag flag)
 {
   (void)a; /* Not yet used. */
 
   switch (flag)
     {
-    case GCRYMPI_FLAG_IMMUTABLE: a->flags &= ~16; break;
+    case GCRYMPI_FLAG_IMMUTABLE:
+      if (!(a->flags & 32))
+        a->flags &= ~16;
+      break;
+    case GCRYMPI_FLAG_CONST:
     case GCRYMPI_FLAG_SECURE:
     case GCRYMPI_FLAG_OPAQUE:
     default: log_bug("invalid flag value\n");
@@ -503,15 +551,30 @@ gcry_mpi_clear_flag( gcry_mpi_t a, enum gcry_mpi_flag flag )
 }
 
 int
-gcry_mpi_get_flag( gcry_mpi_t a, enum gcry_mpi_flag flag )
+gcry_mpi_get_flag (gcry_mpi_t a, enum gcry_mpi_flag flag)
 {
   switch (flag)
     {
-    case GCRYMPI_FLAG_SECURE: return (a->flags & 1);
-    case GCRYMPI_FLAG_OPAQUE: return (a->flags & 4);
-    case GCRYMPI_FLAG_IMMUTABLE:  return (a->flags & 16);
+    case GCRYMPI_FLAG_SECURE:    return !!(a->flags & 1);
+    case GCRYMPI_FLAG_OPAQUE:    return !!(a->flags & 4);
+    case GCRYMPI_FLAG_IMMUTABLE: return !!(a->flags & 16);
+    case GCRYMPI_FLAG_CONST:     return !!(a->flags & 32);
     default: log_bug("invalid flag value\n");
     }
   /*NOTREACHED*/
   return 0;
 }
+
+
+/* Return a constant MPI descripbed by NO which is one of the
+   MPI_C_xxx macros.  There is no need to copy this returned value; it
+   may be used directly.  */
+gcry_mpi_t
+_gcry_mpi_const (enum gcry_mpi_constants no)
+{
+  if ((int)no < 0 || no > MPI_NUMBER_OF_CONSTANTS)
+    log_bug("invalid mpi_const selector %d\n", no);
+  if (!constants[no])
+    log_bug("MPI subsystem not initialized\n");
+  return constants[no];
+}
diff --git a/src/g10lib.h b/src/g10lib.h
index da76c7b..3caa2be 100644
--- a/src/g10lib.h
+++ b/src/g10lib.h
@@ -348,6 +348,7 @@ gcry_err_code_t _gcry_cipher_init (void);
 gcry_err_code_t _gcry_md_init (void);
 gcry_err_code_t _gcry_pk_init (void);
 gcry_err_code_t _gcry_secmem_module_init (void);
+gcry_err_code_t _gcry_mpi_init (void);
 
 gcry_err_code_t _gcry_pk_module_lookup (int id, gcry_module_t *module);
 void _gcry_pk_module_release (gcry_module_t module);
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 9f6438c..eb9a11d 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -457,7 +457,8 @@ enum gcry_mpi_flag
     GCRYMPI_FLAG_OPAQUE = 2,  /* The number is not a real one but just
                                  a way to store some bytes.  This is
                                  useful for encrypted big integers.  */
-    GCRYMPI_FLAG_IMMUTABLE = 4  /* Mark the MPI as immutable.  */
+    GCRYMPI_FLAG_IMMUTABLE = 4, /* Mark the MPI as immutable.  */
+    GCRYMPI_FLAG_CONST     = 8  /* Mark the MPI as a constant.  */
   };
 
 
diff --git a/src/global.c b/src/global.c
index a1a83e9..0c6fbbd 100644
--- a/src/global.c
+++ b/src/global.c
@@ -140,6 +140,9 @@ global_init (void)
   err = _gcry_secmem_module_init ();
   if (err)
     goto fail;
+  err = _gcry_mpi_init ();
+  if (err)
+    goto fail;
 
   return;
 
diff --git a/src/mpi.h b/src/mpi.h
index 93ad889..9c22141 100644
--- a/src/mpi.h
+++ b/src/mpi.h
@@ -70,7 +70,8 @@ struct gcry_mpi
 		          for opaque MPIs to store the length.  */
   unsigned int flags; /* Bit 0: Array to be allocated in secure memory space.*/
                       /* Bit 2: The limb is a pointer to some m_alloced data.*/
-                      /* Bit 4: Const MPI - the MPI may not be modified.  */
+                      /* Bit 4: Immutable MPI - the MPI may not be modified.  */
+                      /* Bit 5: Constant MPI - the MPI will not be freed.  */
   mpi_limb_t *d;      /* Array with the limbs */
 };
 
@@ -108,6 +109,7 @@ struct gcry_mpi
 void _gcry_mpi_immutable_failed (void);
 #define mpi_immutable_failed() _gcry_mpi_immutable_failed ()
 
+#define mpi_is_const(a)       ((a) && ((a)->flags&32))
 #define mpi_is_immutable(a)   ((a) && ((a)->flags&16))
 #define mpi_is_opaque(a)      ((a) && ((a)->flags&4))
 #define mpi_is_secure(a)      ((a) && ((a)->flags&1))
@@ -122,6 +124,7 @@ void _gcry_mpi_immutable_failed (void);
 #define mpi_swap(a,b)         _gcry_mpi_swap ((a),(b))
 #define mpi_new(n)            _gcry_mpi_new ((n))
 #define mpi_snew(n)           _gcry_mpi_snew ((n))
+#define mpi_const(n)          _gcry_mpi_const ((n))
 
 void _gcry_mpi_clear( gcry_mpi_t a );
 gcry_mpi_t  _gcry_mpi_alloc_like( gcry_mpi_t a );
@@ -132,6 +135,23 @@ 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);
 
+/* Constants used to return constant MPIs.  See _gcry_mpi_init if you
+   want to add more constants. */
+#define MPI_NUMBER_OF_CONSTANTS 6
+enum gcry_mpi_constants
+  {
+    MPI_C_ZERO,
+    MPI_C_ONE,
+    MPI_C_TWO,
+    MPI_C_THREE,
+    MPI_C_FOUR,
+    MPI_C_EIGHT
+  };
+
+
+gcry_mpi_t _gcry_mpi_const (enum gcry_mpi_constants no);
+
+
 /*-- mpicoder.c --*/
 void  _gcry_log_mpidump( const char *text, gcry_mpi_t a );
 u32   _gcry_mpi_get_keyid( gcry_mpi_t a, u32 *keyid );
diff --git a/tests/mpitests.c b/tests/mpitests.c
index cf82842..3b75ea7 100644
--- a/tests/mpitests.c
+++ b/tests/mpitests.c
@@ -88,6 +88,67 @@ unsigned char manyff[] = {
 };
 
 
+static int
+test_const_and_immutable (void)
+{
+  gcry_mpi_t one, second_one;
+
+  one = gcry_mpi_set_ui (NULL, 1);
+  if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE)
+      || gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST))
+    die ("immutable or const flag initially set\n");
+
+  second_one = gcry_mpi_copy (one);
+  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE))
+    die ("immutable flag set after copy\n");
+  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST))
+    die ("const flag set after copy\n");
+  gcry_mpi_release (second_one);
+
+  gcry_mpi_set_flag (one, GCRYMPI_FLAG_IMMUTABLE);
+  if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE))
+    die ("failed to set immutable flag\n");
+  if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST))
+    die ("const flag unexpectly set\n");
+
+  second_one = gcry_mpi_copy (one);
+  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE))
+    die ("immutable flag not cleared after copy\n");
+  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST))
+    die ("const flag unexpectly set after copy\n");
+  gcry_mpi_release (second_one);
+
+  gcry_mpi_clear_flag (one, GCRYMPI_FLAG_IMMUTABLE);
+  if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE))
+    die ("failed to clear immutable flag\n");
+  if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST))
+    die ("const flag unexpectly set\n");
+
+  gcry_mpi_set_flag (one, GCRYMPI_FLAG_CONST);
+  if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST))
+    die ("failed to set const flag\n");
+  if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE))
+    die ("failed to set immutable flag with const flag\n");
+
+  second_one = gcry_mpi_copy (one);
+  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE))
+    die ("immutable flag not cleared after copy\n");
+  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST))
+    die ("const flag not cleared after copy\n");
+  gcry_mpi_release (second_one);
+
+  gcry_mpi_clear_flag (one, GCRYMPI_FLAG_IMMUTABLE);
+  if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE))
+    die ("clearing immutable flag not ignored for a constant MPI\n");
+  if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST))
+    die ("const flag unexpectly cleared\n");
+
+  /* Due to the the constant flag the release below should be a NOP
+     and will leak memory.  */
+  gcry_mpi_release (one);
+  return 1;
+}
+
 
 static int
 test_add (void)
@@ -292,6 +353,7 @@ main (int argc, char* argv[])
     }
   gcry_control(GCRYCTL_DISABLE_SECMEM);
 
+  test_const_and_immutable ();
   test_add ();
   test_sub ();
   test_mul ();

commit 1fecae98ee7e0fa49b29f98efa6817ca121ed98a
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Mar 12 20:20:42 2013 +0100

    Add GCRYMPI_FLAG_IMMUTABLE to help debugging.
    
    * src/gcrypt.h.in (GCRYMPI_FLAG_IMMUTABLE): New.
    * src/mpi.h (mpi_is_immutable): New macro.
    * mpi/mpiutil.c (gcry_mpi_set_flag, gcry_mpi_clear_flag)
    (gcry_mpi_get_flag): Implement new flag
    (_gcry_mpi_immutable_failed): New.
    
    * mpi/mpiutil.c (_gcry_mpi_clear, _gcry_mpi_free, gcry_mpi_snatch)
    (gcry_mpi_set, gcry_mpi_randomize): Act upon the immutable flag.
    * mpi/mpi-bit.c (gcry_mpi_set_bit, gcry_mpi_set_highbit)
    (gcry_mpi_clear_highbit, gcry_mpi_clear_bit)
    (_gcry_mpi_rshift_limbs, gcry_mpi_lshift): Ditto.
    * mpi/mpicoder.c (_gcry_mpi_set_buffer): Ditto.
    --
    
    Note that this flag is currently only checked by a few MPI functions.
    The reason why we eventually need such a flag is to help implementing
    a generic way to retrieve and set ECC parameters without accidentally
    changing a curve parameter taken from a list of predefined curves.

diff --git a/NEWS b/NEWS
index 733dd88..3a4ca4c 100644
--- a/NEWS
+++ b/NEWS
@@ -50,6 +50,7 @@ Noteworthy changes in version 1.6.0 (unreleased)
  gcry_mpi_ec_dup                 NEW.
  gcry_mpi_ec_add                 NEW.
  gcry_mpi_ec_mul                 NEW.
+ GCRYMPI_FLAG_IMMUTABLE          NEW.
 
 
 Noteworthy changes in version 1.5.0 (2011-06-29)
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index c986ec7..bfc825d 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -3970,6 +3970,9 @@ Multiply the point @var{u} of the elliptic curve described by
 @node Miscellaneous
 @section Miscellaneous
 
+An MPI data type is allowed to be ``misused'' to store an arbitrary
+value.  Two functions implement this kludge:
+
 @deftypefun gcry_mpi_t gcry_mpi_set_opaque (@w{gcry_mpi_t @var{a}}, @w{void *@var{p}}, @w{unsigned int @var{nbits}})
 
 Store @var{nbits} of the value @var{p} points to in @var{a} and mark
@@ -3980,7 +3983,6 @@ math calculation and is only used to store an arbitrary bit pattern in
 WARNING: Never use an opaque MPI for actual math operations.  The only
 valid functions are gcry_mpi_get_opaque and gcry_mpi_release.  Use
 gcry_mpi_scan to convert a string of arbitrary bytes into an MPI.
-
 @end deftypefun
 
 @deftypefun {void *} gcry_mpi_get_opaque (@w{gcry_mpi_t @var{a}}, @w{unsigned int *@var{nbits}})
@@ -3991,23 +3993,46 @@ size in @var{nbits}.  Note that the returned pointer is still owned by
 MPI.
 @end deftypefun
 
- at deftypefun void gcry_mpi_set_flag (@w{gcry_mpi_t @var{a}}, @w{enum gcry_mpi_flag @var{flag}})
+Each MPI has an associated set of flags for special purposes.  The
+currently defined flags are:
 
-Set the @var{flag} for the MPI @var{a}.  Currently only the flag
- at code{GCRYMPI_FLAG_SECURE} is allowed to convert @var{a} into an MPI
-stored in "secure memory".
- at end deftypefun
+ at table @code
+ at item GCRYMPI_FLAG_SECURE
+Setting this flag converts @var{a} into an MPI stored in "secure
+memory".  Clearing this flag is not allowed.
+ at item GCRYMPI_FLAG_OPAQUE
+This is an interanl flag, indicating the an opaque valuue and not an
+integer is stored.  This is an read-only flag; it may not be set or
+cleared.
+ at item GCRYMPI_FLAG_IMMUTABLE
+If this flag is set, the MPI is marked as immutable.  Setting or
+changing the value of that MPI is ignored and an error message is
+logged.  The flag is sometimes useful for debugging.
+ at end table
 
- at deftypefun void gcry_mpi_clear_flag (@w{gcry_mpi_t @var{a}}, @w{enum gcry_mpi_flag @var{flag}})
+ at deftypefun void gcry_mpi_set_flag (@w{gcry_mpi_t @var{a}}, @
+ @w{enum gcry_mpi_flag @var{flag}})
 
-Clear @var{flag} for the multi-precision-integers @var{a}.  Note that
-this function is currently useless as no flags are allowed.
+Set the @var{flag} for the MPI @var{a}.  The only allowed flags are
+ at code{GCRYMPI_FLAG_SECURE} and @code{GCRYMPI_FLAG_IMMUTABLE}.
 @end deftypefun
 
- at deftypefun int gcry_mpi_get_flag (@w{gcry_mpi_t @var{a}}, @w{enum gcry_mpi_flag @var{flag}})
+ at deftypefun void gcry_mpi_clear_flag (@w{gcry_mpi_t @var{a}}, @
+ @w{enum gcry_mpi_flag @var{flag}})
 
-Return true when the @var{flag} is set for @var{a}.
+Clear @var{flag} for the multi-precision-integers @var{a}.  The only
+allowed flag is @code{GCRYMPI_FLAG_IMMUTABLE}.
 @end deftypefun
+o
+ at deftypefun int gcry_mpi_get_flag (@w{gcry_mpi_t @var{a}}, @
+ @w{enum gcry_mpi_flag @var{flag}})
+
+Return true if @var{flag} is set for @var{a}.
+ at end deftypefun
+
+
+To put a random value into an MPI, the following convenience function
+may be used:
 
 @deftypefun void gcry_mpi_randomize (@w{gcry_mpi_t @var{w}}, @w{unsigned int @var{nbits}}, @w{enum gcry_random_level @var{level}})
 
diff --git a/mpi/mpi-bit.c b/mpi/mpi-bit.c
index cdc6b0b..74042e8 100644
--- a/mpi/mpi-bit.c
+++ b/mpi/mpi-bit.c
@@ -1,5 +1,6 @@
 /* mpi-bit.c  -  MPI bit level functions
  * Copyright (C) 1998, 1999, 2001, 2002, 2006 Free Software Foundation, Inc.
+ * Copyright (C) 2013  g10 Code GmbH
  *
  * This file is part of Libgcrypt.
  *
@@ -117,6 +118,12 @@ gcry_mpi_set_bit( gcry_mpi_t a, unsigned int n )
 {
   unsigned int limbno, bitno;
 
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
+
   limbno = n / BITS_PER_MPI_LIMB;
   bitno  = n % BITS_PER_MPI_LIMB;
 
@@ -136,6 +143,12 @@ gcry_mpi_set_highbit( gcry_mpi_t a, unsigned int n )
 {
   unsigned int limbno, bitno;
 
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
+
   limbno = n / BITS_PER_MPI_LIMB;
   bitno  = n % BITS_PER_MPI_LIMB;
 
@@ -156,18 +169,23 @@ gcry_mpi_set_highbit( gcry_mpi_t a, unsigned int n )
 void
 gcry_mpi_clear_highbit( gcry_mpi_t a, unsigned int n )
 {
-    unsigned int limbno, bitno;
+  unsigned int limbno, bitno;
 
-    limbno = n / BITS_PER_MPI_LIMB;
-    bitno  = n % BITS_PER_MPI_LIMB;
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
 
-    if( limbno >= a->nlimbs )
-	return; /* not allocated, therefore no need to clear bits
-		   :-) */
+  limbno = n / BITS_PER_MPI_LIMB;
+  bitno  = n % BITS_PER_MPI_LIMB;
+
+  if( limbno >= a->nlimbs )
+    return; /* not allocated, therefore no need to clear bits :-) */
 
-    for( ; bitno < BITS_PER_MPI_LIMB; bitno++ )
-	a->d[limbno] &= ~(A_LIMB_1 << bitno);
-    a->nlimbs = limbno+1;
+  for( ; bitno < BITS_PER_MPI_LIMB; bitno++ )
+    a->d[limbno] &= ~(A_LIMB_1 << bitno);
+  a->nlimbs = limbno+1;
 }
 
 /****************
@@ -176,14 +194,20 @@ gcry_mpi_clear_highbit( gcry_mpi_t a, unsigned int n )
 void
 gcry_mpi_clear_bit( gcry_mpi_t a, unsigned int n )
 {
-    unsigned int limbno, bitno;
+  unsigned int limbno, bitno;
 
-    limbno = n / BITS_PER_MPI_LIMB;
-    bitno  = n % BITS_PER_MPI_LIMB;
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
 
-    if( limbno >= a->nlimbs )
-	return; /* don't need to clear this bit, it's to far to left */
-    a->d[limbno] &= ~(A_LIMB_1 << bitno);
+  limbno = n / BITS_PER_MPI_LIMB;
+  bitno  = n % BITS_PER_MPI_LIMB;
+
+  if (limbno >= a->nlimbs)
+    return; /* Don't need to clear this bit, it's far too left.  */
+  a->d[limbno] &= ~(A_LIMB_1 << bitno);
 }
 
 
@@ -194,19 +218,26 @@ gcry_mpi_clear_bit( gcry_mpi_t a, unsigned int n )
 void
 _gcry_mpi_rshift_limbs( gcry_mpi_t a, unsigned int count )
 {
-    mpi_ptr_t ap = a->d;
-    mpi_size_t n = a->nlimbs;
-    unsigned int i;
+  mpi_ptr_t ap = a->d;
+  mpi_size_t n = a->nlimbs;
+  unsigned int i;
 
-    if( count >= n ) {
-	a->nlimbs = 0;
-	return;
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
     }
 
-    for( i = 0; i < n - count; i++ )
-	ap[i] = ap[i+count];
-    ap[i] = 0;
-    a->nlimbs -= count;
+  if (count >= n)
+    {
+      a->nlimbs = 0;
+      return;
+    }
+
+  for( i = 0; i < n - count; i++ )
+    ap[i] = ap[i+count];
+  ap[i] = 0;
+  a->nlimbs -= count;
 }
 
 
@@ -221,6 +252,12 @@ gcry_mpi_rshift ( gcry_mpi_t x, gcry_mpi_t a, unsigned int n )
   unsigned int nlimbs = (n/BITS_PER_MPI_LIMB);
   unsigned int nbits = (n%BITS_PER_MPI_LIMB);
 
+  if (mpi_is_immutable (x))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
+
   if ( x == a )
     {
       /* In-place operation.  */
@@ -328,6 +365,12 @@ gcry_mpi_lshift ( gcry_mpi_t x, gcry_mpi_t a, unsigned int n )
   unsigned int nlimbs = (n/BITS_PER_MPI_LIMB);
   unsigned int nbits = (n%BITS_PER_MPI_LIMB);
 
+  if (mpi_is_immutable (x))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
+
   if (x == a && !n)
     return;  /* In-place shift with an amount of zero.  */
 
diff --git a/mpi/mpicoder.c b/mpi/mpicoder.c
index a3435ed..06d5553 100644
--- a/mpi/mpicoder.c
+++ b/mpi/mpicoder.c
@@ -305,6 +305,12 @@ _gcry_mpi_set_buffer (gcry_mpi_t a, const void *buffer_arg,
   int nlimbs;
   int i;
 
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
+
   nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
   RESIZE_IF_NEEDED(a, nlimbs);
   a->sign = sign;
diff --git a/mpi/mpiutil.c b/mpi/mpiutil.c
index d410d90..64a2f7e 100644
--- a/mpi/mpiutil.c
+++ b/mpi/mpiutil.c
@@ -163,8 +163,13 @@ _gcry_mpi_resize (gcry_mpi_t a, unsigned nlimbs)
 void
 _gcry_mpi_clear( gcry_mpi_t a )
 {
-    a->nlimbs = 0;
-    a->flags = 0;
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
+  a->nlimbs = 0;
+  a->flags = 0;
 }
 
 
@@ -179,11 +184,21 @@ _gcry_mpi_free( gcry_mpi_t a )
     {
       _gcry_mpi_free_limb_space(a->d, a->alloced);
     }
-  if ((a->flags & ~7))
-    log_bug("invalid flag value in mpi\n");
+  /* Check that the flags makes sense.  We better allow for bit 1
+     (value 2) for backward ABI compatibility.  */
+  if ((a->flags & ~(1|2|4|16)))
+    log_bug("invalid flag value in mpi_free\n");
   gcry_free(a);
 }
 
+
+void
+_gcry_mpi_immutable_failed (void)
+{
+  log_info ("Warning: trying to change immutable MPI\n");
+}
+
+
 static void
 mpi_set_secure( gcry_mpi_t a )
 {
@@ -303,6 +318,11 @@ gcry_mpi_snatch (gcry_mpi_t w, gcry_mpi_t u)
 {
   if (w)
     {
+      if (mpi_is_immutable (w))
+        {
+          mpi_immutable_failed ();
+          return;
+        }
       _gcry_mpi_assign_limb_space (w, u->d, u->alloced);
       w->nlimbs = u->nlimbs;
       w->sign   = u->sign;
@@ -324,6 +344,11 @@ gcry_mpi_set( gcry_mpi_t w, gcry_mpi_t u)
 
   if (!w)
     w = _gcry_mpi_alloc( mpi_get_nlimbs(u) );
+  if (mpi_is_immutable (w))
+    {
+      mpi_immutable_failed ();
+      return w;
+    }
   RESIZE_IF_NEEDED(w, usize);
   wp = w->d;
   up = u->d;
@@ -342,6 +367,11 @@ gcry_mpi_set_ui( gcry_mpi_t w, unsigned long u)
     w = _gcry_mpi_alloc (1);
   /* FIXME: If U is 0 we have no need to resize and thus possible
      allocating the the limbs. */
+  if (mpi_is_immutable (w))
+    {
+      mpi_immutable_failed ();
+      return w;
+    }
   RESIZE_IF_NEEDED(w, 1);
   w->d[0] = u;
   w->nlimbs = u? 1:0;
@@ -426,6 +456,11 @@ gcry_mpi_randomize( gcry_mpi_t w,
   unsigned char *p;
   size_t nbytes = (nbits+7)/8;
 
+  if (mpi_is_immutable (w))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
   if (level == GCRY_WEAK_RANDOM)
     {
       p = mpi_is_secure(w) ? gcry_xmalloc_secure (nbytes)
@@ -446,7 +481,8 @@ void
 gcry_mpi_set_flag( gcry_mpi_t a, enum gcry_mpi_flag flag )
 {
     switch( flag ) {
-      case GCRYMPI_FLAG_SECURE:  mpi_set_secure(a); break;
+      case GCRYMPI_FLAG_SECURE: mpi_set_secure(a); break;
+      case GCRYMPI_FLAG_IMMUTABLE:  a->flags |= 16; break;
       case GCRYMPI_FLAG_OPAQUE:
       default: log_bug("invalid flag value\n");
     }
@@ -459,6 +495,7 @@ gcry_mpi_clear_flag( gcry_mpi_t a, enum gcry_mpi_flag flag )
 
   switch (flag)
     {
+    case GCRYMPI_FLAG_IMMUTABLE: a->flags &= ~16; break;
     case GCRYMPI_FLAG_SECURE:
     case GCRYMPI_FLAG_OPAQUE:
     default: log_bug("invalid flag value\n");
@@ -472,6 +509,7 @@ gcry_mpi_get_flag( gcry_mpi_t a, enum gcry_mpi_flag flag )
     {
     case GCRYMPI_FLAG_SECURE: return (a->flags & 1);
     case GCRYMPI_FLAG_OPAQUE: return (a->flags & 4);
+    case GCRYMPI_FLAG_IMMUTABLE:  return (a->flags & 16);
     default: log_bug("invalid flag value\n");
     }
   /*NOTREACHED*/
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 57b841e..9f6438c 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -454,9 +454,10 @@ enum gcry_mpi_format
 enum gcry_mpi_flag
   {
     GCRYMPI_FLAG_SECURE = 1,  /* Allocate the number in "secure" memory.  */
-    GCRYMPI_FLAG_OPAQUE = 2   /* The number is not a real one but just
+    GCRYMPI_FLAG_OPAQUE = 2,  /* The number is not a real one but just
                                  a way to store some bytes.  This is
                                  useful for encrypted big integers.  */
+    GCRYMPI_FLAG_IMMUTABLE = 4  /* Mark the MPI as immutable.  */
   };
 
 
diff --git a/src/mpi.h b/src/mpi.h
index 23afa68..93ad889 100644
--- a/src/mpi.h
+++ b/src/mpi.h
@@ -69,7 +69,8 @@ struct gcry_mpi
   int sign;	       /* Indicates a negative number and is also used
 		          for opaque MPIs to store the length.  */
   unsigned int flags; /* Bit 0: Array to be allocated in secure memory space.*/
-                      /* Bit 2: the limb is a pointer to some m_alloced data.*/
+                      /* Bit 2: The limb is a pointer to some m_alloced data.*/
+                      /* Bit 4: Const MPI - the MPI may not be modified.  */
   mpi_limb_t *d;      /* Array with the limbs */
 };
 
@@ -104,8 +105,12 @@ struct gcry_mpi
   gcry_mpi_t  _gcry_mpi_copy( gcry_mpi_t a );
 #endif
 
-#define mpi_is_opaque(a) ((a) && ((a)->flags&4))
-#define mpi_is_secure(a) ((a) && ((a)->flags&1))
+void _gcry_mpi_immutable_failed (void);
+#define mpi_immutable_failed() _gcry_mpi_immutable_failed ()
+
+#define mpi_is_immutable(a)   ((a) && ((a)->flags&16))
+#define mpi_is_opaque(a)      ((a) && ((a)->flags&4))
+#define mpi_is_secure(a)      ((a) && ((a)->flags&1))
 #define mpi_clear(a)          _gcry_mpi_clear ((a))
 #define mpi_alloc_like(a)     _gcry_mpi_alloc_like((a))
 #define mpi_snatch(a,b)       _gcry_mpi_snatch ((a),(b))

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

Summary of changes:
 NEWS                |    9 ++-
 cipher/ecc.c        |  287 +++++++++++++++++++++++++++++++++++++++++++++-
 doc/gcrypt.texi     |  141 +++++++++++++++++++----
 mpi/ec.c            |  297 ++++++++++++++++++++++++++++++------------------
 mpi/mpi-bit.c       |   93 +++++++++++----
 mpi/mpicoder.c      |    6 +
 mpi/mpiutil.c       |  127 ++++++++++++++++++--
 src/Makefile.am     |    1 +
 src/context.c       |    2 +-
 src/ec-context.h    |   57 +++++++++
 src/g10lib.h        |    1 +
 src/gcrypt.h.in     |   25 ++++-
 src/global.c        |    3 +
 src/libgcrypt.def   |   14 ++-
 src/libgcrypt.vers  |    4 +-
 src/mpi.h           |   44 +++++++-
 src/visibility.c    |   32 +++++-
 src/visibility.h    |    8 +-
 tests/mpitests.c    |   62 ++++++++++
 tests/t-mpi-point.c |  318 ++++++++++++++++++++++++++++++++++++++++++++++++---
 20 files changed, 1318 insertions(+), 213 deletions(-)
 create mode 100644 src/ec-context.h


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




More information about the Gnupg-commits mailing list