X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=crypto%2Fec%2Fec_mult.c;h=596b5f8062319cda7a2b98551c335195804f75ac;hb=d6755bb6ac6676cf0f219cd4caf352ac48907206;hp=3055b05d572019c18c98a5d73323c057bc1500bc;hpb=7793f30e09c104b209206608a20f2088b1b635fd;p=oweals%2Fopenssl.git diff --git a/crypto/ec/ec_mult.c b/crypto/ec/ec_mult.c index 3055b05d57..596b5f8062 100644 --- a/crypto/ec/ec_mult.c +++ b/crypto/ec/ec_mult.c @@ -1,13 +1,15 @@ -/* crypto/ec/ec_mult.c */ +/* + * Originally written by Bodo Moeller and Nils Larsch for the OpenSSL project. + */ /* ==================================================================== - * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. + * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. * * 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. + * 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 @@ -58,471 +60,649 @@ * and contributed to the OpenSSL project. */ +#include #include +#include "internal/bn_int.h" #include "ec_lcl.h" - -/* TODO: optional precomputation of multiples of the generator */ - - - /* - * wNAF-based interleaving multi-exponentation method - * () + * This file implements the wNAF-based interleaving multi-exponentation method + * (); + * for multiplication with precomputation, we use wNAF splitting + * (). */ +/* structure for precomputed multiples of the generator */ +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) */ + int references; +}; + +static EC_PRE_COMP *ec_pre_comp_new(const EC_GROUP *group) +{ + EC_PRE_COMP *ret = NULL; + + if (!group) + return NULL; + + ret = OPENSSL_zalloc(sizeof(*ret)); + if (ret == NULL) { + ECerr(EC_F_EC_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE); + return ret; + } + ret->group = group; + ret->blocksize = 8; /* default */ + ret->w = 4; /* default */ + ret->references = 1; + return ret; +} + +EC_PRE_COMP *EC_ec_pre_comp_dup(EC_PRE_COMP *pre) +{ + if (pre != NULL) + CRYPTO_add(&pre->references, 1, CRYPTO_LOCK_EC_PRE_COMP); + return pre; +} + +void EC_ec_pre_comp_free(EC_PRE_COMP *pre) +{ + if (pre == NULL + || CRYPTO_add(&pre->references, -1, CRYPTO_LOCK_EC_PRE_COMP) > 0) + return; + + if (pre->points != NULL) { + EC_POINT **pts; + + for (pts = pre->points; *pts != NULL; pts++) + EC_POINT_free(*pts); + OPENSSL_free(pre->points); + } + OPENSSL_free(pre); +} -/* Determine the modified width-(w+1) Non-Adjacent Form (wNAF) of 'scalar'. - * This is an array r[] of values that are either zero or odd with an - * absolute value less than 2^w satisfying - * scalar = \sum_j r[j]*2^j - * where at most one of any w+1 consecutive digits is non-zero - * with the exception that the most significant digit may be only - * w-1 zeros away from that next non-zero digit. - */ -static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) - { - int window_val; - int ok = 0; - signed char *r = NULL; - int sign = 1; - int bit, next_bit, mask; - size_t len = 0, j; - - if (w <= 0 || w > 7) /* 'signed char' can represent integers with absolute values less than 2^7 */ - { - ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); - goto err; - } - bit = 1 << w; /* at most 128 */ - next_bit = bit << 1; /* at most 256 */ - mask = next_bit - 1; /* at most 255 */ - - if (scalar->neg) - { - sign = -1; - } - - len = BN_num_bits(scalar); - r = OPENSSL_malloc(len + 1); /* modified wNAF may be one digit longer than binary representation */ - if (r == NULL) goto err; - - if (scalar->d == NULL || scalar->top == 0) - { - ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); - goto err; - } - window_val = scalar->d[0] & mask; - j = 0; - while ((window_val != 0) || (j + w + 1 < len)) /* if j+w+1 >= len, window_val will not increase */ - { - int digit = 0; - - /* 0 <= window_val <= 2^(w+1) */ - - if (window_val & 1) - { - /* 0 < window_val < 2^(w+1) */ - - if (window_val & bit) - { - digit = window_val - next_bit; /* -2^w < digit < 0 */ - -#if 1 /* modified wNAF */ - if (j + w + 1 >= len) - { - /* special case for generating modified wNAFs: - * no new bits will be added into window_val, - * so using a positive digit here will decrease - * the total length of the representation */ - - digit = window_val & (mask >> 1); /* 0 < digit < 2^w */ - } -#endif - } - else - { - digit = window_val; /* 0 < digit < 2^w */ - } - - if (digit <= -bit || digit >= bit || !(digit & 1)) - { - ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); - goto err; - } - - window_val -= digit; - - /* now window_val is 0 or 2^(w+1) in standard wNAF generation; - * for modified window NAFs, it may also be 2^w - */ - if (window_val != 0 && window_val != next_bit && window_val != bit) - { - ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); - goto err; - } - } - - r[j++] = sign * digit; - - window_val >>= 1; - window_val += bit * BN_is_bit_set(scalar, j + w); - - if (window_val > next_bit) - { - ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); - goto err; - } - } - - if (j > len + 1) - { - ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); - goto err; - } - len = j; - ok = 1; - - err: - if (!ok) - { - OPENSSL_free(r); - r = NULL; - } - if (ok) - *ret_len = len; - return r; - } - - -/* TODO: table should be optimised for the wNAF-based implementation, - * sometimes smaller windows will give better performance - * (thus the boundaries should be increased) +/* + * TODO: table should be optimised for the wNAF-based implementation, + * sometimes smaller windows will give better performance (thus the + * boundaries should be increased) */ #define EC_window_bits_for_scalar_size(b) \ - ((b) >= 2000 ? 6 : \ - (b) >= 800 ? 5 : \ - (b) >= 300 ? 4 : \ - (b) >= 70 ? 3 : \ - (b) >= 20 ? 2 : \ - 1) - -/* Compute + ((size_t) \ + ((b) >= 2000 ? 6 : \ + (b) >= 800 ? 5 : \ + (b) >= 300 ? 4 : \ + (b) >= 70 ? 3 : \ + (b) >= 20 ? 2 : \ + 1)) + +/*- + * Compute * \sum scalars[i]*points[i], * also including * scalar*generator * in the addition if scalar != NULL */ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, - size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx) - { - BN_CTX *new_ctx = NULL; - EC_POINT *generator = NULL; - EC_POINT *tmp = NULL; - size_t totalnum; - size_t i, j; - int k; - int r_is_inverted = 0; - int r_is_at_infinity = 1; - size_t *wsize = NULL; /* individual window sizes */ - signed char **wNAF = NULL; /* individual wNAFs */ - size_t *wNAF_len = NULL; - size_t max_len = 0; - size_t num_val; - EC_POINT **val = NULL; /* precomputation */ - EC_POINT **v; - EC_POINT ***val_sub = NULL; /* pointers to sub-arrays of 'val' */ - int ret = 0; - - if (scalar != NULL) - { - generator = EC_GROUP_get0_generator(group); - if (generator == NULL) - { - ECerr(EC_F_EC_WNAF_MUL, EC_R_UNDEFINED_GENERATOR); - return 0; - } - } - - for (i = 0; i < num; i++) - { - if (group->meth != points[i]->meth) - { - ECerr(EC_F_EC_WNAF_MUL, EC_R_INCOMPATIBLE_OBJECTS); - return 0; - } - } - - totalnum = num + (scalar != NULL); - - wsize = OPENSSL_malloc(totalnum * sizeof wsize[0]); - wNAF_len = OPENSSL_malloc(totalnum * sizeof wNAF_len[0]); - wNAF = OPENSSL_malloc((totalnum + 1) * sizeof wNAF[0]); - if (wNAF != NULL) - { - wNAF[0] = NULL; /* preliminary pivot */ - } - if (wsize == NULL || wNAF_len == NULL || wNAF == NULL) goto err; - - /* num_val := total number of points to precompute */ - num_val = 0; - for (i = 0; i < totalnum; i++) - { - size_t bits; - - bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(scalar); - wsize[i] = EC_window_bits_for_scalar_size(bits); - num_val += 1u << (wsize[i] - 1); - } - - /* all precomputed points go into a single array 'val', - * 'val_sub[i]' is a pointer to the subarray for the i-th point */ - val = OPENSSL_malloc((num_val + 1) * sizeof val[0]); - if (val == NULL) goto err; - val[num_val] = NULL; /* pivot element */ - - val_sub = OPENSSL_malloc(totalnum * sizeof val_sub[0]); - if (val_sub == NULL) goto err; - - /* allocate points for precomputation */ - v = val; - for (i = 0; i < totalnum; i++) - { - val_sub[i] = v; - for (j = 0; j < (1u << (wsize[i] - 1)); j++) - { - *v = EC_POINT_new(group); - if (*v == NULL) goto err; - v++; - } - } - if (!(v == val + num_val)) - { - ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR); - goto err; - } - - if (ctx == NULL) - { - ctx = new_ctx = BN_CTX_new(); - if (ctx == NULL) - goto err; - } - - tmp = EC_POINT_new(group); - if (tmp == NULL) goto err; - - /* prepare precomputed values: - * val_sub[i][0] := points[i] - * val_sub[i][1] := 3 * points[i] - * val_sub[i][2] := 5 * points[i] - * ... - */ - for (i = 0; i < totalnum; i++) - { - 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; - for (j = 1; j < (1u << (wsize[i] - 1)); j++) - { - if (!EC_POINT_add(group, val_sub[i][j], val_sub[i][j - 1], tmp, ctx)) goto err; - } - } - - wNAF[i + 1] = NULL; /* make sure we always have a pivot */ - wNAF[i] = compute_wNAF((i < num ? scalars[i] : scalar), wsize[i], &wNAF_len[i]); - if (wNAF[i] == NULL) goto err; - if (wNAF_len[i] > max_len) - max_len = wNAF_len[i]; - } - -#if 1 /* optional; EC_window_bits_for_scalar_size assumes we do this step */ - if (!EC_POINTs_make_affine(group, num_val, val, ctx)) goto err; -#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++) - { - if (wNAF_len[i] > (size_t)k) - { - 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; + size_t num, const EC_POINT *points[], const BIGNUM *scalars[], + BN_CTX *ctx) +{ + BN_CTX *new_ctx = NULL; + const EC_POINT *generator = NULL; + EC_POINT *tmp = NULL; + size_t totalnum; + size_t blocksize = 0, numblocks = 0; /* for wNAF splitting */ + size_t pre_points_per_block = 0; + size_t i, j; + int k; + int r_is_inverted = 0; + int r_is_at_infinity = 1; + size_t *wsize = NULL; /* individual window sizes */ + signed char **wNAF = NULL; /* individual wNAFs */ + size_t *wNAF_len = NULL; + size_t max_len = 0; + size_t num_val; + EC_POINT **val = NULL; /* precomputation */ + EC_POINT **v; + EC_POINT ***val_sub = NULL; /* pointers to sub-arrays of 'val' or + * 'pre_comp->points' */ + const EC_PRE_COMP *pre_comp = NULL; + int num_scalar = 0; /* flag: will be set to 1 if 'scalar' must be + * treated like other scalars, i.e. + * precomputation is not available */ + int ret = 0; + + if (group->meth != r->meth) { + ECerr(EC_F_EC_WNAF_MUL, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + + if ((scalar == NULL) && (num == 0)) { + return EC_POINT_set_to_infinity(group, r); + } + + for (i = 0; i < num; i++) { + if (group->meth != points[i]->meth) { + ECerr(EC_F_EC_WNAF_MUL, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + goto err; + } + + if (scalar != NULL) { + 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 */ + + pre_comp = group->pre_comp.ec; + 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; + + pre_points_per_block = (size_t)1 << (pre_comp->w - 1); + + /* 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' */ + } + } + + 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]); + + /* Ensure wNAF is initialised in case we end up going to err */ + if (wNAF != NULL) + wNAF[0] = NULL; /* preliminary pivot */ + + if (wsize == NULL || wNAF_len == NULL || wNAF == NULL || val_sub == NULL) { + ECerr(EC_F_EC_WNAF_MUL, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* + * num_val will be the total number of temporarily precomputed points + */ + num_val = 0; + + for (i = 0; i < num + num_scalar; i++) { + size_t bits; + + bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(scalar); + wsize[i] = EC_window_bits_for_scalar_size(bits); + num_val += (size_t)1 << (wsize[i] - 1); + wNAF[i + 1] = NULL; /* make sure we always have a pivot */ + wNAF[i] = + bn_compute_wNAF((i < num ? scalars[i] : scalar), wsize[i], + &wNAF_len[i]); + if (wNAF[i] == NULL) + goto err; + if (wNAF_len[i] > max_len) + max_len = wNAF_len[i]; + } + + 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; + tmp_wNAF = bn_compute_wNAF(scalar, wsize[num], &tmp_len); + 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) { + ECerr(EC_F_EC_WNAF_MUL, ERR_R_MALLOC_FAILURE); + 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. + */ + val = OPENSSL_malloc((num_val + 1) * sizeof val[0]); + if (val == NULL) { + ECerr(EC_F_EC_WNAF_MUL, ERR_R_MALLOC_FAILURE); + goto err; + } + val[num_val] = NULL; /* pivot element */ + + /* allocate points for precomputation */ + v = val; + for (i = 0; i < num + num_scalar; i++) { + val_sub[i] = v; + for (j = 0; j < ((size_t)1 << (wsize[i] - 1)); j++) { + *v = EC_POINT_new(group); + if (*v == NULL) + goto err; + v++; + } + } + if (!(v == val + num_val)) { + ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR); + goto err; + } + + if ((tmp = EC_POINT_new(group)) == NULL) + goto err; + + /*- + * prepare precomputed values: + * val_sub[i][0] := points[i] + * val_sub[i][1] := 3 * points[i] + * val_sub[i][2] := 5 * points[i] + * ... + */ + for (i = 0; i < num + num_scalar; i++) { + 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; + for (j = 1; j < ((size_t)1 << (wsize[i] - 1)); j++) { + if (!EC_POINT_add + (group, val_sub[i][j], val_sub[i][j - 1], tmp, ctx)) + goto err; + } + } + } + + if (!EC_POINTs_make_affine(group, num_val, val, ctx)) + goto err; + + 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++) { + if (wNAF_len[i] > (size_t)k) { + 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; - } - - -/* Generic multiplication method. - * If group->meth does not provide a multiplication method, default to ec_wNAF_mul; - * otherwise use the group->meth's multiplication. + BN_CTX_free(new_ctx); + EC_POINT_free(tmp); + OPENSSL_free(wsize); + 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); + } + OPENSSL_free(val_sub); + return ret; +} + +/*- + * ec_wNAF_precompute_mult() + * 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 */ -int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, - size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx) - { - if (group->meth->mul == 0) - return ec_wNAF_mul(group, r, scalar, num, points, scalars, ctx); - else - return group->meth->mul(group, r, scalar, num, points, scalars, ctx); - } - - -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) - { - const EC_POINT *points[1]; - const BIGNUM *scalars[1]; - - points[0] = point; - scalars[0] = p_scalar; - - return EC_POINTs_mul(group, r, g_scalar, (point != NULL && p_scalar != NULL), points, scalars, ctx); - } - - int ec_wNAF_precompute_mult(EC_GROUP *group, BN_CTX *ctx) - { - const EC_POINT *generator; - BN_CTX *new_ctx = NULL; - BIGNUM *order; - int ret = 0; - - generator = EC_GROUP_get0_generator(group); - if (generator == NULL) - { - ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, EC_R_UNDEFINED_GENERATOR); - return 0; - } - - if (ctx == NULL) - { - ctx = new_ctx = BN_CTX_new(); - if (ctx == NULL) - return 0; - } - - BN_CTX_start(ctx); - order = BN_CTX_get(ctx); - if (order == NULL) goto err; - - if (!EC_GROUP_get_order(group, order, ctx)) return 0; - if (BN_is_zero(order)) - { - ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, EC_R_UNKNOWN_ORDER); - goto err; - } - - /* TODO */ - - ret = 1; - - err: - BN_CTX_end(ctx); - if (new_ctx != NULL) - BN_CTX_free(new_ctx); - return ret; - } - +{ + const EC_POINT *generator; + EC_POINT *tmp_point = NULL, *base = NULL, **var; + BN_CTX *new_ctx = NULL; + const BIGNUM *order; + size_t i, bits, w, pre_points_per_block, blocksize, numblocks, num; + EC_POINT **points = NULL; + EC_PRE_COMP *pre_comp; + int ret = 0; + + /* if there is an old EC_PRE_COMP object, throw it away */ + EC_pre_comp_free(group); + if ((pre_comp = ec_pre_comp_new(group)) == NULL) + return 0; + + generator = EC_GROUP_get0_generator(group); + if (generator == NULL) { + ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, EC_R_UNDEFINED_GENERATOR); + goto err; + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + goto err; + } + + BN_CTX_start(ctx); + + order = EC_GROUP_get0_order(group); + if (order == NULL) + goto err; + if (BN_is_zero(order)) { + ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, EC_R_UNKNOWN_ORDER); + goto err; + } + + bits = BN_num_bits(order); + /* + * 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. + */ + 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 */ + + pre_points_per_block = (size_t)1 << (w - 1); + num = pre_points_per_block * numblocks; /* number of points to compute + * and store */ + + points = OPENSSL_malloc(sizeof(*points) * (num + 1)); + if (points == NULL) { + 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; + } + } + + if ((tmp_point = EC_POINT_new(group)) == NULL + || (base = EC_POINT_new(group)) == NULL) { + 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; + + 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; + SETPRECOMP(group, ec, pre_comp); + pre_comp = NULL; + ret = 1; -/* Generic multiplicaiton precomputation method. - * If group->meth does not provide a multiplication method, default to ec_wNAF_mul and do its - * precomputation; otherwise use the group->meth's precomputation if it exists. - */ -int EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx) - { - if (group->meth->mul == 0) - return ec_wNAF_precompute_mult(group, ctx); - else if (group->meth->precompute_mult != 0) - return group->meth->precompute_mult(group, ctx); - else - return 1; - } + err: + if (ctx != NULL) + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + EC_ec_pre_comp_free(pre_comp); + if (points) { + EC_POINT **p; + + for (p = points; *p != NULL; p++) + EC_POINT_free(*p); + OPENSSL_free(points); + } + EC_POINT_free(tmp_point); + EC_POINT_free(base); + return ret; +} + +int ec_wNAF_have_precompute_mult(const EC_GROUP *group) +{ + return HAVEPRECOMP(group, ec); +}