6683189ddb60de368d6b27c3ae947610b2109461
[libgcrypt.git] / tests / t-mpi-point.c
1 /* t-mpi-point.c  - Tests for mpi point functions
2  * Copyright (C) 2013 g10 Code GmbH
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <stdarg.h>
28
29 #include "../src/gcrypt-int.h"
30
31 #define PGM "t-mpi-point"
32
33 static const char *wherestr;
34 static int verbose;
35 static int debug;
36 static int error_count;
37
38
39 #define xmalloc(a)    gcry_xmalloc ((a))
40 #define xcalloc(a,b)  gcry_xcalloc ((a),(b))
41 #define xfree(a)      gcry_free ((a))
42 #define pass() do { ; } while (0)
43
44
45 static struct
46 {
47   const char *desc;           /* Description of the curve.  */
48   const char *p;              /* Order of the prime field.  */
49   const char *a, *b;          /* The coefficients. */
50   const char *n;              /* The order of the base point.  */
51   const char *g_x, *g_y;      /* Base point.  */
52 } test_curve[] =
53   {
54     {
55       "NIST P-192",
56       "0xfffffffffffffffffffffffffffffffeffffffffffffffff",
57       "0xfffffffffffffffffffffffffffffffefffffffffffffffc",
58       "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
59       "0xffffffffffffffffffffffff99def836146bc9b1b4d22831",
60
61       "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
62       "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"
63     },
64     {
65       "NIST P-224",
66       "0xffffffffffffffffffffffffffffffff000000000000000000000001",
67       "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe",
68       "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
69       "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" ,
70
71       "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
72       "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"
73     },
74     {
75       "NIST P-256",
76       "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
77       "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc",
78       "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
79       "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
80
81       "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
82       "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
83     },
84     {
85       "NIST P-384",
86       "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
87       "ffffffff0000000000000000ffffffff",
88       "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
89       "ffffffff0000000000000000fffffffc",
90       "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a"
91       "c656398d8a2ed19d2a85c8edd3ec2aef",
92       "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf"
93       "581a0db248b0a77aecec196accc52973",
94
95       "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38"
96       "5502f25dbf55296c3a545e3872760ab7",
97       "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0"
98       "0a60b1ce1d7e819d7a431d7c90ea0e5f"
99     },
100     {
101       "NIST P-521",
102       "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
103       "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
104       "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
105       "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc",
106       "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10"
107       "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
108       "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
109       "ffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409",
110
111       "0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3d"
112       "baa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
113       "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e6"
114       "62c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"
115     },
116     { NULL, NULL, NULL, NULL, NULL }
117   };
118
119 /* A sample public key for NIST P-256.  */
120 static const char sample_p256_q[] =
121   "04"
122   "42B927242237639A36CE9221B340DB1A9AB76DF2FE3E171277F6A4023DED146E"
123   "E86525E38CCECFF3FB8D152CC6334F70D23A525175C1BCBDDE6E023B2228770E";
124 static const char sample_p256_q_x[] =
125   "42B927242237639A36CE9221B340DB1A9AB76DF2FE3E171277F6A4023DED146E";
126 static const char sample_p256_q_y[] =
127   "00E86525E38CCECFF3FB8D152CC6334F70D23A525175C1BCBDDE6E023B2228770E";
128
129
130
131 static void
132 show (const char *format, ...)
133 {
134   va_list arg_ptr;
135
136   if (!verbose)
137     return;
138   fprintf (stderr, "%s: ", PGM);
139   va_start (arg_ptr, format);
140   vfprintf (stderr, format, arg_ptr);
141   va_end (arg_ptr);
142 }
143
144 static void
145 fail (const char *format, ...)
146 {
147   va_list arg_ptr;
148
149   fflush (stdout);
150   fprintf (stderr, "%s: ", PGM);
151   if (wherestr)
152     fprintf (stderr, "%s: ", wherestr);
153   va_start (arg_ptr, format);
154   vfprintf (stderr, format, arg_ptr);
155   va_end (arg_ptr);
156   error_count++;
157 }
158
159 static void
160 die (const char *format, ...)
161 {
162   va_list arg_ptr;
163
164   fflush (stdout);
165   fprintf (stderr, "%s: ", PGM);
166   if (wherestr)
167     fprintf (stderr, "%s: ", wherestr);
168   va_start (arg_ptr, format);
169   vfprintf (stderr, format, arg_ptr);
170   va_end (arg_ptr);
171   exit (1);
172 }
173
174
175 static void
176 print_mpi_2 (const char *text, const char *text2, gcry_mpi_t a)
177 {
178   gcry_error_t err;
179   char *buf;
180   void *bufaddr = &buf;
181
182   err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a);
183   if (err)
184     fprintf (stderr, "%s%s: [error printing number: %s]\n",
185              text, text2? text2:"", gpg_strerror (err));
186   else
187     {
188       fprintf (stderr, "%s%s: %s\n", text, text2? text2:"", buf);
189       gcry_free (buf);
190     }
191 }
192
193
194 static void
195 print_mpi (const char *text, gcry_mpi_t a)
196 {
197   print_mpi_2 (text, NULL, a);
198 }
199
200
201 static void
202 print_point (const char *text, gcry_mpi_point_t a)
203 {
204   gcry_mpi_t x, y, z;
205
206   x = gcry_mpi_new (0);
207   y = gcry_mpi_new (0);
208   z = gcry_mpi_new (0);
209   gcry_mpi_point_get (x, y, z, a);
210   print_mpi_2 (text, ".x", x);
211   print_mpi_2 (text, ".y", y);
212   print_mpi_2 (text, ".z", z);
213   gcry_mpi_release (x);
214   gcry_mpi_release (y);
215   gcry_mpi_release (z);
216 }
217
218
219 static void
220 print_sexp (const char *prefix, gcry_sexp_t a)
221 {
222   char *buf;
223   size_t size;
224
225   if (prefix)
226     fputs (prefix, stderr);
227   size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0);
228   buf = gcry_xmalloc (size);
229
230   gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size);
231   fprintf (stderr, "%.*s", (int)size, buf);
232   gcry_free (buf);
233 }
234
235
236 static gcry_mpi_t
237 hex2mpi (const char *string)
238 {
239   gpg_error_t err;
240   gcry_mpi_t val;
241
242   err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
243   if (err)
244     die ("hex2mpi '%s' failed: %s\n", gpg_strerror (err));
245   return val;
246 }
247
248
249 /* Compare A to B, where B is given as a hex string.  */
250 static int
251 cmp_mpihex (gcry_mpi_t a, const char *b)
252 {
253   gcry_mpi_t bval;
254   int res;
255
256   bval = hex2mpi (b);
257   res = gcry_mpi_cmp (a, bval);
258   gcry_mpi_release (bval);
259   return res;
260 }
261
262
263 /* Wrapper to emulate the libgcrypt internal EC context allocation
264    function.  */
265 static gpg_error_t
266 ec_p_new (gcry_ctx_t *r_ctx, gcry_mpi_t p, gcry_mpi_t a)
267 {
268   gpg_error_t err;
269   gcry_sexp_t sexp;
270
271   if (p && a)
272     err = gcry_sexp_build (&sexp, NULL, "(ecdsa (p %m)(a %m))", p, a);
273   else if (p)
274     err = gcry_sexp_build (&sexp, NULL, "(ecdsa (p %m))", p);
275   else if (a)
276     err = gcry_sexp_build (&sexp, NULL, "(ecdsa (a %m))", a);
277   else
278     err = gcry_sexp_build (&sexp, NULL, "(ecdsa)");
279   if (err)
280     return err;
281   err = gcry_mpi_ec_new (r_ctx, sexp, NULL);
282   gcry_sexp_release (sexp);
283   return err;
284 }
285
286
287 \f
288 static void
289 set_get_point (void)
290 {
291   gcry_mpi_point_t point;
292   gcry_mpi_t x, y, z;
293
294   wherestr = "set_get_point";
295   show ("checking point setting functions\n");
296
297   point = gcry_mpi_point_new (0);
298   x = gcry_mpi_set_ui (NULL, 17);
299   y = gcry_mpi_set_ui (NULL, 42);
300   z = gcry_mpi_set_ui (NULL, 11371);
301   gcry_mpi_point_get (x, y, z, point);
302   if (gcry_mpi_cmp_ui (x, 0)
303       || gcry_mpi_cmp_ui (y, 0) || gcry_mpi_cmp_ui (z, 0))
304     fail ("new point not initialized to (0,0,0)\n");
305   gcry_mpi_point_snatch_get (x, y, z, point);
306   point = NULL;
307   if (gcry_mpi_cmp_ui (x, 0)
308       || gcry_mpi_cmp_ui (y, 0) || gcry_mpi_cmp_ui (z, 0))
309     fail ("snatch_get failed\n");
310   gcry_mpi_release (x);
311   gcry_mpi_release (y);
312   gcry_mpi_release (z);
313
314   point = gcry_mpi_point_new (0);
315   x = gcry_mpi_set_ui (NULL, 17);
316   y = gcry_mpi_set_ui (NULL, 42);
317   z = gcry_mpi_set_ui (NULL, 11371);
318   gcry_mpi_point_set (point, x, y, z);
319   gcry_mpi_set_ui (x, 23);
320   gcry_mpi_set_ui (y, 24);
321   gcry_mpi_set_ui (z, 25);
322   gcry_mpi_point_get (x, y, z, point);
323   if (gcry_mpi_cmp_ui (x, 17)
324       || gcry_mpi_cmp_ui (y, 42) || gcry_mpi_cmp_ui (z, 11371))
325     fail ("point_set/point_get failed\n");
326   gcry_mpi_point_snatch_set (point, x, y, z);
327   x = gcry_mpi_new (0);
328   y = gcry_mpi_new (0);
329   z = gcry_mpi_new (0);
330   gcry_mpi_point_get (x, y, z, point);
331   if (gcry_mpi_cmp_ui (x, 17)
332       || gcry_mpi_cmp_ui (y, 42) || gcry_mpi_cmp_ui (z, 11371))
333     fail ("point_snatch_set/point_get failed\n");
334
335   gcry_mpi_point_release (point);
336   gcry_mpi_release (x);
337   gcry_mpi_release (y);
338   gcry_mpi_release (z);
339 }
340
341
342 static void
343 context_alloc (void)
344 {
345   gpg_error_t err;
346   gcry_ctx_t ctx;
347   gcry_mpi_t p, a;
348
349   wherestr = "context_alloc";
350   show ("checking context functions\n");
351
352   p = gcry_mpi_set_ui (NULL, 1);
353   a = gcry_mpi_set_ui (NULL, 1);
354   err = ec_p_new (&ctx, p, a);
355   if (err)
356     die ("ec_p_new returned an error: %s\n", gpg_strerror (err));
357   gcry_mpi_release (p);
358   gcry_mpi_release (a);
359   gcry_ctx_release (ctx);
360
361   p = gcry_mpi_set_ui (NULL, 0);
362   a = gcry_mpi_set_ui (NULL, 0);
363   err = ec_p_new (&ctx, p, a);
364   if (!err || gpg_err_code (err) != GPG_ERR_EINVAL)
365     fail ("ec_p_new: bad parameter detection failed (1)\n");
366
367   gcry_mpi_set_ui (p, 1);
368   err = ec_p_new (&ctx, p, a);
369   if (!err || gpg_err_code (err) != GPG_ERR_EINVAL)
370     fail ("ec_p_new: bad parameter detection failed (2)\n");
371
372   gcry_mpi_release (p);
373   p = NULL;
374   err = ec_p_new (&ctx, p, a);
375   if (!err || gpg_err_code (err) != GPG_ERR_EINVAL)
376     fail ("ec_p_new: bad parameter detection failed (3)\n");
377
378   gcry_mpi_release (a);
379   a = NULL;
380   err = ec_p_new (&ctx, p, a);
381   if (!err || gpg_err_code (err) != GPG_ERR_EINVAL)
382     fail ("ec_p_new: bad parameter detection failed (4)\n");
383
384 }
385
386
387 static int
388 get_and_cmp_mpi (const char *name, const char *mpistring, const char *desc,
389                  gcry_ctx_t ctx)
390 {
391   gcry_mpi_t mpi;
392
393   mpi = gcry_mpi_ec_get_mpi (name, ctx, 1);
394   if (!mpi)
395     {
396       fail ("error getting parameter '%s' of curve '%s'\n", name, desc);
397       return 1;
398     }
399   if (debug)
400     print_mpi (name, mpi);
401   if (cmp_mpihex (mpi, mpistring))
402     {
403       fail ("parameter '%s' of curve '%s' does not match\n", name, desc);
404       gcry_mpi_release (mpi);
405       return 1;
406     }
407   gcry_mpi_release (mpi);
408   return 0;
409 }
410
411
412 static int
413 get_and_cmp_point (const char *name,
414                    const char *mpi_x_string, const char *mpi_y_string,
415                    const char *desc, gcry_ctx_t ctx)
416 {
417   gcry_mpi_point_t point;
418   gcry_mpi_t x, y, z;
419   int result = 0;
420
421   point = gcry_mpi_ec_get_point (name, ctx, 1);
422   if (!point)
423     {
424       fail ("error getting point parameter '%s' of curve '%s'\n", name, desc);
425       return 1;
426     }
427   if (debug)
428     print_point (name, point);
429
430   x = gcry_mpi_new (0);
431   y = gcry_mpi_new (0);
432   z = gcry_mpi_new (0);
433   gcry_mpi_point_snatch_get (x, y, z, point);
434   if (cmp_mpihex (x, mpi_x_string))
435     {
436       fail ("x coordinate of '%s' of curve '%s' does not match\n", name, desc);
437       result = 1;
438     }
439   if (cmp_mpihex (y, mpi_y_string))
440     {
441       fail ("y coordinate of '%s' of curve '%s' does not match\n", name, desc);
442       result = 1;
443     }
444   if (cmp_mpihex (z, "01"))
445     {
446       fail ("z coordinate of '%s' of curve '%s' is not 1\n", name, desc);
447       result = 1;
448     }
449   gcry_mpi_release (x);
450   gcry_mpi_release (y);
451   gcry_mpi_release (z);
452   return result;
453 }
454
455
456 static void
457 context_param (void)
458 {
459   gpg_error_t err;
460   int idx;
461   gcry_ctx_t ctx = NULL;
462   gcry_mpi_t q;
463   gcry_sexp_t keyparam;
464
465   wherestr = "context_param";
466
467   show ("checking standard curves\n");
468   for (idx=0; test_curve[idx].desc; idx++)
469     {
470       gcry_ctx_release (ctx);
471       err = gcry_mpi_ec_new (&ctx, NULL, test_curve[idx].desc);
472       if (err)
473         {
474           fail ("can't create context for curve '%s': %s\n",
475                 test_curve[idx].desc, gpg_strerror (err));
476           continue;
477         }
478       if (get_and_cmp_mpi ("p", test_curve[idx].p, test_curve[idx].desc, ctx))
479         continue;
480       if (get_and_cmp_mpi ("a", test_curve[idx].a, test_curve[idx].desc, ctx))
481         continue;
482       if (get_and_cmp_mpi ("b", test_curve[idx].b, test_curve[idx].desc, ctx))
483         continue;
484       if (get_and_cmp_mpi ("g.x",test_curve[idx].g_x, test_curve[idx].desc,ctx))
485         continue;
486       if (get_and_cmp_mpi ("g.y",test_curve[idx].g_y, test_curve[idx].desc,ctx))
487         continue;
488       if (get_and_cmp_mpi ("n", test_curve[idx].n, test_curve[idx].desc, ctx))
489         continue;
490       if (get_and_cmp_point ("g", test_curve[idx].g_x, test_curve[idx].g_y,
491                              test_curve[idx].desc, ctx))
492         continue;
493
494     }
495   gcry_ctx_release (ctx);
496
497
498   show ("checking sample public key\n");
499   q = hex2mpi (sample_p256_q);
500   err = gcry_sexp_build (&keyparam, NULL,
501                         "(public-key(ecdsa(curve %s)(q %m)))",
502                         "NIST P-256", q);
503   if (err)
504     die ("gcry_sexp_build failed: %s\n", gpg_strerror (err));
505   gcry_mpi_release (q);
506
507   /* We can't call gcry_pk_testkey because it is only implemented for
508      private keys.  */
509   /* err = gcry_pk_testkey (keyparam); */
510   /* if (err) */
511   /*   fail ("gcry_pk_testkey failed for sample public key: %s\n", */
512   /*         gpg_strerror (err)); */
513
514   err = gcry_mpi_ec_new (&ctx, keyparam, NULL);
515   if (err)
516     fail ("gcry_mpi_ec_new failed for sample public key: %s\n",
517           gpg_strerror (err));
518   else
519     {
520       gcry_sexp_t sexp;
521
522       get_and_cmp_mpi ("q", sample_p256_q, "NIST P-256", ctx);
523       get_and_cmp_point ("q", sample_p256_q_x, sample_p256_q_y, "NIST P-256",
524                          ctx);
525
526       err = gcry_pubkey_get_sexp (&sexp, 0, ctx);
527       if (err)
528         fail ("gcry_pubkey_get_sexp(0) failed: %s\n", gpg_strerror (err));
529       else if (debug)
530         print_sexp ("Result of gcry_pubkey_get_sexp (0):\n", sexp);
531       gcry_sexp_release (sexp);
532
533       err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_PUBKEY, ctx);
534       if (err)
535         fail ("gcry_pubkey_get_sexp(GET_PUBKEY) failed: %s\n",
536               gpg_strerror (err));
537       else if (debug)
538         print_sexp ("Result of gcry_pubkey_get_sexp (GET_PUBKEY):\n", sexp);
539       gcry_sexp_release (sexp);
540
541       err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_SECKEY, ctx);
542       if (gpg_err_code (err) != GPG_ERR_NO_SECKEY)
543         fail ("gcry_pubkey_get_sexp(GET_SECKEY) returned wrong error: %s\n",
544               gpg_strerror (err));
545       gcry_sexp_release (sexp);
546
547       gcry_ctx_release (ctx);
548     }
549
550   gcry_sexp_release (keyparam);
551 }
552
553
554
555
556 /* Create a new point from (X,Y,Z) given as hex strings.  */
557 gcry_mpi_point_t
558 make_point (const char *x, const char *y, const char *z)
559 {
560   gcry_mpi_point_t point;
561
562   point = gcry_mpi_point_new (0);
563   gcry_mpi_point_snatch_set (point, hex2mpi (x), hex2mpi (y), hex2mpi (z));
564
565   return point;
566 }
567
568
569 /* This tests checks that the low-level EC API yields the same result
570    as using the high level API.  The values have been taken from a
571    test run using the high level API.  */
572 static void
573 basic_ec_math (void)
574 {
575   gpg_error_t err;
576   gcry_ctx_t ctx;
577   gcry_mpi_t P, A;
578   gcry_mpi_point_t G, Q;
579   gcry_mpi_t d;
580   gcry_mpi_t x, y, z;
581
582   wherestr = "basic_ec_math";
583   show ("checking basic math functions for EC\n");
584
585   P = hex2mpi ("0xfffffffffffffffffffffffffffffffeffffffffffffffff");
586   A = hex2mpi ("0xfffffffffffffffffffffffffffffffefffffffffffffffc");
587   G = make_point ("188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
588                   "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
589                   "1");
590   d = hex2mpi ("D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D");
591   Q = gcry_mpi_point_new (0);
592
593   err = ec_p_new (&ctx, P, A);
594   if (err)
595     die ("ec_p_new failed: %s\n", gpg_strerror (err));
596
597   x = gcry_mpi_new (0);
598   y = gcry_mpi_new (0);
599   z = gcry_mpi_new (0);
600
601   {
602     /* A quick check that multiply by zero works.  */
603     gcry_mpi_t tmp;
604
605     tmp = gcry_mpi_new (0);
606     gcry_mpi_ec_mul (Q, tmp, G, ctx);
607     gcry_mpi_release (tmp);
608     gcry_mpi_point_get (x, y, z, Q);
609     if (gcry_mpi_cmp_ui (x, 0) || gcry_mpi_cmp_ui (y, 0)
610         || gcry_mpi_cmp_ui (z, 0))
611       fail ("multiply a point by zero failed\n");
612   }
613
614   gcry_mpi_ec_mul (Q, d, G, ctx);
615   gcry_mpi_point_get (x, y, z, Q);
616   if (cmp_mpihex (x, "222D9EC717C89D047E0898C9185B033CD11C0A981EE6DC66")
617       || cmp_mpihex (y, "605DE0A82D70D3E0F84A127D0739ED33D657DF0D054BFDE8")
618       || cmp_mpihex (z, "00B06B519071BC536999AC8F2D3934B3C1FC9EACCD0A31F88F"))
619     fail ("computed public key does not match\n");
620   if (debug)
621     {
622       print_mpi ("Q.x", x);
623       print_mpi ("Q.y", y);
624       print_mpi ("Q.z", z);
625     }
626
627   if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
628     fail ("failed to get affine coordinates\n");
629   if (cmp_mpihex (x, "008532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE")
630       || cmp_mpihex (y, "00C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966"))
631     fail ("computed affine coordinates of public key do not match\n");
632   if (debug)
633     {
634       print_mpi ("q.x", x);
635       print_mpi ("q.y", y);
636     }
637
638   gcry_mpi_release (z);
639   gcry_mpi_release (y);
640   gcry_mpi_release (x);
641   gcry_mpi_point_release (Q);
642   gcry_mpi_release (d);
643   gcry_mpi_point_release (G);
644   gcry_mpi_release (A);
645   gcry_mpi_release (P);
646   gcry_ctx_release (ctx);
647 }
648
649
650 /* This is the same as basic_ec_math but uses more advanced
651    features.  */
652 static void
653 basic_ec_math_simplified (void)
654 {
655   gpg_error_t err;
656   gcry_ctx_t ctx;
657   gcry_mpi_point_t G, Q;
658   gcry_mpi_t d;
659   gcry_mpi_t x, y, z;
660   gcry_sexp_t sexp;
661
662   wherestr = "basic_ec_math_simplified";
663   show ("checking basic math functions for EC (variant)\n");
664
665   d = hex2mpi ("D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D");
666   Q = gcry_mpi_point_new (0);
667
668   err = gcry_mpi_ec_new (&ctx, NULL, "NIST P-192");
669   if (err)
670     die ("gcry_mpi_ec_new failed: %s\n", gpg_strerror (err));
671   G = gcry_mpi_ec_get_point ("g", ctx, 1);
672   if (!G)
673     die ("gcry_mpi_ec_get_point(G) failed\n");
674   gcry_mpi_ec_mul (Q, d, G, ctx);
675
676   x = gcry_mpi_new (0);
677   y = gcry_mpi_new (0);
678   z = gcry_mpi_new (0);
679   gcry_mpi_point_get (x, y, z, Q);
680   if (cmp_mpihex (x, "222D9EC717C89D047E0898C9185B033CD11C0A981EE6DC66")
681       || cmp_mpihex (y, "605DE0A82D70D3E0F84A127D0739ED33D657DF0D054BFDE8")
682       || cmp_mpihex (z, "00B06B519071BC536999AC8F2D3934B3C1FC9EACCD0A31F88F"))
683     fail ("computed public key does not match\n");
684   if (debug)
685     {
686       print_mpi ("Q.x", x);
687       print_mpi ("Q.y", y);
688       print_mpi ("Q.z", z);
689     }
690
691   if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
692     fail ("failed to get affine coordinates\n");
693   if (cmp_mpihex (x, "008532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE")
694       || cmp_mpihex (y, "00C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966"))
695     fail ("computed affine coordinates of public key do not match\n");
696   if (debug)
697     {
698       print_mpi ("q.x", x);
699       print_mpi ("q.y", y);
700     }
701
702   gcry_mpi_release (z);
703   gcry_mpi_release (y);
704   gcry_mpi_release (x);
705
706   /* Let us also check whether we can update the context.  */
707   err = gcry_mpi_ec_set_point ("g", G, ctx);
708   if (err)
709     die ("gcry_mpi_ec_set_point(G) failed\n");
710   err = gcry_mpi_ec_set_mpi ("d", d, ctx);
711   if (err)
712     die ("gcry_mpi_ec_set_mpi(d) failed\n");
713
714   /* FIXME: Below we need to check that the returned S-expression is
715      as requested.  For now we use manual inspection using --debug.  */
716
717   /* Does get_sexp return the private key?  */
718   err = gcry_pubkey_get_sexp (&sexp, 0, ctx);
719   if (err)
720     fail ("gcry_pubkey_get_sexp(0) failed: %s\n", gpg_strerror (err));
721   else if (debug)
722     print_sexp ("Result of gcry_pubkey_get_sexp (0):\n", sexp);
723   gcry_sexp_release (sexp);
724
725   /* Does get_sexp return the public key if requested?  */
726   err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_PUBKEY, ctx);
727   if (err)
728     fail ("gcry_pubkey_get_sexp(GET_PUBKEY) failed: %s\n", gpg_strerror (err));
729   else if (debug)
730     print_sexp ("Result of gcry_pubkey_get_sexp (GET_PUBKEY):\n", sexp);
731   gcry_sexp_release (sexp);
732
733   /* Does get_sexp return the public key if after d has been deleted?  */
734   err = gcry_mpi_ec_set_mpi ("d", NULL, ctx);
735   if (err)
736     die ("gcry_mpi_ec_set_mpi(d=NULL) failed\n");
737   err = gcry_pubkey_get_sexp (&sexp, 0, ctx);
738   if (err)
739     fail ("gcry_pubkey_get_sexp(0 w/o d) failed: %s\n", gpg_strerror (err));
740   else if (debug)
741     print_sexp ("Result of gcry_pubkey_get_sexp (0 w/o d):\n", sexp);
742   gcry_sexp_release (sexp);
743
744   /* Does get_sexp return an error after d has been deleted?  */
745   err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_SECKEY, ctx);
746   if (gpg_err_code (err) != GPG_ERR_NO_SECKEY)
747     fail ("gcry_pubkey_get_sexp(GET_SECKEY) returned wrong error: %s\n",
748           gpg_strerror (err));
749   gcry_sexp_release (sexp);
750
751   /* Does get_sexp return an error after d and Q have been deleted?  */
752   err = gcry_mpi_ec_set_point ("q", NULL, ctx);
753   if (err)
754     die ("gcry_mpi_ec_set_point(q=NULL) failed\n");
755   err = gcry_pubkey_get_sexp (&sexp, 0, ctx);
756   if (gpg_err_code (err) != GPG_ERR_BAD_CRYPT_CTX)
757     fail ("gcry_pubkey_get_sexp(0 w/o Q,d) returned wrong error: %s\n",
758           gpg_strerror (err));
759   gcry_sexp_release (sexp);
760
761
762   gcry_mpi_point_release (Q);
763   gcry_mpi_release (d);
764   gcry_mpi_point_release (G);
765   gcry_ctx_release (ctx);
766 }
767
768
769 /* Check the math used with Twisted Edwards curves.  */
770 static void
771 twistededwards_math (void)
772 {
773   gpg_error_t err;
774   gcry_ctx_t ctx;
775   gcry_mpi_point_t G, Q;
776   gcry_mpi_t k;
777   gcry_mpi_t w, a, x, y, z, p, n, b, I;
778
779   wherestr = "twistededwards_math";
780   show ("checking basic Twisted Edwards math\n");
781
782   err = gcry_mpi_ec_new (&ctx, NULL, "Ed25519");
783   if (err)
784     die ("gcry_mpi_ec_new failed: %s\n", gpg_strerror (err));
785
786   k = hex2mpi
787     ("2D3501E723239632802454EE5DDC406EFB0BDF18486A5BDE9C0390A9C2984004"
788      "F47252B628C953625B8DEB5DBCB8DA97AA43A1892D11FA83596F42E0D89CB1B6");
789   G = gcry_mpi_ec_get_point ("g", ctx, 1);
790   if (!G)
791     die ("gcry_mpi_ec_get_point(G) failed\n");
792   Q = gcry_mpi_point_new (0);
793
794
795   w = gcry_mpi_new (0);
796   a = gcry_mpi_new (0);
797   x = gcry_mpi_new (0);
798   y = gcry_mpi_new (0);
799   z = gcry_mpi_new (0);
800   I = gcry_mpi_new (0);
801   p = gcry_mpi_ec_get_mpi ("p", ctx, 1);
802   n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
803   b = gcry_mpi_ec_get_mpi ("b", ctx, 1);
804
805   /* Check: 2^{p-1} mod p == 1 */
806   gcry_mpi_sub_ui (a, p, 1);
807   gcry_mpi_powm (w, GCRYMPI_CONST_TWO, a, p);
808   if (gcry_mpi_cmp_ui (w, 1))
809     fail ("failed assertion: 2^{p-1} mod p == 1\n");
810
811   /* Check: p % 4 == 1 */
812   gcry_mpi_mod (w, p, GCRYMPI_CONST_FOUR);
813   if (gcry_mpi_cmp_ui (w, 1))
814     fail ("failed assertion: p % 4 == 1\n");
815
816   /* Check: 2^{n-1} mod n == 1 */
817   gcry_mpi_sub_ui (a, n, 1);
818   gcry_mpi_powm (w, GCRYMPI_CONST_TWO, a, n);
819   if (gcry_mpi_cmp_ui (w, 1))
820     fail ("failed assertion: 2^{n-1} mod n == 1\n");
821
822   /* Check: b^{(p-1)/2} mod p == p-1 */
823   gcry_mpi_sub_ui (a, p, 1);
824   gcry_mpi_div (x, NULL, a, GCRYMPI_CONST_TWO, -1);
825   gcry_mpi_powm (w, b, x, p);
826   gcry_mpi_abs (w);
827   if (gcry_mpi_cmp (w, a))
828     fail ("failed assertion: b^{(p-1)/2} mod p == p-1\n");
829
830   /* I := 2^{(p-1)/4} mod p */
831   gcry_mpi_sub_ui (a, p, 1);
832   gcry_mpi_div (x, NULL, a, GCRYMPI_CONST_FOUR, -1);
833   gcry_mpi_powm (I, GCRYMPI_CONST_TWO, x, p);
834
835   /* Check: I^2 mod p == p-1 */
836   gcry_mpi_powm (w, I, GCRYMPI_CONST_TWO, p);
837   if (gcry_mpi_cmp (w, a))
838     fail ("failed assertion: I^2 mod p == p-1\n");
839
840   /* Check: G is on the curve */
841   if (!gcry_mpi_ec_curve_point (G, ctx))
842     fail ("failed assertion: G is on the curve\n");
843
844   /* Check: nG == (0,1) */
845   gcry_mpi_ec_mul (Q, n, G, ctx);
846   if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
847     fail ("failed to get affine coordinates\n");
848   if (gcry_mpi_cmp_ui (x, 0) || gcry_mpi_cmp_ui (y, 1))
849     fail ("failed assertion: nG == (0,1)\n");
850
851   /* Now two arbitrary point operations taken from the ed25519.py
852      sample data.  */
853   gcry_mpi_release (a);
854   a = hex2mpi
855     ("4f71d012df3c371af3ea4dc38385ca5bb7272f90cb1b008b3ed601c76de1d496"
856      "e30cbf625f0a756a678d8f256d5325595cccc83466f36db18f0178eb9925edd3");
857   gcry_mpi_ec_mul (Q, a, G, ctx);
858   if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
859     fail ("failed to get affine coordinates\n");
860   if (cmp_mpihex (x, ("157f7361c577aad36f67ed33e38dc7be"
861                       "00014fecc2165ca5cee9eee19fe4d2c1"))
862       || cmp_mpihex (y, ("5a69dbeb232276b38f3f5016547bb2a2"
863                          "4025645f0b820e72b8cad4f0a909a092")))
864     {
865       fail ("sample point multiply failed:\n");
866       print_mpi ("r", a);
867       print_mpi ("Rx", x);
868       print_mpi ("Ry", y);
869     }
870
871   gcry_mpi_release (a);
872   a = hex2mpi
873     ("2d3501e723239632802454ee5ddc406efb0bdf18486a5bde9c0390a9c2984004"
874      "f47252b628c953625b8deb5dbcb8da97aa43a1892d11fa83596f42e0d89cb1b6");
875   gcry_mpi_ec_mul (Q, a, G, ctx);
876   if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
877     fail ("failed to get affine coordinates\n");
878   if (cmp_mpihex (x, ("6218e309d40065fcc338b3127f468371"
879                       "82324bd01ce6f3cf81ab44e62959c82a"))
880       || cmp_mpihex (y, ("5501492265e073d874d9e5b81e7f8784"
881                          "8a826e80cce2869072ac60c3004356e5")))
882     {
883       fail ("sample point multiply failed:\n");
884       print_mpi ("r", a);
885       print_mpi ("Rx", x);
886       print_mpi ("Ry", y);
887     }
888
889
890   gcry_mpi_release (I);
891   gcry_mpi_release (b);
892   gcry_mpi_release (n);
893   gcry_mpi_release (p);
894   gcry_mpi_release (w);
895   gcry_mpi_release (a);
896   gcry_mpi_release (x);
897   gcry_mpi_release (y);
898   gcry_mpi_release (z);
899   gcry_mpi_point_release (Q);
900   gcry_mpi_point_release (G);
901   gcry_mpi_release (k);
902   gcry_ctx_release (ctx);
903 }
904
905
906 int
907 main (int argc, char **argv)
908 {
909
910   if (argc > 1 && !strcmp (argv[1], "--verbose"))
911     verbose = 1;
912   else if (argc > 1 && !strcmp (argv[1], "--debug"))
913     verbose = debug = 1;
914
915   if (!gcry_check_version (GCRYPT_VERSION))
916     die ("version mismatch\n");
917
918   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
919   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
920   if (debug)
921     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
922   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
923
924   set_get_point ();
925   context_alloc ();
926   context_param ();
927   basic_ec_math ();
928   basic_ec_math_simplified ();
929   twistededwards_math ();
930
931   show ("All tests completed. Errors: %d\n", error_count);
932   return error_count ? 1 : 0;
933 }