summaryrefslogtreecommitdiff
path: root/plugins/MirOTR/Libgcrypt/mpi/ec.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/MirOTR/Libgcrypt/mpi/ec.c')
-rw-r--r--plugins/MirOTR/Libgcrypt/mpi/ec.c1241
1 files changed, 916 insertions, 325 deletions
diff --git a/plugins/MirOTR/Libgcrypt/mpi/ec.c b/plugins/MirOTR/Libgcrypt/mpi/ec.c
index 4a3a5f8c08..168076f4bd 100644
--- a/plugins/MirOTR/Libgcrypt/mpi/ec.c
+++ b/plugins/MirOTR/Libgcrypt/mpi/ec.c
@@ -1,73 +1,117 @@
/* ec.c - Elliptic Curve functions
- Copyright (C) 2007 Free Software Foundation, Inc.
-
- 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ * 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 <errno.h>
#include "mpi-internal.h"
#include "longlong.h"
#include "g10lib.h"
+#include "context.h"
+#include "ec-context.h"
+#include "ec-internal.h"
-#define point_init(a) _gcry_mpi_ec_point_init ((a))
-#define point_free(a) _gcry_mpi_ec_point_free ((a))
-
+#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
+/* Print a point using the log fucntions. If CTX is not NULL affine
+ coordinates will be printed. */
+void
+_gcry_mpi_point_log (const char *name, mpi_point_t point, mpi_ec_t ctx)
{
- /* Domain parameters. */
- gcry_mpi_t p; /* Prime specifying the field GF(p). */
- gcry_mpi_t a; /* First coefficient of the Weierstrass equation. */
+ gcry_mpi_t x, y;
+ char buf[100];
- int a_is_pminus3; /* True if A = P - 3. */
+ if (!point)
+ {
+ snprintf (buf, sizeof buf - 1, "%s.*", name);
+ log_mpidump (buf, NULL);
+ return;
+ }
+ snprintf (buf, sizeof buf - 1, "%s.X", name);
+
+ if (ctx)
+ {
+ x = mpi_new (0);
+ y = mpi_new (0);
+ }
+ if (!ctx || _gcry_mpi_ec_get_affine (x, y, point, ctx))
+ {
+ log_mpidump (buf, point->x);
+ buf[strlen(buf)-1] = 'Y';
+ log_mpidump (buf, point->y);
+ buf[strlen(buf)-1] = 'Z';
+ log_mpidump (buf, point->z);
+ }
+ else
+ {
+ buf[strlen(buf)-1] = 'x';
+ log_mpidump (buf, x);
+ buf[strlen(buf)-1] = 'y';
+ log_mpidump (buf, y);
- /* 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;
+ }
+ if (ctx)
+ {
+ _gcry_mpi_release (x);
+ _gcry_mpi_release (y);
+ }
+}
- /* 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. */
+mpi_point_t
+_gcry_mpi_point_new (unsigned int nbits)
+{
+ mpi_point_t p;
+ (void)nbits; /* Currently not used. */
+ p = xmalloc (sizeof *p);
+ _gcry_mpi_point_init (p);
+ return p;
+}
-/* Initialized a point object. gcry_mpi_ec_point_free shall be used
- to release this object. */
+
+/* Release the point object P. P may be NULL. */
void
-_gcry_mpi_ec_point_init (mpi_point_t *p)
+_gcry_mpi_point_release (mpi_point_t p)
+{
+ if (p)
+ {
+ _gcry_mpi_point_free_parts (p);
+ xfree (p);
+ }
+}
+
+
+/* Initialize the fields of a point object. gcry_mpi_point_free_parts
+ may be used to release the fields. */
+void
+_gcry_mpi_point_init (mpi_point_t p)
{
p->x = mpi_new (0);
p->y = mpi_new (0);
@@ -75,18 +119,19 @@ _gcry_mpi_ec_point_init (mpi_point_t *p)
}
-/* Release a point object. */
+/* Release the parts of a point object. */
void
-_gcry_mpi_ec_point_free (mpi_point_t *p)
+_gcry_mpi_point_free_parts (mpi_point_t p)
{
mpi_free (p->x); p->x = NULL;
mpi_free (p->y); p->y = NULL;
mpi_free (p->z); p->z = NULL;
}
+
/* Set the value from S into D. */
static void
-point_set (mpi_point_t *d, mpi_point_t *s)
+point_set (mpi_point_t d, mpi_point_t s)
{
mpi_set (d->x, s->x);
mpi_set (d->y, s->y);
@@ -94,132 +139,132 @@ point_set (mpi_point_t *d, mpi_point_t *s)
}
+/* 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
+_gcry_mpi_point_get (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z,
+ mpi_point_t point)
+{
+ if (x)
+ mpi_set (x, point->x);
+ if (y)
+ mpi_set (y, point->y);
+ if (z)
+ mpi_set (z, point->z);
+}
+
+
+/* Set the projective coordinates from POINT into X, Y, and Z and
+ release POINT. If a coordinate is not required, X, Y, or Z may be
+ passed as NULL. */
+void
+_gcry_mpi_point_snatch_get (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z,
+ mpi_point_t point)
+{
+ mpi_snatch (x, point->x);
+ mpi_snatch (y, point->y);
+ mpi_snatch (z, point->z);
+ xfree (point);
+}
+
+
+/* Set the projective coordinates from X, Y, and Z into POINT. If a
+ coordinate is given as NULL, the value 0 is stored into point. If
+ POINT is given as NULL a new point object is allocated. Returns
+ POINT or the newly allocated point object. */
+mpi_point_t
+_gcry_mpi_point_set (mpi_point_t point,
+ gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z)
+{
+ if (!point)
+ point = mpi_point_new (0);
+
+ if (x)
+ mpi_set (point->x, x);
+ else
+ mpi_clear (point->x);
+ if (y)
+ mpi_set (point->y, y);
+ else
+ mpi_clear (point->y);
+ if (z)
+ mpi_set (point->z, z);
+ else
+ mpi_clear (point->z);
+
+ return point;
+}
+
+
+/* Set the projective coordinates from X, Y, and Z into POINT. If a
+ coordinate is given as NULL, the value 0 is stored into point. If
+ POINT is given as NULL a new point object is allocated. The
+ coordinates X, Y, and Z are released. Returns POINT or the newly
+ allocated point object. */
+mpi_point_t
+_gcry_mpi_point_snatch_set (mpi_point_t point,
+ gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z)
+{
+ if (!point)
+ point = mpi_point_new (0);
+
+ if (x)
+ mpi_snatch (point->x, x);
+ else
+ mpi_clear (point->x);
+ if (y)
+ mpi_snatch (point->y, y);
+ else
+ mpi_clear (point->y);
+ if (z)
+ mpi_snatch (point->z, z);
+ else
+ mpi_clear (point->z);
+
+ return point;
+}
+
+
+/* W = W mod P. */
+static void
+ec_mod (gcry_mpi_t w, mpi_ec_t ec)
+{
+ if (0 && ec->dialect == ECC_DIALECT_ED25519)
+ _gcry_mpi_ec_ed25519_mod (w);
+ else if (ec->t.p_barrett)
+ _gcry_mpi_mod_barrett (w, w, ec->t.p_barrett);
+ else
+ _gcry_mpi_mod (w, w, ec->p);
+}
static void
ec_addm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx)
{
- mpi_addm (w, u, v, ctx->p);
+ mpi_add (w, u, v);
+ ec_mod (w, ctx);
}
static void
-ec_subm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx)
+ec_subm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ec)
{
- mpi_subm (w, u, v, ctx->p);
+ (void)ec;
+ mpi_sub (w, u, v);
+ /*ec_mod (w, ec);*/
}
static void
ec_mulm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx)
{
-#if 0
- /* NOTE: This code works only for limb sizes of 32 bit. */
- mpi_limb_t *wp, *sp;
+ mpi_mul (w, u, v);
+ ec_mod (w, ctx);
+}
- if (ctx->nist_nbits == 192)
- {
- mpi_mul (w, u, v);
- mpi_resize (w, 12);
- wp = w->d;
-
- sp = ctx->s[0]->d;
- sp[0*2+0] = wp[0*2+0];
- sp[0*2+1] = wp[0*2+1];
- sp[1*2+0] = wp[1*2+0];
- sp[1*2+1] = wp[1*2+1];
- sp[2*2+0] = wp[2*2+0];
- sp[2*2+1] = wp[2*2+1];
-
- sp = ctx->s[1]->d;
- sp[0*2+0] = wp[3*2+0];
- sp[0*2+1] = wp[3*2+1];
- sp[1*2+0] = wp[3*2+0];
- sp[1*2+1] = wp[3*2+1];
- sp[2*2+0] = 0;
- sp[2*2+1] = 0;
-
- sp = ctx->s[2]->d;
- sp[0*2+0] = 0;
- sp[0*2+1] = 0;
- sp[1*2+0] = wp[4*2+0];
- sp[1*2+1] = wp[4*2+1];
- sp[2*2+0] = wp[4*2+0];
- sp[2*2+1] = wp[4*2+1];
-
- sp = ctx->s[3]->d;
- sp[0*2+0] = wp[5*2+0];
- sp[0*2+1] = wp[5*2+1];
- sp[1*2+0] = wp[5*2+0];
- sp[1*2+1] = wp[5*2+1];
- sp[2*2+0] = wp[5*2+0];
- sp[2*2+1] = wp[5*2+1];
-
- ctx->s[0]->nlimbs = 6;
- ctx->s[1]->nlimbs = 6;
- ctx->s[2]->nlimbs = 6;
- ctx->s[3]->nlimbs = 6;
-
- mpi_add (ctx->c, ctx->s[0], ctx->s[1]);
- mpi_add (ctx->c, ctx->c, ctx->s[2]);
- mpi_add (ctx->c, ctx->c, ctx->s[3]);
-
- while ( mpi_cmp (ctx->c, ctx->p ) >= 0 )
- mpi_sub ( ctx->c, ctx->c, ctx->p );
- mpi_set (w, ctx->c);
- }
- else if (ctx->nist_nbits == 384)
- {
- int i;
- mpi_mul (w, u, v);
- mpi_resize (w, 24);
- wp = w->d;
-
-#define NEXT(a) do { ctx->s[(a)]->nlimbs = 12; \
- sp = ctx->s[(a)]->d; \
- i = 0; } while (0)
-#define X(a) do { sp[i++] = wp[(a)];} while (0)
-#define X0(a) do { sp[i++] = 0; } while (0)
- NEXT(0);
- X(0);X(1);X(2);X(3);X(4);X(5);X(6);X(7);X(8);X(9);X(10);X(11);
- NEXT(1);
- X0();X0();X0();X0();X(21);X(22);X(23);X0();X0();X0();X0();X0();
- NEXT(2);
- X(12);X(13);X(14);X(15);X(16);X(17);X(18);X(19);X(20);X(21);X(22);X(23);
- NEXT(3);
- X(21);X(22);X(23);X(12);X(13);X(14);X(15);X(16);X(17);X(18);X(19);X(20);
- NEXT(4);
- X0();X(23);X0();X(20);X(12);X(13);X(14);X(15);X(16);X(17);X(18);X(19);
- NEXT(5);
- X0();X0();X0();X0();X(20);X(21);X(22);X(23);X0();X0();X0();X0();
- NEXT(6);
- X(20);X0();X0();X(21);X(22);X(23);X0();X0();X0();X0();X0();X0();
- NEXT(7);
- X(23);X(12);X(13);X(14);X(15);X(16);X(17);X(18);X(19);X(20);X(21);X(22);
- NEXT(8);
- X0();X(20);X(21);X(22);X(23);X0();X0();X0();X0();X0();X0();X0();
- NEXT(9);
- X0();X0();X0();X(23);X(23);X0();X0();X0();X0();X0();X0();X0();
-#undef X0
-#undef X
-#undef NEXT
- mpi_add (ctx->c, ctx->s[0], ctx->s[1]);
- mpi_add (ctx->c, ctx->c, ctx->s[1]);
- mpi_add (ctx->c, ctx->c, ctx->s[2]);
- mpi_add (ctx->c, ctx->c, ctx->s[3]);
- mpi_add (ctx->c, ctx->c, ctx->s[4]);
- mpi_add (ctx->c, ctx->c, ctx->s[5]);
- mpi_add (ctx->c, ctx->c, ctx->s[6]);
- mpi_sub (ctx->c, ctx->c, ctx->s[7]);
- mpi_sub (ctx->c, ctx->c, ctx->s[8]);
- mpi_sub (ctx->c, ctx->c, ctx->s[9]);
-
- while ( mpi_cmp (ctx->c, ctx->p ) >= 0 )
- mpi_sub ( ctx->c, ctx->c, ctx->p );
- while ( ctx->c->sign )
- mpi_add ( ctx->c, ctx->c, ctx->p );
- mpi_set (w, ctx->c);
- }
- else
-#endif /*0*/
- mpi_mulm (w, u, v, ctx->p);
+/* W = 2 * U mod P. */
+static void
+ec_mul2 (gcry_mpi_t w, gcry_mpi_t u, mpi_ec_t ctx)
+{
+ mpi_lshift (w, u, 1);
+ ec_mod (w, ctx);
}
static void
@@ -227,58 +272,128 @@ ec_powm (gcry_mpi_t w, const gcry_mpi_t b, const gcry_mpi_t e,
mpi_ec_t ctx)
{
mpi_powm (w, b, e, ctx->p);
+ /* _gcry_mpi_abs (w); */
}
+
+/* Shortcut for
+ ec_powm (B, B, mpi_const (MPI_C_TWO), ctx);
+ for easier optimization. */
+static void
+ec_pow2 (gcry_mpi_t w, const gcry_mpi_t b, mpi_ec_t ctx)
+{
+ /* Using mpi_mul is slightly faster (at least on amd64). */
+ /* mpi_powm (w, b, mpi_const (MPI_C_TWO), ctx->p); */
+ ec_mulm (w, b, b, 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)
{
- mpi_invm (x, a, ctx->p);
+ if (!mpi_invm (x, a, ctx->p))
+ {
+ log_error ("ec_invm: inverse does not exist:\n");
+ log_mpidump (" a", a);
+ log_mpidump (" p", ctx->p);
+ }
}
+/* Force recomputation of all helper variables. */
+void
+_gcry_mpi_ec_get_reset (mpi_ec_t ec)
+{
+ ec->t.valid.a_is_pminus3 = 0;
+ ec->t.valid.two_inv_p = 0;
+}
-/* 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)
+/* Accessor for helper variable. */
+static int
+ec_get_a_is_pminus3 (mpi_ec_t ec)
{
- int i;
- mpi_ec_t ctx;
gcry_mpi_t tmp;
- mpi_normalize (p);
- mpi_normalize (a);
+ if (!ec->t.valid.a_is_pminus3)
+ {
+ ec->t.valid.a_is_pminus3 = 1;
+ tmp = mpi_alloc_like (ec->p);
+ mpi_sub_ui (tmp, ec->p, 3);
+ ec->t.a_is_pminus3 = !mpi_cmp (ec->a, tmp);
+ mpi_free (tmp);
+ }
+
+ return ec->t.a_is_pminus3;
+}
+
+
+/* Accessor for helper variable. */
+static gcry_mpi_t
+ec_get_two_inv_p (mpi_ec_t ec)
+{
+ if (!ec->t.valid.two_inv_p)
+ {
+ ec->t.valid.two_inv_p = 1;
+ if (!ec->t.two_inv_p)
+ ec->t.two_inv_p = mpi_alloc (0);
+ ec_invm (ec->t.two_inv_p, mpi_const (MPI_C_TWO), ec);
+ }
+ return ec->t.two_inv_p;
+}
+
+
- /* Fixme: Do we want to check some constraints? e.g.
- a < p
- */
+/* 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, 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;
+ static int use_barrett;
+
+ if (!use_barrett)
+ {
+ if (getenv ("GCRYPT_BARRETT"))
+ use_barrett = 1;
+ else
+ use_barrett = -1;
+ }
- ctx = gcry_xcalloc (1, sizeof *ctx);
+ /* Fixme: Do we want to check some constraints? e.g. a < p */
+ 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);
+ ctx->b = mpi_copy (b);
- tmp = mpi_alloc_like (ctx->p);
- mpi_sub_ui (tmp, ctx->p, 3);
- ctx->a_is_pminus3 = !mpi_cmp (ctx->a, tmp);
- mpi_free (tmp);
-
+ ctx->t.p_barrett = use_barrett > 0? _gcry_mpi_barrett_init (ctx->p, 0):NULL;
- /* 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);
+ _gcry_mpi_ec_get_reset (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
@@ -297,31 +412,33 @@ _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;
+ _gcry_mpi_barrett_free (ctx->t.p_barrett);
+ /* Domain parameter. */
mpi_free (ctx->p);
mpi_free (ctx->a);
+ mpi_free (ctx->b);
+ _gcry_mpi_point_release (ctx->G);
+ mpi_free (ctx->n);
- mpi_free (ctx->one);
- mpi_free (ctx->two);
- mpi_free (ctx->three);
- mpi_free (ctx->four);
- mpi_free (ctx->eight);
+ /* 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) */
/* { */
@@ -335,64 +452,198 @@ _gcry_mpi_ec_free (mpi_ec_t ctx)
/* mpi_free (ctx->s[i]); */
/* mpi_free (ctx->c); */
/* } */
+}
+
+
+/* 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, B is the second coefficient, and MODEL is the model
+ for the curve. 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 (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 = xcalloc (1, sizeof *ctx);
+ 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 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.
+
+ The context needs to be released using gcry_ctx_release. */
+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;
+ mpi_ec_t ec;
- gcry_free (ctx);
+ *r_ctx = NULL;
+ if (!p || !a || !mpi_cmp_ui (a, 0))
+ return GPG_ERR_EINVAL;
+
+ ctx = _gcry_ctx_alloc (CONTEXT_TYPE_EC, sizeof *ec, ec_deinit);
+ if (!ctx)
+ return gpg_err_code_from_syserror ();
+ ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
+ ec_p_init (ec, model, dialect, flags, p, a, b);
+
+ *r_ctx = ctx;
+ return 0;
+}
+
+
+void
+_gcry_mpi_ec_free (mpi_ec_t ctx)
+{
+ if (ctx)
+ {
+ ec_deinit (ctx);
+ xfree (ctx);
+ }
}
+
+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);
+
+ return _gcry_ecc_get_mpi (name, ec, copy);
+}
+
+
+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. */
+
+ return _gcry_ecc_get_point (name, ec);
+}
+
+
+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);
+
+ return _gcry_ecc_set_mpi (name, newvalue, ec);
+}
+
+
+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);
+
+ return _gcry_ecc_set_point (name, newvalue, ec);
+}
+
+
/* Compute the affine coordinates from the projective coordinates in
POINT. Set them into X and Y. If one coordinate is not required,
X or Y may be passed as NULL. CTX is the usual context. Returns: 0
on success or !0 if POINT is at infinity. */
int
-_gcry_mpi_ec_get_affine (gcry_mpi_t x, gcry_mpi_t y, mpi_point_t *point,
+_gcry_mpi_ec_get_affine (gcry_mpi_t x, gcry_mpi_t y, mpi_point_t point,
mpi_ec_t ctx)
{
- gcry_mpi_t z1, z2, z3;
-
if (!mpi_cmp_ui (point->z, 0))
return -1;
- z1 = mpi_new (0);
- z2 = mpi_new (0);
- ec_invm (z1, point->z, ctx); /* z1 = z^(-1) mod p */
- ec_mulm (z2, z1, z1, ctx); /* z2 = z^(-2) mod p */
-
- if (x)
- ec_mulm (x, point->x, z2, ctx);
-
- if (y)
+ switch (ctx->model)
{
- z3 = mpi_new (0);
- ec_mulm (z3, z2, z1, ctx); /* z3 = z^(-3) mod p */
- ec_mulm (y, point->y, z3, ctx);
- mpi_free (z3);
+ case MPI_EC_WEIERSTRASS: /* Using Jacobian coordinates. */
+ {
+ gcry_mpi_t z1, z2, z3;
+
+ z1 = mpi_new (0);
+ z2 = mpi_new (0);
+ ec_invm (z1, point->z, ctx); /* z1 = z^(-1) mod p */
+ ec_mulm (z2, z1, z1, ctx); /* z2 = z^(-2) mod p */
+
+ if (x)
+ ec_mulm (x, point->x, z2, ctx);
+
+ if (y)
+ {
+ z3 = mpi_new (0);
+ ec_mulm (z3, z2, z1, ctx); /* z3 = z^(-3) mod p */
+ ec_mulm (y, point->y, z3, ctx);
+ mpi_free (z3);
+ }
+
+ mpi_free (z2);
+ mpi_free (z1);
+ }
+ return 0;
+
+ case MPI_EC_MONTGOMERY:
+ {
+ log_fatal ("%s: %s not yet supported\n",
+ "_gcry_mpi_ec_get_affine", "Montgomery");
+ }
+ return -1;
+
+ case MPI_EC_TWISTEDEDWARDS:
+ {
+ gcry_mpi_t z;
+
+ z = mpi_new (0);
+ ec_invm (z, point->z, ctx);
+
+ if (x)
+ ec_mulm (x, point->x, z, ctx);
+ if (y)
+ ec_mulm (y, point->y, z, ctx);
+
+ _gcry_mpi_release (z);
+ }
+ return 0;
+
+ default:
+ return -1;
}
-
- mpi_free (z2);
- mpi_free (z1);
- return 0;
}
-
-
-/* RESULT = 2 * POINT */
-void
-_gcry_mpi_ec_dup_point (mpi_point_t *result, mpi_point_t *point, mpi_ec_t ctx)
+/* RESULT = 2 * POINT (Weierstrass version). */
+static void
+dup_point_weierstrass (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))
- {
+ {
/* P_y == 0 || P_z == 0 => [1:1:0] */
mpi_set_ui (x3, 1);
mpi_set_ui (y3, 1);
@@ -400,47 +651,47 @@ _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 (ec_get_a_is_pminus3 (ctx)) /* Use the faster case. */
+ {
/* 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_subm (l1, point->x, t1, ctx);
- ec_mulm (l1, l1, ctx->three, ctx);
- ec_addm (t2, point->x, t1, ctx);
- ec_mulm (l1, l1, t2, ctx);
+ ec_pow2 (t1, point->z, ctx);
+ ec_subm (l1, point->x, t1, ctx);
+ ec_mulm (l1, l1, mpi_const (MPI_C_THREE), ctx);
+ ec_addm (t2, point->x, t1, ctx);
+ ec_mulm (l1, l1, t2, ctx);
}
else /* Standard case. */
{
/* 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_mulm (t1, t1, ctx->a, ctx);
- ec_addm (l1, l1, t1, ctx);
+ ec_pow2 (l1, point->x, 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_mul2 (z3, z3, ctx);
/* L2 = 4XY^2 */
/* T2: used for Y2; required later. */
- ec_powm (t2, point->y, ctx->two, ctx);
+ ec_pow2 (t2, point->y, 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_pow2 (x3, l1, ctx);
+ ec_mul2 (t1, l2, 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_pow2 (t2, t2, ctx);
+ ec_mulm (l3, t2, mpi_const (MPI_C_EIGHT), ctx);
/* Y3 = L1(L2 - X3) - L3 */
ec_subm (y3, l2, x3, ctx);
@@ -460,12 +711,118 @@ _gcry_mpi_ec_dup_point (mpi_point_t *result, mpi_point_t *point, mpi_ec_t ctx)
}
+/* RESULT = 2 * POINT (Montgomery version). */
+static void
+dup_point_montgomery (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx)
+{
+ (void)result;
+ (void)point;
+ (void)ctx;
+ log_fatal ("%s: %s not yet supported\n",
+ "_gcry_mpi_ec_dup_point", "Montgomery");
+}
+
+
+/* RESULT = 2 * POINT (Twisted Edwards version). */
+static void
+dup_point_twistededwards (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx)
+{
+#define X1 (point->x)
+#define Y1 (point->y)
+#define Z1 (point->z)
+#define X3 (result->x)
+#define Y3 (result->y)
+#define Z3 (result->z)
+#define B (ctx->t.scratch[0])
+#define C (ctx->t.scratch[1])
+#define D (ctx->t.scratch[2])
+#define E (ctx->t.scratch[3])
+#define F (ctx->t.scratch[4])
+#define H (ctx->t.scratch[5])
+#define J (ctx->t.scratch[6])
+
+ /* Compute: (X_3 : Y_3 : Z_3) = 2( X_1 : Y_1 : Z_1 ) */
+
+ /* B = (X_1 + Y_1)^2 */
+ ec_addm (B, X1, Y1, ctx);
+ ec_pow2 (B, B, ctx);
+
+ /* C = X_1^2 */
+ /* D = Y_1^2 */
+ ec_pow2 (C, X1, ctx);
+ ec_pow2 (D, Y1, ctx);
+
+ /* E = aC */
+ if (ctx->dialect == ECC_DIALECT_ED25519)
+ {
+ mpi_set (E, C);
+ _gcry_mpi_neg (E, E);
+ }
+ else
+ ec_mulm (E, ctx->a, C, ctx);
+
+ /* F = E + D */
+ ec_addm (F, E, D, ctx);
+
+ /* H = Z_1^2 */
+ ec_pow2 (H, Z1, ctx);
+
+ /* J = F - 2H */
+ ec_mul2 (J, H, ctx);
+ ec_subm (J, F, J, ctx);
+
+ /* X_3 = (B - C - D) · J */
+ ec_subm (X3, B, C, ctx);
+ ec_subm (X3, X3, D, ctx);
+ ec_mulm (X3, X3, J, ctx);
+
+ /* Y_3 = F · (E - D) */
+ ec_subm (Y3, E, D, ctx);
+ ec_mulm (Y3, Y3, F, ctx);
+
+ /* Z_3 = F · J */
+ ec_mulm (Z3, F, J, ctx);
+
+#undef X1
+#undef Y1
+#undef Z1
+#undef X3
+#undef Y3
+#undef Z3
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+#undef H
+#undef J
+}
-/* RESULT = P1 + P2 */
+
+/* RESULT = 2 * POINT */
void
-_gcry_mpi_ec_add_points (mpi_point_t *result,
- mpi_point_t *p1, mpi_point_t *p2,
- mpi_ec_t ctx)
+_gcry_mpi_ec_dup_point (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx)
+{
+ switch (ctx->model)
+ {
+ case MPI_EC_WEIERSTRASS:
+ dup_point_weierstrass (result, point, ctx);
+ break;
+ case MPI_EC_MONTGOMERY:
+ dup_point_montgomery (result, point, ctx);
+ break;
+ case MPI_EC_TWISTEDEDWARDS:
+ dup_point_twistededwards (result, point, ctx);
+ break;
+ }
+}
+
+
+/* RESULT = P1 + P2 (Weierstrass version).*/
+static void
+add_points_weierstrass (mpi_point_t result,
+ mpi_point_t p1, mpi_point_t p2,
+ mpi_ec_t ctx)
{
#define x1 (p1->x )
#define y1 (p1->y )
@@ -476,17 +833,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)) )
{
@@ -518,23 +875,23 @@ _gcry_mpi_ec_add_points (mpi_point_t *result,
mpi_set (l1, x1);
else
{
- ec_powm (l1, z2, ctx->two, ctx);
+ ec_pow2 (l1, z2, ctx);
ec_mulm (l1, l1, x1, ctx);
}
if (z1_is_one)
- mpi_set (l2, x1);
+ mpi_set (l2, x2);
else
{
- ec_powm (l2, z1, ctx->two, ctx);
+ ec_pow2 (l2, z1, 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);
@@ -564,19 +921,19 @@ _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_pow2 (t1, l6, ctx);
+ ec_pow2 (t2, l3, 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_mul2 (t1, x3, 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);
+ ec_mulm (y3, y3, ec_get_two_inv_p (ctx), ctx);
}
}
@@ -603,51 +960,205 @@ _gcry_mpi_ec_add_points (mpi_point_t *result,
}
+/* RESULT = P1 + P2 (Montgomery version).*/
+static void
+add_points_montgomery (mpi_point_t result,
+ mpi_point_t p1, mpi_point_t p2,
+ mpi_ec_t ctx)
+{
+ (void)result;
+ (void)p1;
+ (void)p2;
+ (void)ctx;
+ log_fatal ("%s: %s not yet supported\n",
+ "_gcry_mpi_ec_add_points", "Montgomery");
+}
+
+
+/* RESULT = P1 + P2 (Twisted Edwards version).*/
+static void
+add_points_twistededwards (mpi_point_t result,
+ mpi_point_t p1, mpi_point_t p2,
+ mpi_ec_t ctx)
+{
+#define X1 (p1->x)
+#define Y1 (p1->y)
+#define Z1 (p1->z)
+#define X2 (p2->x)
+#define Y2 (p2->y)
+#define Z2 (p2->z)
+#define X3 (result->x)
+#define Y3 (result->y)
+#define Z3 (result->z)
+#define A (ctx->t.scratch[0])
+#define B (ctx->t.scratch[1])
+#define C (ctx->t.scratch[2])
+#define D (ctx->t.scratch[3])
+#define E (ctx->t.scratch[4])
+#define F (ctx->t.scratch[5])
+#define G (ctx->t.scratch[6])
+#define tmp (ctx->t.scratch[7])
+
+ /* Compute: (X_3 : Y_3 : Z_3) = (X_1 : Y_1 : Z_1) + (X_2 : Y_2 : Z_3) */
+
+ /* A = Z1 · Z2 */
+ ec_mulm (A, Z1, Z2, ctx);
+
+ /* B = A^2 */
+ ec_pow2 (B, A, ctx);
+
+ /* C = X1 · X2 */
+ ec_mulm (C, X1, X2, ctx);
+
+ /* D = Y1 · Y2 */
+ ec_mulm (D, Y1, Y2, ctx);
+
+ /* E = d · C · D */
+ ec_mulm (E, ctx->b, C, ctx);
+ ec_mulm (E, E, D, ctx);
+
+ /* F = B - E */
+ ec_subm (F, B, E, ctx);
+
+ /* G = B + E */
+ ec_addm (G, B, E, ctx);
+
+ /* X_3 = A · F · ((X_1 + Y_1) · (X_2 + Y_2) - C - D) */
+ ec_addm (tmp, X1, Y1, ctx);
+ ec_addm (X3, X2, Y2, ctx);
+ ec_mulm (X3, X3, tmp, ctx);
+ ec_subm (X3, X3, C, ctx);
+ ec_subm (X3, X3, D, ctx);
+ ec_mulm (X3, X3, F, ctx);
+ ec_mulm (X3, X3, A, ctx);
+
+ /* Y_3 = A · G · (D - aC) */
+ if (ctx->dialect == ECC_DIALECT_ED25519)
+ {
+ /* Using ec_addm (Y3, D, C, ctx) is possible but a litte bit
+ slower because a subm does currently skip the mod step. */
+ mpi_set (Y3, C);
+ _gcry_mpi_neg (Y3, Y3);
+ ec_subm (Y3, D, Y3, ctx);
+ }
+ else
+ {
+ ec_mulm (Y3, ctx->a, C, ctx);
+ ec_subm (Y3, D, Y3, ctx);
+ }
+ ec_mulm (Y3, Y3, G, ctx);
+ ec_mulm (Y3, Y3, A, ctx);
+
+ /* Z_3 = F · G */
+ ec_mulm (Z3, F, G, ctx);
+
+
+#undef X1
+#undef Y1
+#undef Z1
+#undef X2
+#undef Y2
+#undef Z2
+#undef X3
+#undef Y3
+#undef Z3
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+#undef G
+#undef tmp
+}
+
+
+/* RESULT = P1 + P2 */
+void
+_gcry_mpi_ec_add_points (mpi_point_t result,
+ mpi_point_t p1, mpi_point_t p2,
+ mpi_ec_t ctx)
+{
+ switch (ctx->model)
+ {
+ case MPI_EC_WEIERSTRASS:
+ add_points_weierstrass (result, p1, p2, ctx);
+ break;
+ case MPI_EC_MONTGOMERY:
+ add_points_montgomery (result, p1, p2, ctx);
+ break;
+ case MPI_EC_TWISTEDEDWARDS:
+ add_points_twistededwards (result, p1, p2, ctx);
+ break;
+ }
+}
+
/* Scalar point multiplication - the main function for ECC. If takes
an integer SCALAR and a POINT as well as the usual context CTX.
RESULT will be set to the resulting point. */
void
-_gcry_mpi_ec_mul_point (mpi_point_t *result,
- gcry_mpi_t scalar, mpi_point_t *point,
+_gcry_mpi_ec_mul_point (mpi_point_t result,
+ gcry_mpi_t scalar, mpi_point_t point,
mpi_ec_t ctx)
{
-#if 0
- /* Simple left to right binary method. GECC Algorithm 3.27 */
- unsigned int nbits;
- int i;
-
- nbits = mpi_get_nbits (scalar);
- mpi_set_ui (result->x, 1);
- mpi_set_ui (result->y, 1);
- mpi_set_ui (result->z, 0);
+ gcry_mpi_t x1, y1, z1, k, h, yy;
+ unsigned int i, loops;
+ mpi_point_struct p1, p2, p1inv;
- for (i=nbits-1; i >= 0; i--)
+ if (ctx->model == MPI_EC_TWISTEDEDWARDS)
{
- _gcry_mpi_ec_dup_point (result, result, ctx);
- if (mpi_test_bit (scalar, i) == 1)
- _gcry_mpi_ec_add_points (result, result, point, ctx);
- }
+ /* Simple left to right binary method. GECC Algorithm 3.27 */
+ unsigned int nbits;
+ int j;
-#else
- gcry_mpi_t x1, y1, z1, k, h, yy;
- unsigned int i, loops;
- mpi_point_t p1, p2, p1inv;
+ nbits = mpi_get_nbits (scalar);
+ mpi_set_ui (result->x, 0);
+ mpi_set_ui (result->y, 1);
+ mpi_set_ui (result->z, 1);
+
+ 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
+ {
+ 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;
+ }
x1 = mpi_alloc_like (ctx->p);
y1 = mpi_alloc_like (ctx->p);
h = mpi_alloc_like (ctx->p);
k = mpi_copy (scalar);
- yy = mpi_copy (point->y);
+ yy = mpi_copy (point->y);
- if ( mpi_is_neg (k) )
- {
+ if ( mpi_has_sign (k) )
+ {
k->sign = 0;
ec_invm (yy, yy, ctx);
}
if (!mpi_cmp_ui (point->z, 1))
- {
+ {
mpi_set (x1, point->x);
mpi_set (y1, yy);
}
@@ -657,23 +1168,36 @@ _gcry_mpi_ec_mul_point (mpi_point_t *result,
z2 = mpi_alloc_like (ctx->p);
z3 = mpi_alloc_like (ctx->p);
- ec_mulm (z2, point->z, point->z, ctx);
- ec_mulm (z3, point->z, z2, ctx);
- ec_invm (z2, z2, ctx);
+ ec_mulm (z2, point->z, point->z, ctx);
+ ec_mulm (z3, point->z, z2, ctx);
+ ec_invm (z2, z2, ctx);
ec_mulm (x1, point->x, z2, ctx);
- ec_invm (z3, z3, ctx);
- ec_mulm (y1, yy, z3, ctx);
+ ec_invm (z3, z3, ctx);
+ ec_mulm (y1, yy, z3, ctx);
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);
- mpi_set (result->y, yy); mpi_free (yy); yy = NULL;
- mpi_set (result->z, point->z);
+ if (loops < 2)
+ {
+ /* If SCALAR is zero, the above mpi_mul sets H to zero and thus
+ LOOPs will be zero. To avoid an underflow of I in the main
+ loop we set LOOP to 2 and the result to (0,0,0). */
+ loops = 2;
+ mpi_clear (result->x);
+ mpi_clear (result->y);
+ mpi_clear (result->z);
+ }
+ else
+ {
+ mpi_set (result->x, point->x);
+ mpi_set (result->y, yy);
+ mpi_set (result->z, point->z);
+ }
+ mpi_free (yy); yy = NULL;
p1.x = x1; x1 = NULL;
p1.y = y1; y1 = NULL;
@@ -682,12 +1206,12 @@ _gcry_mpi_ec_mul_point (mpi_point_t *result,
point_init (&p1inv);
for (i=loops-2; i > 0; i--)
- {
+ {
_gcry_mpi_ec_dup_point (result, result, ctx);
if (mpi_test_bit (h, i) == 1 && mpi_test_bit (k, i) == 0)
- {
+ {
point_set (&p2, result);
- _gcry_mpi_ec_add_points (result, &p2, &p1, ctx);
+ _gcry_mpi_ec_add_points (result, &p2, &p1, ctx);
}
if (mpi_test_bit (h, i) == 0 && mpi_test_bit (k, i) == 1)
{
@@ -695,7 +1219,7 @@ _gcry_mpi_ec_mul_point (mpi_point_t *result,
/* Invert point: y = p - y mod p */
point_set (&p1inv, &p1);
ec_subm (p1inv.y, ctx->p, p1inv.y, ctx);
- _gcry_mpi_ec_add_points (result, &p2, &p1inv, ctx);
+ _gcry_mpi_ec_add_points (result, &p2, &p1inv, ctx);
}
}
@@ -704,6 +1228,73 @@ _gcry_mpi_ec_mul_point (mpi_point_t *result,
point_free (&p1inv);
mpi_free (h);
mpi_free (k);
-#endif
}
+
+/* Return true if POINT is on the curve described by CTX. */
+int
+_gcry_mpi_ec_curve_point (gcry_mpi_point_t point, mpi_ec_t ctx)
+{
+ int res = 0;
+ gcry_mpi_t x, y, w;
+
+ x = mpi_new (0);
+ y = mpi_new (0);
+ w = mpi_new (0);
+
+ if (_gcry_mpi_ec_get_affine (x, y, point, ctx))
+ return 0;
+
+ switch (ctx->model)
+ {
+ case MPI_EC_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",
+ "_gcry_mpi_ec_curve_point", "Montgomery");
+ break;
+ case MPI_EC_TWISTEDEDWARDS:
+ {
+ /* a · x^2 + y^2 - 1 - b · x^2 · y^2 == 0 */
+ ec_pow2 (x, x, ctx);
+ ec_pow2 (y, y, ctx);
+ if (ctx->dialect == ECC_DIALECT_ED25519)
+ {
+ mpi_set (w, x);
+ _gcry_mpi_neg (w, w);
+ }
+ else
+ ec_mulm (w, ctx->a, x, ctx);
+ ec_addm (w, w, y, ctx);
+ ec_subm (w, w, mpi_const (MPI_C_ONE), ctx);
+ ec_mulm (x, x, y, ctx);
+ ec_mulm (x, x, ctx->b, ctx);
+ ec_subm (w, w, x, ctx);
+ if (!mpi_cmp_ui (w, 0))
+ res = 1;
+ }
+ break;
+ }
+
+ _gcry_mpi_release (w);
+ _gcry_mpi_release (x);
+ _gcry_mpi_release (y);
+
+ return res;
+}