Prepare support for non-Weierstrass EC equations.
[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.p = mpi_copy (E.p);
57   R.a = mpi_copy (E.a);
58   R.b = mpi_copy (E.b);
59   _gcry_mpi_point_init (&R.G);
60   point_set (&R.G, &E.G);
61   R.n = mpi_copy (E.n);
62
63   return R;
64 }
65
66
67 /*
68  * Return a description of the curve model.
69  */
70 const char *
71 _gcry_ecc_model2str (enum gcry_mpi_ec_models model)
72 {
73   const char *str = "?";
74   switch (model)
75     {
76     case MPI_EC_WEIERSTRASS:    str = "Weierstrass"; break;
77     case MPI_EC_MONTGOMERY:     str = "Montgomery";  break;
78     case MPI_EC_TWISTEDEDWARDS: str = "Twisted Edwards"; break;
79     }
80   return str;
81 }
82
83
84
85
86 gcry_mpi_t
87 _gcry_ecc_ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p)
88 {
89   gpg_error_t err;
90   int pbytes = (mpi_get_nbits (p)+7)/8;
91   size_t n;
92   unsigned char *buf, *ptr;
93   gcry_mpi_t result;
94
95   buf = gcry_xmalloc ( 1 + 2*pbytes );
96   *buf = 04; /* Uncompressed point.  */
97   ptr = buf+1;
98   err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, x);
99   if (err)
100     log_fatal ("mpi_print failed: %s\n", gpg_strerror (err));
101   if (n < pbytes)
102     {
103       memmove (ptr+(pbytes-n), ptr, n);
104       memset (ptr, 0, (pbytes-n));
105     }
106   ptr += pbytes;
107   err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, y);
108   if (err)
109     log_fatal ("mpi_print failed: %s\n", gpg_strerror (err));
110   if (n < pbytes)
111     {
112       memmove (ptr+(pbytes-n), ptr, n);
113       memset (ptr, 0, (pbytes-n));
114     }
115
116   err = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, buf, 1+2*pbytes, NULL);
117   if (err)
118     log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err));
119   gcry_free (buf);
120
121   return result;
122 }
123
124
125 /* Convert POINT into affine coordinates using the context CTX and
126    return a newly allocated MPI.  If the conversion is not possible
127    NULL is returned.  This function won't print an error message.  */
128 gcry_mpi_t
129 _gcry_mpi_ec_ec2os (gcry_mpi_point_t point, mpi_ec_t ectx)
130 {
131   gcry_mpi_t g_x, g_y, result;
132
133   g_x = mpi_new (0);
134   g_y = mpi_new (0);
135   if (_gcry_mpi_ec_get_affine (g_x, g_y, point, ectx))
136     result = NULL;
137   else
138     result = _gcry_ecc_ec2os (g_x, g_y, ectx->p);
139   mpi_free (g_x);
140   mpi_free (g_y);
141
142   return result;
143 }
144
145
146 /* RESULT must have been initialized and is set on success to the
147    point given by VALUE.  */
148 gcry_error_t
149 _gcry_ecc_os2ec (mpi_point_t result, gcry_mpi_t value)
150 {
151   gcry_error_t err;
152   size_t n;
153   unsigned char *buf;
154   gcry_mpi_t x, y;
155
156   n = (mpi_get_nbits (value)+7)/8;
157   buf = gcry_xmalloc (n);
158   err = gcry_mpi_print (GCRYMPI_FMT_USG, buf, n, &n, value);
159   if (err)
160     {
161       gcry_free (buf);
162       return err;
163     }
164   if (n < 1)
165     {
166       gcry_free (buf);
167       return GPG_ERR_INV_OBJ;
168     }
169   if (*buf != 4)
170     {
171       gcry_free (buf);
172       return GPG_ERR_NOT_IMPLEMENTED; /* No support for point compression.  */
173     }
174   if ( ((n-1)%2) )
175     {
176       gcry_free (buf);
177       return GPG_ERR_INV_OBJ;
178     }
179   n = (n-1)/2;
180   err = gcry_mpi_scan (&x, GCRYMPI_FMT_USG, buf+1, n, NULL);
181   if (err)
182     {
183       gcry_free (buf);
184       return err;
185     }
186   err = gcry_mpi_scan (&y, GCRYMPI_FMT_USG, buf+1+n, n, NULL);
187   gcry_free (buf);
188   if (err)
189     {
190       mpi_free (x);
191       return err;
192     }
193
194   mpi_set (result->x, x);
195   mpi_set (result->y, y);
196   mpi_set_ui (result->z, 1);
197
198   mpi_free (x);
199   mpi_free (y);
200
201   return 0;
202 }