744734073290656602576a533505a0305a9bd92b
[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 (!*name)
816     return NULL;
817
818   if (!strcmp (name, "p") && ec->p)
819     return mpi_is_const (ec->p) && !copy? ec->p : mpi_copy (ec->p);
820   if (!strcmp (name, "a") && ec->a)
821     return mpi_is_const (ec->a) && !copy? ec->a : mpi_copy (ec->a);
822   if (!strcmp (name, "b") && ec->b)
823     return mpi_is_const (ec->b) && !copy? ec->b : mpi_copy (ec->b);
824   if (!strcmp (name, "n") && ec->n)
825     return mpi_is_const (ec->n) && !copy? ec->n : mpi_copy (ec->n);
826   if (!strcmp (name, "d") && ec->d)
827     return mpi_is_const (ec->d) && !copy? ec->d : mpi_copy (ec->d);
828
829   /* Return a requested point coordinate.  */
830   if (!strcmp (name, "g.x") && ec->G && ec->G->x)
831     return mpi_is_const (ec->G->x) && !copy? ec->G->x : mpi_copy (ec->G->x);
832   if (!strcmp (name, "g.y") && ec->G && ec->G->y)
833     return mpi_is_const (ec->G->y) && !copy? ec->G->y : mpi_copy (ec->G->y);
834   if (!strcmp (name, "q.x") && ec->Q && ec->Q->x)
835     return mpi_is_const (ec->Q->x) && !copy? ec->Q->x : mpi_copy (ec->Q->x);
836   if (!strcmp (name, "q.y") && ec->Q && ec->Q->y)
837     return mpi_is_const (ec->G->y) && !copy? ec->Q->y : mpi_copy (ec->Q->y);
838
839   /* If the base point has been requested, return it in standard
840      encoding.  */
841   if (!strcmp (name, "g") && ec->G)
842     return _gcry_mpi_ec_ec2os (ec->G, ec);
843
844   /* If the public key has been requested, return it by default in
845      standard uncompressed encoding or if requested in other
846      encodings.  */
847   if (*name == 'q' && (!name[1] || name[1] == '@'))
848     {
849       /* If only the private key is given, compute the public key.  */
850       if (!ec->Q)
851         ec->Q = _gcry_ecc_compute_public (NULL, ec);
852
853       if (!ec->Q)
854         return NULL;
855
856       if (name[1] != '@')
857         return _gcry_mpi_ec_ec2os (ec->Q, ec);
858
859       if (!strcmp (name+2, "eddsa") && ec->model == MPI_EC_TWISTEDEDWARDS)
860         {
861           unsigned char *encpk;
862           unsigned int encpklen;
863
864           if (!_gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL,
865                                             &encpk, &encpklen))
866             return gcry_mpi_set_opaque (NULL, encpk, encpklen*8);
867         }
868     }
869
870   return NULL;
871 }
872
873
874 /* Return a point described by NAME and the context EC.  */
875 gcry_mpi_point_t
876 _gcry_ecc_get_point (const char *name, mpi_ec_t ec)
877 {
878   if (!strcmp (name, "g") && ec->G)
879     return point_copy (ec->G);
880   if (!strcmp (name, "q"))
881     {
882       /* If only the private key is given, compute the public key.  */
883       if (!ec->Q)
884         ec->Q = _gcry_ecc_compute_public (NULL, ec);
885
886       if (ec->Q)
887         return point_copy (ec->Q);
888     }
889
890   return NULL;
891 }
892
893
894 /* Store the MPI NEWVALUE into the context EC under NAME. */
895 gpg_err_code_t
896 _gcry_ecc_set_mpi (const char *name, gcry_mpi_t newvalue, mpi_ec_t ec)
897 {
898   gpg_err_code_t rc = 0;
899
900   if (!*name)
901     ;
902   else if (!strcmp (name, "p"))
903     {
904       mpi_free (ec->p);
905       ec->p = mpi_copy (newvalue);
906       _gcry_mpi_ec_get_reset (ec);
907     }
908   else if (!strcmp (name, "a"))
909     {
910       mpi_free (ec->a);
911       ec->a = mpi_copy (newvalue);
912       _gcry_mpi_ec_get_reset (ec);
913     }
914   else if (!strcmp (name, "b"))
915     {
916       mpi_free (ec->b);
917       ec->b = mpi_copy (newvalue);
918     }
919   else if (!strcmp (name, "n"))
920     {
921       mpi_free (ec->n);
922       ec->n = mpi_copy (newvalue);
923     }
924   else if (*name == 'q' && (!name[1] || name[1] == '@'))
925     {
926       if (newvalue)
927         {
928           if (!ec->Q)
929             ec->Q = gcry_mpi_point_new (0);
930           if (ec->dialect == ECC_DIALECT_ED25519)
931             rc = _gcry_ecc_eddsa_decodepoint (newvalue, ec, ec->Q, NULL, NULL);
932           else
933             rc = _gcry_ecc_os2ec (ec->Q, newvalue);
934         }
935       if (rc || !newvalue)
936         {
937           gcry_mpi_point_release (ec->Q);
938           ec->Q = NULL;
939         }
940       /* Note: We assume that Q matches d and thus do not reset d.  */
941     }
942   else if (!strcmp (name, "d"))
943     {
944       mpi_free (ec->d);
945       ec->d = mpi_copy (newvalue);
946       if (ec->d)
947         {
948           /* We need to reset the public key because it may not
949              anymore match.  */
950           gcry_mpi_point_release (ec->Q);
951           ec->Q = NULL;
952         }
953     }
954   else
955    rc = GPG_ERR_UNKNOWN_NAME;
956
957   return rc;
958 }
959
960
961 /* Store the point NEWVALUE into the context EC under NAME.  */
962 gpg_err_code_t
963 _gcry_ecc_set_point (const char *name, gcry_mpi_point_t newvalue, mpi_ec_t ec)
964 {
965   if (!strcmp (name, "g"))
966     {
967       gcry_mpi_point_release (ec->G);
968       ec->G = point_copy (newvalue);
969     }
970   else if (!strcmp (name, "q"))
971     {
972       gcry_mpi_point_release (ec->Q);
973       ec->Q = point_copy (newvalue);
974     }
975   else
976     return GPG_ERR_UNKNOWN_NAME;
977
978   return 0;
979 }