mpi: Add an API for EC math.
authorWerner Koch <wk@gnupg.org>
Fri, 8 Mar 2013 21:10:23 +0000 (22:10 +0100)
committerWerner Koch <wk@gnupg.org>
Fri, 8 Mar 2013 21:13:52 +0000 (22:13 +0100)
* src/context.c, src/context.h: New.
* src/Makefile.am (libgcrypt_la_SOURCES): Add new files.
* src/gcrypt.h.in (struct gcry_context, gcry_ctx_t): New types.
(gcry_ctx_release): New prototype.
(gcry_mpi_ec_p_new, gcry_mpi_ec_get_affine, gcry_mpi_ec_dup)
(gcry_mpi_ec_add, gcry_mpi_ec_mul): New prototypes.
* mpi/ec.c: Include errno.h and context.h.
(_gcry_mpi_ec_init): Rename to ..
(ec_p_init): this, make static, remove allocation and add arg CTX.
(_gcry_mpi_ec_p_internal_new): New; to replace _gcry_mpi_ec_init.
Change all callers to use this func.
(_gcry_mpi_ec_free): Factor code out to ..
(ec_deinit): New func.
(gcry_mpi_ec_p_new): New.
* src/visibility.c: Include context.h and mpi.h.
(gcry_mpi_ec_p_new, gcry_mpi_ec_get_affine, gcry_mpi_ec_dup)
(gcry_mpi_ec_add, gcry_mpi_ec_mul)
(gcry_ctx_release): New wrapper functions.
* src/visibility.h: Mark new wrapper functions visible.
* src/libgcrypt.def, src/libgcrypt.vers: Add new symbols.
* tests/t-mpi-point.c (print_mpi, hex2mpi, cmp_mpihex): New.
(context_alloc): New.
(make_point, basic_ec_math): New.
--

This part finishes the basic API to do EC math.  It provides a wrapper
around all internal functions.  tests/t-mpi-point.c may be useful as
sample code.  Eventually we will add function to retrieve curve
parameters etc.

13 files changed:
NEWS
cipher/ecc.c
mpi/ec.c
src/Makefile.am
src/context.c [new file with mode: 0644]
src/context.h [new file with mode: 0644]
src/gcrypt.h.in
src/libgcrypt.def
src/libgcrypt.vers
src/mpi.h
src/visibility.c
src/visibility.h
tests/t-mpi-point.c

diff --git a/NEWS b/NEWS
index e0ba536..733dd88 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -44,6 +44,12 @@ Noteworthy changes in version 1.6.0 (unreleased)
  gcry_mpi_point_snatch_get       NEW.
  gcry_mpi_point_set              NEW.
  gcry_mpi_point_snatch_set       NEW.
+ gcry_ctx_t                      NEW.
+ gcry_ctx_release                NEW.
+ gcry_mpi_ec_p_new               NEW.
+ gcry_mpi_ec_dup                 NEW.
+ gcry_mpi_ec_add                 NEW.
+ gcry_mpi_ec_mul                 NEW.
 
 
 Noteworthy changes in version 1.5.0 (2011-06-29)
index 789fc6c..4efbef4 100644 (file)
@@ -547,7 +547,7 @@ generate_key (ECC_secret_key *sk, unsigned int nbits, const char *name,
 
   /* Compute Q.  */
   point_init (&Q);
-  ctx = _gcry_mpi_ec_init (E.p, E.a);
+  ctx = _gcry_mpi_ec_p_internal_new (E.p, E.a);
   _gcry_mpi_ec_mul_point (&Q, d, &E.G, ctx);
 
   /* Copy the stuff to the key structures. */
@@ -672,7 +672,7 @@ check_secret_key (ECC_secret_key * sk)
       goto leave;
     }
 
-  ctx = _gcry_mpi_ec_init (sk->E.p, sk->E.a);
+  ctx = _gcry_mpi_ec_p_internal_new (sk->E.p, sk->E.a);
 
   _gcry_mpi_ec_mul_point (&Q, sk->E.n, &sk->E.G, ctx);
   if (mpi_cmp_ui (Q.z, 0))
@@ -733,7 +733,7 @@ sign (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s)
   mpi_set_ui (s, 0);
   mpi_set_ui (r, 0);
 
-  ctx = _gcry_mpi_ec_init (skey->E.p, skey->E.a);
+  ctx = _gcry_mpi_ec_p_internal_new (skey->E.p, skey->E.a);
 
   while (!mpi_cmp_ui (s, 0)) /* s == 0 */
     {
@@ -805,7 +805,7 @@ verify (gcry_mpi_t input, ECC_public_key *pkey, gcry_mpi_t r, gcry_mpi_t s)
   point_init (&Q1);
   point_init (&Q2);
 
-  ctx = _gcry_mpi_ec_init (pkey->E.p, pkey->E.a);
+  ctx = _gcry_mpi_ec_p_internal_new (pkey->E.p, pkey->E.a);
 
   /* h  = s^(-1) (mod n) */
   mpi_invm (h, s, pkey->E.n);
@@ -1095,7 +1095,7 @@ ecc_get_param (const char *name, gcry_mpi_t *pkey)
 
   g_x = mpi_new (0);
   g_y = mpi_new (0);
-  ctx = _gcry_mpi_ec_init (E.p, E.a);
+  ctx = _gcry_mpi_ec_p_internal_new (E.p, E.a);
   if (_gcry_mpi_ec_get_affine (g_x, g_y, &E.G, ctx))
     log_fatal ("ecc get param: Failed to get affine coordinates\n");
   _gcry_mpi_ec_free (ctx);
@@ -1424,7 +1424,7 @@ ecc_encrypt_raw (int algo, gcry_mpi_t *resarr, gcry_mpi_t k,
       return err;
     }
 
-  ctx = _gcry_mpi_ec_init (pk.E.p, pk.E.a);
+  ctx = _gcry_mpi_ec_p_internal_new (pk.E.p, pk.E.a);
 
   /* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so */
   {
@@ -1536,7 +1536,7 @@ ecc_decrypt_raw (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
     }
   sk.d = skey[6];
 
-  ctx = _gcry_mpi_ec_init (sk.E.p, sk.E.a);
+  ctx = _gcry_mpi_ec_p_internal_new (sk.E.p, sk.E.a);
 
   /* R = dkG */
   point_init (&R);
index bb9bea4..e85ec04 100644 (file)
--- a/mpi/ec.c
+++ b/mpi/ec.c
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <errno.h>
 
 #include "mpi-internal.h"
 #include "longlong.h"
 #include "g10lib.h"
+#include "context.h"
 
 
 #define point_init(a)  _gcry_mpi_point_init ((a))
@@ -348,16 +350,13 @@ ec_invm (gcry_mpi_t x, gcry_mpi_t a, mpi_ec_t ctx)
 
 
 
-/* This function returns a new context for elliptic curve based on the
-   field GF(p).  P is the prime specifying thuis field, A is the first
-   coefficient.
-
-   This context needs to be released using _gcry_mpi_ec_free.  */
-mpi_ec_t
-_gcry_mpi_ec_init (gcry_mpi_t p, gcry_mpi_t a)
+/* This function initialized a context for elliptic curve based on the
+   field GF(p).  P is the prime specifying this field, A is the first
+   coefficient.  CTX is expected to be zeroized.  */
+static void
+ec_p_init (mpi_ec_t ctx, gcry_mpi_t p, gcry_mpi_t a)
 {
   int i;
-  mpi_ec_t ctx;
   gcry_mpi_t tmp;
 
   mpi_normalize (p);
@@ -367,8 +366,6 @@ _gcry_mpi_ec_init (gcry_mpi_t p, gcry_mpi_t a)
      a < p
   */
 
-  ctx = gcry_xcalloc (1, sizeof *ctx);
-
   ctx->p = mpi_copy (p);
   ctx->a = mpi_copy (a);
 
@@ -408,18 +405,15 @@ _gcry_mpi_ec_init (gcry_mpi_t p, gcry_mpi_t a)
 /*         ctx->s[i] = mpi_new (384); */
 /*       ctx->c    = mpi_new (384*2); */
 /*     } */
-
-  return ctx;
 }
 
-void
-_gcry_mpi_ec_free (mpi_ec_t ctx)
+
+static void
+ec_deinit (void *opaque)
 {
+  mpi_ec_t ctx = opaque;
   int i;
 
-  if (!ctx)
-    return;
-
   mpi_free (ctx->p);
   mpi_free (ctx->a);
 
@@ -446,8 +440,62 @@ _gcry_mpi_ec_free (mpi_ec_t ctx)
 /*         mpi_free (ctx->s[i]); */
 /*       mpi_free (ctx->c); */
 /*     } */
+}
+
 
-  gcry_free (ctx);
+/* This function returns a new context for elliptic curve based on the
+   field GF(p).  P is the prime specifying this field, A is the first
+   coefficient.  This function is only used within Libgcrypt and not
+   part of the public API.
+
+   This context needs to be released using _gcry_mpi_ec_free.  */
+mpi_ec_t
+_gcry_mpi_ec_p_internal_new (gcry_mpi_t p, gcry_mpi_t a)
+{
+  mpi_ec_t ctx;
+
+  ctx = gcry_xcalloc (1, sizeof *ctx);
+  ec_p_init (ctx, p, a);
+
+  return ctx;
+}
+
+
+void
+_gcry_mpi_ec_free (mpi_ec_t ctx)
+{
+  if (ctx)
+    {
+      ec_deinit (ctx);
+      gcry_free (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)
+{
+  gcry_ctx_t ctx;
+  mpi_ec_t ec;
+
+  if (!p || !a || !mpi_cmp_ui (a, 0))
+    {
+      gpg_err_set_errno (EINVAL);
+      return NULL;
+    }
+
+  ctx = _gcry_ctx_alloc (CONTEXT_TYPE_EC, sizeof *ec, ec_deinit);
+  if (!ctx)
+    return NULL;
+  ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
+  ec_p_init (ec, p, a);
+
+  return ctx;
 }
 
 
index 9e7dcd5..1869ad3 100644 (file)
@@ -59,7 +59,7 @@ libgcrypt_la_SOURCES = g10lib.h visibility.c visibility.h types.h \
        misc.c global.c sexp.c hwfeatures.c hwf-common.h \
        stdmem.c stdmem.h secmem.c secmem.h \
        mpi.h missing-string.c module.c fips.c \
-       hmac256.c hmac256.h \
+       hmac256.c hmac256.h context.c context.h \
        ath.h ath.c
 
 EXTRA_libgcrypt_la_SOURCES = hwf-x86.c
diff --git a/src/context.c b/src/context.c
new file mode 100644 (file)
index 0000000..ae991c5
--- /dev/null
@@ -0,0 +1,118 @@
+/* context.c - Context management
+ * 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/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "g10lib.h"
+#include "mpi.h"
+#include "context.h"
+
+#define CTX_MAGIC "cTx"
+#define CTX_MAGIC_LEN 3
+
+
+/* The definition of the generic context object.  The public typedef
+   gcry_ctx_t is used to access it.  */
+struct gcry_context
+{
+  char magic[CTX_MAGIC_LEN]; /* Magic value to cross check that this
+                                is really a context object. */
+  char type;     /* The type of the context (CONTEXT_TYPE_foo).  */
+
+  void (*deinit)(void*); /* Function used to free the private part. */
+  PROPERLY_ALIGNED_TYPE u;
+};
+
+
+/* Allocate a fresh generic context of contect TYPE and allocate
+   LENGTH extra bytes for private use of the type handler. DEINIT is a
+   fucntion used called to deinitialize the private part; it may be
+   NULL if de-initialization is not required.  Returns NULL and sets
+   ERRNO if memory allocation failed.  */
+gcry_ctx_t
+_gcry_ctx_alloc (int type, size_t length, void (*deinit)(void*))
+{
+  gcry_ctx_t ctx;
+
+  switch (type)
+    {
+    case CONTEXT_TYPE_EC:
+      break;
+    default:
+      log_bug ("bad context type %d given to _gcry_ctx_alloc\n", type);
+      break;
+    }
+
+  if (length < sizeof (PROPERLY_ALIGNED_TYPE))
+    length = sizeof (PROPERLY_ALIGNED_TYPE);
+
+  ctx = gcry_calloc (1, sizeof *ctx - sizeof (PROPERLY_ALIGNED_TYPE) + length);
+  if (!ctx)
+    return NULL;
+  memcpy (ctx->magic, CTX_MAGIC, CTX_MAGIC_LEN);
+  ctx->type = type;
+  ctx->deinit = deinit;
+
+  return ctx;
+}
+
+
+/* Return a pointer to the private part of the context CTX.  TYPE is
+   the requested context type.  Using an explicit type allows to cross
+   check the type and eventually allows to store several private
+   contexts in one context object.  The function does not return an
+   error but aborts if the provided CTX is not valid.  */
+void *
+_gcry_ctx_get_pointer (gcry_ctx_t ctx, int type)
+{
+  if (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",
+               type, ctx, ctx->type);
+  return &ctx->u;
+}
+
+
+/* Release the generic context CTX.  */
+void
+gcry_ctx_release (gcry_ctx_t ctx)
+{
+  if (!ctx)
+    return;
+  if (memcmp (ctx->magic, CTX_MAGIC, CTX_MAGIC_LEN))
+    log_fatal ("bad pointer %p passed to gcry_ctx_relase\n", ctx);
+  switch (ctx->type)
+    {
+    case CONTEXT_TYPE_EC:
+      break;
+    default:
+      log_fatal ("bad context type %d detected in gcry_ctx_relase\n",
+                 ctx->type);
+      break;
+    }
+  if (ctx->deinit)
+    ctx->deinit (&ctx->u);
+  gcry_free (ctx);
+}
diff --git a/src/context.h b/src/context.h
new file mode 100644 (file)
index 0000000..72f14d4
--- /dev/null
@@ -0,0 +1,31 @@
+/* context.h - Declarations for the context management
+ * 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_CONTEXT_H
+#define GCRY_CONTEXT_H
+
+/* Context types as used in struct gcry_context.  */
+#define CONTEXT_TYPE_EC 1  /* The context is used with EC functions.  */
+
+
+gcry_ctx_t _gcry_ctx_alloc (int type, size_t length, void (*deinit)(void*));
+void *_gcry_ctx_get_pointer (gcry_ctx_t ctx, int type);
+
+
+#endif /*GCRY_CONTEXT_H*/
index 5d2a779..57b841e 100644 (file)
@@ -212,6 +212,10 @@ struct gcry_thread_cbs
 
 
 \f
+/* A generic context object as used by some functions.  */
+struct gcry_context;
+typedef struct gcry_context *gcry_ctx_t;
+
 /* The data objects used to hold multi precision integers.  */
 struct gcry_mpi;
 typedef struct gcry_mpi *gcry_mpi_t;
@@ -599,6 +603,26 @@ gcry_mpi_point_t gcry_mpi_point_snatch_set (gcry_mpi_point_t point,
                                             gcry_mpi_t x, gcry_mpi_t y,
                                             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);
+
+/* 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,
+                            gcry_ctx_t ctx);
+
+/* W = 2 * U.  */
+void gcry_mpi_ec_dup (gcry_mpi_point_t w, gcry_mpi_point_t u, gcry_ctx_t ctx);
+
+/* W = U + V.  */
+void gcry_mpi_ec_add (gcry_mpi_point_t w,
+                      gcry_mpi_point_t u, gcry_mpi_point_t v, gcry_ctx_t ctx);
+
+/* W = N * U.  */
+void gcry_mpi_ec_mul (gcry_mpi_point_t w, gcry_mpi_t n, gcry_mpi_point_t u,
+                      gcry_ctx_t ctx);
+
 
 /* Return the number of bits required to represent A. */
 unsigned int gcry_mpi_get_nbits (gcry_mpi_t a);
@@ -1294,6 +1318,9 @@ gcry_error_t gcry_prime_check (gcry_mpi_t x, unsigned int flags);
  *                                  *
  ************************************/
 
+/* Release the context object CTX.  */
+void gcry_ctx_release (gcry_ctx_t ctx);
+
 /* Log levels used by the internal logging facility. */
 enum gcry_log_levels
   {
index 8f14dff..611f10f 100644 (file)
@@ -220,3 +220,11 @@ EXPORTS
       gcry_mpi_point_snatch_get @199
       gcry_mpi_point_set        @200
       gcry_mpi_point_snatch_set @201
+
+      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
index 5c43b95..4a375b2 100644 (file)
@@ -90,7 +90,11 @@ 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_get_affine;
+    gcry_mpi_ec_dup; gcry_mpi_ec_add; gcry_mpi_ec_mul;
 
+    gcry_ctx_release;
 
   local:
     *;
index b3f19e5..23afa68 100644 (file)
--- a/src/mpi.h
+++ b/src/mpi.h
@@ -251,7 +251,7 @@ void _gcry_mpi_snatch_point (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z,
 struct mpi_ec_ctx_s;
 typedef struct mpi_ec_ctx_s *mpi_ec_t;
 
-mpi_ec_t _gcry_mpi_ec_init (gcry_mpi_t p, gcry_mpi_t a);
+mpi_ec_t _gcry_mpi_ec_p_internal_new (gcry_mpi_t p, gcry_mpi_t a);
 void _gcry_mpi_ec_free (mpi_ec_t ctx);
 int _gcry_mpi_ec_get_affine (gcry_mpi_t x, gcry_mpi_t y, mpi_point_t point,
                              mpi_ec_t ctx);
index 1fb29f2..5c3216d 100644 (file)
@@ -24,8 +24,8 @@
 #define _GCRY_INCLUDED_BY_VISIBILITY_C
 #include "g10lib.h"
 #include "cipher-proto.h"
-
-
+#include "context.h"
+#include "mpi.h"
 
 const char *
 gcry_strerror (gcry_error_t err)
@@ -461,6 +461,42 @@ 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)
+{
+  return _gcry_mpi_ec_p_new (p, a);
+}
+
+int
+gcry_mpi_ec_get_affine (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_point_t point,
+                        gcry_ctx_t ctx)
+{
+  return _gcry_mpi_ec_get_affine (x, y, point,
+                                  _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC));
+}
+
+void
+gcry_mpi_ec_dup (gcry_mpi_point_t w, gcry_mpi_point_t u, gcry_ctx_t ctx)
+{
+  _gcry_mpi_ec_dup_point (w, u, _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC));
+}
+
+void
+gcry_mpi_ec_add (gcry_mpi_point_t w,
+                 gcry_mpi_point_t u, gcry_mpi_point_t v, gcry_ctx_t ctx)
+{
+  _gcry_mpi_ec_add_points (w, u, v,
+                           _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC));
+}
+
+void
+gcry_mpi_ec_mul (gcry_mpi_point_t w, gcry_mpi_t n, gcry_mpi_point_t u,
+                 gcry_ctx_t ctx)
+{
+  _gcry_mpi_ec_mul_point (w, n, u,
+                          _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC));
+}
+
 unsigned int
 gcry_mpi_get_nbits (gcry_mpi_t a)
 {
@@ -1067,6 +1103,12 @@ gcry_prime_check (gcry_mpi_t x, unsigned int flags)
 }
 
 void
+gcry_ctx_release (gcry_ctx_t ctx)
+{
+  _gcry_ctx_release (ctx);
+}
+
+void
 gcry_set_progress_handler (gcry_handler_progress_t cb, void *cb_data)
 {
   _gcry_set_progress_handler (cb, cb_data);
index f4507ce..90c6ad1 100644 (file)
 #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
 #define gcry_mpi_swap               _gcry_mpi_swap
 #define gcry_mpi_test_bit           _gcry_mpi_test_bit
 
+#define gcry_ctx_release            _gcry_ctx_release
+
 
 /* Include the main header here so that public symbols are mapped to
    the internal underscored ones.  */
@@ -367,6 +370,7 @@ 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
@@ -405,6 +409,8 @@ gcry_err_code_t gcry_md_get (gcry_md_hd_t hd, int algo,
 #undef gcry_mpi_swap
 #undef gcry_mpi_test_bit
 
+#undef gcry_ctx_release
+
 
 /* Now mark all symbols.  */
 
@@ -540,6 +546,11 @@ MARK_VISIBLE (gcry_mpi_cmp_ui)
 MARK_VISIBLE (gcry_mpi_copy)
 MARK_VISIBLE (gcry_mpi_div)
 MARK_VISIBLE (gcry_mpi_dump)
+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_VISIBLE (gcry_mpi_gcd)
 MARK_VISIBLE (gcry_mpi_get_flag)
 MARK_VISIBLE (gcry_mpi_get_nbits)
@@ -578,6 +589,7 @@ MARK_VISIBLE (gcry_mpi_subm)
 MARK_VISIBLE (gcry_mpi_swap)
 MARK_VISIBLE (gcry_mpi_test_bit)
 
+MARK_VISIBLE (gcry_ctx_release)
 
 
 #undef MARK_VISIBLE
index 548d6c7..8714d38 100644 (file)
 
 static const char *wherestr;
 static int verbose;
+static int debug;
 static int error_count;
 
+
 #define xmalloc(a)    gcry_xmalloc ((a))
 #define xcalloc(a,b)  gcry_xcalloc ((a),(b))
 #define xfree(a)      gcry_free ((a))
@@ -83,6 +85,52 @@ die (const char *format, ...)
 }
 
 
+static void
+print_mpi (const char *text, gcry_mpi_t a)
+{
+  gcry_error_t err;
+  char *buf;
+  void *bufaddr = &buf;
+
+  err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a);
+  if (err)
+    fprintf (stderr, "%s: [error printing number: %s]\n",
+             text, gpg_strerror (err));
+  else
+    {
+      fprintf (stderr, "%s: %s\n", text, buf);
+      gcry_free (buf);
+    }
+}
+
+
+static gcry_mpi_t
+hex2mpi (const char *string)
+{
+  gpg_error_t err;
+  gcry_mpi_t val;
+
+  err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
+  if (err)
+    die ("hex2mpi '%s' failed: %s\n", gpg_strerror (err));
+  return val;
+}
+
+
+/* Compare A to B, where B is given as a hex string.  */
+static int
+cmp_mpihex (gcry_mpi_t a, const char *b)
+{
+  gcry_mpi_t bval;
+  int res;
+
+  bval = hex2mpi (b);
+  res = gcry_mpi_cmp (a, bval);
+  gcry_mpi_release (bval);
+  return res;
+}
+
+
 \f
 static void
 set_get_point (void)
@@ -138,10 +186,127 @@ set_get_point (void)
 }
 
 
+static void
+context_alloc (void)
+{
+  gcry_ctx_t ctx;
+  gcry_mpi_t p, a;
+
+  wherestr = "context_alloc";
+  show ("checking context functions\n");
+
+  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 ()));
+  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");
+
+  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");
+
+  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");
+
+  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");
+
+}
+
+
+/* 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)
+{
+  gcry_mpi_point_t point;
+
+  point = gcry_mpi_point_new (0);
+  gcry_mpi_point_snatch_set (point, hex2mpi (x), hex2mpi (y), hex2mpi (z));
+
+  return point;
+}
+
+
+static void
+basic_ec_math (void)
+{
+  gcry_ctx_t ctx;
+  gcry_mpi_t P, A;
+  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\n");
+
+  P = hex2mpi ("0xfffffffffffffffffffffffffffffffeffffffffffffffff");
+  A = hex2mpi ("0xfffffffffffffffffffffffffffffffefffffffffffffffc");
+  G = make_point ("188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
+                  "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
+                  "1");
+  d = hex2mpi ("D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D");
+  Q = gcry_mpi_point_new (0);
+
+  ctx = gcry_mpi_ec_p_new (P, A);
+  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);
+  gcry_mpi_release (A);
+  gcry_mpi_release (P);
+}
+
+
 int
 main (int argc, char **argv)
 {
-  int debug = 0;
 
   if (argc > 1 && !strcmp (argv[1], "--verbose"))
     verbose = 1;
@@ -158,7 +323,8 @@ main (int argc, char **argv)
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 
   set_get_point ();
-
+  context_alloc ();
+  basic_ec_math ();
 
   show ("All tests completed. Errors: %d\n", error_count);
   return error_count ? 1 : 0;