Add GCRYMPI_FLAG_CONST and make use constants.
authorWerner Koch <wk@gnupg.org>
Wed, 13 Mar 2013 14:08:33 +0000 (15:08 +0100)
committerWerner Koch <wk@gnupg.org>
Wed, 13 Mar 2013 14:08:33 +0000 (15:08 +0100)
* 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.

NEWS
doc/gcrypt.texi
mpi/ec.c
mpi/mpiutil.c
src/g10lib.h
src/gcrypt.h.in
src/global.c
src/mpi.h
tests/mpitests.c

diff --git a/NEWS b/NEWS
index 3a4ca4c..c0a7e8e 100644 (file)
--- 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)
index bfc825d..a56d527 100644 (file)
@@ -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.
+@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
-@code{GCRYMPI_FLAG_SECURE} and @code{GCRYMPI_FLAG_IMMUTABLE}.
+@code{GCRYMPI_FLAG_SECURE}, @code{GCRYMPI_FLAG_IMMUTABLE}, and
+@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
+@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}}, @
index e85ec04..7f310ea 100644 (file)
--- 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);
index 64a2f7e..cff15b7 100644 (file)
 #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];
+}
index da76c7b..3caa2be 100644 (file)
@@ -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);
index 9f6438c..eb9a11d 100644 (file)
@@ -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.  */
   };
 
 
index a1a83e9..0c6fbbd 100644 (file)
@@ -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;
 
index 93ad889..9c22141 100644 (file)
--- 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 );
index cf82842..3b75ea7 100644 (file)
@@ -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 ();