Flatten the Curve 448 source structure
[openssl.git] / crypto / ec / ec2_mult.c
1 /*
2  * Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved.
3  * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
4  *
5  * Licensed under the OpenSSL license (the "License").  You may not use
6  * this file except in compliance with the License.  You can obtain a copy
7  * in the file LICENSE in the source distribution or at
8  * https://www.openssl.org/source/license.html
9  */
10
11 #include <openssl/err.h>
12
13 #include "internal/bn_int.h"
14 #include "ec_lcl.h"
15
16 #ifndef OPENSSL_NO_EC2M
17
18 /*-
19  * Compute the x-coordinate x/z for the point 2*(x/z) in Montgomery projective
20  * coordinates.
21  * Uses algorithm Mdouble in appendix of
22  *     Lopez, J. and Dahab, R.  "Fast multiplication on elliptic curves over
23  *     GF(2^m) without precomputation" (CHES '99, LNCS 1717).
24  * modified to not require precomputation of c=b^{2^{m-1}}.
25  */
26 static int gf2m_Mdouble(const EC_GROUP *group, BIGNUM *x, BIGNUM *z,
27                         BN_CTX *ctx)
28 {
29     BIGNUM *t1;
30     int ret = 0;
31
32     /* Since Mdouble is static we can guarantee that ctx != NULL. */
33     BN_CTX_start(ctx);
34     t1 = BN_CTX_get(ctx);
35     if (t1 == NULL)
36         goto err;
37
38     if (!group->meth->field_sqr(group, x, x, ctx))
39         goto err;
40     if (!group->meth->field_sqr(group, t1, z, ctx))
41         goto err;
42     if (!group->meth->field_mul(group, z, x, t1, ctx))
43         goto err;
44     if (!group->meth->field_sqr(group, x, x, ctx))
45         goto err;
46     if (!group->meth->field_sqr(group, t1, t1, ctx))
47         goto err;
48     if (!group->meth->field_mul(group, t1, group->b, t1, ctx))
49         goto err;
50     if (!BN_GF2m_add(x, x, t1))
51         goto err;
52
53     ret = 1;
54
55  err:
56     BN_CTX_end(ctx);
57     return ret;
58 }
59
60 /*-
61  * Compute the x-coordinate x1/z1 for the point (x1/z1)+(x2/x2) in Montgomery
62  * projective coordinates.
63  * Uses algorithm Madd in appendix of
64  *     Lopez, J. and Dahab, R.  "Fast multiplication on elliptic curves over
65  *     GF(2^m) without precomputation" (CHES '99, LNCS 1717).
66  */
67 static int gf2m_Madd(const EC_GROUP *group, const BIGNUM *x, BIGNUM *x1,
68                      BIGNUM *z1, const BIGNUM *x2, const BIGNUM *z2,
69                      BN_CTX *ctx)
70 {
71     BIGNUM *t1, *t2;
72     int ret = 0;
73
74     /* Since Madd is static we can guarantee that ctx != NULL. */
75     BN_CTX_start(ctx);
76     t1 = BN_CTX_get(ctx);
77     t2 = BN_CTX_get(ctx);
78     if (t2 == NULL)
79         goto err;
80
81     if (!BN_copy(t1, x))
82         goto err;
83     if (!group->meth->field_mul(group, x1, x1, z2, ctx))
84         goto err;
85     if (!group->meth->field_mul(group, z1, z1, x2, ctx))
86         goto err;
87     if (!group->meth->field_mul(group, t2, x1, z1, ctx))
88         goto err;
89     if (!BN_GF2m_add(z1, z1, x1))
90         goto err;
91     if (!group->meth->field_sqr(group, z1, z1, ctx))
92         goto err;
93     if (!group->meth->field_mul(group, x1, z1, t1, ctx))
94         goto err;
95     if (!BN_GF2m_add(x1, x1, t2))
96         goto err;
97
98     ret = 1;
99
100  err:
101     BN_CTX_end(ctx);
102     return ret;
103 }
104
105 /*-
106  * Compute the x, y affine coordinates from the point (x1, z1) (x2, z2)
107  * using Montgomery point multiplication algorithm Mxy() in appendix of
108  *     Lopez, J. and Dahab, R.  "Fast multiplication on elliptic curves over
109  *     GF(2^m) without precomputation" (CHES '99, LNCS 1717).
110  * Returns:
111  *     0 on error
112  *     1 if return value should be the point at infinity
113  *     2 otherwise
114  */
115 static int gf2m_Mxy(const EC_GROUP *group, const BIGNUM *x, const BIGNUM *y,
116                     BIGNUM *x1, BIGNUM *z1, BIGNUM *x2, BIGNUM *z2,
117                     BN_CTX *ctx)
118 {
119     BIGNUM *t3, *t4, *t5;
120     int ret = 0;
121
122     if (BN_is_zero(z1)) {
123         BN_zero(x2);
124         BN_zero(z2);
125         return 1;
126     }
127
128     if (BN_is_zero(z2)) {
129         if (!BN_copy(x2, x))
130             return 0;
131         if (!BN_GF2m_add(z2, x, y))
132             return 0;
133         return 2;
134     }
135
136     /* Since Mxy is static we can guarantee that ctx != NULL. */
137     BN_CTX_start(ctx);
138     t3 = BN_CTX_get(ctx);
139     t4 = BN_CTX_get(ctx);
140     t5 = BN_CTX_get(ctx);
141     if (t5 == NULL)
142         goto err;
143
144     if (!BN_one(t5))
145         goto err;
146
147     if (!group->meth->field_mul(group, t3, z1, z2, ctx))
148         goto err;
149
150     if (!group->meth->field_mul(group, z1, z1, x, ctx))
151         goto err;
152     if (!BN_GF2m_add(z1, z1, x1))
153         goto err;
154     if (!group->meth->field_mul(group, z2, z2, x, ctx))
155         goto err;
156     if (!group->meth->field_mul(group, x1, z2, x1, ctx))
157         goto err;
158     if (!BN_GF2m_add(z2, z2, x2))
159         goto err;
160
161     if (!group->meth->field_mul(group, z2, z2, z1, ctx))
162         goto err;
163     if (!group->meth->field_sqr(group, t4, x, ctx))
164         goto err;
165     if (!BN_GF2m_add(t4, t4, y))
166         goto err;
167     if (!group->meth->field_mul(group, t4, t4, t3, ctx))
168         goto err;
169     if (!BN_GF2m_add(t4, t4, z2))
170         goto err;
171
172     if (!group->meth->field_mul(group, t3, t3, x, ctx))
173         goto err;
174     if (!group->meth->field_div(group, t3, t5, t3, ctx))
175         goto err;
176     if (!group->meth->field_mul(group, t4, t3, t4, ctx))
177         goto err;
178     if (!group->meth->field_mul(group, x2, x1, t3, ctx))
179         goto err;
180     if (!BN_GF2m_add(z2, x2, x))
181         goto err;
182
183     if (!group->meth->field_mul(group, z2, z2, t4, ctx))
184         goto err;
185     if (!BN_GF2m_add(z2, z2, y))
186         goto err;
187
188     ret = 2;
189
190  err:
191     BN_CTX_end(ctx);
192     return ret;
193 }
194
195 /*-
196  * Computes scalar*point and stores the result in r.
197  * point can not equal r.
198  * Uses a modified algorithm 2P of
199  *     Lopez, J. and Dahab, R.  "Fast multiplication on elliptic curves over
200  *     GF(2^m) without precomputation" (CHES '99, LNCS 1717).
201  *
202  * To protect against side-channel attack the function uses constant time swap,
203  * avoiding conditional branches.
204  */
205 static int ec_GF2m_montgomery_point_multiply(const EC_GROUP *group,
206                                              EC_POINT *r,
207                                              const BIGNUM *scalar,
208                                              const EC_POINT *point,
209                                              BN_CTX *ctx)
210 {
211     BIGNUM *x1, *x2, *z1, *z2;
212     int ret = 0, i, group_top;
213     BN_ULONG mask, word;
214
215     if (r == point) {
216         ECerr(EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY, EC_R_INVALID_ARGUMENT);
217         return 0;
218     }
219
220     /* if result should be point at infinity */
221     if ((scalar == NULL) || BN_is_zero(scalar) || (point == NULL) ||
222         EC_POINT_is_at_infinity(group, point)) {
223         return EC_POINT_set_to_infinity(group, r);
224     }
225
226     /* only support affine coordinates */
227     if (!point->Z_is_one)
228         return 0;
229
230     /*
231      * Since point_multiply is static we can guarantee that ctx != NULL.
232      */
233     BN_CTX_start(ctx);
234     x1 = BN_CTX_get(ctx);
235     z1 = BN_CTX_get(ctx);
236     if (z1 == NULL)
237         goto err;
238
239     x2 = r->X;
240     z2 = r->Y;
241
242     group_top = bn_get_top(group->field);
243     if (bn_wexpand(x1, group_top) == NULL
244         || bn_wexpand(z1, group_top) == NULL
245         || bn_wexpand(x2, group_top) == NULL
246         || bn_wexpand(z2, group_top) == NULL)
247         goto err;
248
249     if (!BN_GF2m_mod_arr(x1, point->X, group->poly))
250         goto err;               /* x1 = x */
251     if (!BN_one(z1))
252         goto err;               /* z1 = 1 */
253     if (!group->meth->field_sqr(group, z2, x1, ctx))
254         goto err;               /* z2 = x1^2 = x^2 */
255     if (!group->meth->field_sqr(group, x2, z2, ctx))
256         goto err;
257     if (!BN_GF2m_add(x2, x2, group->b))
258         goto err;               /* x2 = x^4 + b */
259
260     /* find top most bit and go one past it */
261     i = bn_get_top(scalar) - 1;
262     mask = BN_TBIT;
263     word = bn_get_words(scalar)[i];
264     while (!(word & mask))
265         mask >>= 1;
266     mask >>= 1;
267     /* if top most bit was at word break, go to next word */
268     if (!mask) {
269         i--;
270         mask = BN_TBIT;
271     }
272
273     for (; i >= 0; i--) {
274         word = bn_get_words(scalar)[i];
275         while (mask) {
276             BN_consttime_swap(word & mask, x1, x2, group_top);
277             BN_consttime_swap(word & mask, z1, z2, group_top);
278             if (!gf2m_Madd(group, point->X, x2, z2, x1, z1, ctx))
279                 goto err;
280             if (!gf2m_Mdouble(group, x1, z1, ctx))
281                 goto err;
282             BN_consttime_swap(word & mask, x1, x2, group_top);
283             BN_consttime_swap(word & mask, z1, z2, group_top);
284             mask >>= 1;
285         }
286         mask = BN_TBIT;
287     }
288
289     /* convert out of "projective" coordinates */
290     i = gf2m_Mxy(group, point->X, point->Y, x1, z1, x2, z2, ctx);
291     if (i == 0)
292         goto err;
293     else if (i == 1) {
294         if (!EC_POINT_set_to_infinity(group, r))
295             goto err;
296     } else {
297         if (!BN_one(r->Z))
298             goto err;
299         r->Z_is_one = 1;
300     }
301
302     /* GF(2^m) field elements should always have BIGNUM::neg = 0 */
303     BN_set_negative(r->X, 0);
304     BN_set_negative(r->Y, 0);
305
306     ret = 1;
307
308  err:
309     BN_CTX_end(ctx);
310     return ret;
311 }
312
313 /*-
314  * Computes the sum
315  *     scalar*group->generator + scalars[0]*points[0] + ... + scalars[num-1]*points[num-1]
316  * gracefully ignoring NULL scalar values.
317  */
318 int ec_GF2m_simple_mul(const EC_GROUP *group, EC_POINT *r,
319                        const BIGNUM *scalar, size_t num,
320                        const EC_POINT *points[], const BIGNUM *scalars[],
321                        BN_CTX *ctx)
322 {
323     BN_CTX *new_ctx = NULL;
324     int ret = 0;
325     size_t i;
326     EC_POINT *p = NULL;
327     EC_POINT *acc = NULL;
328
329     if (ctx == NULL) {
330         ctx = new_ctx = BN_CTX_new();
331         if (ctx == NULL)
332             return 0;
333     }
334
335     /*
336      * This implementation is more efficient than the wNAF implementation for
337      * 2 or fewer points.  Use the ec_wNAF_mul implementation for 3 or more
338      * points, or if we can perform a fast multiplication based on
339      * precomputation.
340      */
341     if ((scalar && (num > 1)) || (num > 2)
342         || (num == 0 && EC_GROUP_have_precompute_mult(group))) {
343         ret = ec_wNAF_mul(group, r, scalar, num, points, scalars, ctx);
344         goto err;
345     }
346
347     if ((p = EC_POINT_new(group)) == NULL)
348         goto err;
349     if ((acc = EC_POINT_new(group)) == NULL)
350         goto err;
351
352     if (!EC_POINT_set_to_infinity(group, acc))
353         goto err;
354
355     if (scalar) {
356         if (!ec_GF2m_montgomery_point_multiply
357             (group, p, scalar, group->generator, ctx))
358             goto err;
359         if (BN_is_negative(scalar))
360             if (!group->meth->invert(group, p, ctx))
361                 goto err;
362         if (!group->meth->add(group, acc, acc, p, ctx))
363             goto err;
364     }
365
366     for (i = 0; i < num; i++) {
367         if (!ec_GF2m_montgomery_point_multiply
368             (group, p, scalars[i], points[i], ctx))
369             goto err;
370         if (BN_is_negative(scalars[i]))
371             if (!group->meth->invert(group, p, ctx))
372                 goto err;
373         if (!group->meth->add(group, acc, acc, p, ctx))
374             goto err;
375     }
376
377     if (!EC_POINT_copy(r, acc))
378         goto err;
379
380     ret = 1;
381
382  err:
383     EC_POINT_free(p);
384     EC_POINT_free(acc);
385     BN_CTX_free(new_ctx);
386     return ret;
387 }
388
389 /*
390  * Precomputation for point multiplication: fall back to wNAF methods because
391  * ec_GF2m_simple_mul() uses ec_wNAF_mul() if appropriate
392  */
393
394 int ec_GF2m_precompute_mult(EC_GROUP *group, BN_CTX *ctx)
395 {
396     return ec_wNAF_precompute_mult(group, ctx);
397 }
398
399 int ec_GF2m_have_precompute_mult(const EC_GROUP *group)
400 {
401     return ec_wNAF_have_precompute_mult(group);
402 }
403
404 #endif