ecc: Use constant time point operation for Twisted Edwards.
[libgcrypt.git] / mpi / ec.c
index 889df8e..6fca95b 100644 (file)
--- a/mpi/ec.c
+++ b/mpi/ec.c
@@ -288,6 +288,16 @@ ec_pow2 (gcry_mpi_t w, const gcry_mpi_t b, mpi_ec_t ctx)
 }
 
 
+/* Shortcut for
+     ec_powm (B, B, mpi_const (MPI_C_THREE), ctx);
+   for easier optimization.  */
+static void
+ec_pow3 (gcry_mpi_t w, const gcry_mpi_t b, mpi_ec_t ctx)
+{
+  mpi_powm (w, b, mpi_const (MPI_C_THREE), ctx->p);
+}
+
+
 static void
 ec_invm (gcry_mpi_t x, gcry_mpi_t a, mpi_ec_t ctx)
 {
@@ -350,6 +360,7 @@ ec_get_two_inv_p (mpi_ec_t ec)
 static void
 ec_p_init (mpi_ec_t ctx, enum gcry_mpi_ec_models model,
            enum ecc_dialects dialect,
+           int flags,
            gcry_mpi_t p, gcry_mpi_t a, gcry_mpi_t b)
 {
   int i;
@@ -367,14 +378,14 @@ ec_p_init (mpi_ec_t ctx, enum gcry_mpi_ec_models model,
 
   ctx->model = model;
   ctx->dialect = dialect;
+  ctx->flags = flags;
   if (dialect == ECC_DIALECT_ED25519)
     ctx->nbits = 256;
   else
     ctx->nbits = mpi_get_nbits (p);
   ctx->p = mpi_copy (p);
   ctx->a = mpi_copy (a);
-  if (b && model == MPI_EC_TWISTEDEDWARDS)
-    ctx->b = mpi_copy (b);
+  ctx->b = mpi_copy (b);
 
   ctx->t.p_barrett = use_barrett > 0? _gcry_mpi_barrett_init (ctx->p, 0):NULL;
 
@@ -454,19 +465,20 @@ ec_deinit (void *opaque)
 mpi_ec_t
 _gcry_mpi_ec_p_internal_new (enum gcry_mpi_ec_models model,
                              enum ecc_dialects dialect,
+                             int flags,
                              gcry_mpi_t p, gcry_mpi_t a, gcry_mpi_t b)
 {
   mpi_ec_t ctx;
 
   ctx = gcry_xcalloc (1, sizeof *ctx);
-  ec_p_init (ctx, model, dialect, p, a, b);
+  ec_p_init (ctx, model, dialect, flags, p, a, b);
 
   return ctx;
 }
 
 
 /* This is a variant of _gcry_mpi_ec_p_internal_new which returns an
-   public contect and does some error checking on the supplied
+   public context and does some error checking on the supplied
    arguments.  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.
@@ -476,6 +488,7 @@ gpg_err_code_t
 _gcry_mpi_ec_p_new (gcry_ctx_t *r_ctx,
                     enum gcry_mpi_ec_models model,
                     enum ecc_dialects dialect,
+                    int flags,
                     gcry_mpi_t p, gcry_mpi_t a, gcry_mpi_t b)
 {
   gcry_ctx_t ctx;
@@ -489,7 +502,7 @@ _gcry_mpi_ec_p_new (gcry_ctx_t *r_ctx,
   if (!ctx)
     return gpg_err_code_from_syserror ();
   ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
-  ec_p_init (ec, model, dialect, p, a, b);
+  ec_p_init (ec, model, dialect, flags, p, a, b);
 
   *r_ctx = ctx;
   return 0;
@@ -1104,11 +1117,30 @@ _gcry_mpi_ec_mul_point (mpi_point_t result,
       mpi_set_ui (result->y, 1);
       mpi_set_ui (result->z, 1);
 
-      for (j=nbits-1; j >= 0; j--)
+      if (mpi_is_secure (scalar))
+        {
+          /* If SCALAR is in secure memory we assume that it is the
+             secret key we use constant time operation.  */
+          mpi_point_struct tmppnt;
+
+          point_init (&tmppnt);
+          for (j=nbits-1; j >= 0; j--)
+            {
+              _gcry_mpi_ec_dup_point (result, result, ctx);
+              _gcry_mpi_ec_add_points (&tmppnt, result, point, ctx);
+              if (mpi_test_bit (scalar, j))
+                point_set (result, &tmppnt);
+            }
+          point_free (&tmppnt);
+        }
+      else
         {
-          _gcry_mpi_ec_dup_point (result, result, ctx);
-          if (mpi_test_bit (scalar, j) == 1)
-            _gcry_mpi_ec_add_points (result, result, point, ctx);
+          for (j=nbits-1; j >= 0; j--)
+            {
+              _gcry_mpi_ec_dup_point (result, result, ctx);
+              if (mpi_test_bit (scalar, j))
+                _gcry_mpi_ec_add_points (result, result, point, ctx);
+            }
         }
       return;
     }
@@ -1216,8 +1248,22 @@ _gcry_mpi_ec_curve_point (gcry_mpi_point_t point, mpi_ec_t ctx)
   switch (ctx->model)
     {
     case MPI_EC_WEIERSTRASS:
-      log_fatal ("%s: %s not yet supported\n",
-                 "_gcry_mpi_ec_curve_point", "Weierstrass");
+      {
+        gcry_mpi_t xxx = mpi_new (0);
+
+        /* y^2 == x^3 + a·x + b */
+        ec_pow2 (y, y, ctx);
+
+        ec_pow3 (xxx, x, ctx);
+        ec_mulm (w, ctx->a, x, ctx);
+        ec_addm (w, w, ctx->b, ctx);
+        ec_addm (w, w, xxx, ctx);
+
+        if (!mpi_cmp (y, w))
+          res = 1;
+
+        gcry_mpi_release (xxx);
+      }
       break;
     case MPI_EC_MONTGOMERY:
       log_fatal ("%s: %s not yet supported\n",