improve wNAF generation
[openssl.git] / crypto / ec / ec_mult.c
1 /* crypto/ec/ec_mult.c */
2 /* ====================================================================
3  * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer. 
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the
15  *    distribution.
16  *
17  * 3. All advertising materials mentioning features or use of this
18  *    software must display the following acknowledgment:
19  *    "This product includes software developed by the OpenSSL Project
20  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21  *
22  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23  *    endorse or promote products derived from this software without
24  *    prior written permission. For written permission, please contact
25  *    openssl-core@openssl.org.
26  *
27  * 5. Products derived from this software may not be called "OpenSSL"
28  *    nor may "OpenSSL" appear in their names without prior written
29  *    permission of the OpenSSL Project.
30  *
31  * 6. Redistributions of any form whatsoever must retain the following
32  *    acknowledgment:
33  *    "This product includes software developed by the OpenSSL Project
34  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35  *
36  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47  * OF THE POSSIBILITY OF SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This product includes cryptographic software written by Eric Young
51  * (eay@cryptsoft.com).  This product includes software written by Tim
52  * Hudson (tjh@cryptsoft.com).
53  *
54  */
55
56 #include <openssl/err.h>
57
58 #include "ec_lcl.h"
59
60
61 /* TODO: optional precomputation of multiples of the generator */
62
63
64
65 /*
66  * wNAF-based interleaving multi-exponentation method
67  * (<URL:http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/moeller.html#multiexp>)
68  */
69
70
71 /* Determine the modified width-(w+1) Non-Adjacent Form (wNAF) of 'scalar'.
72  * This is an array  r[]  of values that are either zero or odd with an
73  * absolute value less than  2^w  satisfying
74  *     scalar = \sum_j r[j]*2^j
75  * where at most one of any  w+1  consecutive digits is non-zero
76  * with the exception that the most significant digit may be only
77  * w-1 zeros away from that next non-zero digit.
78  */
79 static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len)
80         {
81         int window_val;
82         int ok = 0;
83         signed char *r = NULL;
84         int sign = 1;
85         int bit, next_bit, mask;
86         size_t len = 0, j;
87         
88         if (w <= 0 || w > 7) /* 'signed char' can represent integers with absolute values less than 2^7 */
89                 {
90                 ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
91                 goto err;
92                 }
93         bit = 1 << w; /* at most 128 */
94         next_bit = bit << 1; /* at most 256 */
95         mask = next_bit - 1; /* at most 255 */
96
97         if (scalar->neg)
98                 {
99                 sign = -1;
100                 }
101
102         len = BN_num_bits(scalar);
103         r = OPENSSL_malloc(len + 1); /* modified wNAF may be one digit longer than binary representation */
104         if (r == NULL) goto err;
105
106         if (scalar->d == NULL || scalar->top == 0)
107                 {
108                 ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
109                 goto err;
110                 }
111         window_val = scalar->d[0] & mask;
112         j = 0;
113         while ((window_val != 0) || (j + w + 1 < len)) /* if j+w+1 >= len, window_val will not increase */
114                 {
115                 int digit = 0;
116
117                 /* 0 <= window_val <= 2^(w+1) */
118
119                 if (window_val & 1)
120                         {
121                         /* 0 < window_val < 2^(w+1) */
122
123                         if (window_val & bit)
124                                 {
125                                 digit = window_val - next_bit; /* -2^w < digit < 0 */
126
127 #if 1 /* modified wNAF */
128                                 if (j + w + 1 >= len)
129                                         {
130                                         /* special case for generating modified wNAFs:
131                                          * no new bits will be added into window_val,
132                                          * so using a positive digit here will decrease
133                                          * the total length of the representation */
134                                         
135                                         digit = window_val & (mask >> 1); /* 0 < digit < 2^w */
136                                         }
137 #endif
138                                 }
139                         else
140                                 {
141                                 digit = window_val; /* 0 < digit < 2^w */
142                                 }
143                         
144                         if (digit <= -bit || digit >= bit || !(digit & 1))
145                                 {
146                                 ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
147                                 goto err;
148                                 }
149
150                         window_val -= digit;
151
152                         /* now window_val is 0 or 2^(w+1) in standard wNAF generation;
153                          * for modified window NAFs, it may also be 2^w
154                          */
155                         if (window_val != 0 && window_val != next_bit && window_val != bit)
156                                 {
157                                 ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
158                                 goto err;
159                                 }
160                         }
161
162                 r[j++] = sign * digit;
163
164                 window_val >>= 1;
165                 window_val += bit * BN_is_bit_set(scalar, j + w);
166
167                 if (window_val > next_bit)
168                         {
169                         ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
170                         goto err;
171                         }
172                 }
173
174         if (j > len + 1)
175                 {
176                 ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
177                 goto err;
178                 }
179         len = j;
180         ok = 1;
181
182  err:
183         if (!ok)
184                 {
185                 OPENSSL_free(r);
186                 r = NULL;
187                 }
188         if (ok)
189                 *ret_len = len;
190         return r;
191         }
192
193
194 /* TODO: table should be optimised for the wNAF-based implementation,
195  *       sometimes smaller windows will give better performance
196  *       (thus the boundaries should be increased)
197  */
198 #define EC_window_bits_for_scalar_size(b) \
199                 ((b) >= 2000 ? 6 : \
200                  (b) >=  800 ? 5 : \
201                  (b) >=  300 ? 4 : \
202                  (b) >=   70 ? 3 : \
203                  (b) >=   20 ? 2 : \
204                   1)
205
206 /* Compute
207  *      \sum scalars[i]*points[i],
208  * also including
209  *      scalar*generator
210  * in the addition if scalar != NULL
211  */
212 int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
213         size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx)
214         {
215         BN_CTX *new_ctx = NULL;
216         EC_POINT *generator = NULL;
217         EC_POINT *tmp = NULL;
218         size_t totalnum;
219         size_t i, j;
220         int k;
221         int r_is_inverted = 0;
222         int r_is_at_infinity = 1;
223         size_t *wsize = NULL; /* individual window sizes */
224         signed char **wNAF = NULL; /* individual wNAFs */
225         size_t *wNAF_len = NULL;
226         size_t max_len = 0;
227         size_t num_val;
228         EC_POINT **val = NULL; /* precomputation */
229         EC_POINT **v;
230         EC_POINT ***val_sub = NULL; /* pointers to sub-arrays of 'val' */
231         int ret = 0;
232         
233         if (scalar != NULL)
234                 {
235                 generator = EC_GROUP_get0_generator(group);
236                 if (generator == NULL)
237                         {
238                         ECerr(EC_F_EC_POINTS_MUL, EC_R_UNDEFINED_GENERATOR);
239                         return 0;
240                         }
241                 }
242         
243         for (i = 0; i < num; i++)
244                 {
245                 if (group->meth != points[i]->meth)
246                         {
247                         ECerr(EC_F_EC_POINTS_MUL, EC_R_INCOMPATIBLE_OBJECTS);
248                         return 0;
249                         }
250                 }
251
252         totalnum = num + (scalar != NULL);
253
254         wsize = OPENSSL_malloc(totalnum * sizeof wsize[0]);
255         wNAF_len = OPENSSL_malloc(totalnum * sizeof wNAF_len[0]);
256         wNAF = OPENSSL_malloc((totalnum + 1) * sizeof wNAF[0]);
257         if (wNAF != NULL)
258                 {
259                 wNAF[0] = NULL; /* preliminary pivot */
260                 }
261         if (wsize == NULL || wNAF_len == NULL || wNAF == NULL) goto err;
262
263         /* num_val := total number of points to precompute */
264         num_val = 0;
265         for (i = 0; i < totalnum; i++)
266                 {
267                 size_t bits;
268
269                 bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(scalar);
270                 wsize[i] = EC_window_bits_for_scalar_size(bits);
271                 num_val += 1u << (wsize[i] - 1);
272                 }
273
274         /* all precomputed points go into a single array 'val',
275          * 'val_sub[i]' is a pointer to the subarray for the i-th point */
276         val = OPENSSL_malloc((num_val + 1) * sizeof val[0]);
277         if (val == NULL) goto err;
278         val[num_val] = NULL; /* pivot element */
279
280         val_sub = OPENSSL_malloc(totalnum * sizeof val_sub[0]);
281         if (val_sub == NULL) goto err;
282
283         /* allocate points for precomputation */
284         v = val;
285         for (i = 0; i < totalnum; i++)
286                 {
287                 val_sub[i] = v;
288                 for (j = 0; j < (1u << (wsize[i] - 1)); j++)
289                         {
290                         *v = EC_POINT_new(group);
291                         if (*v == NULL) goto err;
292                         v++;
293                         }
294                 }
295         if (!(v == val + num_val))
296                 {
297                 ECerr(EC_F_EC_POINTS_MUL, ERR_R_INTERNAL_ERROR);
298                 goto err;
299                 }
300
301         if (ctx == NULL)
302                 {
303                 ctx = new_ctx = BN_CTX_new();
304                 if (ctx == NULL)
305                         goto err;
306                 }
307         
308         tmp = EC_POINT_new(group);
309         if (tmp == NULL) goto err;
310
311         /* prepare precomputed values:
312          *    val_sub[i][0] :=     points[i]
313          *    val_sub[i][1] := 3 * points[i]
314          *    val_sub[i][2] := 5 * points[i]
315          *    ...
316          */
317         for (i = 0; i < totalnum; i++)
318                 {
319                 if (i < num)
320                         {
321                         if (!EC_POINT_copy(val_sub[i][0], points[i])) goto err;
322                         }
323                 else
324                         {
325                         if (!EC_POINT_copy(val_sub[i][0], generator)) goto err;
326                         }
327
328                 if (wsize[i] > 1)
329                         {
330                         if (!EC_POINT_dbl(group, tmp, val_sub[i][0], ctx)) goto err;
331                         for (j = 1; j < (1u << (wsize[i] - 1)); j++)
332                                 {
333                                 if (!EC_POINT_add(group, val_sub[i][j], val_sub[i][j - 1], tmp, ctx)) goto err;
334                                 }
335                         }
336
337                 wNAF[i + 1] = NULL; /* make sure we always have a pivot */
338                 wNAF[i] = compute_wNAF((i < num ? scalars[i] : scalar), wsize[i], &wNAF_len[i]);
339                 if (wNAF[i] == NULL) goto err;
340                 if (wNAF_len[i] > max_len)
341                         max_len = wNAF_len[i];
342                 }
343
344 #if 1 /* optional; EC_window_bits_for_scalar_size assumes we do this step */
345         if (!EC_POINTs_make_affine(group, num_val, val, ctx)) goto err;
346 #endif
347
348         r_is_at_infinity = 1;
349
350         for (k = max_len - 1; k >= 0; k--)
351                 {
352                 if (!r_is_at_infinity)
353                         {
354                         if (!EC_POINT_dbl(group, r, r, ctx)) goto err;
355                         }
356                 
357                 for (i = 0; i < totalnum; i++)
358                         {
359                         if (wNAF_len[i] > (size_t)k)
360                                 {
361                                 int digit = wNAF[i][k];
362                                 int is_neg;
363
364                                 if (digit) 
365                                         {
366                                         is_neg = digit < 0;
367
368                                         if (is_neg)
369                                                 digit = -digit;
370
371                                         if (is_neg != r_is_inverted)
372                                                 {
373                                                 if (!r_is_at_infinity)
374                                                         {
375                                                         if (!EC_POINT_invert(group, r, ctx)) goto err;
376                                                         }
377                                                 r_is_inverted = !r_is_inverted;
378                                                 }
379
380                                         /* digit > 0 */
381
382                                         if (r_is_at_infinity)
383                                                 {
384                                                 if (!EC_POINT_copy(r, val_sub[i][digit >> 1])) goto err;
385                                                 r_is_at_infinity = 0;
386                                                 }
387                                         else
388                                                 {
389                                                 if (!EC_POINT_add(group, r, r, val_sub[i][digit >> 1], ctx)) goto err;
390                                                 }
391                                         }
392                                 }
393                         }
394                 }
395
396         if (r_is_at_infinity)
397                 {
398                 if (!EC_POINT_set_to_infinity(group, r)) goto err;
399                 }
400         else
401                 {
402                 if (r_is_inverted)
403                         if (!EC_POINT_invert(group, r, ctx)) goto err;
404                 }
405         
406         ret = 1;
407
408  err:
409         if (new_ctx != NULL)
410                 BN_CTX_free(new_ctx);
411         if (tmp != NULL)
412                 EC_POINT_free(tmp);
413         if (wsize != NULL)
414                 OPENSSL_free(wsize);
415         if (wNAF_len != NULL)
416                 OPENSSL_free(wNAF_len);
417         if (wNAF != NULL)
418                 {
419                 signed char **w;
420                 
421                 for (w = wNAF; *w != NULL; w++)
422                         OPENSSL_free(*w);
423                 
424                 OPENSSL_free(wNAF);
425                 }
426         if (val != NULL)
427                 {
428                 for (v = val; *v != NULL; v++)
429                         EC_POINT_clear_free(*v);
430
431                 OPENSSL_free(val);
432                 }
433         if (val_sub != NULL)
434                 {
435                 OPENSSL_free(val_sub);
436                 }
437         return ret;
438         }
439
440
441 int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, const EC_POINT *point, const BIGNUM *p_scalar, BN_CTX *ctx)
442         {
443         const EC_POINT *points[1];
444         const BIGNUM *scalars[1];
445
446         points[0] = point;
447         scalars[0] = p_scalar;
448
449         return EC_POINTs_mul(group, r, g_scalar, (point != NULL && p_scalar != NULL), points, scalars, ctx);
450         }
451
452
453 int EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx)
454         {
455         const EC_POINT *generator;
456         BN_CTX *new_ctx = NULL;
457         BIGNUM *order;
458         int ret = 0;
459
460         generator = EC_GROUP_get0_generator(group);
461         if (generator == NULL)
462                 {
463                 ECerr(EC_F_EC_GROUP_PRECOMPUTE_MULT, EC_R_UNDEFINED_GENERATOR);
464                 return 0;
465                 }
466
467         if (ctx == NULL)
468                 {
469                 ctx = new_ctx = BN_CTX_new();
470                 if (ctx == NULL)
471                         return 0;
472                 }
473         
474         BN_CTX_start(ctx);
475         order = BN_CTX_get(ctx);
476         if (order == NULL) goto err;
477         
478         if (!EC_GROUP_get_order(group, order, ctx)) return 0;
479         if (BN_is_zero(order))
480                 {
481                 ECerr(EC_F_EC_GROUP_PRECOMPUTE_MULT, EC_R_UNKNOWN_ORDER);
482                 goto err;
483                 }
484
485         /* TODO */
486
487         ret = 1;
488         
489  err:
490         BN_CTX_end(ctx);
491         if (new_ctx != NULL)
492                 BN_CTX_free(new_ctx);
493         return ret;
494         }