Remove macro hacks for internal vs. external functions. Part 2 and last.
[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 "cipher.h"
30 #include "context.h"
31 #include "ec-context.h"
32 #include "ecc-common.h"
33
34
35 /*
36  * Release a curve object.
37  */
38 void
39 _gcry_ecc_curve_free (elliptic_curve_t *E)
40 {
41   mpi_free (E->p); E->p = NULL;
42   mpi_free (E->a); E->a = NULL;
43   mpi_free (E->b);  E->b = NULL;
44   _gcry_mpi_point_free_parts (&E->G);
45   mpi_free (E->n);  E->n = NULL;
46 }
47
48
49 /*
50  * Return a copy of a curve object.
51  */
52 elliptic_curve_t
53 _gcry_ecc_curve_copy (elliptic_curve_t E)
54 {
55   elliptic_curve_t R;
56
57   R.model = E.model;
58   R.dialect = E.dialect;
59   R.name = E.name;
60   R.p = mpi_copy (E.p);
61   R.a = mpi_copy (E.a);
62   R.b = mpi_copy (E.b);
63   _gcry_mpi_point_init (&R.G);
64   point_set (&R.G, &E.G);
65   R.n = mpi_copy (E.n);
66
67   return R;
68 }
69
70
71 /*
72  * Return a description of the curve model.
73  */
74 const char *
75 _gcry_ecc_model2str (enum gcry_mpi_ec_models model)
76 {
77   const char *str = "?";
78   switch (model)
79     {
80     case MPI_EC_WEIERSTRASS:    str = "Weierstrass"; break;
81     case MPI_EC_MONTGOMERY:     str = "Montgomery";  break;
82     case MPI_EC_TWISTEDEDWARDS: str = "Twisted Edwards"; break;
83     }
84   return str;
85 }
86
87
88 /*
89  * Return a description of the curve dialect.
90  */
91 const char *
92 _gcry_ecc_dialect2str (enum ecc_dialects dialect)
93 {
94   const char *str = "?";
95   switch (dialect)
96     {
97     case ECC_DIALECT_STANDARD:  str = "Standard"; break;
98     case ECC_DIALECT_ED25519:   str = "Ed25519"; break;
99     }
100   return str;
101 }
102
103
104 gcry_mpi_t
105 _gcry_ecc_ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p)
106 {
107   gpg_err_code_t rc;
108   int pbytes = (mpi_get_nbits (p)+7)/8;
109   size_t n;
110   unsigned char *buf, *ptr;
111   gcry_mpi_t result;
112
113   buf = xmalloc ( 1 + 2*pbytes );
114   *buf = 04; /* Uncompressed point.  */
115   ptr = buf+1;
116   rc = _gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, x);
117   if (rc)
118     log_fatal ("mpi_print failed: %s\n", gpg_strerror (rc));
119   if (n < pbytes)
120     {
121       memmove (ptr+(pbytes-n), ptr, n);
122       memset (ptr, 0, (pbytes-n));
123     }
124   ptr += pbytes;
125   rc = _gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, y);
126   if (rc)
127     log_fatal ("mpi_print failed: %s\n", gpg_strerror (rc));
128   if (n < pbytes)
129     {
130       memmove (ptr+(pbytes-n), ptr, n);
131       memset (ptr, 0, (pbytes-n));
132     }
133
134   rc = _gcry_mpi_scan (&result, GCRYMPI_FMT_USG, buf, 1+2*pbytes, NULL);
135   if (rc)
136     log_fatal ("mpi_scan failed: %s\n", gpg_strerror (rc));
137   xfree (buf);
138
139   return result;
140 }
141
142
143 /* Convert POINT into affine coordinates using the context CTX and
144    return a newly allocated MPI.  If the conversion is not possible
145    NULL is returned.  This function won't print an error message.  */
146 gcry_mpi_t
147 _gcry_mpi_ec_ec2os (gcry_mpi_point_t point, mpi_ec_t ectx)
148 {
149   gcry_mpi_t g_x, g_y, result;
150
151   g_x = mpi_new (0);
152   g_y = mpi_new (0);
153   if (_gcry_mpi_ec_get_affine (g_x, g_y, point, ectx))
154     result = NULL;
155   else
156     result = _gcry_ecc_ec2os (g_x, g_y, ectx->p);
157   mpi_free (g_x);
158   mpi_free (g_y);
159
160   return result;
161 }
162
163
164 /* RESULT must have been initialized and is set on success to the
165    point given by VALUE.  */
166 gcry_err_code_t
167 _gcry_ecc_os2ec (mpi_point_t result, gcry_mpi_t value)
168 {
169   gcry_err_code_t rc;
170   size_t n;
171   const unsigned char *buf;
172   unsigned char *buf_memory;
173   gcry_mpi_t x, y;
174
175   if (mpi_is_opaque (value))
176     {
177       unsigned int nbits;
178
179       buf = mpi_get_opaque (value, &nbits);
180       if (!buf)
181         return GPG_ERR_INV_OBJ;
182       n = (nbits + 7)/8;
183       buf_memory = NULL;
184     }
185   else
186     {
187       n = (mpi_get_nbits (value)+7)/8;
188       buf_memory = xmalloc (n);
189       rc = _gcry_mpi_print (GCRYMPI_FMT_USG, buf_memory, n, &n, value);
190       if (rc)
191         {
192           xfree (buf_memory);
193           return rc;
194         }
195       buf = buf_memory;
196     }
197
198   if (n < 1)
199     {
200       xfree (buf_memory);
201       return GPG_ERR_INV_OBJ;
202     }
203   if (*buf != 4)
204     {
205       xfree (buf_memory);
206       return GPG_ERR_NOT_IMPLEMENTED; /* No support for point compression.  */
207     }
208   if ( ((n-1)%2) )
209     {
210       xfree (buf_memory);
211       return GPG_ERR_INV_OBJ;
212     }
213   n = (n-1)/2;
214   rc = _gcry_mpi_scan (&x, GCRYMPI_FMT_USG, buf+1, n, NULL);
215   if (rc)
216     {
217       xfree (buf_memory);
218       return rc;
219     }
220   rc = _gcry_mpi_scan (&y, GCRYMPI_FMT_USG, buf+1+n, n, NULL);
221   xfree (buf_memory);
222   if (rc)
223     {
224       mpi_free (x);
225       return rc;
226     }
227
228   mpi_set (result->x, x);
229   mpi_set (result->y, y);
230   mpi_set_ui (result->z, 1);
231
232   mpi_free (x);
233   mpi_free (y);
234
235   return 0;
236 }
237
238
239 /* Compute the public key from the the context EC.  Obviously a
240    requirement is that the secret key is available in EC.  On success
241    Q is returned; on error NULL.  If Q is NULL a newly allocated point
242    is returned.  If G or D are given they override the values taken
243    from EC. */
244 mpi_point_t
245 _gcry_ecc_compute_public (mpi_point_t Q, mpi_ec_t ec,
246                           mpi_point_t G, gcry_mpi_t d)
247 {
248   if (!G)
249     G = ec->G;
250   if (!d)
251     d = ec->d;
252
253   if (!d || !G || !ec->p || !ec->a)
254     return NULL;
255   if (ec->model == MPI_EC_TWISTEDEDWARDS && !ec->b)
256     return NULL;
257
258   if (ec->dialect == ECC_DIALECT_ED25519
259       && (ec->flags & PUBKEY_FLAG_EDDSA))
260     {
261       gcry_mpi_t a;
262       unsigned char *digest;
263
264       if (_gcry_ecc_eddsa_compute_h_d (&digest, d, ec))
265         return NULL;
266
267       a = mpi_snew (0);
268       _gcry_mpi_set_buffer (a, digest, 32, 0);
269       xfree (digest);
270
271       /* And finally the public key.  */
272       if (!Q)
273         Q = mpi_point_new (0);
274       if (Q)
275         _gcry_mpi_ec_mul_point (Q, a, G, ec);
276       mpi_free (a);
277     }
278   else
279     {
280       if (!Q)
281         Q = mpi_point_new (0);
282       if (Q)
283         _gcry_mpi_ec_mul_point (Q, d, G, ec);
284     }
285
286   return Q;
287 }