ec_mult.c 20.1 KB
Newer Older
1
/* crypto/ec/ec_mult.c */
2
/*
3
 * Originally written by Bodo Moeller and Nils Larsch for the OpenSSL project.
4
 */
5
/* ====================================================================
6
 * Copyright (c) 1998-2007 The OpenSSL Project.  All rights reserved.
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
 *
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    openssl-core@openssl.org.
 *
 * 5. Products derived from this software may not be called "OpenSSL"
 *    nor may "OpenSSL" appear in their names without prior written
 *    permission of the OpenSSL Project.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 *
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 * This product includes cryptographic software written by Eric Young
 * (eay@cryptsoft.com).  This product includes software written by Tim
 * Hudson (tjh@cryptsoft.com).
 *
 */
58 59 60 61 62
/* ====================================================================
 * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
 * Portions of this software developed by SUN MICROSYSTEMS, INC.,
 * and contributed to the OpenSSL project.
 */
63

D
Dr. Stephen Henson 已提交
64

65

66
#include <string.h>
67 68
#include <openssl/err.h>

69
#include "internal/bn_int.h"
70
#include "ec_lcl.h"
71 72


73 74 75 76 77 78
/*
 * This file implements the wNAF-based interleaving multi-exponentation method
 * (<URL:http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/moeller.html#multiexp>);
 * for multiplication with precomputation, we use wNAF splitting
 * (<URL:http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/moeller.html#fastexp>).
 */
79 80


B
Bodo Möller 已提交
81

82 83 84 85 86 87 88 89 90 91

/* structure for precomputed multiples of the generator */
typedef struct ec_pre_comp_st {
	const EC_GROUP *group; /* parent EC_GROUP object */
	size_t blocksize;      /* block size for wNAF splitting */
	size_t numblocks;      /* max. number of blocks for which we have precomputation */
	size_t w;              /* window size */
	EC_POINT **points;     /* array with pre-calculated multiples of generator:
	                        * 'num' pointers to EC_POINT objects followed by a NULL */
	size_t num;            /* numblocks * 2^(w-1) */
92
	int references;
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
} EC_PRE_COMP;
 
/* functions to manage EC_PRE_COMP within the EC_GROUP extra_data framework */
static void *ec_pre_comp_dup(void *);
static void ec_pre_comp_free(void *);
static void ec_pre_comp_clear_free(void *);

static EC_PRE_COMP *ec_pre_comp_new(const EC_GROUP *group)
	{
	EC_PRE_COMP *ret = NULL;

	if (!group)
		return NULL;

	ret = (EC_PRE_COMP *)OPENSSL_malloc(sizeof(EC_PRE_COMP));
	if (!ret)
109 110
		{
		ECerr(EC_F_EC_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE);
111
		return ret;
112
		}
113 114 115 116 117 118
	ret->group = group;
	ret->blocksize = 8; /* default */
	ret->numblocks = 0;
	ret->w = 4; /* default */
	ret->points = NULL;
	ret->num = 0;
119
	ret->references = 1;
120 121 122 123 124
	return ret;
	}

static void *ec_pre_comp_dup(void *src_)
	{
125
	EC_PRE_COMP *src = src_;
126

127
	/* no need to actually copy, these objects never change! */
128

129
	CRYPTO_add(&src->references, 1, CRYPTO_LOCK_EC_PRE_COMP);
130

131
	return src_;
132 133 134 135
	}

static void ec_pre_comp_free(void *pre_)
	{
136
	int i;
137 138 139 140
	EC_PRE_COMP *pre = pre_;

	if (!pre)
		return;
141 142 143 144 145

	i = CRYPTO_add(&pre->references, -1, CRYPTO_LOCK_EC_PRE_COMP);
	if (i > 0)
		return;

146 147
	if (pre->points)
		{
148
		EC_POINT **p;
149

150 151
		for (p = pre->points; *p != NULL; p++)
			EC_POINT_free(*p);
152 153 154 155 156 157 158
		OPENSSL_free(pre->points);
		}
	OPENSSL_free(pre);
	}

static void ec_pre_comp_clear_free(void *pre_)
	{
159
	int i;
160 161 162 163
	EC_PRE_COMP *pre = pre_;

	if (!pre)
		return;
164 165 166 167 168

	i = CRYPTO_add(&pre->references, -1, CRYPTO_LOCK_EC_PRE_COMP);
	if (i > 0)
		return;

169 170 171 172 173
	if (pre->points)
		{
		EC_POINT **p;

		for (p = pre->points; *p != NULL; p++)
B
Bodo Möller 已提交
174
			{
175
			EC_POINT_clear_free(*p);
B
Bodo Möller 已提交
176 177
			OPENSSL_cleanse(p, sizeof *p);
			}
178 179
		OPENSSL_free(pre->points);
		}
B
Bodo Möller 已提交
180
	OPENSSL_cleanse(pre, sizeof *pre);
181 182 183 184
	OPENSSL_free(pre);
	}


B
Bodo Möller 已提交
185 186 187 188 189





B
comment  
Bodo Möller 已提交
190 191 192 193
/* TODO: table should be optimised for the wNAF-based implementation,
 *       sometimes smaller windows will give better performance
 *       (thus the boundaries should be increased)
 */
B
Bodo Möller 已提交
194
#define EC_window_bits_for_scalar_size(b) \
195 196 197 198 199 200 201
		((size_t) \
		 ((b) >= 2000 ? 6 : \
		  (b) >=  800 ? 5 : \
		  (b) >=  300 ? 4 : \
		  (b) >=   70 ? 3 : \
		  (b) >=   20 ? 2 : \
		  1))
B
Bodo Möller 已提交
202 203 204 205 206 207 208

/* Compute
 *      \sum scalars[i]*points[i],
 * also including
 *      scalar*generator
 * in the addition if scalar != NULL
 */
209
int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
B
Bodo Möller 已提交
210 211 212
	size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx)
	{
	BN_CTX *new_ctx = NULL;
N
Nils Larsch 已提交
213
	const EC_POINT *generator = NULL;
B
Bodo Möller 已提交
214 215
	EC_POINT *tmp = NULL;
	size_t totalnum;
216 217
	size_t blocksize = 0, numblocks = 0; /* for wNAF splitting */
	size_t pre_points_per_block = 0;
B
Bodo Möller 已提交
218 219 220 221 222
	size_t i, j;
	int k;
	int r_is_inverted = 0;
	int r_is_at_infinity = 1;
	size_t *wsize = NULL; /* individual window sizes */
B
Bodo Möller 已提交
223
	signed char **wNAF = NULL; /* individual wNAFs */
B
Bodo Möller 已提交
224 225 226 227 228
	size_t *wNAF_len = NULL;
	size_t max_len = 0;
	size_t num_val;
	EC_POINT **val = NULL; /* precomputation */
	EC_POINT **v;
229
	EC_POINT ***val_sub = NULL; /* pointers to sub-arrays of 'val' or 'pre_comp->points' */
230
	const EC_PRE_COMP *pre_comp = NULL;
231 232
	int num_scalar = 0; /* flag: will be set to 1 if 'scalar' must be treated like other scalars,
	                     * i.e. precomputation is not available */
B
Bodo Möller 已提交
233 234
	int ret = 0;
	
235
	if (group->meth != r->meth)
B
Bodo Möller 已提交
236
		{
237 238
		ECerr(EC_F_EC_WNAF_MUL, EC_R_INCOMPATIBLE_OBJECTS);
		return 0;
B
Bodo Möller 已提交
239
		}
240 241 242 243 244 245

	if ((scalar == NULL) && (num == 0))
		{
		return EC_POINT_set_to_infinity(group, r);
		}

B
Bodo Möller 已提交
246 247 248 249
	for (i = 0; i < num; i++)
		{
		if (group->meth != points[i]->meth)
			{
250
			ECerr(EC_F_EC_WNAF_MUL, EC_R_INCOMPATIBLE_OBJECTS);
B
Bodo Möller 已提交
251 252 253 254
			return 0;
			}
		}

255 256 257 258 259 260
	if (ctx == NULL)
		{
		ctx = new_ctx = BN_CTX_new();
		if (ctx == NULL)
			goto err;
		}
B
Bodo Möller 已提交
261

262
	if (scalar != NULL)
B
Bodo Möller 已提交
263
		{
264 265 266 267 268 269 270 271 272
		generator = EC_GROUP_get0_generator(group);
		if (generator == NULL)
			{
			ECerr(EC_F_EC_WNAF_MUL, EC_R_UNDEFINED_GENERATOR);
			goto err;
			}
		
		/* look if we can use precomputed multiples of generator */

N
Nils Larsch 已提交
273
		pre_comp = EC_EX_DATA_get_data(group->extra_data, ec_pre_comp_dup, ec_pre_comp_free, ec_pre_comp_clear_free);
274 275 276 277 278 279 280 281 282 283 284 285 286

		if (pre_comp && pre_comp->numblocks && (EC_POINT_cmp(group, generator, pre_comp->points[0], ctx) == 0))
			{
			blocksize = pre_comp->blocksize;

			/* determine maximum number of blocks that wNAF splitting may yield
			 * (NB: maximum wNAF length is bit length plus one) */
			numblocks = (BN_num_bits(scalar) / blocksize) + 1;

			/* we cannot use more blocks than we have precomputation for */
			if (numblocks > pre_comp->numblocks)
				numblocks = pre_comp->numblocks;

287
			pre_points_per_block = (size_t)1 << (pre_comp->w - 1);
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302

			/* check that pre_comp looks sane */
			if (pre_comp->num != (pre_comp->numblocks * pre_points_per_block))
				{
				ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR);
				goto err;
				}
			}
		else
			{
			/* can't use precomputation */
			pre_comp = NULL;
			numblocks = 1;
			num_scalar = 1; /* treat 'scalar' like 'num'-th element of 'scalars' */
			}
B
Bodo Möller 已提交
303
		}
304 305 306 307 308 309 310
	
	totalnum = num + numblocks;

	wsize    = OPENSSL_malloc(totalnum * sizeof wsize[0]);
	wNAF_len = OPENSSL_malloc(totalnum * sizeof wNAF_len[0]);
	wNAF     = OPENSSL_malloc((totalnum + 1) * sizeof wNAF[0]); /* includes space for pivot */
	val_sub  = OPENSSL_malloc(totalnum * sizeof val_sub[0]);
311 312 313 314

	/* Ensure wNAF is initialised in case we end up going to err */
	if (wNAF) wNAF[0] = NULL;	/* preliminary pivot */

315
	if (!wsize || !wNAF_len || !wNAF || !val_sub)
316 317
		{
		ECerr(EC_F_EC_WNAF_MUL, ERR_R_MALLOC_FAILURE);
318
		goto err;
319
		}
B
Bodo Möller 已提交
320

321
	/* num_val will be the total number of temporarily precomputed points */
B
Bodo Möller 已提交
322
	num_val = 0;
323 324

	for (i = 0; i < num + num_scalar; i++)
B
Bodo Möller 已提交
325 326 327 328 329
		{
		size_t bits;

		bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(scalar);
		wsize[i] = EC_window_bits_for_scalar_size(bits);
330
		num_val += (size_t)1 << (wsize[i] - 1);
331
		wNAF[i + 1] = NULL; /* make sure we always have a pivot */
332
		wNAF[i] = bn_compute_wNAF((i < num ? scalars[i] : scalar), wsize[i], &wNAF_len[i]);
333 334 335 336
		if (wNAF[i] == NULL)
			goto err;
		if (wNAF_len[i] > max_len)
			max_len = wNAF_len[i];
B
Bodo Möller 已提交
337 338
		}

339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
	if (numblocks)
		{
		/* we go here iff scalar != NULL */
		
		if (pre_comp == NULL)
			{
			if (num_scalar != 1)
				{
				ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR);
				goto err;
				}
			/* we have already generated a wNAF for 'scalar' */
			}
		else
			{
			signed char *tmp_wNAF = NULL;
			size_t tmp_len = 0;
			
			if (num_scalar != 0)
				{
				ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR);
				goto err;
				}

			/* use the window size for which we have precomputation */
			wsize[num] = pre_comp->w;
365
			tmp_wNAF = bn_compute_wNAF(scalar, wsize[num], &tmp_len);
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
			if (!tmp_wNAF)
				goto err;

			if (tmp_len <= max_len)
				{
				/* One of the other wNAFs is at least as long
				 * as the wNAF belonging to the generator,
				 * so wNAF splitting will not buy us anything. */

				numblocks = 1;
				totalnum = num + 1; /* don't use wNAF splitting */
				wNAF[num] = tmp_wNAF;
				wNAF[num + 1] = NULL;
				wNAF_len[num] = tmp_len;
				if (tmp_len > max_len)
					max_len = tmp_len;
				/* pre_comp->points starts with the points that we need here: */
				val_sub[num] = pre_comp->points;
				}
			else
				{
				/* don't include tmp_wNAF directly into wNAF array
				 * - use wNAF splitting and include the blocks */

				signed char *pp;
				EC_POINT **tmp_points;
				
				if (tmp_len < numblocks * blocksize)
					{
					/* possibly we can do with fewer blocks than estimated */
					numblocks = (tmp_len + blocksize - 1) / blocksize;
					if (numblocks > pre_comp->numblocks)
						{
						ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR);
						goto err;
						}
					totalnum = num + numblocks;
					}
				
				/* split wNAF in 'numblocks' parts */
				pp = tmp_wNAF;
				tmp_points = pre_comp->points;

				for (i = num; i < totalnum; i++)
					{
					if (i < totalnum - 1)
						{
						wNAF_len[i] = blocksize;
						if (tmp_len < blocksize)
							{
							ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR);
							goto err;
							}
						tmp_len -= blocksize;
						}
					else
						/* last block gets whatever is left
						 * (this could be more or less than 'blocksize'!) */
						wNAF_len[i] = tmp_len;
					
					wNAF[i + 1] = NULL;
					wNAF[i] = OPENSSL_malloc(wNAF_len[i]);
					if (wNAF[i] == NULL)
						{
430
						ECerr(EC_F_EC_WNAF_MUL, ERR_R_MALLOC_FAILURE);
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
						OPENSSL_free(tmp_wNAF);
						goto err;
						}
					memcpy(wNAF[i], pp, wNAF_len[i]);
					if (wNAF_len[i] > max_len)
						max_len = wNAF_len[i];

					if (*tmp_points == NULL)
						{
						ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR);
						OPENSSL_free(tmp_wNAF);
						goto err;
						}
					val_sub[i] = tmp_points;
					tmp_points += pre_points_per_block;
					pp += blocksize;
					}
				OPENSSL_free(tmp_wNAF);
				}
			}
		}

	/* All points we precompute now go into a single array 'val'.
	 * 'val_sub[i]' is a pointer to the subarray for the i-th point,
	 * or to a subarray of 'pre_comp->points' if we already have precomputation. */
B
Bodo Möller 已提交
456
	val = OPENSSL_malloc((num_val + 1) * sizeof val[0]);
457 458 459 460 461
	if (val == NULL)
		{
		ECerr(EC_F_EC_WNAF_MUL, ERR_R_MALLOC_FAILURE);
		goto err;
		}
B
Bodo Möller 已提交
462 463 464 465
	val[num_val] = NULL; /* pivot element */

	/* allocate points for precomputation */
	v = val;
466
	for (i = 0; i < num + num_scalar; i++)
B
Bodo Möller 已提交
467 468
		{
		val_sub[i] = v;
469
		for (j = 0; j < ((size_t)1 << (wsize[i] - 1)); j++)
B
Bodo Möller 已提交
470 471 472 473 474 475 476 477
			{
			*v = EC_POINT_new(group);
			if (*v == NULL) goto err;
			v++;
			}
		}
	if (!(v == val + num_val))
		{
478
		ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR);
B
Bodo Möller 已提交
479 480 481
		goto err;
		}

482 483
	if (!(tmp = EC_POINT_new(group)))
		goto err;
B
Bodo Möller 已提交
484

485 486
	/*-
	 * prepare precomputed values:
B
Bodo Möller 已提交
487 488 489 490 491
	 *    val_sub[i][0] :=     points[i]
	 *    val_sub[i][1] := 3 * points[i]
	 *    val_sub[i][2] := 5 * points[i]
	 *    ...
	 */
492
	for (i = 0; i < num + num_scalar; i++)
B
Bodo Möller 已提交
493 494 495 496 497 498 499 500 501 502 503 504 505
		{
		if (i < num)
			{
			if (!EC_POINT_copy(val_sub[i][0], points[i])) goto err;
			}
		else
			{
			if (!EC_POINT_copy(val_sub[i][0], generator)) goto err;
			}

		if (wsize[i] > 1)
			{
			if (!EC_POINT_dbl(group, tmp, val_sub[i][0], ctx)) goto err;
506
			for (j = 1; j < ((size_t)1 << (wsize[i] - 1)); j++)
B
Bodo Möller 已提交
507 508 509 510 511 512 513
				{
				if (!EC_POINT_add(group, val_sub[i][j], val_sub[i][j - 1], tmp, ctx)) goto err;
				}
			}
		}

#if 1 /* optional; EC_window_bits_for_scalar_size assumes we do this step */
514 515
	if (!EC_POINTs_make_affine(group, num_val, val, ctx))
		goto err;
B
Bodo Möller 已提交
516 517 518 519 520 521 522 523 524 525 526 527 528
#endif

	r_is_at_infinity = 1;

	for (k = max_len - 1; k >= 0; k--)
		{
		if (!r_is_at_infinity)
			{
			if (!EC_POINT_dbl(group, r, r, ctx)) goto err;
			}
		
		for (i = 0; i < totalnum; i++)
			{
529
			if (wNAF_len[i] > (size_t)k)
B
Bodo Möller 已提交
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
				{
				int digit = wNAF[i][k];
				int is_neg;

				if (digit) 
					{
					is_neg = digit < 0;

					if (is_neg)
						digit = -digit;

					if (is_neg != r_is_inverted)
						{
						if (!r_is_at_infinity)
							{
							if (!EC_POINT_invert(group, r, ctx)) goto err;
							}
						r_is_inverted = !r_is_inverted;
						}

					/* digit > 0 */

					if (r_is_at_infinity)
						{
						if (!EC_POINT_copy(r, val_sub[i][digit >> 1])) goto err;
						r_is_at_infinity = 0;
						}
					else
						{
						if (!EC_POINT_add(group, r, r, val_sub[i][digit >> 1], ctx)) goto err;
						}
					}
				}
			}
		}

	if (r_is_at_infinity)
		{
		if (!EC_POINT_set_to_infinity(group, r)) goto err;
		}
	else
		{
		if (r_is_inverted)
			if (!EC_POINT_invert(group, r, ctx)) goto err;
		}
	
	ret = 1;

 err:
	if (new_ctx != NULL)
		BN_CTX_free(new_ctx);
	if (tmp != NULL)
		EC_POINT_free(tmp);
	if (wsize != NULL)
		OPENSSL_free(wsize);
	if (wNAF_len != NULL)
		OPENSSL_free(wNAF_len);
	if (wNAF != NULL)
		{
		signed char **w;
		
		for (w = wNAF; *w != NULL; w++)
			OPENSSL_free(*w);
		
		OPENSSL_free(wNAF);
		}
	if (val != NULL)
		{
		for (v = val; *v != NULL; v++)
			EC_POINT_clear_free(*v);

		OPENSSL_free(val);
		}
	if (val_sub != NULL)
		{
		OPENSSL_free(val_sub);
		}
	return ret;
	}

610

611 612
/*-
 * ec_wNAF_precompute_mult()
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629
 * creates an EC_PRE_COMP object with preprecomputed multiples of the generator
 * for use with wNAF splitting as implemented in ec_wNAF_mul().
 * 
 * 'pre_comp->points' is an array of multiples of the generator
 * of the following form:
 * points[0] =     generator;
 * points[1] = 3 * generator;
 * ...
 * points[2^(w-1)-1] =     (2^(w-1)-1) * generator;
 * points[2^(w-1)]   =     2^blocksize * generator;
 * points[2^(w-1)+1] = 3 * 2^blocksize * generator;
 * ...
 * points[2^(w-1)*(numblocks-1)-1] = (2^(w-1)) *  2^(blocksize*(numblocks-2)) * generator
 * points[2^(w-1)*(numblocks-1)]   =              2^(blocksize*(numblocks-1)) * generator
 * ...
 * points[2^(w-1)*numblocks-1]     = (2^(w-1)) *  2^(blocksize*(numblocks-1)) * generator
 * points[2^(w-1)*numblocks]       = NULL
630 631
 */
int ec_wNAF_precompute_mult(EC_GROUP *group, BN_CTX *ctx)
632 633
	{
	const EC_POINT *generator;
634
	EC_POINT *tmp_point = NULL, *base = NULL, **var;
635 636
	BN_CTX *new_ctx = NULL;
	BIGNUM *order;
637 638
	size_t i, bits, w, pre_points_per_block, blocksize, numblocks, num;
	EC_POINT **points = NULL;
639
	EC_PRE_COMP *pre_comp;
640 641
	int ret = 0;

642
	/* if there is an old EC_PRE_COMP object, throw it away */
N
Nils Larsch 已提交
643
	EC_EX_DATA_free_data(&group->extra_data, ec_pre_comp_dup, ec_pre_comp_free, ec_pre_comp_clear_free);
644 645 646

	if ((pre_comp = ec_pre_comp_new(group)) == NULL)
		return 0;
647

648 649 650
	generator = EC_GROUP_get0_generator(group);
	if (generator == NULL)
		{
651
		ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, EC_R_UNDEFINED_GENERATOR);
652
		goto err;
653 654 655 656 657 658
		}

	if (ctx == NULL)
		{
		ctx = new_ctx = BN_CTX_new();
		if (ctx == NULL)
659
			goto err;
660 661 662 663 664 665
		}
	
	BN_CTX_start(ctx);
	order = BN_CTX_get(ctx);
	if (order == NULL) goto err;
	
666
	if (!EC_GROUP_get_order(group, order, ctx)) goto err;		
667 668
	if (BN_is_zero(order))
		{
669
		ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, EC_R_UNKNOWN_ORDER);
670 671 672
		goto err;
		}

673
	bits = BN_num_bits(order);
B
comment  
Bodo Möller 已提交
674 675 676 677 678 679 680
	/* The following parameters mean we precompute (approximately)
	 * one point per bit.
	 *
	 * TBD: The combination  8, 4  is perfect for 160 bits; for other
	 * bit lengths, other parameter combinations might provide better
	 * efficiency.
	 */
681 682 683 684 685 686 687 688 689 690
	blocksize = 8;
	w = 4;
	if (EC_window_bits_for_scalar_size(bits) > w)
		{
		/* let's not make the window too small ... */
		w = EC_window_bits_for_scalar_size(bits);
		}

	numblocks = (bits + blocksize - 1) / blocksize; /* max. number of blocks to use for wNAF splitting */
	
691
	pre_points_per_block = (size_t)1 << (w - 1);
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
	num = pre_points_per_block * numblocks; /* number of points to compute and store */

	points = OPENSSL_malloc(sizeof (EC_POINT*)*(num + 1));
	if (!points)
		{
		ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, ERR_R_MALLOC_FAILURE);
		goto err;
		}

	var = points;
	var[num] = NULL; /* pivot */
	for (i = 0; i < num; i++)
		{
		if ((var[i] = EC_POINT_new(group)) == NULL)
			{
			ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, ERR_R_MALLOC_FAILURE);
			goto err;
			}
		}
711

712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
	if (!(tmp_point = EC_POINT_new(group)) || !(base = EC_POINT_new(group)))
		{
		ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, ERR_R_MALLOC_FAILURE);
		goto err;
		}	
	
	if (!EC_POINT_copy(base, generator))
		goto err;
	
	/* do the precomputation */
	for (i = 0; i < numblocks; i++)
		{
		size_t j;

		if (!EC_POINT_dbl(group, tmp_point, base, ctx))
			goto err;

		if (!EC_POINT_copy(*var++, base))
			goto err;

		for (j = 1; j < pre_points_per_block; j++, var++)
			{
			/* calculate odd multiples of the current base point */
			if (!EC_POINT_add(group, *var, tmp_point, *(var - 1), ctx))
				goto err;
			}

		if (i < numblocks - 1)
			{
			/* get the next base (multiply current one by 2^blocksize) */
			size_t k;

			if (blocksize <= 2)
				{
				ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, ERR_R_INTERNAL_ERROR);
				goto err;
				}				

			if (!EC_POINT_dbl(group, base, tmp_point, ctx))
				goto err;
			for (k = 2; k < blocksize; k++)
				{
				if (!EC_POINT_dbl(group,base,base,ctx))
					goto err;
				}
			}
 		}

	if (!EC_POINTs_make_affine(group, num, points, ctx))
		goto err;
762
	
763 764 765 766 767 768 769 770
	pre_comp->group = group;
	pre_comp->blocksize = blocksize;
	pre_comp->numblocks = numblocks;
	pre_comp->w = w;
	pre_comp->points = points;
	points = NULL;
	pre_comp->num = num;

N
Nils Larsch 已提交
771
	if (!EC_EX_DATA_set_data(&group->extra_data, pre_comp,
772 773 774
		ec_pre_comp_dup, ec_pre_comp_free, ec_pre_comp_clear_free))
		goto err;
	pre_comp = NULL;
775 776

	ret = 1;
777
 err:
778 779
	if (ctx != NULL)
		BN_CTX_end(ctx);
780 781
	if (new_ctx != NULL)
		BN_CTX_free(new_ctx);
782 783
	if (pre_comp)
		ec_pre_comp_free(pre_comp);
784 785 786 787 788 789 790 791 792 793 794 795
	if (points)
		{
		EC_POINT **p;

		for (p = points; *p != NULL; p++)
			EC_POINT_free(*p);
		OPENSSL_free(points);
		}
	if (tmp_point)
		EC_POINT_free(tmp_point);
	if (base)
		EC_POINT_free(base);
796 797
	return ret;
	}
798 799


800
int ec_wNAF_have_precompute_mult(const EC_GROUP *group)
801
	{
N
Nils Larsch 已提交
802
	if (EC_EX_DATA_get_data(group->extra_data, ec_pre_comp_dup, ec_pre_comp_free, ec_pre_comp_clear_free) != NULL)
803
		return 1;
804 805
	else
		return 0;
806
	}