diff options
-rw-r--r-- | NEWS | 7 | ||||
-rw-r--r-- | cipher/ecc.c | 287 | ||||
-rw-r--r-- | doc/gcrypt.texi | 82 | ||||
-rw-r--r-- | mpi/ec.c | 236 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/context.c | 2 | ||||
-rw-r--r-- | src/ec-context.h | 57 | ||||
-rw-r--r-- | src/gcrypt.h.in | 21 | ||||
-rw-r--r-- | src/libgcrypt.def | 14 | ||||
-rw-r--r-- | src/libgcrypt.vers | 4 | ||||
-rw-r--r-- | src/mpi.h | 13 | ||||
-rw-r--r-- | src/visibility.c | 32 | ||||
-rw-r--r-- | src/visibility.h | 8 | ||||
-rw-r--r-- | tests/t-mpi-point.c | 318 |
14 files changed, 963 insertions, 119 deletions
@@ -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 4efbef45..c95a57af 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 a56d5278..4d48eb4c 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 +@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 -@anchor{gcry_mpi_ec_p_new} -@deftypefun gcry_ctx_t gcry_mpi_ec_p_new (@w{gcry_mpi_t @var{p}}, @ - @w{gcry_mpi_t @var{a}} +@anchor{gcry_mpi_ec_new} +@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 -@ref{gcry_ctx_release}. On error this function returns @code{NULL} -and sets @code{errno}. +Allocate a new context for elliptic curve operations. If +@var{keyparam} is given it specifies the parameters of the curve +(@pxref{ecc_keyparam}). If @var{curvename} is given in addition to +@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 +@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 +@var{r_ctx}; this object eventually needs to be released +(@pxref{gcry_ctx_release}). On error the function stores @code{NULL} at +@var{r_ctx} and returns an error code. +@end deftypefun + +@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 +@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}. +@end deftypefun + +@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 +@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. +@end deftypefun + +@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}). +@end deftypefun + +@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 +@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 -@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. +@var{y}. @var{ctx} is the context object which has been created using +@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 ( @ @@ -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 1869ad3c..713e616e 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 ae991c52..2c02c9c4 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 00000000..88742bf2 --- /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 eb9a11db..ad4da049 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 611f10f9..061c7e36 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 4a375b22..65959d36 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; @@ -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 5c3216d2..ed68b860 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 90c6ad14..031537a1 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 8714d388..31df12b8 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; |