mpi: Add functions to manipulate an EC context.
[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.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
120
121
122 static void
123 show (const char *format, ...)
124 {
125   va_list arg_ptr;
126
127   if (!verbose)
128     return;
129   fprintf (stderr, "%s: ", PGM);
130   va_start (arg_ptr, format);
131   vfprintf (stderr, format, arg_ptr);
132   va_end (arg_ptr);
133 }
134
135 static void
136 fail (const char *format, ...)
137 {
138   va_list arg_ptr;
139
140   fflush (stdout);
141   fprintf (stderr, "%s: ", PGM);
142   if (wherestr)
143     fprintf (stderr, "%s: ", wherestr);
144   va_start (arg_ptr, format);
145   vfprintf (stderr, format, arg_ptr);
146   va_end (arg_ptr);
147   error_count++;
148 }
149
150 static void
151 die (const char *format, ...)
152 {
153   va_list arg_ptr;
154
155   fflush (stdout);
156   fprintf (stderr, "%s: ", PGM);
157   if (wherestr)
158     fprintf (stderr, "%s: ", wherestr);
159   va_start (arg_ptr, format);
160   vfprintf (stderr, format, arg_ptr);
161   va_end (arg_ptr);
162   exit (1);
163 }
164
165
166 static void
167 print_mpi (const char *text, gcry_mpi_t a)
168 {
169   gcry_error_t err;
170   char *buf;
171   void *bufaddr = &buf;
172
173   err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a);
174   if (err)
175     fprintf (stderr, "%s: [error printing number: %s]\n",
176              text, gpg_strerror (err));
177   else
178     {
179       fprintf (stderr, "%s: %s\n", text, buf);
180       gcry_free (buf);
181     }
182 }
183
184
185 static gcry_mpi_t
186 hex2mpi (const char *string)
187 {
188   gpg_error_t err;
189   gcry_mpi_t val;
190
191   err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
192   if (err)
193     die ("hex2mpi '%s' failed: %s\n", gpg_strerror (err));
194   return val;
195 }
196
197
198 /* Compare A to B, where B is given as a hex string.  */
199 static int
200 cmp_mpihex (gcry_mpi_t a, const char *b)
201 {
202   gcry_mpi_t bval;
203   int res;
204
205   bval = hex2mpi (b);
206   res = gcry_mpi_cmp (a, bval);
207   gcry_mpi_release (bval);
208   return res;
209 }
210
211
212 /* Wrapper to emulate the libgcrypt internal EC context allocation
213    function.  */
214 static gpg_error_t
215 ec_p_new (gcry_ctx_t *r_ctx, gcry_mpi_t p, gcry_mpi_t a)
216 {
217   gpg_error_t err;
218   gcry_sexp_t sexp;
219
220   if (p && a)
221     err = gcry_sexp_build (&sexp, NULL, "(ecdsa (p %m)(a %m))", p, a);
222   else if (p)
223     err = gcry_sexp_build (&sexp, NULL, "(ecdsa (p %m))", p);
224   else if (a)
225     err = gcry_sexp_build (&sexp, NULL, "(ecdsa (a %m))", a);
226   else
227     err = gcry_sexp_build (&sexp, NULL, "(ecdsa)");
228   if (err)
229     return err;
230   err = gcry_mpi_ec_new (r_ctx, sexp, NULL);
231   gcry_sexp_release (sexp);
232   return err;
233 }
234
235
236 \f
237 static void
238 set_get_point (void)
239 {
240   gcry_mpi_point_t point;
241   gcry_mpi_t x, y, z;
242
243   wherestr = "set_get_point";
244   show ("checking point setting functions\n");
245
246   point = gcry_mpi_point_new (0);
247   x = gcry_mpi_set_ui (NULL, 17);
248   y = gcry_mpi_set_ui (NULL, 42);
249   z = gcry_mpi_set_ui (NULL, 11371);
250   gcry_mpi_point_get (x, y, z, point);
251   if (gcry_mpi_cmp_ui (x, 0)
252       || gcry_mpi_cmp_ui (y, 0) || gcry_mpi_cmp_ui (z, 0))
253     fail ("new point not initialized to (0,0,0)\n");
254   gcry_mpi_point_snatch_get (x, y, z, point);
255   point = NULL;
256   if (gcry_mpi_cmp_ui (x, 0)
257       || gcry_mpi_cmp_ui (y, 0) || gcry_mpi_cmp_ui (z, 0))
258     fail ("snatch_get failed\n");
259   gcry_mpi_release (x);
260   gcry_mpi_release (y);
261   gcry_mpi_release (z);
262
263   point = gcry_mpi_point_new (0);
264   x = gcry_mpi_set_ui (NULL, 17);
265   y = gcry_mpi_set_ui (NULL, 42);
266   z = gcry_mpi_set_ui (NULL, 11371);
267   gcry_mpi_point_set (point, x, y, z);
268   gcry_mpi_set_ui (x, 23);
269   gcry_mpi_set_ui (y, 24);
270   gcry_mpi_set_ui (z, 25);
271   gcry_mpi_point_get (x, y, z, point);
272   if (gcry_mpi_cmp_ui (x, 17)
273       || gcry_mpi_cmp_ui (y, 42) || gcry_mpi_cmp_ui (z, 11371))
274     fail ("point_set/point_get failed\n");
275   gcry_mpi_point_snatch_set (point, x, y, z);
276   x = gcry_mpi_new (0);
277   y = gcry_mpi_new (0);
278   z = gcry_mpi_new (0);
279   gcry_mpi_point_get (x, y, z, point);
280   if (gcry_mpi_cmp_ui (x, 17)
281       || gcry_mpi_cmp_ui (y, 42) || gcry_mpi_cmp_ui (z, 11371))
282     fail ("point_snatch_set/point_get failed\n");
283
284   gcry_mpi_point_release (point);
285   gcry_mpi_release (x);
286   gcry_mpi_release (y);
287   gcry_mpi_release (z);
288 }
289
290
291 static void
292 context_alloc (void)
293 {
294   gpg_error_t err;
295   gcry_ctx_t ctx;
296   gcry_mpi_t p, a;
297
298   wherestr = "context_alloc";
299   show ("checking context functions\n");
300
301   p = gcry_mpi_set_ui (NULL, 1);
302   a = gcry_mpi_set_ui (NULL, 1);
303   err = ec_p_new (&ctx, p, a);
304   if (err)
305     die ("ec_p_new returned an error: %s\n", gpg_strerror (err));
306   gcry_mpi_release (p);
307   gcry_mpi_release (a);
308   gcry_ctx_release (ctx);
309
310   p = gcry_mpi_set_ui (NULL, 0);
311   a = gcry_mpi_set_ui (NULL, 0);
312   err = ec_p_new (&ctx, p, a);
313   if (!err || gpg_err_code (err) != GPG_ERR_EINVAL)
314     fail ("ec_p_new: bad parameter detection failed (1)\n");
315
316   gcry_mpi_set_ui (p, 1);
317   err = ec_p_new (&ctx, p, a);
318   if (!err || gpg_err_code (err) != GPG_ERR_EINVAL)
319     fail ("ec_p_new: bad parameter detection failed (2)\n");
320
321   gcry_mpi_release (p);
322   p = NULL;
323   err = ec_p_new (&ctx, p, a);
324   if (!err || gpg_err_code (err) != GPG_ERR_EINVAL)
325     fail ("ec_p_new: bad parameter detection failed (3)\n");
326
327   gcry_mpi_release (a);
328   a = NULL;
329   err = ec_p_new (&ctx, p, a);
330   if (!err || gpg_err_code (err) != GPG_ERR_EINVAL)
331     fail ("ec_p_new: bad parameter detection failed (4)\n");
332
333 }
334
335
336 static int
337 get_and_cmp_mpi (const char *name, const char *mpistring, const char *desc,
338                  gcry_ctx_t ctx)
339 {
340   gcry_mpi_t mpi;
341
342   mpi = gcry_mpi_ec_get_mpi (name, ctx, 1);
343   if (!mpi)
344     {
345       fail ("error getting parameter '%s' of curve '%s'\n", name, desc);
346       return 1;
347     }
348   if (cmp_mpihex (mpi, mpistring))
349     {
350       fail ("parameter '%s' of curve '%s' does not match\n", name, desc);
351       gcry_mpi_release (mpi);
352       return 1;
353     }
354   gcry_mpi_release (mpi);
355   return 0;
356 }
357
358
359 static int
360 get_and_cmp_point (const char *name,
361                    const char *mpi_x_string, const char *mpi_y_string,
362                    const char *desc, gcry_ctx_t ctx)
363 {
364   gcry_mpi_point_t point;
365   gcry_mpi_t x, y, z;
366   int result = 0;
367
368   point = gcry_mpi_ec_get_point (name, ctx, 1);
369   if (!point)
370     {
371       fail ("error getting point parameter '%s' of curve '%s'\n", name, desc);
372       return 1;
373     }
374
375   x = gcry_mpi_new (0);
376   y = gcry_mpi_new (0);
377   z = gcry_mpi_new (0);
378   gcry_mpi_point_snatch_get (x, y, z, point);
379   if (cmp_mpihex (x, mpi_x_string))
380     {
381       fail ("x coordinate of '%s' of curve '%s' does not match\n", name, desc);
382       result = 1;
383     }
384   if (cmp_mpihex (y, mpi_y_string))
385     {
386       fail ("y coordinate of '%s' of curve '%s' does not match\n", name, desc);
387       result = 1;
388     }
389   if (cmp_mpihex (z, "01"))
390     {
391       fail ("z coordinate of '%s' of curve '%s' is not 1\n", name, desc);
392       result = 1;
393     }
394   gcry_mpi_release (x);
395   gcry_mpi_release (y);
396   gcry_mpi_release (z);
397   return result;
398 }
399
400
401 static void
402 context_param (void)
403 {
404   gpg_error_t err;
405   int idx;
406   gcry_ctx_t ctx = NULL;
407
408   wherestr = "context_param";
409
410   for (idx=0; test_curve[idx].desc; idx++)
411     {
412       show ("checking curve '%s'\n", test_curve[idx].desc);
413       gcry_ctx_release (ctx);
414       err = gcry_mpi_ec_new (&ctx, NULL, test_curve[idx].desc);
415       if (err)
416         {
417           fail ("can't create context for curve '%s': %s\n",
418                 test_curve[idx].desc, gpg_strerror (err));
419           continue;
420         }
421       if (get_and_cmp_mpi ("p", test_curve[idx].p, test_curve[idx].desc, ctx))
422         continue;
423       if (get_and_cmp_mpi ("a", test_curve[idx].a, test_curve[idx].desc, ctx))
424         continue;
425       if (get_and_cmp_mpi ("b", test_curve[idx].b, test_curve[idx].desc, ctx))
426         continue;
427       if (get_and_cmp_mpi ("g.x",test_curve[idx].g_x, test_curve[idx].desc,ctx))
428         continue;
429       if (get_and_cmp_mpi ("g.y",test_curve[idx].g_y, test_curve[idx].desc,ctx))
430         continue;
431       if (get_and_cmp_mpi ("n", test_curve[idx].n, test_curve[idx].desc, ctx))
432         continue;
433       if (get_and_cmp_point ("g", test_curve[idx].g_x, test_curve[idx].g_y,
434                              test_curve[idx].desc, ctx))
435         continue;
436
437     }
438   gcry_ctx_release (ctx);
439
440   /* FIXME: Add tests for Q and d.  */
441
442   /* FIXME: Add test sor the set functions.  */
443
444
445 }
446
447
448
449
450 /* Create a new point from (X,Y,Z) given as hex strings.  */
451 gcry_mpi_point_t
452 make_point (const char *x, const char *y, const char *z)
453 {
454   gcry_mpi_point_t point;
455
456   point = gcry_mpi_point_new (0);
457   gcry_mpi_point_snatch_set (point, hex2mpi (x), hex2mpi (y), hex2mpi (z));
458
459   return point;
460 }
461
462
463 /* This tests checks that the low-level EC API yields the same result
464    as using the high level API.  The values have been taken from a
465    test run using the high level API.  */
466 static void
467 basic_ec_math (void)
468 {
469   gpg_error_t err;
470   gcry_ctx_t ctx;
471   gcry_mpi_t P, A;
472   gcry_mpi_point_t G, Q;
473   gcry_mpi_t d;
474   gcry_mpi_t x, y, z;
475
476   wherestr = "set_get_point";
477   show ("checking basic math functions for EC\n");
478
479   P = hex2mpi ("0xfffffffffffffffffffffffffffffffeffffffffffffffff");
480   A = hex2mpi ("0xfffffffffffffffffffffffffffffffefffffffffffffffc");
481   G = make_point ("188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
482                   "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
483                   "1");
484   d = hex2mpi ("D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D");
485   Q = gcry_mpi_point_new (0);
486
487   err = ec_p_new (&ctx, P, A);
488   if (err)
489     die ("ec_p_new failed: %s\n", gpg_strerror (err));
490   gcry_mpi_ec_mul (Q, d, G, ctx);
491
492   x = gcry_mpi_new (0);
493   y = gcry_mpi_new (0);
494   z = gcry_mpi_new (0);
495   gcry_mpi_point_get (x, y, z, Q);
496   if (cmp_mpihex (x, "222D9EC717C89D047E0898C9185B033CD11C0A981EE6DC66")
497       || cmp_mpihex (y, "605DE0A82D70D3E0F84A127D0739ED33D657DF0D054BFDE8")
498       || cmp_mpihex (z, "00B06B519071BC536999AC8F2D3934B3C1FC9EACCD0A31F88F"))
499     fail ("computed public key does not match\n");
500   if (debug)
501     {
502       print_mpi ("Q.x", x);
503       print_mpi ("Q.y", y);
504       print_mpi ("Q.z", z);
505     }
506
507   if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
508     fail ("failed to get affine coordinates\n");
509   if (cmp_mpihex (x, "008532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE")
510       || cmp_mpihex (y, "00C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966"))
511     fail ("computed affine coordinates of public key do not match\n");
512   if (debug)
513     {
514       print_mpi ("q.x", x);
515       print_mpi ("q.y", y);
516     }
517
518   gcry_mpi_release (z);
519   gcry_mpi_release (y);
520   gcry_mpi_release (x);
521   gcry_mpi_point_release (Q);
522   gcry_mpi_release (d);
523   gcry_mpi_point_release (G);
524   gcry_mpi_release (A);
525   gcry_mpi_release (P);
526 }
527
528
529 /* This is the same as basic_ec_math but uses more advanced
530    features.  */
531 static void
532 basic_ec_math_simplified (void)
533 {
534   gpg_error_t err;
535   gcry_ctx_t ctx;
536   gcry_mpi_point_t G, Q;
537   gcry_mpi_t d;
538   gcry_mpi_t x, y, z;
539
540   wherestr = "set_get_point";
541   show ("checking basic math functions for EC (variant)\n");
542
543   d = hex2mpi ("D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D");
544   Q = gcry_mpi_point_new (0);
545
546   err = gcry_mpi_ec_new (&ctx, NULL, "NIST P-192");
547   if (err)
548     die ("gcry_mpi_ec_new failed: %s\n", gpg_strerror (err));
549   G = gcry_mpi_ec_get_point ("g", ctx, 1);
550   if (!G)
551     die ("gcry_mpi_ec_get_point(G) failed\n");
552   gcry_mpi_ec_mul (Q, d, G, ctx);
553
554   x = gcry_mpi_new (0);
555   y = gcry_mpi_new (0);
556   z = gcry_mpi_new (0);
557   gcry_mpi_point_get (x, y, z, Q);
558   if (cmp_mpihex (x, "222D9EC717C89D047E0898C9185B033CD11C0A981EE6DC66")
559       || cmp_mpihex (y, "605DE0A82D70D3E0F84A127D0739ED33D657DF0D054BFDE8")
560       || cmp_mpihex (z, "00B06B519071BC536999AC8F2D3934B3C1FC9EACCD0A31F88F"))
561     fail ("computed public key does not match\n");
562   if (debug)
563     {
564       print_mpi ("Q.x", x);
565       print_mpi ("Q.y", y);
566       print_mpi ("Q.z", z);
567     }
568
569   if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
570     fail ("failed to get affine coordinates\n");
571   if (cmp_mpihex (x, "008532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE")
572       || cmp_mpihex (y, "00C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966"))
573     fail ("computed affine coordinates of public key do not match\n");
574   if (debug)
575     {
576       print_mpi ("q.x", x);
577       print_mpi ("q.y", y);
578     }
579
580   gcry_mpi_release (z);
581   gcry_mpi_release (y);
582   gcry_mpi_release (x);
583   gcry_mpi_point_release (Q);
584   gcry_mpi_release (d);
585   gcry_mpi_point_release (G);
586 }
587
588
589 int
590 main (int argc, char **argv)
591 {
592
593   if (argc > 1 && !strcmp (argv[1], "--verbose"))
594     verbose = 1;
595   else if (argc > 1 && !strcmp (argv[1], "--debug"))
596     verbose = debug = 1;
597
598   if (!gcry_check_version (GCRYPT_VERSION))
599     die ("version mismatch\n");
600
601   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
602   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
603   if (debug)
604     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
605   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
606
607   set_get_point ();
608   context_alloc ();
609   context_param ();
610   basic_ec_math ();
611   basic_ec_math_simplified ();
612
613   show ("All tests completed. Errors: %d\n", error_count);
614   return error_count ? 1 : 0;
615 }