e6a993f2738be33cd20f1cbf50e4257910c1aef0
[libgcrypt.git] / cipher / ecc-curves.c
1 /* ecc-curves.c  -  Elliptic Curve parameter mangement
2  * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
3  * Copyright (C) 2013 g10 Code GmbH
4  *
5  * This file is part of Libgcrypt.
6  *
7  * Libgcrypt is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * Libgcrypt is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26
27 #include "g10lib.h"
28 #include "mpi.h"
29 #include "context.h"
30 #include "ec-context.h"
31 #include "ecc-common.h"
32
33
34 /* This tables defines aliases for curve names.  */
35 static const struct
36 {
37   const char *name;  /* Our name.  */
38   const char *other; /* Other name. */
39 } curve_aliases[] =
40   {
41     { "NIST P-192", "1.2.840.10045.3.1.1" }, /* X9.62 OID  */
42     { "NIST P-192", "prime192v1" },          /* X9.62 name.  */
43     { "NIST P-192", "secp192r1"  },          /* SECP name.  */
44     { "NIST P-192", "nistp192"   },          /* rfc5656.  */
45
46     { "NIST P-224", "secp224r1" },
47     { "NIST P-224", "1.3.132.0.33" },        /* SECP OID.  */
48     { "NIST P-224", "nistp224"   },          /* rfc5656.  */
49
50     { "NIST P-256", "1.2.840.10045.3.1.7" }, /* From NIST SP 800-78-1.  */
51     { "NIST P-256", "prime256v1" },
52     { "NIST P-256", "secp256r1"  },
53     { "NIST P-256", "nistp256"   },          /* rfc5656.  */
54
55     { "NIST P-384", "secp384r1" },
56     { "NIST P-384", "1.3.132.0.34" },
57     { "NIST P-384", "nistp384"   },          /* rfc5656.  */
58
59     { "NIST P-521", "secp521r1" },
60     { "NIST P-521", "1.3.132.0.35" },
61     { "NIST P-521", "nistp521"   },          /* rfc5656.  */
62
63     { "brainpoolP160r1", "1.3.36.3.3.2.8.1.1.1" },
64     { "brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3" },
65     { "brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5" },
66     { "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7" },
67     { "brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9" },
68     { "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11"},
69     { "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13"},
70
71     { NULL, NULL}
72   };
73
74
75 typedef struct
76 {
77   const char *desc;           /* Description of the curve.  */
78   unsigned int nbits;         /* Number of bits.  */
79   unsigned int fips:1;        /* True if this is a FIPS140-2 approved curve. */
80
81   /* The model describing this curve.  This is mainly used to select
82      the group equation. */
83   enum gcry_mpi_ec_models model;
84
85   /* The actual ECC dialect used.  This is used for curve specific
86      optimizations and to select encodings etc. */
87   enum ecc_dialects dialect;
88
89   const char *p;              /* The prime defining the field.  */
90   const char *a, *b;          /* The coefficients.  For Twisted Edwards
91                                  Curves b is used for d.  */
92   const char *n;              /* The order of the base point.  */
93   const char *g_x, *g_y;      /* Base point.  */
94 } ecc_domain_parms_t;
95
96
97 /* This static table defines all available curves.  */
98 static const ecc_domain_parms_t domain_parms[] =
99   {
100     {
101       /* (-x^2 + y^2 = 1 + dx^2y^2) */
102       "Ed25519", 256, 0,
103       MPI_EC_TWISTEDEDWARDS, ECC_DIALECT_ED25519,
104       "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
105       "-0x01",
106       "-0x98412DFC9311D490018C7338BF8688861767FF8FF5B2BEBE27548A14B235EC8FEDA4",
107       "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED",
108       "0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A",
109       "0x6666666666666666666666666666666666666666666666666666666666666658"
110     },
111     {
112       "NIST P-192", 192, 1,
113       MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
114       "0xfffffffffffffffffffffffffffffffeffffffffffffffff",
115       "0xfffffffffffffffffffffffffffffffefffffffffffffffc",
116       "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
117       "0xffffffffffffffffffffffff99def836146bc9b1b4d22831",
118
119       "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
120       "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"
121     },
122     {
123       "NIST P-224", 224, 1,
124       MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
125       "0xffffffffffffffffffffffffffffffff000000000000000000000001",
126       "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe",
127       "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
128       "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" ,
129
130       "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
131       "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"
132     },
133     {
134       "NIST P-256", 256, 1,
135       MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
136       "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
137       "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc",
138       "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
139       "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
140
141       "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
142       "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
143     },
144     {
145       "NIST P-384", 384, 1,
146       MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
147       "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
148       "ffffffff0000000000000000ffffffff",
149       "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
150       "ffffffff0000000000000000fffffffc",
151       "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a"
152       "c656398d8a2ed19d2a85c8edd3ec2aef",
153       "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf"
154       "581a0db248b0a77aecec196accc52973",
155
156       "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38"
157       "5502f25dbf55296c3a545e3872760ab7",
158       "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0"
159       "0a60b1ce1d7e819d7a431d7c90ea0e5f"
160     },
161     {
162       "NIST P-521", 521, 1,
163       MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
164       "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
165       "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
166       "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
167       "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc",
168       "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10"
169       "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
170       "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
171       "ffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409",
172
173       "0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3d"
174       "baa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
175       "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e6"
176       "62c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"
177     },
178
179     { "brainpoolP160r1", 160, 0,
180       MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
181       "0xe95e4a5f737059dc60dfc7ad95b3d8139515620f",
182       "0x340e7be2a280eb74e2be61bada745d97e8f7c300",
183       "0x1e589a8595423412134faa2dbdec95c8d8675e58",
184       "0xe95e4a5f737059dc60df5991d45029409e60fc09",
185       "0xbed5af16ea3f6a4f62938c4631eb5af7bdbcdbc3",
186       "0x1667cb477a1a8ec338f94741669c976316da6321"
187     },
188
189     { "brainpoolP192r1", 192, 0,
190       MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
191       "0xc302f41d932a36cda7a3463093d18db78fce476de1a86297",
192       "0x6a91174076b1e0e19c39c031fe8685c1cae040e5c69a28ef",
193       "0x469a28ef7c28cca3dc721d044f4496bcca7ef4146fbf25c9",
194       "0xc302f41d932a36cda7a3462f9e9e916b5be8f1029ac4acc1",
195       "0xc0a0647eaab6a48753b033c56cb0f0900a2f5c4853375fd6",
196       "0x14b690866abd5bb88b5f4828c1490002e6773fa2fa299b8f"
197     },
198
199     { "brainpoolP224r1", 224, 0,
200       MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
201       "0xd7c134aa264366862a18302575d1d787b09f075797da89f57ec8c0ff",
202       "0x68a5e62ca9ce6c1c299803a6c1530b514e182ad8b0042a59cad29f43",
203       "0x2580f63ccfe44138870713b1a92369e33e2135d266dbb372386c400b",
204       "0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939f",
205       "0x0d9029ad2c7e5cf4340823b2a87dc68c9e4ce3174c1e6efdee12c07d",
206       "0x58aa56f772c0726f24c6b89e4ecdac24354b9e99caa3f6d3761402cd"
207     },
208
209     { "brainpoolP256r1", 256, 0,
210       MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
211       "0xa9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5377",
212       "0x7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9",
213       "0x26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6",
214       "0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7",
215       "0x8bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262",
216       "0x547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f046997"
217     },
218
219     { "brainpoolP320r1", 320, 0,
220       MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
221       "0xd35e472036bc4fb7e13c785ed201e065f98fcfa6f6f40def4f92b9ec7893ec28"
222       "fcd412b1f1b32e27",
223       "0x3ee30b568fbab0f883ccebd46d3f3bb8a2a73513f5eb79da66190eb085ffa9f4"
224       "92f375a97d860eb4",
225       "0x520883949dfdbc42d3ad198640688a6fe13f41349554b49acc31dccd88453981"
226       "6f5eb4ac8fb1f1a6",
227       "0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e9"
228       "8691555b44c59311",
229       "0x43bd7e9afb53d8b85289bcc48ee5bfe6f20137d10a087eb6e7871e2a10a599c7"
230       "10af8d0d39e20611",
231       "0x14fdd05545ec1cc8ab4093247f77275e0743ffed117182eaa9c77877aaac6ac7"
232       "d35245d1692e8ee1"
233     },
234
235     { "brainpoolP384r1", 384, 0,
236       MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
237       "0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123"
238       "acd3a729901d1a71874700133107ec53",
239       "0x7bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f"
240       "8aa5814a503ad4eb04a8c7dd22ce2826",
241       "0x04a8c7dd22ce28268b39b55416f0447c2fb77de107dcd2a62e880ea53eeb62d5"
242       "7cb4390295dbc9943ab78696fa504c11",
243       "0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7"
244       "cf3ab6af6b7fc3103b883202e9046565",
245       "0x1d1c64f068cf45ffa2a63a81b7c13f6b8847a3e77ef14fe3db7fcafe0cbd10e8"
246       "e826e03436d646aaef87b2e247d4af1e",
247       "0x8abe1d7520f9c2a45cb1eb8e95cfd55262b70b29feec5864e19c054ff9912928"
248       "0e4646217791811142820341263c5315"
249     },
250
251     { "brainpoolP512r1", 512, 0,
252       MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
253       "0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330871"
254       "7d4d9b009bc66842aecda12ae6a380e62881ff2f2d82c68528aa6056583a48f3",
255       "0x7830a3318b603b89e2327145ac234cc594cbdd8d3df91610a83441caea9863bc"
256       "2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94ca",
257       "0x3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a7"
258       "2bf2c7b9e7c1ac4d77fc94cadc083e67984050b75ebae5dd2809bd638016f723",
259       "0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870"
260       "553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90069",
261       "0x81aee4bdd82ed9645a21322e9c4c6a9385ed9f70b5d916c1b43b62eef4d0098e"
262       "ff3b1f78e2d0d48d50d1687b93b97d5f7c6d5047406a5e688b352209bcb9f822",
263       "0x7dde385d566332ecc0eabfa9cf7822fdf209f70024a57b1aa000c55b881f8111"
264       "b2dcde494a5f485e5bca4bd88a2763aed1ca2b2fa8f0540678cd1e0f3ad80892"
265     },
266
267     { NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
268   };
269
270
271
272 \f
273 /* Return a copy of POINT.  */
274 static gcry_mpi_point_t
275 point_copy (gcry_mpi_point_t point)
276 {
277   gcry_mpi_point_t newpoint;
278
279   if (point)
280     {
281       newpoint = gcry_mpi_point_new (0);
282       point_set (newpoint, point);
283     }
284   else
285     newpoint = NULL;
286   return newpoint;
287 }
288
289
290 /* Helper to scan a hex string. */
291 static gcry_mpi_t
292 scanval (const char *string)
293 {
294   gpg_error_t err;
295   gcry_mpi_t val;
296
297   err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
298   if (err)
299     log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (err));
300   return val;
301 }
302
303
304 /* Generate the crypto system setup.  This function takes the NAME of
305    a curve or the desired number of bits and stores at R_CURVE the
306    parameters of the named curve or those of a suitable curve.  If
307    R_NBITS is not NULL, the chosen number of bits is stored there.  */
308 gpg_err_code_t
309 _gcry_ecc_fill_in_curve (unsigned int nbits, const char *name,
310                          elliptic_curve_t *curve, unsigned int *r_nbits)
311 {
312   int idx, aliasno;
313   const char *resname = NULL; /* Set to a found curve name.  */
314
315   if (name)
316     {
317       /* First check our native curves.  */
318       for (idx = 0; domain_parms[idx].desc; idx++)
319         if (!strcmp (name, domain_parms[idx].desc))
320           {
321             resname = domain_parms[idx].desc;
322             break;
323           }
324       /* If not found consult the alias table.  */
325       if (!domain_parms[idx].desc)
326         {
327           for (aliasno = 0; curve_aliases[aliasno].name; aliasno++)
328             if (!strcmp (name, curve_aliases[aliasno].other))
329               break;
330           if (curve_aliases[aliasno].name)
331             {
332               for (idx = 0; domain_parms[idx].desc; idx++)
333                 if (!strcmp (curve_aliases[aliasno].name,
334                              domain_parms[idx].desc))
335                   {
336                     resname = domain_parms[idx].desc;
337                     break;
338                   }
339             }
340         }
341     }
342   else
343     {
344       for (idx = 0; domain_parms[idx].desc; idx++)
345         if (nbits == domain_parms[idx].nbits
346             && domain_parms[idx].model == MPI_EC_WEIERSTRASS)
347           break;
348     }
349   if (!domain_parms[idx].desc)
350     return GPG_ERR_UNKNOWN_CURVE;
351
352   /* In fips mode we only support NIST curves.  Note that it is
353      possible to bypass this check by specifying the curve parameters
354      directly.  */
355   if (fips_mode () && !domain_parms[idx].fips )
356     return GPG_ERR_NOT_SUPPORTED;
357
358   switch (domain_parms[idx].model)
359     {
360     case MPI_EC_WEIERSTRASS:
361     case MPI_EC_TWISTEDEDWARDS:
362       break;
363     case MPI_EC_MONTGOMERY:
364       return GPG_ERR_NOT_SUPPORTED;
365     default:
366       return GPG_ERR_BUG;
367     }
368
369
370   if (r_nbits)
371     *r_nbits = domain_parms[idx].nbits;
372
373   curve->model = domain_parms[idx].model;
374   curve->dialect = domain_parms[idx].dialect;
375   curve->p = scanval (domain_parms[idx].p);
376   curve->a = scanval (domain_parms[idx].a);
377   curve->b = scanval (domain_parms[idx].b);
378   curve->n = scanval (domain_parms[idx].n);
379   curve->G.x = scanval (domain_parms[idx].g_x);
380   curve->G.y = scanval (domain_parms[idx].g_y);
381   curve->G.z = mpi_alloc_set_ui (1);
382   curve->name = resname;
383
384   return 0;
385 }
386
387
388 /* Return the name matching the parameters in PKEY.  This works only
389    with curves described by the Weierstrass equation. */
390 const char *
391 _gcry_ecc_get_curve (gcry_mpi_t *pkey, int iterator, unsigned int *r_nbits)
392 {
393   gpg_err_code_t err;
394   elliptic_curve_t E;
395   int idx;
396   gcry_mpi_t tmp;
397   const char *result = NULL;
398
399   if (r_nbits)
400     *r_nbits = 0;
401
402   if (!pkey)
403     {
404       idx = iterator;
405       if (idx >= 0 && idx < DIM (domain_parms))
406         {
407           result = domain_parms[idx].desc;
408           if (r_nbits)
409             *r_nbits = domain_parms[idx].nbits;
410         }
411       return result;
412     }
413
414   if (!pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] || !pkey[4])
415     return NULL;
416
417   E.model = MPI_EC_WEIERSTRASS;
418   E.dialect = ECC_DIALECT_STANDARD;
419   E.name = NULL;
420   E.p = pkey[0];
421   E.a = pkey[1];
422   E.b = pkey[2];
423   _gcry_mpi_point_init (&E.G);
424   err = _gcry_ecc_os2ec (&E.G, pkey[3]);
425   if (err)
426     {
427       _gcry_mpi_point_free_parts (&E.G);
428       return NULL;
429     }
430   E.n = pkey[4];
431
432   for (idx = 0; domain_parms[idx].desc; idx++)
433     {
434       tmp = scanval (domain_parms[idx].p);
435       if (!mpi_cmp (tmp, E.p))
436         {
437           mpi_free (tmp);
438           tmp = scanval (domain_parms[idx].a);
439           if (!mpi_cmp (tmp, E.a))
440             {
441               mpi_free (tmp);
442               tmp = scanval (domain_parms[idx].b);
443               if (!mpi_cmp (tmp, E.b))
444                 {
445                   mpi_free (tmp);
446                   tmp = scanval (domain_parms[idx].n);
447                   if (!mpi_cmp (tmp, E.n))
448                     {
449                       mpi_free (tmp);
450                       tmp = scanval (domain_parms[idx].g_x);
451                       if (!mpi_cmp (tmp, E.G.x))
452                         {
453                           mpi_free (tmp);
454                           tmp = scanval (domain_parms[idx].g_y);
455                           if (!mpi_cmp (tmp, E.G.y))
456                             {
457                               mpi_free (tmp);
458                               result = domain_parms[idx].desc;
459                               if (r_nbits)
460                                 *r_nbits = domain_parms[idx].nbits;
461                               break;
462                             }
463                         }
464                     }
465                 }
466             }
467         }
468       mpi_free (tmp);
469     }
470
471   _gcry_mpi_point_free_parts (&E.G);
472
473   return result;
474 }
475
476
477 /* Helper to extract an MPI from key parameters.  */
478 static gpg_err_code_t
479 mpi_from_keyparam (gcry_mpi_t *r_a, gcry_sexp_t keyparam, const char *name)
480 {
481   gcry_err_code_t ec = 0;
482   gcry_sexp_t l1;
483
484   l1 = gcry_sexp_find_token (keyparam, name, 0);
485   if (l1)
486     {
487       *r_a = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
488       gcry_sexp_release (l1);
489       if (!*r_a)
490         ec = GPG_ERR_INV_OBJ;
491     }
492   return ec;
493 }
494
495 /* Helper to extract a point from key parameters.  If no parameter
496    with NAME is found, the functions tries to find a non-encoded point
497    by appending ".x", ".y" and ".z" to NAME.  ".z" is in this case
498    optional and defaults to 1.  */
499 static gpg_err_code_t
500 point_from_keyparam (gcry_mpi_point_t *r_a,
501                      gcry_sexp_t keyparam, const char *name)
502 {
503   gcry_err_code_t ec;
504   gcry_mpi_t a = NULL;
505   gcry_mpi_point_t point;
506
507   ec = mpi_from_keyparam (&a, keyparam, name);
508   if (ec)
509     return ec;
510
511   if (a)
512     {
513       point = gcry_mpi_point_new (0);
514       ec = _gcry_ecc_os2ec (point, a);
515       mpi_free (a);
516       if (ec)
517         {
518           gcry_mpi_point_release (point);
519           return ec;
520         }
521     }
522   else
523     {
524       char *tmpname;
525       gcry_mpi_t x = NULL;
526       gcry_mpi_t y = NULL;
527       gcry_mpi_t z = NULL;
528
529       tmpname = gcry_malloc (strlen (name) + 2 + 1);
530       if (!tmpname)
531         return gpg_err_code_from_syserror ();
532       strcpy (stpcpy (tmpname, name), ".x");
533       ec = mpi_from_keyparam (&x, keyparam, tmpname);
534       if (ec)
535         {
536           gcry_free (tmpname);
537           return ec;
538         }
539       strcpy (stpcpy (tmpname, name), ".y");
540       ec = mpi_from_keyparam (&y, keyparam, tmpname);
541       if (ec)
542         {
543           mpi_free (x);
544           gcry_free (tmpname);
545           return ec;
546         }
547       strcpy (stpcpy (tmpname, name), ".z");
548       ec = mpi_from_keyparam (&z, keyparam, tmpname);
549       if (ec)
550         {
551           mpi_free (y);
552           mpi_free (x);
553           gcry_free (tmpname);
554           return ec;
555         }
556       if (!z)
557         z = mpi_set_ui (NULL, 1);
558       if (x && y)
559         point = gcry_mpi_point_snatch_set (NULL, x, y, z);
560       else
561         {
562           mpi_free (x);
563           mpi_free (y);
564           mpi_free (z);
565           point = NULL;
566         }
567       gcry_free (tmpname);
568     }
569
570   if (point)
571     *r_a = point;
572   return 0;
573 }
574
575
576 /* This function creates a new context for elliptic curve operations.
577    Either KEYPARAM or CURVENAME must be given.  If both are given and
578    KEYPARAM has no curve parameter, CURVENAME is used to add missing
579    parameters.  On success 0 is returned and the new context stored at
580    R_CTX.  On error NULL is stored at R_CTX and an error code is
581    returned.  The context needs to be released using
582    gcry_ctx_release.  */
583 gpg_err_code_t
584 _gcry_mpi_ec_new (gcry_ctx_t *r_ctx,
585                   gcry_sexp_t keyparam, const char *curvename)
586 {
587   gpg_err_code_t errc;
588   gcry_ctx_t ctx = NULL;
589   enum gcry_mpi_ec_models model = MPI_EC_WEIERSTRASS;
590   enum ecc_dialects dialect = ECC_DIALECT_STANDARD;
591   gcry_mpi_t p = NULL;
592   gcry_mpi_t a = NULL;
593   gcry_mpi_t b = NULL;
594   gcry_mpi_point_t G = NULL;
595   gcry_mpi_t n = NULL;
596   gcry_mpi_point_t Q = NULL;
597   gcry_mpi_t d = NULL;
598   gcry_sexp_t l1;
599
600   *r_ctx = NULL;
601
602   if (keyparam)
603     {
604       errc = mpi_from_keyparam (&p, keyparam, "p");
605       if (errc)
606         goto leave;
607       errc = mpi_from_keyparam (&a, keyparam, "a");
608       if (errc)
609         goto leave;
610       errc = mpi_from_keyparam (&b, keyparam, "b");
611       if (errc)
612         goto leave;
613       errc = point_from_keyparam (&G, keyparam, "g");
614       if (errc)
615         goto leave;
616       errc = mpi_from_keyparam (&n, keyparam, "n");
617       if (errc)
618         goto leave;
619       errc = point_from_keyparam (&Q, keyparam, "q");
620       if (errc)
621         goto leave;
622       errc = mpi_from_keyparam (&d, keyparam, "d");
623       if (errc)
624         goto leave;
625     }
626
627
628   /* Check whether a curve parameter is available and use that to fill
629      in missing values.  If no curve parameter is available try an
630      optional provided curvename.  If only the curvename has been
631      given use that one. */
632   if (keyparam)
633     l1 = gcry_sexp_find_token (keyparam, "curve", 5);
634   else
635     l1 = NULL;
636   if (l1 || curvename)
637     {
638       char *name;
639       elliptic_curve_t *E;
640
641       if (l1)
642         {
643           name = _gcry_sexp_nth_string (l1, 1);
644           gcry_sexp_release (l1);
645           if (!name)
646             {
647               errc = GPG_ERR_INV_OBJ; /* Name missing or out of core. */
648               goto leave;
649             }
650         }
651       else
652         name = NULL;
653
654       E = gcry_calloc (1, sizeof *E);
655       if (!E)
656         {
657           errc = gpg_err_code_from_syserror ();
658           gcry_free (name);
659           goto leave;
660         }
661
662       errc = _gcry_ecc_fill_in_curve (0, name? name : curvename, E, NULL);
663       gcry_free (name);
664       if (errc)
665         {
666           gcry_free (E);
667           goto leave;
668         }
669
670       model = E->model;
671       dialect = E->dialect;
672
673       if (!p)
674         {
675           p = E->p;
676           E->p = NULL;
677         }
678       if (!a)
679         {
680           a = E->a;
681           E->a = NULL;
682         }
683       if (!b)
684         {
685           b = E->b;
686           E->b = NULL;
687         }
688       if (!G)
689         {
690           G = gcry_mpi_point_snatch_set (NULL, E->G.x, E->G.y, E->G.z);
691           E->G.x = NULL;
692           E->G.y = NULL;
693           E->G.z = NULL;
694         }
695       if (!n)
696         {
697           n = E->n;
698           E->n = NULL;
699         }
700       _gcry_ecc_curve_free (E);
701       gcry_free (E);
702     }
703
704   errc = _gcry_mpi_ec_p_new (&ctx, model, dialect, p, a, b);
705   if (!errc)
706     {
707       mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
708
709       if (b)
710         {
711           ec->b = b;
712           b = NULL;
713         }
714       if (G)
715         {
716           ec->G = G;
717           G = NULL;
718         }
719       if (n)
720         {
721           ec->n = n;
722           n = NULL;
723         }
724       if (Q)
725         {
726           ec->Q = Q;
727           Q = NULL;
728         }
729       if (d)
730         {
731           ec->d = d;
732           d = NULL;
733         }
734
735       *r_ctx = ctx;
736     }
737
738  leave:
739   mpi_free (p);
740   mpi_free (a);
741   mpi_free (b);
742   gcry_mpi_point_release (G);
743   mpi_free (n);
744   gcry_mpi_point_release (Q);
745   mpi_free (d);
746   return errc;
747 }
748
749
750 /* Return the parameters of the curve NAME in an MPI array.  */
751 gcry_err_code_t
752 _gcry_ecc_get_param (const char *name, gcry_mpi_t *pkey)
753 {
754   gpg_err_code_t err;
755   unsigned int nbits;
756   elliptic_curve_t E;
757   mpi_ec_t ctx;
758   gcry_mpi_t g_x, g_y;
759
760   err = _gcry_ecc_fill_in_curve (0, name, &E, &nbits);
761   if (err)
762     return err;
763
764   g_x = mpi_new (0);
765   g_y = mpi_new (0);
766   ctx = _gcry_mpi_ec_p_internal_new (0, ECC_DIALECT_STANDARD, E.p, E.a, NULL);
767   if (_gcry_mpi_ec_get_affine (g_x, g_y, &E.G, ctx))
768     log_fatal ("ecc get param: Failed to get affine coordinates\n");
769   _gcry_mpi_ec_free (ctx);
770   _gcry_mpi_point_free_parts (&E.G);
771
772   pkey[0] = E.p;
773   pkey[1] = E.a;
774   pkey[2] = E.b;
775   pkey[3] = _gcry_ecc_ec2os (g_x, g_y, E.p);
776   pkey[4] = E.n;
777   pkey[5] = NULL;
778
779   mpi_free (g_x);
780   mpi_free (g_y);
781
782   return 0;
783 }
784
785
786 /* Return the parameters of the curve NAME as an S-expression.  */
787 gcry_sexp_t
788 _gcry_ecc_get_param_sexp (const char *name)
789 {
790   gcry_mpi_t pkey[6];
791   gcry_sexp_t result;
792   int i;
793
794   if (_gcry_ecc_get_param (name, pkey))
795     return NULL;
796
797   if (gcry_sexp_build (&result, NULL,
798                        "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)))",
799                        pkey[0], pkey[1], pkey[2], pkey[3], pkey[4]))
800     result = NULL;
801
802   for (i=0; pkey[i]; i++)
803     gcry_mpi_release (pkey[i]);
804
805   return result;
806 }
807
808
809 /* Return an MPI (or opaque MPI) described by NAME and the context EC.
810    If COPY is true a copy is returned, if not a const MPI may be
811    returned.  In any case mpi_free must be used.  */
812 gcry_mpi_t
813 _gcry_ecc_get_mpi (const char *name, mpi_ec_t ec, int copy)
814 {
815   if (!strcmp (name, "p") && ec->p)
816     return mpi_is_const (ec->p) && !copy? ec->p : mpi_copy (ec->p);
817   if (!strcmp (name, "a") && ec->a)
818     return mpi_is_const (ec->a) && !copy? ec->a : mpi_copy (ec->a);
819   if (!strcmp (name, "b") && ec->b)
820     return mpi_is_const (ec->b) && !copy? ec->b : mpi_copy (ec->b);
821   if (!strcmp (name, "n") && ec->n)
822     return mpi_is_const (ec->n) && !copy? ec->n : mpi_copy (ec->n);
823   if (!strcmp (name, "d") && ec->d)
824     return mpi_is_const (ec->d) && !copy? ec->d : mpi_copy (ec->d);
825
826   /* Return a requested point coordinate.  */
827   if (!strcmp (name, "g.x") && ec->G && ec->G->x)
828     return mpi_is_const (ec->G->x) && !copy? ec->G->x : mpi_copy (ec->G->x);
829   if (!strcmp (name, "g.y") && ec->G && ec->G->y)
830     return mpi_is_const (ec->G->y) && !copy? ec->G->y : mpi_copy (ec->G->y);
831   if (!strcmp (name, "q.x") && ec->Q && ec->Q->x)
832     return mpi_is_const (ec->Q->x) && !copy? ec->Q->x : mpi_copy (ec->Q->x);
833   if (!strcmp (name, "q.y") && ec->Q && ec->Q->y)
834     return mpi_is_const (ec->G->y) && !copy? ec->Q->y : mpi_copy (ec->Q->y);
835
836   /* If a point has been requested, return it in standard encoding.  */
837   if (!strcmp (name, "g") && ec->G)
838     return _gcry_mpi_ec_ec2os (ec->G, ec);
839   if (!strcmp (name, "q"))
840     {
841       /* If only the private key is given, compute the public key.  */
842       if (!ec->Q)
843         ec->Q = _gcry_ecc_compute_public (NULL, ec);
844
845       if (ec->Q)
846         return _gcry_mpi_ec_ec2os (ec->Q, ec);
847     }
848
849   return NULL;
850 }
851
852
853 /* Return a point described by NAME and the context EC.  */
854 gcry_mpi_point_t
855 _gcry_ecc_get_point (const char *name, mpi_ec_t ec)
856 {
857   if (!strcmp (name, "g") && ec->G)
858     return point_copy (ec->G);
859   if (!strcmp (name, "q"))
860     {
861       /* If only the private key is given, compute the public key.  */
862       if (!ec->Q)
863         ec->Q = _gcry_ecc_compute_public (NULL, ec);
864
865       if (ec->Q)
866         return point_copy (ec->Q);
867     }
868
869   return NULL;
870 }
871
872
873 /* Store the MPI NEWVALUE into the context EC under NAME. */
874 gpg_err_code_t
875 _gcry_ecc_set_mpi (const char *name, gcry_mpi_t newvalue, mpi_ec_t ec)
876 {
877   if (!strcmp (name, "p"))
878     {
879       mpi_free (ec->p);
880       ec->p = mpi_copy (newvalue);
881       _gcry_mpi_ec_get_reset (ec);
882     }
883   else if (!strcmp (name, "a"))
884     {
885       mpi_free (ec->a);
886       ec->a = mpi_copy (newvalue);
887       _gcry_mpi_ec_get_reset (ec);
888     }
889   else if (!strcmp (name, "b"))
890     {
891       mpi_free (ec->b);
892       ec->b = mpi_copy (newvalue);
893     }
894   else if (!strcmp (name, "n"))
895     {
896       mpi_free (ec->n);
897       ec->n = mpi_copy (newvalue);
898     }
899   else if (!strcmp (name, "d"))
900     {
901       mpi_free (ec->d);
902       ec->d = mpi_copy (newvalue);
903     }
904   else
905     return GPG_ERR_UNKNOWN_NAME;
906
907   return 0;
908 }
909
910
911 /* Store the point NEWVALUE into the context EC under NAME.  */
912 gpg_err_code_t
913 _gcry_ecc_set_point (const char *name, gcry_mpi_point_t newvalue, mpi_ec_t ec)
914 {
915   if (!strcmp (name, "g"))
916     {
917       gcry_mpi_point_release (ec->G);
918       ec->G = point_copy (newvalue);
919     }
920   else if (!strcmp (name, "q"))
921     {
922       gcry_mpi_point_release (ec->Q);
923       ec->Q = point_copy (newvalue);
924     }
925   else
926     return GPG_ERR_UNKNOWN_NAME;
927
928   return 0;
929 }