summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cipher/ecc.c25
-rw-r--r--doc/gcrypt.texi9
-rw-r--r--mpi/ec.c67
-rw-r--r--src/ec-context.h2
-rw-r--r--src/mpi.h2
-rw-r--r--tests/t-mpi-point.c78
6 files changed, 163 insertions, 20 deletions
diff --git a/cipher/ecc.c b/cipher/ecc.c
index c95a57af..c23ba08b 100644
--- a/cipher/ecc.c
+++ b/cipher/ecc.c
@@ -930,6 +930,27 @@ ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p)
}
+/* Convert POINT into affine coordinates using the context CTX and
+ return a newly allocated MPI. If the conversion is not possible
+ NULL is returned. This function won't print an error message. */
+gcry_mpi_t
+_gcry_mpi_ec_ec2os (gcry_mpi_point_t point, mpi_ec_t ectx)
+{
+ gcry_mpi_t g_x, g_y, result;
+
+ g_x = mpi_new (0);
+ g_y = mpi_new (0);
+ if (_gcry_mpi_ec_get_affine (g_x, g_y, point, ectx))
+ result = NULL;
+ else
+ result = ec2os (g_x, g_y, ectx->p);
+ mpi_free (g_x);
+ mpi_free (g_y);
+
+ return result;
+}
+
+
/* RESULT must have been initialized and is set on success to the
point given by VALUE. */
static gcry_error_t
@@ -1838,13 +1859,13 @@ _gcry_mpi_ec_new (gcry_ctx_t *r_ctx,
errc = mpi_from_keyparam (&b, keyparam, "b");
if (errc)
goto leave;
- errc = point_from_keyparam (&G, keyparam, "G");
+ 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");
+ errc = point_from_keyparam (&Q, keyparam, "q");
if (errc)
goto leave;
errc = mpi_from_keyparam (&d, keyparam, "d");
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 4d48eb4c..a6b585df 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -3953,7 +3953,10 @@ 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}.
+to release the result. For valid names @ref{ecc_keyparam}. If a
+point parameter is requested it is returned as an uncompressed encoded
+point. If the public key @code{q} is requested but only the private
+key @code{d} is available, @code{q} will be recomputed on the fly.
@end deftypefun
@deftypefun gcry_mpi_point_t gcry_mpi_ec_get_point ( @
@@ -3965,7 +3968,9 @@ 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.
+called to release the result. If the public key @code{q} is requested
+but only the private key @code{d} is available, @code{q} will be
+recomputed on the fly.
@end deftypefun
@deftypefun gpg_error_t gcry_mpi_ec_set_mpi ( @
diff --git a/mpi/ec.c b/mpi/ec.c
index 9a6868b7..0a348d2e 100644
--- a/mpi/ec.c
+++ b/mpi/ec.c
@@ -337,6 +337,25 @@ ec_invm (gcry_mpi_t x, gcry_mpi_t a, mpi_ec_t ctx)
}
+/* Sync changed data in the context. */
+static void
+ec_p_sync (mpi_ec_t ec)
+{
+ gcry_mpi_t tmp;
+
+ if (!ec->t.need_sync)
+ return;
+
+ 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);
+
+ ec_invm (ec->t.two_inv_p, mpi_const (MPI_C_TWO), ec);
+ ec->t.need_sync = 0;
+}
+
+
/* 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
@@ -345,20 +364,14 @@ static void
ec_p_init (mpi_ec_t ctx, gcry_mpi_t p, gcry_mpi_t a)
{
int i;
- gcry_mpi_t tmp;
/* 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->t.a_is_pminus3 = !mpi_cmp (ctx->a, tmp);
- mpi_free (tmp);
-
+ ctx->t.need_sync = 1;
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->t.scratch); i++)
@@ -492,10 +505,29 @@ _gcry_mpi_ec_get_mpi (const char *name, gcry_ctx_t ctx, int copy)
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);
+
+ /* Return a requested point coordinate. */
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);
+ if (!strcmp (name, "q.x") && ec->Q && ec->Q->x)
+ return mpi_is_const (ec->Q->x) && !copy? ec->Q->x : mpi_copy (ec->Q->x);
+ if (!strcmp (name, "q.y") && ec->Q && ec->Q->y)
+ return mpi_is_const (ec->G->y) && !copy? ec->Q->y : mpi_copy (ec->Q->y);
+
+ /* If a point has been requested, return it in standard encoding. */
+ if (!strcmp (name, "g") && ec->G)
+ return _gcry_mpi_ec_ec2os (ec->G, ec);
+ if (!strcmp (name, "q"))
+ {
+ /* If only the private key is given, compute the public key. */
+ if (!ec->Q && ec->d && ec->G && ec->p && ec->a)
+ _gcry_mpi_ec_mul_point (ec->Q, ec->d, ec->G, ec);
+
+ if (ec->Q)
+ return _gcry_mpi_ec_ec2os (ec->Q, ec);
+ }
return NULL;
}
@@ -510,8 +542,15 @@ _gcry_mpi_ec_get_point (const char *name, gcry_ctx_t ctx, int copy)
if (!strcmp (name, "g") && ec->G)
return point_copy (ec->G);
- if (!strcmp (name, "q") && ec->Q)
- return point_copy (ec->Q);
+ if (!strcmp (name, "q"))
+ {
+ /* If only the private key is given, compute the public key. */
+ if (!ec->Q && ec->d && ec->G && ec->p && ec->a)
+ _gcry_mpi_ec_mul_point (ec->Q, ec->d, ec->G, ec);
+
+ if (ec->Q)
+ return point_copy (ec->Q);
+ }
return NULL;
}
@@ -527,11 +566,13 @@ _gcry_mpi_ec_set_mpi (const char *name, gcry_mpi_t newvalue,
{
mpi_free (ec->p);
ec->p = mpi_copy (newvalue);
+ ec->t.need_sync = 1;
}
else if (!strcmp (name, "a"))
{
mpi_free (ec->a);
ec->a = mpi_copy (newvalue);
+ ec->t.need_sync = 1;
}
else if (!strcmp (name, "b"))
{
@@ -628,6 +669,8 @@ _gcry_mpi_ec_dup_point (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx)
#define l2 (ctx->t.scratch[4])
#define l3 (ctx->t.scratch[5])
+ ec_p_sync (ctx);
+
if (!mpi_cmp_ui (point->y, 0) || !mpi_cmp_ui (point->z, 0))
{
/* P_y == 0 || P_z == 0 => [1:1:0] */
@@ -725,6 +768,8 @@ _gcry_mpi_ec_add_points (mpi_point_t result,
#define t1 (ctx->t.scratch[9])
#define t2 (ctx->t.scratch[10])
+ ec_p_sync (ctx);
+
if ( (!mpi_cmp (x1, x2)) && (!mpi_cmp (y1, y2)) && (!mpi_cmp (z1, z2)) )
{
/* Same point; need to call the duplicate function. */
@@ -854,6 +899,8 @@ _gcry_mpi_ec_mul_point (mpi_point_t result,
unsigned int nbits;
int i;
+ ec_p_sync (ctx);
+
nbits = mpi_get_nbits (scalar);
mpi_set_ui (result->x, 1);
mpi_set_ui (result->y, 1);
@@ -871,6 +918,8 @@ _gcry_mpi_ec_mul_point (mpi_point_t result,
unsigned int i, loops;
mpi_point_struct p1, p2, p1inv;
+ ec_p_sync (ctx);
+
x1 = mpi_alloc_like (ctx->p);
y1 = mpi_alloc_like (ctx->p);
h = mpi_alloc_like (ctx->p);
diff --git a/src/ec-context.h b/src/ec-context.h
index 88742bf2..6827e188 100644
--- a/src/ec-context.h
+++ b/src/ec-context.h
@@ -38,6 +38,8 @@ struct mpi_ec_ctx_s
/* This structure is private to mpi/ec.c! */
struct {
+ int need_sync; /* Helper for ec_p_sync. */
+
int a_is_pminus3; /* True if A = P - 3. */
gcry_mpi_t two_inv_p;
diff --git a/src/mpi.h b/src/mpi.h
index b727d5f9..fd265bf2 100644
--- a/src/mpi.h
+++ b/src/mpi.h
@@ -289,6 +289,8 @@ void _gcry_mpi_ec_mul_point (mpi_point_t result,
gcry_mpi_t scalar, mpi_point_t point,
mpi_ec_t ctx);
+gcry_mpi_t _gcry_mpi_ec_ec2os (gcry_mpi_point_t point, mpi_ec_t ectx);
+
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,
diff --git a/tests/t-mpi-point.c b/tests/t-mpi-point.c
index 31df12b8..a3b6c569 100644
--- a/tests/t-mpi-point.c
+++ b/tests/t-mpi-point.c
@@ -116,6 +116,15 @@ static struct
{ NULL, NULL, NULL, NULL, NULL }
};
+/* A sample public key for NIST P-256. */
+static const char sample_p256_q[] =
+ "04"
+ "42B927242237639A36CE9221B340DB1A9AB76DF2FE3E171277F6A4023DED146E"
+ "E86525E38CCECFF3FB8D152CC6334F70D23A525175C1BCBDDE6E023B2228770E";
+static const char sample_p256_q_x[] =
+ "42B927242237639A36CE9221B340DB1A9AB76DF2FE3E171277F6A4023DED146E";
+static const char sample_p256_q_y[] =
+ "00E86525E38CCECFF3FB8D152CC6334F70D23A525175C1BCBDDE6E023B2228770E";
@@ -164,7 +173,7 @@ die (const char *format, ...)
static void
-print_mpi (const char *text, gcry_mpi_t a)
+print_mpi_2 (const char *text, const char *text2, gcry_mpi_t a)
{
gcry_error_t err;
char *buf;
@@ -172,16 +181,41 @@ print_mpi (const char *text, gcry_mpi_t a)
err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a);
if (err)
- fprintf (stderr, "%s: [error printing number: %s]\n",
- text, gpg_strerror (err));
+ fprintf (stderr, "%s%s: [error printing number: %s]\n",
+ text, text2? text2:"", gpg_strerror (err));
else
{
- fprintf (stderr, "%s: %s\n", text, buf);
+ fprintf (stderr, "%s%s: %s\n", text, text2? text2:"", buf);
gcry_free (buf);
}
}
+static void
+print_mpi (const char *text, gcry_mpi_t a)
+{
+ print_mpi_2 (text, NULL, a);
+}
+
+
+static void
+print_point (const char *text, gcry_mpi_point_t a)
+{
+ gcry_mpi_t x, y, z;
+
+ x = gcry_mpi_new (0);
+ y = gcry_mpi_new (0);
+ z = gcry_mpi_new (0);
+ gcry_mpi_point_get (x, y, z, a);
+ print_mpi_2 (text, ".x", x);
+ print_mpi_2 (text, ".y", y);
+ print_mpi_2 (text, ".z", z);
+ gcry_mpi_release (x);
+ gcry_mpi_release (y);
+ gcry_mpi_release (z);
+}
+
+
static gcry_mpi_t
hex2mpi (const char *string)
{
@@ -345,6 +379,8 @@ get_and_cmp_mpi (const char *name, const char *mpistring, const char *desc,
fail ("error getting parameter '%s' of curve '%s'\n", name, desc);
return 1;
}
+ if (debug)
+ print_mpi (name, mpi);
if (cmp_mpihex (mpi, mpistring))
{
fail ("parameter '%s' of curve '%s' does not match\n", name, desc);
@@ -371,6 +407,8 @@ get_and_cmp_point (const char *name,
fail ("error getting point parameter '%s' of curve '%s'\n", name, desc);
return 1;
}
+ if (debug)
+ print_point (name, point);
x = gcry_mpi_new (0);
y = gcry_mpi_new (0);
@@ -404,12 +442,14 @@ context_param (void)
gpg_error_t err;
int idx;
gcry_ctx_t ctx = NULL;
+ gcry_mpi_t q;
+ gcry_sexp_t keyparam;
wherestr = "context_param";
+ show ("checking standard curves\n");
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)
@@ -437,11 +477,35 @@ context_param (void)
}
gcry_ctx_release (ctx);
- /* FIXME: Add tests for Q and d. */
- /* FIXME: Add test sor the set functions. */
+ show ("checking sample public key\n");
+ q = hex2mpi (sample_p256_q);
+ err = gcry_sexp_build (&keyparam, NULL,
+ "(public-key(ecdsa(curve %s)(q %m)))",
+ "NIST P-256", q);
+ if (err)
+ die ("gcry_sexp_build failed: %s\n", gpg_strerror (err));
+ gcry_mpi_release (q);
+
+ /* We can't call gcry_pk_testkey because it is only implemented for
+ private keys. */
+ /* err = gcry_pk_testkey (keyparam); */
+ /* if (err) */
+ /* fail ("gcry_pk_testkey failed for sample public key: %s\n", */
+ /* gpg_strerror (err)); */
+ err = gcry_mpi_ec_new (&ctx, keyparam, NULL);
+ if (err)
+ fail ("gcry_mpi_ec_new failed for sample public key: %s\n",
+ gpg_strerror (err));
+ else
+ {
+ get_and_cmp_mpi ("q", sample_p256_q, "NIST P-256", ctx);
+ get_and_cmp_point ("q", sample_p256_q_x, sample_p256_q_y, "NIST P-256",
+ ctx);
+ }
+ gcry_sexp_release (keyparam);
}