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: 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 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 */
77static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len, BN_CTX *ctx)
78	{
79	BIGNUM *c;
80	int ok = 0;
81	signed char *r = NULL;
82	int sign = 1;
83	int bit, next_bit, mask;
84	size_t len = 0, j;
85
86	BN_CTX_start(ctx);
87	c = BN_CTX_get(ctx);
88	if (c == NULL) goto err;
89
90	if (w <= 0 || w > 7) /* 'signed char' can represent integers with absolute values less than 2^7 */
91		{
92		ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
93		goto err;
94		}
95	bit = 1 << w; /* at most 128 */
96	next_bit = bit << 1; /* at most 256 */
97	mask = next_bit - 1; /* at most 255 */
98
99	if (!BN_copy(c, scalar)) goto err;
100	if (c->neg)
101		{
102		sign = -1;
103		c->neg = 0;
104		}
105
106	len = BN_num_bits(c) + 1; /* wNAF may be one digit longer than binary representation */
107	r = OPENSSL_malloc(len);
108	if (r == NULL) goto err;
109
110	j = 0;
111	while (!BN_is_zero(c))
112		{
113		int u = 0;
114
115		if (BN_is_odd(c))
116			{
117			if (c->d == NULL || c->top == 0)
118				{
119				ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
120				goto err;
121				}
122			u = c->d[0] & mask;
123			if (u & bit)
124				{
125				u -= next_bit;
126				/* u < 0 */
127				if (!BN_add_word(c, -u)) goto err;
128				}
129			else
130				{
131				/* u > 0 */
132				if (!BN_sub_word(c, u)) goto err;
133				}
134
135			if (u <= -bit || u >= bit || !(u & 1) || c->neg)
136				{
137				ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
138				goto err;
139				}
140			}
141
142		r[j++] = sign * u;
143
144		if (BN_is_odd(c))
145			{
146			ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
147			goto err;
148			}
149		if (!BN_rshift1(c, c)) goto err;
150		}
151
152	if (j > len)
153		{
154		ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
155		goto err;
156		}
157	len = j;
158	ok = 1;
159
160 err:
161	BN_CTX_end(ctx);
162	if (!ok)
163		{
164		OPENSSL_free(r);
165		r = NULL;
166		}
167	if (ok)
168		*ret_len = len;
169	return r;
170	}
171
172
173/* TODO: table should be optimised for the wNAF-based implementation,
174 *       sometimes smaller windows will give better performance
175 *       (thus the boundaries should be increased)
176 */
177#define EC_window_bits_for_scalar_size(b) \
178		((size_t) \
179		 ((b) >= 2000 ? 6 : \
180		  (b) >=  800 ? 5 : \
181		  (b) >=  300 ? 4 : \
182		  (b) >=   70 ? 3 : \
183		  (b) >=   20 ? 2 : \
184		   1))
185
186/* Compute
187 *      \sum scalars[i]*points[i],
188 * also including
189 *      scalar*generator
190 * in the addition if scalar != NULL
191 */
192int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
193	size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx)
194	{
195	BN_CTX *new_ctx = NULL;
196	EC_POINT *generator = NULL;
197	EC_POINT *tmp = NULL;
198	size_t totalnum;
199	size_t i, j;
200	int k;
201	int r_is_inverted = 0;
202	int r_is_at_infinity = 1;
203	size_t *wsize = NULL; /* individual window sizes */
204	signed char **wNAF = NULL; /* individual wNAFs */
205	size_t *wNAF_len = NULL;
206	size_t max_len = 0;
207	size_t num_val;
208	EC_POINT **val = NULL; /* precomputation */
209	EC_POINT **v;
210	EC_POINT ***val_sub = NULL; /* pointers to sub-arrays of 'val' */
211	int ret = 0;
212
213	if (group->meth != r->meth)
214		{
215		ECerr(EC_F_EC_POINTS_MUL, EC_R_INCOMPATIBLE_OBJECTS);
216		return 0;
217		}
218
219	if ((scalar == NULL) && (num == 0))
220		{
221		return EC_POINT_set_to_infinity(group, r);
222		}
223
224	if (scalar != NULL)
225		{
226		generator = EC_GROUP_get0_generator(group);
227		if (generator == NULL)
228			{
229			ECerr(EC_F_EC_POINTS_MUL, EC_R_UNDEFINED_GENERATOR);
230			return 0;
231			}
232		}
233
234	for (i = 0; i < num; i++)
235		{
236		if (group->meth != points[i]->meth)
237			{
238			ECerr(EC_F_EC_POINTS_MUL, EC_R_INCOMPATIBLE_OBJECTS);
239			return 0;
240			}
241		}
242
243	totalnum = num + (scalar != NULL);
244
245	wsize = OPENSSL_malloc(totalnum * sizeof wsize[0]);
246	wNAF_len = OPENSSL_malloc(totalnum * sizeof wNAF_len[0]);
247	wNAF = OPENSSL_malloc((totalnum + 1) * sizeof wNAF[0]);
248	if (wNAF != NULL)
249		{
250		wNAF[0] = NULL; /* preliminary pivot */
251		}
252	if (wsize == NULL || wNAF_len == NULL || wNAF == NULL) goto err;
253
254	/* num_val := total number of points to precompute */
255	num_val = 0;
256	for (i = 0; i < totalnum; i++)
257		{
258		size_t bits;
259
260		bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(scalar);
261		wsize[i] = EC_window_bits_for_scalar_size(bits);
262		num_val += 1u << (wsize[i] - 1);
263		}
264
265	/* all precomputed points go into a single array 'val',
266	 * 'val_sub[i]' is a pointer to the subarray for the i-th point */
267	val = OPENSSL_malloc((num_val + 1) * sizeof val[0]);
268	if (val == NULL) goto err;
269	val[num_val] = NULL; /* pivot element */
270
271	val_sub = OPENSSL_malloc(totalnum * sizeof val_sub[0]);
272	if (val_sub == NULL) goto err;
273
274	/* allocate points for precomputation */
275	v = val;
276	for (i = 0; i < totalnum; i++)
277		{
278		val_sub[i] = v;
279		for (j = 0; j < (1u << (wsize[i] - 1)); j++)
280			{
281			*v = EC_POINT_new(group);
282			if (*v == NULL) goto err;
283			v++;
284			}
285		}
286	if (!(v == val + num_val))
287		{
288		ECerr(EC_F_EC_POINTS_MUL, ERR_R_INTERNAL_ERROR);
289		goto err;
290		}
291
292	if (ctx == NULL)
293		{
294		ctx = new_ctx = BN_CTX_new();
295		if (ctx == NULL)
296			goto err;
297		}
298
299	tmp = EC_POINT_new(group);
300	if (tmp == NULL) goto err;
301
302	/* prepare precomputed values:
303	 *    val_sub[i][0] :=     points[i]
304	 *    val_sub[i][1] := 3 * points[i]
305	 *    val_sub[i][2] := 5 * points[i]
306	 *    ...
307	 */
308	for (i = 0; i < totalnum; i++)
309		{
310		if (i < num)
311			{
312			if (!EC_POINT_copy(val_sub[i][0], points[i])) goto err;
313			}
314		else
315			{
316			if (!EC_POINT_copy(val_sub[i][0], generator)) goto err;
317			}
318
319		if (wsize[i] > 1)
320			{
321			if (!EC_POINT_dbl(group, tmp, val_sub[i][0], ctx)) goto err;
322			for (j = 1; j < (1u << (wsize[i] - 1)); j++)
323				{
324				if (!EC_POINT_add(group, val_sub[i][j], val_sub[i][j - 1], tmp, ctx)) goto err;
325				}
326			}
327
328		wNAF[i + 1] = NULL; /* make sure we always have a pivot */
329		wNAF[i] = compute_wNAF((i < num ? scalars[i] : scalar), wsize[i], &wNAF_len[i], ctx);
330		if (wNAF[i] == NULL) goto err;
331		if (wNAF_len[i] > max_len)
332			max_len = wNAF_len[i];
333		}
334
335#if 1 /* optional; EC_window_bits_for_scalar_size assumes we do this step */
336	if (!EC_POINTs_make_affine(group, num_val, val, ctx)) goto err;
337#endif
338
339	r_is_at_infinity = 1;
340
341	for (k = max_len - 1; k >= 0; k--)
342		{
343		if (!r_is_at_infinity)
344			{
345			if (!EC_POINT_dbl(group, r, r, ctx)) goto err;
346			}
347
348		for (i = 0; i < totalnum; i++)
349			{
350			if (wNAF_len[i] > (size_t)k)
351				{
352				int digit = wNAF[i][k];
353				int is_neg;
354
355				if (digit)
356					{
357					is_neg = digit < 0;
358
359					if (is_neg)
360						digit = -digit;
361
362					if (is_neg != r_is_inverted)
363						{
364						if (!r_is_at_infinity)
365							{
366							if (!EC_POINT_invert(group, r, ctx)) goto err;
367							}
368						r_is_inverted = !r_is_inverted;
369						}
370
371					/* digit > 0 */
372
373					if (r_is_at_infinity)
374						{
375						if (!EC_POINT_copy(r, val_sub[i][digit >> 1])) goto err;
376						r_is_at_infinity = 0;
377						}
378					else
379						{
380						if (!EC_POINT_add(group, r, r, val_sub[i][digit >> 1], ctx)) goto err;
381						}
382					}
383				}
384			}
385		}
386
387	if (r_is_at_infinity)
388		{
389		if (!EC_POINT_set_to_infinity(group, r)) goto err;
390		}
391	else
392		{
393		if (r_is_inverted)
394			if (!EC_POINT_invert(group, r, ctx)) goto err;
395		}
396
397	ret = 1;
398
399 err:
400	if (new_ctx != NULL)
401		BN_CTX_free(new_ctx);
402	if (tmp != NULL)
403		EC_POINT_free(tmp);
404	if (wsize != NULL)
405		OPENSSL_free(wsize);
406	if (wNAF_len != NULL)
407		OPENSSL_free(wNAF_len);
408	if (wNAF != NULL)
409		{
410		signed char **w;
411
412		for (w = wNAF; *w != NULL; w++)
413			OPENSSL_free(*w);
414
415		OPENSSL_free(wNAF);
416		}
417	if (val != NULL)
418		{
419		for (v = val; *v != NULL; v++)
420			EC_POINT_clear_free(*v);
421
422		OPENSSL_free(val);
423		}
424	if (val_sub != NULL)
425		{
426		OPENSSL_free(val_sub);
427		}
428	return ret;
429	}
430
431
432int 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)
433	{
434	const EC_POINT *points[1];
435	const BIGNUM *scalars[1];
436
437	points[0] = point;
438	scalars[0] = p_scalar;
439
440	return EC_POINTs_mul(group, r, g_scalar, (point != NULL && p_scalar != NULL), points, scalars, ctx);
441	}
442
443
444int EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx)
445	{
446	const EC_POINT *generator;
447	BN_CTX *new_ctx = NULL;
448	BIGNUM *order;
449	int ret = 0;
450
451	generator = EC_GROUP_get0_generator(group);
452	if (generator == NULL)
453		{
454		ECerr(EC_F_EC_GROUP_PRECOMPUTE_MULT, EC_R_UNDEFINED_GENERATOR);
455		return 0;
456		}
457
458	if (ctx == NULL)
459		{
460		ctx = new_ctx = BN_CTX_new();
461		if (ctx == NULL)
462			return 0;
463		}
464
465	BN_CTX_start(ctx);
466	order = BN_CTX_get(ctx);
467	if (order == NULL) goto err;
468
469	if (!EC_GROUP_get_order(group, order, ctx)) return 0;
470	if (BN_is_zero(order))
471		{
472		ECerr(EC_F_EC_GROUP_PRECOMPUTE_MULT, EC_R_UNKNOWN_ORDER);
473		goto err;
474		}
475
476	/* TODO */
477
478	ret = 1;
479
480 err:
481	BN_CTX_end(ctx);
482	if (new_ctx != NULL)
483		BN_CTX_free(new_ctx);
484	return ret;
485	}
486