19d2336784fab5f55215b0dd49dc25d1f1b655da
[openssl.git] / crypto / ec / ec_mult.c
1 /* crypto/ec/ec_mult.c */
2 /* ====================================================================
3  * Copyright (c) 1998-2001 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: width-m NAFs */
62
63 /* TODO: optional Lim-Lee precomputation for the generator */
64
65
66 /* this is just BN_window_bits_for_exponent_size from bn_lcl.h for now;
67  * the table should be updated for EC */ /* TODO */
68 #define EC_window_bits_for_scalar_size(b) \
69                 ((b) > 671 ? 6 : \
70                  (b) > 239 ? 5 : \
71                  (b) >  79 ? 4 : \
72                  (b) >  23 ? 3 : 1)
73
74 /* Compute
75  *      \sum scalars[i]*points[i]
76  * where
77  *      scalar*generator
78  * is included in the addition if scalar != NULL
79  */
80 int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
81         size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx)
82         {
83         BN_CTX *new_ctx = NULL;
84         EC_POINT *generator = NULL;
85         EC_POINT *tmp = NULL;
86         size_t totalnum;
87         size_t i, j;
88         int k, t;
89         int r_is_at_infinity = 1;
90         size_t max_bits = 0;
91         size_t *wsize = NULL; /* individual window sizes */
92         unsigned long *wbits = NULL; /* individual window contents */
93         int *wpos = NULL; /* position of bottom bit of current individual windows
94                            * (wpos[i] is valid if wbits[i] != 0) */
95         size_t num_val;
96         EC_POINT **val = NULL; /* precomputation */
97         EC_POINT **v;
98         EC_POINT ***val_sub = NULL; /* pointers to sub-arrays of 'val' */
99         int ret = 0;
100         
101         if (scalar != NULL)
102                 {
103                 generator = EC_GROUP_get0_generator(group);
104                 if (generator == NULL)
105                         {
106                         ECerr(EC_F_EC_POINTS_MUL, EC_R_UNDEFINED_GENERATOR);
107                         return 0;
108                         }
109                 }
110         
111         for (i = 0; i < num; i++)
112                 {
113                 if (group->meth != points[i]->meth)
114                         {
115                         ECerr(EC_F_EC_POINTS_MUL, EC_R_INCOMPATIBLE_OBJECTS);
116                         return 0;
117                         }
118                 }
119
120         totalnum = num + (scalar != NULL);
121
122         wsize = OPENSSL_malloc(totalnum * sizeof wsize[0]);
123         wbits = OPENSSL_malloc(totalnum * sizeof wbits[0]);
124         wpos = OPENSSL_malloc(totalnum * sizeof wpos[0]);
125         if (wsize == NULL || wbits == NULL || wpos == NULL) goto err;
126
127         /* num_val := total number of points to precompute */
128         num_val = 0;
129         for (i = 0; i < totalnum; i++)
130                 {
131                 size_t bits;
132
133                 bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(scalar);
134                 wsize[i] = EC_window_bits_for_scalar_size(bits);
135                 num_val += 1 << (wsize[i] - 1);
136                 if (bits > max_bits)
137                         max_bits = bits;
138                 wbits[i] = 0;
139                 wpos[i] = 0;
140                 }
141
142         /* all precomputed points go into a single array 'val',
143          * 'val_sub[i]' is a pointer to the subarray for the i-th point */
144         val = OPENSSL_malloc((num_val + 1) * sizeof val[0]);
145         if (val == NULL) goto err;
146         val[num_val] = NULL; /* pivot element */
147
148         val_sub = OPENSSL_malloc(totalnum * sizeof val_sub[0]);
149         if (val_sub == NULL) goto err;
150
151         /* allocate points for precomputation */
152         v = val;
153         for (i = 0; i < totalnum; i++)
154                 {
155                 val_sub[i] = v;
156                 for (j = 0; j < (1 << (wsize[i] - 1)); j++)
157                         {
158                         *v = EC_POINT_new(group);
159                         if (*v == NULL) goto err;
160                         v++;
161                         }
162                 }
163         if (!(v == val + num_val))
164                 {
165                 ECerr(EC_F_EC_POINTS_MUL, ERR_R_INTERNAL_ERROR);
166                 goto err;
167                 }
168
169         if (ctx == NULL)
170                 {
171                 ctx = new_ctx = BN_CTX_new();
172                 if (ctx == NULL)
173                         goto err;
174                 }
175         
176         tmp = EC_POINT_new(group);
177         if (tmp == NULL) goto err;
178
179         /* prepare precomputed values:
180          *    val_sub[i][0] :=     points[i]
181          *    val_sub[i][1] := 3 * points[i]
182          *    val_sub[i][2] := 5 * points[i]
183          *    ...
184          */
185         for (i = 0; i < totalnum; i++)
186                 {
187                 if (i < num)
188                         {
189                         if (!EC_POINT_copy(val_sub[i][0], points[i])) goto err;
190                         if (scalars[i]->neg)
191                                 {
192                                 if (!EC_POINT_invert(group, val_sub[i][0], ctx)) goto err;
193                                 }
194                         }
195                 else
196                         {
197                         if (!EC_POINT_copy(val_sub[i][0], generator)) goto err;
198                         if (scalar->neg)
199                                 {
200                                 if (!EC_POINT_invert(group, val_sub[i][0], ctx)) goto err;
201                                 }
202                         }
203
204                 if (wsize[i] > 1)
205                         {
206                         if (!EC_POINT_dbl(group, tmp, val_sub[i][0], ctx)) goto err;
207                         for (j = 1; j < (1 << (wsize[i] - 1)); j++)
208                                 {
209                                 if (!EC_POINT_add(group, val_sub[i][j], val_sub[i][j - 1], tmp, ctx)) goto err;
210                                 }
211                         }
212                 }
213
214 #if 1 /* optional, maybe we should only do this if total_num > 1 */
215         if (!EC_POINTs_make_affine(group, num_val, val, ctx)) goto err;
216 #endif
217
218         r_is_at_infinity = 1;
219
220         for (k = max_bits - 1; k >= 0; k--)
221                 {
222                 if (!r_is_at_infinity)
223                         {
224                         if (!EC_POINT_dbl(group, r, r, ctx)) goto err;
225                         }
226                 
227                 for (i = 0; i < totalnum; i++)
228                         {
229                         if (wbits[i] == 0)
230                                 {
231                                 const BIGNUM *s;
232
233                                 s = i < num ? scalars[i] : scalar;
234
235                                 if (BN_is_bit_set(s, k))
236                                         {
237                                         /* look at bits  k - wsize[i] + 1 .. k  for this window */
238                                         t = k - wsize[i] + 1;
239                                         while (!BN_is_bit_set(s, t)) /* BN_is_bit_set is false for t < 0 */
240                                                 t++;
241                                         wpos[i] = t;
242                                         wbits[i] = 1;
243                                         for (t = k - 1; t >= wpos[i]; t--)
244                                                 {
245                                                 wbits[i] <<= 1;
246                                                 if (BN_is_bit_set(s, t))
247                                                         wbits[i]++;
248                                                 }
249                                         /* now wbits[i] is the odd bit pattern at bits wpos[i] .. k */
250                                         }
251                                 }
252                         
253                         if ((wbits[i] != 0) && (wpos[i] == k))
254                                 {
255                                 if (r_is_at_infinity)
256                                         {
257                                         if (!EC_POINT_copy(r, val_sub[i][wbits[i] >> 1])) goto err;
258                                         r_is_at_infinity = 0;
259                                         }
260                                 else
261                                         {
262                                         if (!EC_POINT_add(group, r, r, val_sub[i][wbits[i] >> 1], ctx)) goto err;
263                                         }
264                                 wbits[i] = 0;
265                                 }
266                         }
267                 }
268
269         if (r_is_at_infinity)
270                 if (!EC_POINT_set_to_infinity(group, r)) goto err;
271         
272         ret = 1;
273
274  err:
275         if (new_ctx != NULL)
276                 BN_CTX_free(new_ctx);
277         if (tmp != NULL)
278                 EC_POINT_free(tmp);
279         if (wsize != NULL)
280                 OPENSSL_free(wsize);
281         if (wbits != NULL)
282                 OPENSSL_free(wbits);
283         if (wpos != NULL)
284                 OPENSSL_free(wpos);
285         if (val != NULL)
286                 {
287                 for (v = val; *v != NULL; v++)
288                         EC_POINT_clear_free(*v);
289
290                 OPENSSL_free(val);
291                 }
292         if (val_sub != NULL)
293                 {
294                 OPENSSL_free(val_sub);
295                 }
296         return ret;
297         }
298
299
300 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)
301         {
302         const EC_POINT *points[1];
303         const BIGNUM *scalars[1];
304
305         points[0] = point;
306         scalars[0] = p_scalar;
307
308         return EC_POINTs_mul(group, r, g_scalar, (point != NULL && p_scalar != NULL), points, scalars, ctx);
309         }
310
311
312 int EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx)
313         {
314         const EC_POINT *generator;
315         BN_CTX *new_ctx = NULL;
316         BIGNUM *order;
317         int ret = 0;
318
319         generator = EC_GROUP_get0_generator(group);
320         if (generator == NULL)
321                 {
322                 ECerr(EC_F_EC_GROUP_PRECOMPUTE_MULT, EC_R_UNDEFINED_GENERATOR);
323                 return 0;
324                 }
325
326         if (ctx == NULL)
327                 {
328                 ctx = new_ctx = BN_CTX_new();
329                 if (ctx == NULL)
330                         return 0;
331                 }
332         
333         BN_CTX_start(ctx);
334         order = BN_CTX_get(ctx);
335         if (order == NULL) goto err;
336         
337         if (!EC_GROUP_get_order(group, order, ctx)) return 0;
338         if (BN_is_zero(order))
339                 {
340                 ECerr(EC_F_EC_GROUP_PRECOMPUTE_MULT, EC_R_UNKNOWN_ORDER);
341                 goto err;
342                 }
343
344         /* TODO */
345
346         ret = 1;
347         
348  err:
349         BN_CTX_end(ctx);
350         if (new_ctx != NULL)
351                 BN_CTX_free(new_ctx);
352         return ret;
353         }