1 /*
2  * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
3  * Use is subject to license terms.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /* *********************************************************************
25  *
26  * The Original Code is the elliptic curve math library for binary polynomial field curves.
27  *
28  * The Initial Developer of the Original Code is
29  * Sun Microsystems, Inc.
30  * Portions created by the Initial Developer are Copyright (C) 2003
31  * the Initial Developer. All Rights Reserved.
32  *
33  * Contributor(s):
34  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
35  *
36  * Last Modified Date from the Original Code: May 2017
37  *********************************************************************** */
38 
39 #include "ec2.h"
40 #include "mplogic.h"
41 #include "mp_gf2m.h"
42 #ifndef _KERNEL
43 #include <stdlib.h>
44 #endif
45 
46 /* Checks if point P(px, py) is at infinity.  Uses affine coordinates. */
47 mp_err
ec_GF2m_pt_is_inf_aff(const mp_int * px,const mp_int * py)48 ec_GF2m_pt_is_inf_aff(const mp_int *px, const mp_int *py)
49 {
50 
51         if ((mp_cmp_z(px) == 0) && (mp_cmp_z(py) == 0)) {
52                 return MP_YES;
53         } else {
54                 return MP_NO;
55         }
56 
57 }
58 
59 /* Sets P(px, py) to be the point at infinity.  Uses affine coordinates. */
60 mp_err
ec_GF2m_pt_set_inf_aff(mp_int * px,mp_int * py)61 ec_GF2m_pt_set_inf_aff(mp_int *px, mp_int *py)
62 {
63         mp_zero(px);
64         mp_zero(py);
65         return MP_OKAY;
66 }
67 
68 /* Computes R = P + Q based on IEEE P1363 A.10.2. Elliptic curve points P,
69  * Q, and R can all be identical. Uses affine coordinates. */
70 mp_err
ec_GF2m_pt_add_aff(const mp_int * px,const mp_int * py,const mp_int * qx,const mp_int * qy,mp_int * rx,mp_int * ry,const ECGroup * group)71 ec_GF2m_pt_add_aff(const mp_int *px, const mp_int *py, const mp_int *qx,
72                                    const mp_int *qy, mp_int *rx, mp_int *ry,
73                                    const ECGroup *group)
74 {
75         mp_err res = MP_OKAY;
76         mp_int lambda, tempx, tempy;
77 
78         MP_DIGITS(&lambda) = 0;
79         MP_DIGITS(&tempx) = 0;
80         MP_DIGITS(&tempy) = 0;
81         MP_CHECKOK(mp_init(&lambda, FLAG(px)));
82         MP_CHECKOK(mp_init(&tempx, FLAG(px)));
83         MP_CHECKOK(mp_init(&tempy, FLAG(px)));
84         /* if P = inf, then R = Q */
85         if (ec_GF2m_pt_is_inf_aff(px, py) == 0) {
86                 MP_CHECKOK(mp_copy(qx, rx));
87                 MP_CHECKOK(mp_copy(qy, ry));
88                 res = MP_OKAY;
89                 goto CLEANUP;
90         }
91         /* if Q = inf, then R = P */
92         if (ec_GF2m_pt_is_inf_aff(qx, qy) == 0) {
93                 MP_CHECKOK(mp_copy(px, rx));
94                 MP_CHECKOK(mp_copy(py, ry));
95                 res = MP_OKAY;
96                 goto CLEANUP;
97         }
98         /* if px != qx, then lambda = (py+qy) / (px+qx), tempx = a + lambda^2
99          * + lambda + px + qx */
100         if (mp_cmp(px, qx) != 0) {
101                 MP_CHECKOK(group->meth->field_add(py, qy, &tempy, group->meth));
102                 MP_CHECKOK(group->meth->field_add(px, qx, &tempx, group->meth));
103                 MP_CHECKOK(group->meth->
104                                    field_div(&tempy, &tempx, &lambda, group->meth));
105                 MP_CHECKOK(group->meth->field_sqr(&lambda, &tempx, group->meth));
106                 MP_CHECKOK(group->meth->
107                                    field_add(&tempx, &lambda, &tempx, group->meth));
108                 MP_CHECKOK(group->meth->
109                                    field_add(&tempx, &group->curvea, &tempx, group->meth));
110                 MP_CHECKOK(group->meth->
111                                    field_add(&tempx, px, &tempx, group->meth));
112                 MP_CHECKOK(group->meth->
113                                    field_add(&tempx, qx, &tempx, group->meth));
114         } else {
115                 /* if py != qy or qx = 0, then R = inf */
116                 if (((mp_cmp(py, qy) != 0)) || (mp_cmp_z(qx) == 0)) {
117                         mp_zero(rx);
118                         mp_zero(ry);
119                         res = MP_OKAY;
120                         goto CLEANUP;
121                 }
122                 /* lambda = qx + qy / qx */
123                 MP_CHECKOK(group->meth->field_div(qy, qx, &lambda, group->meth));
124                 MP_CHECKOK(group->meth->
125                                    field_add(&lambda, qx, &lambda, group->meth));
126                 /* tempx = a + lambda^2 + lambda */
127                 MP_CHECKOK(group->meth->field_sqr(&lambda, &tempx, group->meth));
128                 MP_CHECKOK(group->meth->
129                                    field_add(&tempx, &lambda, &tempx, group->meth));
130                 MP_CHECKOK(group->meth->
131                                    field_add(&tempx, &group->curvea, &tempx, group->meth));
132         }
133         /* ry = (qx + tempx) * lambda + tempx + qy */
134         MP_CHECKOK(group->meth->field_add(qx, &tempx, &tempy, group->meth));
135         MP_CHECKOK(group->meth->
136                            field_mul(&tempy, &lambda, &tempy, group->meth));
137         MP_CHECKOK(group->meth->
138                            field_add(&tempy, &tempx, &tempy, group->meth));
139         MP_CHECKOK(group->meth->field_add(&tempy, qy, ry, group->meth));
140         /* rx = tempx */
141         MP_CHECKOK(mp_copy(&tempx, rx));
142 
143   CLEANUP:
144         mp_clear(&lambda);
145         mp_clear(&tempx);
146         mp_clear(&tempy);
147         return res;
148 }
149 
150 /* Computes R = P - Q. Elliptic curve points P, Q, and R can all be
151  * identical. Uses affine coordinates. */
152 mp_err
ec_GF2m_pt_sub_aff(const mp_int * px,const mp_int * py,const mp_int * qx,const mp_int * qy,mp_int * rx,mp_int * ry,const ECGroup * group)153 ec_GF2m_pt_sub_aff(const mp_int *px, const mp_int *py, const mp_int *qx,
154                                    const mp_int *qy, mp_int *rx, mp_int *ry,
155                                    const ECGroup *group)
156 {
157         mp_err res = MP_OKAY;
158         mp_int nqy;
159 
160         MP_DIGITS(&nqy) = 0;
161         MP_CHECKOK(mp_init(&nqy, FLAG(px)));
162         /* nqy = qx+qy */
163         MP_CHECKOK(group->meth->field_add(qx, qy, &nqy, group->meth));
164         MP_CHECKOK(group->point_add(px, py, qx, &nqy, rx, ry, group));
165   CLEANUP:
166         mp_clear(&nqy);
167         return res;
168 }
169 
170 /* Computes R = 2P. Elliptic curve points P and R can be identical. Uses
171  * affine coordinates. */
172 mp_err
ec_GF2m_pt_dbl_aff(const mp_int * px,const mp_int * py,mp_int * rx,mp_int * ry,const ECGroup * group)173 ec_GF2m_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx,
174                                    mp_int *ry, const ECGroup *group)
175 {
176         return group->point_add(px, py, px, py, rx, ry, group);
177 }
178 
179 /* by default, this routine is unused and thus doesn't need to be compiled */
180 #ifdef ECL_ENABLE_GF2M_PT_MUL_AFF
181 /* Computes R = nP based on IEEE P1363 A.10.3. Elliptic curve points P and
182  * R can be identical. Uses affine coordinates. */
183 mp_err
ec_GF2m_pt_mul_aff(const mp_int * n,const mp_int * px,const mp_int * py,mp_int * rx,mp_int * ry,const ECGroup * group)184 ec_GF2m_pt_mul_aff(const mp_int *n, const mp_int *px, const mp_int *py,
185                                    mp_int *rx, mp_int *ry, const ECGroup *group)
186 {
187         mp_err res = MP_OKAY;
188         mp_int k, k3, qx, qy, sx, sy;
189         int b1, b3, i, l;
190 
191         MP_DIGITS(&k) = 0;
192         MP_DIGITS(&k3) = 0;
193         MP_DIGITS(&qx) = 0;
194         MP_DIGITS(&qy) = 0;
195         MP_DIGITS(&sx) = 0;
196         MP_DIGITS(&sy) = 0;
197         MP_CHECKOK(mp_init(&k));
198         MP_CHECKOK(mp_init(&k3));
199         MP_CHECKOK(mp_init(&qx));
200         MP_CHECKOK(mp_init(&qy));
201         MP_CHECKOK(mp_init(&sx));
202         MP_CHECKOK(mp_init(&sy));
203 
204         /* if n = 0 then r = inf */
205         if (mp_cmp_z(n) == 0) {
206                 mp_zero(rx);
207                 mp_zero(ry);
208                 res = MP_OKAY;
209                 goto CLEANUP;
210         }
211         /* Q = P, k = n */
212         MP_CHECKOK(mp_copy(px, &qx));
213         MP_CHECKOK(mp_copy(py, &qy));
214         MP_CHECKOK(mp_copy(n, &k));
215         /* if n < 0 then Q = -Q, k = -k */
216         if (mp_cmp_z(n) < 0) {
217                 MP_CHECKOK(group->meth->field_add(&qx, &qy, &qy, group->meth));
218                 MP_CHECKOK(mp_neg(&k, &k));
219         }
220 #ifdef ECL_DEBUG                                /* basic double and add method */
221         l = mpl_significant_bits(&k) - 1;
222         MP_CHECKOK(mp_copy(&qx, &sx));
223         MP_CHECKOK(mp_copy(&qy, &sy));
224         for (i = l - 1; i >= 0; i--) {
225                 /* S = 2S */
226                 MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group));
227                 /* if k_i = 1, then S = S + Q */
228                 if (mpl_get_bit(&k, i) != 0) {
229                         MP_CHECKOK(group->
230                                            point_add(&sx, &sy, &qx, &qy, &sx, &sy, group));
231                 }
232         }
233 #else                                                   /* double and add/subtract method from
234                                                                  * standard */
235         /* k3 = 3 * k */
236         MP_CHECKOK(mp_set_int(&k3, 3));
237         MP_CHECKOK(mp_mul(&k, &k3, &k3));
238         /* S = Q */
239         MP_CHECKOK(mp_copy(&qx, &sx));
240         MP_CHECKOK(mp_copy(&qy, &sy));
241         /* l = index of high order bit in binary representation of 3*k */
242         l = mpl_significant_bits(&k3) - 1;
243         /* for i = l-1 downto 1 */
244         for (i = l - 1; i >= 1; i--) {
245                 /* S = 2S */
246                 MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group));
247                 b3 = MP_GET_BIT(&k3, i);
248                 b1 = MP_GET_BIT(&k, i);
249                 /* if k3_i = 1 and k_i = 0, then S = S + Q */
250                 if ((b3 == 1) && (b1 == 0)) {
251                         MP_CHECKOK(group->
252                                            point_add(&sx, &sy, &qx, &qy, &sx, &sy, group));
253                         /* if k3_i = 0 and k_i = 1, then S = S - Q */
254                 } else if ((b3 == 0) && (b1 == 1)) {
255                         MP_CHECKOK(group->
256                                            point_sub(&sx, &sy, &qx, &qy, &sx, &sy, group));
257                 }
258         }
259 #endif
260         /* output S */
261         MP_CHECKOK(mp_copy(&sx, rx));
262         MP_CHECKOK(mp_copy(&sy, ry));
263 
264   CLEANUP:
265         mp_clear(&k);
266         mp_clear(&k3);
267         mp_clear(&qx);
268         mp_clear(&qy);
269         mp_clear(&sx);
270         mp_clear(&sy);
271         return res;
272 }
273 #endif
274 
275 /* Validates a point on a GF2m curve. */
276 mp_err
ec_GF2m_validate_point(const mp_int * px,const mp_int * py,const ECGroup * group)277 ec_GF2m_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group)
278 {
279         mp_err res = MP_NO;
280         mp_int accl, accr, tmp, pxt, pyt;
281 
282         MP_DIGITS(&accl) = 0;
283         MP_DIGITS(&accr) = 0;
284         MP_DIGITS(&tmp) = 0;
285         MP_DIGITS(&pxt) = 0;
286         MP_DIGITS(&pyt) = 0;
287         MP_CHECKOK(mp_init(&accl, FLAG(px)));
288         MP_CHECKOK(mp_init(&accr, FLAG(px)));
289         MP_CHECKOK(mp_init(&tmp, FLAG(px)));
290         MP_CHECKOK(mp_init(&pxt, FLAG(px)));
291         MP_CHECKOK(mp_init(&pyt, FLAG(px)));
292 
293     /* 1: Verify that publicValue is not the point at infinity */
294         if (ec_GF2m_pt_is_inf_aff(px, py) == MP_YES) {
295                 res = MP_NO;
296                 goto CLEANUP;
297         }
298     /* 2: Verify that the coordinates of publicValue are elements
299      *    of the field.
300      */
301         if ((MP_SIGN(px) == MP_NEG) || (mp_cmp(px, &group->meth->irr) >= 0) ||
302                 (MP_SIGN(py) == MP_NEG) || (mp_cmp(py, &group->meth->irr) >= 0)) {
303                 res = MP_NO;
304                 goto CLEANUP;
305         }
306     /* 3: Verify that publicValue is on the curve. */
307         if (group->meth->field_enc) {
308                 group->meth->field_enc(px, &pxt, group->meth);
309                 group->meth->field_enc(py, &pyt, group->meth);
310         } else {
311                 mp_copy(px, &pxt);
312                 mp_copy(py, &pyt);
313         }
314         /* left-hand side: y^2 + x*y  */
315         MP_CHECKOK( group->meth->field_sqr(&pyt, &accl, group->meth) );
316         MP_CHECKOK( group->meth->field_mul(&pxt, &pyt, &tmp, group->meth) );
317         MP_CHECKOK( group->meth->field_add(&accl, &tmp, &accl, group->meth) );
318         /* right-hand side: x^3 + a*x^2 + b */
319         MP_CHECKOK( group->meth->field_sqr(&pxt, &tmp, group->meth) );
320         MP_CHECKOK( group->meth->field_mul(&pxt, &tmp, &accr, group->meth) );
321         MP_CHECKOK( group->meth->field_mul(&group->curvea, &tmp, &tmp, group->meth) );
322         MP_CHECKOK( group->meth->field_add(&tmp, &accr, &accr, group->meth) );
323         MP_CHECKOK( group->meth->field_add(&accr, &group->curveb, &accr, group->meth) );
324         /* check LHS - RHS == 0 */
325         MP_CHECKOK( group->meth->field_add(&accl, &accr, &accr, group->meth) );
326         if (mp_cmp_z(&accr) != 0) {
327                 res = MP_NO;
328                 goto CLEANUP;
329         }
330     /* 4: Verify that the order of the curve times the publicValue
331      *    is the point at infinity.
332      */
333         /* timing mitigation is not supported */
334         MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt, /*timing*/ 0) );
335         if (ec_GF2m_pt_is_inf_aff(&pxt, &pyt) != MP_YES) {
336                 res = MP_NO;
337                 goto CLEANUP;
338         }
339 
340         res = MP_YES;
341 
342 CLEANUP:
343         mp_clear(&accl);
344         mp_clear(&accr);
345         mp_clear(&tmp);
346         mp_clear(&pxt);
347         mp_clear(&pyt);
348         return res;
349 }
350