[PATCH] Curve25519 patch revised
NIIBE Yutaka
gniibe at fsij.org
Fri Jun 20 04:23:55 CEST 2014
On 2014-06-19 at 18:04 +0900, NIIBE Yutaka wrote:
> Next time, I will post after confirming that it will pass all tests of
> "make check".
Here is revised patch which include mpi_swap_conditional.
mpi_swap_conditional is used in _gcry_mpi_ec_mul_point for Montgomery
curve (model == MPI_EC_MONTGOMERY).
It success for "make check". It's not yet complete, I have not
decided where we should put the code of:
mpi_clear_bit (scalar, 255);
mpi_set_bit (scalar, 254);
mpi_clear_bit (scalar, 2);
mpi_clear_bit (scalar, 1);
mpi_clear_bit (scalar, 0);
To do so, we need to add two more fields in the curve specification:
co-factor and number of bits of the curve (to set MSB of above code).
diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c
index 0f622f7..e7dbc17 100644
--- a/cipher/ecc-curves.c
+++ b/cipher/ecc-curves.c
@@ -40,7 +40,7 @@ static const struct
const char *other; /* Other name. */
} curve_aliases[] =
{
- /*{ "Curve25519", "1.3.6.1.4.1.3029.1.5.1" },*/
+ { "Curve25519", "1.3.6.1.4.1.3029.1.5.1" },
{ "Ed25519", "1.3.6.1.4.1.11591.15.1" },
{ "NIST P-192", "1.2.840.10045.3.1.1" }, /* X9.62 OID */
@@ -127,6 +127,17 @@ static const ecc_domain_parms_t domain_parms[] =
"0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A",
"0x6666666666666666666666666666666666666666666666666666666666666658"
},
+ {
+ /* (y^2 = x^3 + 486662*x^2 + x) */
+ "Curve25519", 256, 0,
+ MPI_EC_MONTGOMERY, ECC_DIALECT_STANDARD,
+ "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
+ "0x01DB41",
+ "0x01",
+ "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED",
+ "0x0000000000000000000000000000000000000000000000000000000000000009",
+ "0x20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9"
+ },
#if 0 /* No real specs yet found. */
{
/* x^2 + y^2 = 1 + 3617x^2y^2 mod 2^414 - 17 */
@@ -507,9 +518,8 @@ _gcry_ecc_fill_in_curve (unsigned int nbits, const char *name,
{
case MPI_EC_WEIERSTRASS:
case MPI_EC_EDWARDS:
- break;
case MPI_EC_MONTGOMERY:
- return GPG_ERR_NOT_SUPPORTED;
+ break;
default:
return GPG_ERR_BUG;
}
diff --git a/cipher/ecc.c b/cipher/ecc.c
index e0be2d4..09de65f 100644
--- a/cipher/ecc.c
+++ b/cipher/ecc.c
@@ -117,7 +117,24 @@ nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
point_init (&Q);
/* Generate a secret. */
- if (ctx->dialect == ECC_DIALECT_ED25519)
+ /*
+ * FIXME. It should be something like this:
+ *
+ * When the co-factor of the curve is not 1, we guarantee that
+ * scalar value k is multiple of its co-factor to avoid sub-group
+ * attack. Also, we make sure that the most significant bit of k
+ * is 1.
+ *
+ * It works for now as we only have two curves which have co-factor!=1;
+ * Ed25519 and Curve25519.
+ * Note that we need some a way to get number of bits of the curve to
+ * set MSB of k. Currently, E.nbits is not precise for this purpuse.
+ * We also need a way to get co-factor of a curve.
+ *
+ * Currently, we distinguish the two curves by ECC_DIALECT_ED25519
+ * and MPI_EC_MONTGOMERY, which works, but is not that correct.
+ */
+ if (ctx->dialect == ECC_DIALECT_ED25519 || E->model == MPI_EC_MONTGOMERY)
{
char *rndbuf;
@@ -156,7 +174,7 @@ nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
* possibilities without any loss of security. Note that we don't
* do that for Ed25519 so that we do not violate the special
* construction of the secret key. */
- if (E->dialect == ECC_DIALECT_ED25519)
+ if (E->dialect == ECC_DIALECT_ED25519 || E->model == MPI_EC_MONTGOMERY)
point_set (&sk->Q, &Q);
else
{
@@ -227,12 +245,8 @@ static void
test_keys (ECC_secret_key *sk, unsigned int nbits)
{
ECC_public_key pk;
- gcry_mpi_t test = mpi_new (nbits);
+ gcry_mpi_t test;
mpi_point_struct R_;
- gcry_mpi_t c = mpi_new (nbits);
- gcry_mpi_t out = mpi_new (nbits);
- gcry_mpi_t r = mpi_new (nbits);
- gcry_mpi_t s = mpi_new (nbits);
if (DBG_CIPHER)
log_debug ("Testing key.\n");
@@ -243,27 +257,82 @@ test_keys (ECC_secret_key *sk, unsigned int nbits)
point_init (&pk.Q);
point_set (&pk.Q, &sk->Q);
- _gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
+ if (sk->E.model == MPI_EC_MONTGOMERY)
+ /* It's ECDH only. */
+ /* FIXME: see the FIXME comment of nist_generate_key.
+ * Here, we generate ephemeral key, same handling is needed for secret.
+ */
+ {
+ char *rndbuf;
+ gcry_mpi_t x0, x1;
+ mpi_ec_t ec;
+
+ test = mpi_new (256);
+ rndbuf = _gcry_random_bytes (32, GCRY_WEAK_RANDOM);
+ rndbuf[0] &= 0x7f; /* Clear bit 255. */
+ rndbuf[0] |= 0x40; /* Set bit 254. */
+ rndbuf[31] &= 0xf8; /* Clear bits 2..0 so that d mod 8 == 0 */
+ _gcry_mpi_set_buffer (test, rndbuf, 32, 0);
+ xfree (rndbuf);
+
+ ec = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect, 0,
+ pk.E.p, pk.E.a, pk.E.b);
+ x0 = mpi_new (0);
+ x1 = mpi_new (0);
- if (_gcry_ecc_ecdsa_sign (test, sk, r, s, 0, 0) )
- log_fatal ("ECDSA operation: sign failed\n");
+ /* R_ = kQ <=> R_ = kdG */
+ _gcry_mpi_ec_mul_point (&R_, test, &pk.Q, ec);
+ if (_gcry_mpi_ec_get_affine (x0, NULL, &R_, ec))
+ log_fatal ("ecdh: Failed to get affine coordinates for kQ\n");
- if (_gcry_ecc_ecdsa_verify (test, &pk, r, s))
- {
- log_fatal ("ECDSA operation: sign, verify failed\n");
+ /* R_ = kG */
+ _gcry_mpi_ec_mul_point (&R_, test, &pk.E.G, ec);
+ /* R_ = dkG */
+ _gcry_mpi_ec_mul_point (&R_, sk->d, &R_, ec);
+
+ if (_gcry_mpi_ec_get_affine (x1, NULL, &R_, ec))
+ log_fatal ("ecdh: Failed to get affine coordinates for dkG\n");
+
+ if (mpi_cmp (x0, x1))
+ {
+ log_fatal ("ECDH test failed.\n");
+ }
+
+ mpi_free (x0);
+ mpi_free (x1);
+ _gcry_mpi_ec_free (ec);
}
+ else
+ {
+ gcry_mpi_t c = mpi_new (nbits);
+ gcry_mpi_t out = mpi_new (nbits);
+ gcry_mpi_t r = mpi_new (nbits);
+ gcry_mpi_t s = mpi_new (nbits);
- if (DBG_CIPHER)
- log_debug ("ECDSA operation: sign, verify ok.\n");
+ test = mpi_new (nbits);
+ _gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
+
+ if (_gcry_ecc_ecdsa_sign (test, sk, r, s, 0, 0) )
+ log_fatal ("ECDSA operation: sign failed\n");
+
+ if (_gcry_ecc_ecdsa_verify (test, &pk, r, s))
+ {
+ log_fatal ("ECDSA operation: sign, verify failed\n");
+ }
+
+ if (DBG_CIPHER)
+ log_debug ("ECDSA operation: sign, verify ok.\n");
+
+ mpi_free (s);
+ mpi_free (r);
+ mpi_free (out);
+ mpi_free (c);
+ }
point_free (&pk.Q);
_gcry_ecc_curve_free (&pk.E);
point_free (&R_);
- mpi_free (s);
- mpi_free (r);
- mpi_free (out);
- mpi_free (c);
mpi_free (test);
}
@@ -302,7 +371,7 @@ check_secret_key (ECC_secret_key *sk, mpi_ec_t ec, int flags)
}
/* Check order of curve. */
- if (sk->E.dialect != ECC_DIALECT_ED25519)
+ if (sk->E.dialect != ECC_DIALECT_ED25519 && sk->E.model != MPI_EC_MONTGOMERY)
{
_gcry_mpi_ec_mul_point (&Q, sk->E.n, &sk->E.G, ec);
if (mpi_cmp_ui (Q.z, 0))
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index d59c095..91d9d8f 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -4341,6 +4341,11 @@ small values (usually up to the word size of the CPU).
Swap the values of @var{a} and @var{b}.
@end deftypefun
+ at deftypefun void gcry_mpi_swap_conditional (@w{gcry_mpi_t @var{a}}, @w{gcry_mpi_t @var{b}}, @w{unsigned long @var{sw}})
+
+Swap the values of @var{a} and @var{b}, when @var{sw} is 1.
+ at end deftypefun
+
@deftypefun void gcry_mpi_snatch (@w{gcry_mpi_t @var{w}}, @
@w{const gcry_mpi_t @var{u}})
diff --git a/mpi/ec.c b/mpi/ec.c
index 4f35de0..c9997b5 100644
--- a/mpi/ec.c
+++ b/mpi/ec.c
@@ -600,10 +600,13 @@ _gcry_mpi_ec_get_affine (gcry_mpi_t x, gcry_mpi_t y, mpi_point_t point,
case MPI_EC_MONTGOMERY:
{
- log_fatal ("%s: %s not yet supported\n",
- "_gcry_mpi_ec_get_affine", "Montgomery");
+ if (x)
+ mpi_set (x, point->x);
+
+ if (y)
+ mpi_set (y, point->y);
}
- return -1;
+ return 0;
case MPI_EC_EDWARDS:
{
@@ -1073,6 +1076,35 @@ add_points_edwards (mpi_point_t result,
}
+/* PRD = 2 * P1.
+ SUM = P1 + P2.
+ P1 - P2 = DIF */
+static void
+dup_and_add_montgomery (mpi_point_t prd, mpi_point_t sum,
+ mpi_point_t p1, mpi_point_t p2, gcry_mpi_t dif_x,
+ mpi_ec_t ctx)
+{
+ ec_addm (sum->x, p2->x, p2->z, ctx);
+ ec_subm (p2->z, p2->x, p2->z, ctx);
+ ec_addm (prd->x, p1->x, p1->z, ctx);
+ ec_subm (p1->z, p1->x, p1->z, ctx);
+ ec_mulm (p2->x, p1->z, sum->x, ctx);
+ ec_mulm (p2->z, prd->x, p2->z, ctx);
+ ec_pow2 (p1->x, prd->x, ctx);
+ ec_pow2 (p1->z, p1->z, ctx);
+ ec_addm (sum->x, p2->x, p2->z, ctx);
+ ec_subm (p2->z, p2->x, p2->z, ctx);
+ ec_mulm (prd->x, p1->x, p1->z, ctx);
+ ec_subm (p1->z, p1->x, p1->z, ctx);
+ ec_pow2 (sum->x, sum->x, ctx);
+ ec_pow2 (sum->z, p2->z, ctx);
+ ec_mulm (prd->z, p1->z, ctx->a, ctx); /* ctx->a: (A-2)/4 */
+ ec_mulm (sum->z, sum->z, dif_x, ctx);
+ ec_addm (prd->z, p1->x, prd->z, ctx);
+ ec_mulm (prd->z, prd->z, p1->z, ctx);
+}
+
+
/* RESULT = P1 + P2 */
void
_gcry_mpi_ec_add_points (mpi_point_t result,
@@ -1144,6 +1176,86 @@ _gcry_mpi_ec_mul_point (mpi_point_t result,
}
return;
}
+ else if (ctx->model == MPI_EC_MONTGOMERY)
+ {
+ unsigned int nbits;
+ int j;
+ mpi_point_struct p1_, p2_;
+ mpi_point_t q1, q2, prd, sum;
+ unsigned long sw;
+ size_t nlimbs;
+
+ /* FIXME: it's just for Curve25519 */
+ mpi_clear_bit (scalar, 255);
+ mpi_set_bit (scalar, 254);
+ mpi_clear_bit (scalar, 2);
+ mpi_clear_bit (scalar, 1);
+ mpi_clear_bit (scalar, 0);
+
+ nbits = mpi_get_nbits (scalar);
+ point_init (&p1);
+ point_init (&p2);
+ point_init (&p1_);
+ point_init (&p2_);
+ mpi_set_ui (p1.x, 1);
+ mpi_free (p2.x);
+ p2.x = mpi_copy (point->x);
+ mpi_set_ui (p2.z, 1);
+
+ nlimbs = 2*(nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB+1;
+ mpi_resize (p1.x, nlimbs);
+ mpi_resize (p1.z, nlimbs);
+ mpi_resize (p2.x, nlimbs);
+ mpi_resize (p2.z, nlimbs);
+ mpi_resize (p1_.x, nlimbs);
+ mpi_resize (p1_.z, nlimbs);
+ mpi_resize (p2_.x, nlimbs);
+ mpi_resize (p2_.z, nlimbs);
+
+ q1 = &p1;
+ q2 = &p2;
+ prd = &p1_;
+ sum = &p2_;
+ for (j=nbits-1; j >= 0; j--)
+ {
+ mpi_point_t t;
+
+ sw = mpi_test_bit (scalar, j);
+ mpi_swap_conditional (q1->x, q2->x, sw);
+ mpi_swap_conditional (q1->z, q2->z, sw);
+ dup_and_add_montgomery (prd, sum, q1, q2, point->x, ctx);
+ mpi_swap_conditional (prd->x, sum->x, sw);
+ mpi_swap_conditional (prd->z, sum->z, sw);
+
+ t = q1; q1 = prd; prd = t;
+ t = q2; q2 = sum; sum = t;
+ }
+
+ mpi_clear (result->y);
+ sw = (nbits & 1);
+ mpi_swap_conditional (p1.x, p1_.x, sw);
+ mpi_swap_conditional (p1.z, p1_.z, sw);
+
+ if (p1.z->nlimbs == 0)
+ {
+ mpi_set_ui (result->x, 1);
+ mpi_set_ui (result->z, 0);
+ }
+ else
+ {
+ z1 = mpi_new (0);
+ ec_invm (z1, p1.z, ctx);
+ ec_mulm (result->x, p1.x, z1, ctx);
+ mpi_set_ui (result->z, 1);
+ mpi_free (z1);
+ }
+
+ point_free (&p1);
+ point_free (&p2);
+ point_free (&p1_);
+ point_free (&p2_);
+ return;
+ }
x1 = mpi_alloc_like (ctx->p);
y1 = mpi_alloc_like (ctx->p);
@@ -1266,8 +1378,12 @@ _gcry_mpi_ec_curve_point (gcry_mpi_point_t point, mpi_ec_t ctx)
}
break;
case MPI_EC_MONTGOMERY:
+#if 0
log_fatal ("%s: %s not yet supported\n",
"_gcry_mpi_ec_curve_point", "Montgomery");
+#else
+ res = 1;
+#endif
break;
case MPI_EC_EDWARDS:
{
diff --git a/mpi/mpiutil.c b/mpi/mpiutil.c
index fdce578..5e77e12 100644
--- a/mpi/mpiutil.c
+++ b/mpi/mpiutil.c
@@ -541,6 +541,34 @@ _gcry_mpi_swap (gcry_mpi_t a, gcry_mpi_t b)
tmp = *a; *a = *b; *b = tmp;
}
+void
+_gcry_mpi_swap_conditional (gcry_mpi_t a, gcry_mpi_t b, unsigned long swap)
+{
+ size_t i;
+ size_t nlimbs = a->alloced;
+ unsigned long mask = 0UL - !!swap;
+ unsigned long x;
+
+ if (a->alloced != b->alloced)
+ log_bug ("mpi_swap_conditional: different sizes\n");
+
+ for (i = 0; i < nlimbs; i++)
+ {
+ x = mask & (a->d[i] ^ b->d[i]);
+ a->d[i] = a->d[i] ^ x;
+ b->d[i] = b->d[i] ^ x;
+ }
+
+ x = mask & (a->nlimbs ^ b->nlimbs);
+ a->nlimbs = a->nlimbs ^ x;
+ b->nlimbs = b->nlimbs ^ x;
+
+ x = mask & (a->sign ^ b->sign);
+ a->sign = a->sign ^ x;
+ b->sign = b->sign ^ x;
+}
+
+
gcry_mpi_t
_gcry_mpi_new (unsigned int nbits)
diff --git a/src/gcrypt-int.h b/src/gcrypt-int.h
index 8a6df84..42b72d6 100644
--- a/src/gcrypt-int.h
+++ b/src/gcrypt-int.h
@@ -371,6 +371,7 @@ gcry_mpi_t _gcry_mpi_set (gcry_mpi_t w, const gcry_mpi_t u);
gcry_mpi_t _gcry_mpi_set_ui (gcry_mpi_t w, unsigned long u);
gcry_err_code_t _gcry_mpi_get_ui (gcry_mpi_t w, ulong *u);
void _gcry_mpi_swap (gcry_mpi_t a, gcry_mpi_t b);
+void _gcry_mpi_swap_conditional (gcry_mpi_t a, gcry_mpi_t b, unsigned long sw);
int _gcry_mpi_is_neg (gcry_mpi_t a);
void _gcry_mpi_neg (gcry_mpi_t w, gcry_mpi_t u);
void _gcry_mpi_abs (gcry_mpi_t w);
@@ -475,6 +476,7 @@ int _gcry_mpi_get_flag (gcry_mpi_t a, enum gcry_mpi_flag flag);
#define mpi_set_ui( w, u) _gcry_mpi_set_ui( (w), (u) )
#define mpi_get_ui(a,b) _gcry_mpi_get_ui( (a), (b) )
#define mpi_swap(a,b) _gcry_mpi_swap ((a),(b))
+#define mpi_swap_conditional(a,b,sw) _gcry_mpi_swap_conditional ((a),(b),(sw))
#define mpi_abs( w ) _gcry_mpi_abs( (w) )
#define mpi_neg( w, u) _gcry_mpi_neg( (w), (u) )
#define mpi_cmp( u, v ) _gcry_mpi_cmp( (u), (v) )
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index bd38a24..ed0141e 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -544,6 +544,9 @@ gcry_mpi_t gcry_mpi_set_ui (gcry_mpi_t w, unsigned long u);
/* Swap the values of A and B. */
void gcry_mpi_swap (gcry_mpi_t a, gcry_mpi_t b);
+/* Swap the values of A and B if SW is 1. */
+void gcry_mpi_swap_conditional (gcry_mpi_t a, gcry_mpi_t b, unsigned long sw);
+
/* Return 1 if A is negative; 0 if zero or positive. */
int gcry_mpi_is_neg (gcry_mpi_t a);
diff --git a/src/libgcrypt.def b/src/libgcrypt.def
index 57ed490..aee85ac 100644
--- a/src/libgcrypt.def
+++ b/src/libgcrypt.def
@@ -276,5 +276,6 @@ EXPORTS
gcry_mac_ctl @242
gcry_mac_get_algo @243
+ gcry_mpi_swap_conditional @244
;; end of file with public symbols for Windows.
diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers
index 7ee0541..0540850 100644
--- a/src/libgcrypt.vers
+++ b/src/libgcrypt.vers
@@ -96,7 +96,7 @@ GCRYPT_1.6 {
gcry_mpi_set_flag; gcry_mpi_set_highbit;
gcry_mpi_set_opaque; gcry_mpi_set_opaque_copy;
gcry_mpi_set_ui; gcry_mpi_snew; gcry_mpi_sub; gcry_mpi_sub_ui;
- gcry_mpi_subm; gcry_mpi_swap; gcry_mpi_test_bit;
+ gcry_mpi_subm; gcry_mpi_swap; gcry_mpi_swap_conditional; gcry_mpi_test_bit;
gcry_mpi_lshift; gcry_mpi_snatch;
gcry_mpi_point_new; gcry_mpi_point_release;
gcry_mpi_point_get; gcry_mpi_point_snatch_get;
diff --git a/src/mpi.h b/src/mpi.h
index eb0730e..7859dec 100644
--- a/src/mpi.h
+++ b/src/mpi.h
@@ -125,6 +125,7 @@ gcry_mpi_t _gcry_mpi_alloc_like( gcry_mpi_t a );
gcry_mpi_t _gcry_mpi_alloc_set_ui( unsigned long u);
void _gcry_mpi_m_check( gcry_mpi_t a );
void _gcry_mpi_swap( gcry_mpi_t a, gcry_mpi_t b);
+void _gcry_mpi_swap_conditional(gcry_mpi_t a, gcry_mpi_t b, unsigned long sw);
gcry_mpi_t _gcry_mpi_new (unsigned int nbits);
gcry_mpi_t _gcry_mpi_snew (unsigned int nbits);
gcry_mpi_t _gcry_mpi_set_opaque_copy (gcry_mpi_t a,
diff --git a/src/visibility.c b/src/visibility.c
index 6ed57ca..ec3b644 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -319,6 +319,12 @@ gcry_mpi_swap (gcry_mpi_t a, gcry_mpi_t b)
_gcry_mpi_swap (a, b);
}
+void
+gcry_mpi_swap_conditional (gcry_mpi_t a, gcry_mpi_t b, unsigned long sw)
+{
+ _gcry_mpi_swap_conditional (a, b, sw);
+}
+
int
gcry_mpi_is_neg (gcry_mpi_t a)
{
diff --git a/src/visibility.h b/src/visibility.h
index 96b5235..54767e3 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -266,6 +266,7 @@ MARK_VISIBLEX (gcry_mpi_sub)
MARK_VISIBLEX (gcry_mpi_sub_ui)
MARK_VISIBLEX (gcry_mpi_subm)
MARK_VISIBLEX (gcry_mpi_swap)
+MARK_VISIBLEX (gcry_mpi_swap_conditional)
MARK_VISIBLEX (gcry_mpi_test_bit)
MARK_VISIBLEX (gcry_ctx_release)
@@ -482,6 +483,7 @@ MARK_VISIBLEX (_gcry_mpi_get_const)
#define gcry_mpi_sub_ui _gcry_USE_THE_UNDERSCORED_FUNCTION
#define gcry_mpi_subm _gcry_USE_THE_UNDERSCORED_FUNCTION
#define gcry_mpi_swap _gcry_USE_THE_UNDERSCORED_FUNCTION
+#define gcry_mpi_swap_conditional _gcry_USE_THE_UNDERSCORED_FUNCTION
#define gcry_mpi_test_bit _gcry_USE_THE_UNDERSCORED_FUNCTION
#define gcry_mpi_abs _gcry_USE_THE_UNDERSCORED_FUNCTION
diff --git a/tests/curves.c b/tests/curves.c
index 0581452..ae699d4 100644
--- a/tests/curves.c
+++ b/tests/curves.c
@@ -29,7 +29,7 @@
#include "../src/gcrypt-int.h"
/* Number of curves defined in ../cipger/ecc.c */
-#define N_CURVES 21
+#define N_CURVES 22
/* A real world sample public key. */
static char const sample_key_1[] =
@@ -64,6 +64,18 @@ static char const sample_key_2_curve[] = "brainpoolP160r1";
static unsigned int sample_key_2_nbits = 160;
+/* Another sample public key. */
+static char const sample_key_3[] =
+"(public-key\n"
+" (ecdh\n"
+" (curve Curve25519)\n"
+" (q #040000000000000000000000000000000000000000000000000000000000000000"
+" 0000000000000000000000000000000000000000000000000000000000000000#)\n"
+" ))";
+static char const sample_key_3_curve[] = "Curve25519";
+static unsigned int sample_key_3_nbits = 256;
+
+
/* Program option flags. */
static int verbose;
static int error_count;
@@ -91,6 +103,42 @@ die (const char *format, ...)
}
+static gcry_mpi_t
+hex2mpi (const char *string)
+{
+ gpg_error_t err;
+ gcry_mpi_t val;
+
+ err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
+ if (err)
+ die ("hex2mpi '%s' failed: %s\n", string, gpg_strerror (err));
+ return val;
+}
+
+
+/* Print an MPI S-expression. */
+static void
+print_mpi (const char *name, gcry_mpi_t a)
+{
+ gcry_error_t err;
+ unsigned char *buf;
+ int writerr = 0;
+
+ err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buf, NULL, a);
+ if (err)
+ die ("gcry_mpi_aprint failed: %s\n", gcry_strerror (err));
+
+ printf (" (%s #%s#)\n", name, buf);
+ if (ferror (stdout))
+ writerr++;
+ if (!writerr && fflush (stdout) == EOF)
+ writerr++;
+ if (writerr)
+ die ("writing output failed\n");
+ gcry_free (buf);
+}
+
+
static void
list_curves (void)
{
@@ -185,6 +233,85 @@ check_get_params (void)
}
+static void
+check_montgomery (void)
+{
+ gpg_error_t err;
+ gcry_sexp_t key;
+ const char *name;
+ unsigned int nbits;
+
+ gcry_ctx_t ctx;
+ gcry_mpi_point_t G, Q;
+ gcry_mpi_t d;
+ gcry_mpi_t x, y, z;
+
+ err = gcry_sexp_new (&key, sample_key_3, 0, 1);
+ if (err)
+ die ("parsing s-expression string failed: %s\n", gpg_strerror (err));
+ name = gcry_pk_get_curve (key, 0, &nbits);
+ if (!name)
+ fail ("curve name not found for sample_key_3\n");
+ else if (strcmp (name, sample_key_3_curve))
+ fail ("expected curve name %s but got %s for sample_key_3\n",
+ sample_key_3_curve, name);
+ else if (nbits != sample_key_3_nbits)
+ fail ("expected curve size %u but got %u for sample_key_3\n",
+ sample_key_3_nbits, nbits);
+
+ gcry_sexp_release (key);
+
+ Q = gcry_mpi_point_new (0);
+
+ err = gcry_mpi_ec_new (&ctx, NULL, "Curve25519");
+ if (err)
+ fail ("can't create ec context: %s\n", gpg_strerror (err));
+
+#if 0
+ d = hex2mpi ("40000000000000000000000000000000"
+ "00000000000000000000000000000000");
+ G = gcry_mpi_ec_get_point ("g", ctx, 1);
+ if (!G)
+ fail ("can't get basepoint of the curve: %s\n", gpg_strerror (err));
+#else
+ d = hex2mpi ("7d74fb61db3100e11e4d4ae171daf820688f3bcfa631565272a998b8f4e8c290");
+ {
+ gcry_mpi_t gx;
+ gx = hex2mpi ("3dc16d73d4222d12eb54623c85f3fb5ebdab33c1bd5865780654f1b0ed696ddf");
+
+ G = gcry_mpi_point_new (0);
+ gcry_mpi_point_snatch_set (G, gx, NULL, NULL);
+ }
+#endif
+
+ 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);
+
+ print_mpi ("Q.x", x);
+ print_mpi ("Q.y", y);
+ print_mpi ("Q.z", z);
+
+ if (gcry_mpi_ec_get_affine (x, NULL, Q, ctx))
+ fail ("failed to get affine coordinates\n");
+
+ print_mpi ("q.x", x);
+ /* 16B53A046DEEDD81ED6B0D470CE46DD9B5FAC6124F3D22358AA7CD2911FCFABC */
+
+ gcry_mpi_release (z);
+ gcry_mpi_release (y);
+ gcry_mpi_release (x);
+
+ gcry_mpi_point_release (Q);
+ gcry_mpi_release (d);
+ gcry_mpi_point_release (G);
+ gcry_ctx_release (ctx);
+}
+
int
main (int argc, char **argv)
{
@@ -205,6 +332,7 @@ main (int argc, char **argv)
list_curves ();
check_matching ();
check_get_params ();
+ check_montgomery ();
return error_count ? 1 : 0;
}
diff --git a/tests/keygen.c b/tests/keygen.c
index 4aff9c9..c53246c 100644
--- a/tests/keygen.c
+++ b/tests/keygen.c
@@ -365,7 +365,7 @@ static void
check_ecc_keys (void)
{
const char *curves[] = { "NIST P-521", "NIST P-384", "NIST P-256",
- "Ed25519", NULL };
+ "Ed25519", "Curve25519", NULL };
int testno;
gcry_sexp_t keyparm, key;
int rc;
--
More information about the Gcrypt-devel
mailing list