ecc: Add Ed25519 key generation and prepare for optimizations.
[libgcrypt.git] / cipher / ecc-misc.c
1 /* ecc-misc.c  -  Elliptic Curve miscellaneous functions
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 /*
35  * Release a curve object.
36  */
37 void
38 _gcry_ecc_curve_free (elliptic_curve_t *E)
39 {
40   mpi_free (E->p); E->p = NULL;
41   mpi_free (E->a); E->a = NULL;
42   mpi_free (E->b);  E->b = NULL;
43   _gcry_mpi_point_free_parts (&E->G);
44   mpi_free (E->n);  E->n = NULL;
45 }
46
47
48 /*
49  * Return a copy of a curve object.
50  */
51 elliptic_curve_t
52 _gcry_ecc_curve_copy (elliptic_curve_t E)
53 {
54   elliptic_curve_t R;
55
56   R.model = E.model;
57   R.dialect = E.dialect;
58   R.p = mpi_copy (E.p);
59   R.a = mpi_copy (E.a);
60   R.b = mpi_copy (E.b);
61   _gcry_mpi_point_init (&R.G);
62   point_set (&R.G, &E.G);
63   R.n = mpi_copy (E.n);
64
65   return R;
66 }
67
68
69 /*
70  * Return a description of the curve model.
71  */
72 const char *
73 _gcry_ecc_model2str (enum gcry_mpi_ec_models model)
74 {
75   const char *str = "?";
76   switch (model)
77     {
78     case MPI_EC_WEIERSTRASS:    str = "Weierstrass"; break;
79     case MPI_EC_MONTGOMERY:     str = "Montgomery";  break;
80     case MPI_EC_TWISTEDEDWARDS: str = "Twisted Edwards"; break;
81     }
82   return str;
83 }
84
85
86 /*
87  * Return a description of the curve dialect.
88  */
89 const char *
90 _gcry_ecc_dialect2str (enum ecc_dialects dialect)
91 {
92   const char *str = "?";
93   switch (dialect)
94     {
95     case ECC_DIALECT_STANDARD:  str = "Standard"; break;
96     case ECC_DIALECT_ED25519:   str = "Ed25519"; break;
97     }
98   return str;
99 }
100
101
102 gcry_mpi_t
103 _gcry_ecc_ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p)
104 {
105   gpg_error_t err;
106   int pbytes = (mpi_get_nbits (p)+7)/8;
107   size_t n;
108   unsigned char *buf, *ptr;
109   gcry_mpi_t result;
110
111   buf = gcry_xmalloc ( 1 + 2*pbytes );
112   *buf = 04; /* Uncompressed point.  */
113   ptr = buf+1;
114   err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, x);
115   if (err)
116     log_fatal ("mpi_print failed: %s\n", gpg_strerror (err));
117   if (n < pbytes)
118     {
119       memmove (ptr+(pbytes-n), ptr, n);
120       memset (ptr, 0, (pbytes-n));
121     }
122   ptr += pbytes;
123   err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, y);
124   if (err)
125     log_fatal ("mpi_print failed: %s\n", gpg_strerror (err));
126   if (n < pbytes)
127     {
128       memmove (ptr+(pbytes-n), ptr, n);
129       memset (ptr, 0, (pbytes-n));
130     }
131
132   err = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, buf, 1+2*pbytes, NULL);
133   if (err)
134     log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err));
135   gcry_free (buf);
136
137   return result;
138 }
139
140
141 /* Convert POINT into affine coordinates using the context CTX and
142    return a newly allocated MPI.  If the conversion is not possible
143    NULL is returned.  This function won't print an error message.  */
144 gcry_mpi_t
145 _gcry_mpi_ec_ec2os (gcry_mpi_point_t point, mpi_ec_t ectx)
146 {
147   gcry_mpi_t g_x, g_y, result;
148
149   g_x = mpi_new (0);
150   g_y = mpi_new (0);
151   if (_gcry_mpi_ec_get_affine (g_x, g_y, point, ectx))
152     result = NULL;
153   else
154     result = _gcry_ecc_ec2os (g_x, g_y, ectx->p);
155   mpi_free (g_x);
156   mpi_free (g_y);
157
158   return result;
159 }
160
161
162 /* RESULT must have been initialized and is set on success to the
163    point given by VALUE.  */
164 gcry_error_t
165 _gcry_ecc_os2ec (mpi_point_t result, gcry_mpi_t value)
166 {
167   gcry_error_t err;
168   size_t n;
169   const unsigned char *buf;
170   unsigned char *buf_memory;
171   gcry_mpi_t x, y;
172
173   if (mpi_is_opaque (value))
174     {
175       unsigned int nbits;
176
177       buf = gcry_mpi_get_opaque (value, &nbits);
178       if (!buf)
179         return GPG_ERR_INV_OBJ;
180       n = (nbits + 7)/8;
181       buf_memory = NULL;
182     }
183   else
184     {
185       n = (mpi_get_nbits (value)+7)/8;
186       buf_memory= gcry_xmalloc (n);
187       err = gcry_mpi_print (GCRYMPI_FMT_USG, buf_memory, n, &n, value);
188       if (err)
189         {
190           gcry_free (buf_memory);
191           return err;
192         }
193       buf = buf_memory;
194     }
195
196   if (n < 1)
197     {
198       gcry_free (buf_memory);
199       return GPG_ERR_INV_OBJ;
200     }
201   if (*buf != 4)
202     {
203       gcry_free (buf_memory);
204       return GPG_ERR_NOT_IMPLEMENTED; /* No support for point compression.  */
205     }
206   if ( ((n-1)%2) )
207     {
208       gcry_free (buf_memory);
209       return GPG_ERR_INV_OBJ;
210     }
211   n = (n-1)/2;
212   err = gcry_mpi_scan (&x, GCRYMPI_FMT_USG, buf+1, n, NULL);
213   if (err)
214     {
215       gcry_free (buf_memory);
216       return err;
217     }
218   err = gcry_mpi_scan (&y, GCRYMPI_FMT_USG, buf+1+n, n, NULL);
219   gcry_free (buf_memory);
220   if (err)
221     {
222       mpi_free (x);
223       return err;
224     }
225
226   mpi_set (result->x, x);
227   mpi_set (result->y, y);
228   mpi_set_ui (result->z, 1);
229
230   mpi_free (x);
231   mpi_free (y);
232
233   return 0;
234 }