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