Improve EC efficiency.

This commit is contained in:
Bodo Möller 2001-11-15 22:32:11 +00:00
parent bbc206fdf7
commit 3ba1f11147
4 changed files with 373 additions and 13 deletions

13
CHANGES
View File

@ -12,6 +12,10 @@
*) applies to 0.9.6a/0.9.6b/0.9.6c and 0.9.7 *) applies to 0.9.6a/0.9.6b/0.9.6c and 0.9.7
+) applies to 0.9.7 only +) applies to 0.9.7 only
+) Use wNAFs in EC_POINTs_mul() for improved efficiency (about 10%
better than before for single multiplications over P-192 or P-224).
[Bodo Moeller]
-) [In 0.9.6c-engine release:] -) [In 0.9.6c-engine release:]
Add support for Broadcom crypto accelerator cards, backported Add support for Broadcom crypto accelerator cards, backported
from 0.9.7. from 0.9.7.
@ -943,9 +947,12 @@ des-cbc 3624.96k 5258.21k 5530.91k 5624.30k 5628.26k
don't write to the wrong index in ERR_set_error_data. don't write to the wrong index in ERR_set_error_data.
[Bodo Moeller] [Bodo Moeller]
+) Function EC_POINTs_mul for simultaneous scalar multiplication +) Function EC_POINTs_mul for multiple scalar multiplication
of an arbitrary number of elliptic curve points, optionally of an arbitrary number of elliptic curve points
including the generator defined for the EC_GROUP. \sum scalars[i]*points[i],
optionally including the generator defined for the EC_GROUP:
scalar*generator + \sum scalars[i]*points[i].
EC_POINT_mul is a simple wrapper function for the typical case EC_POINT_mul is a simple wrapper function for the typical case
that the point list has just one item (besides the optional that the point list has just one item (besides the optional
generator). generator).

View File

@ -177,6 +177,7 @@ void ERR_load_EC_strings(void);
/* Error codes for the EC functions. */ /* Error codes for the EC functions. */
/* Function codes. */ /* Function codes. */
#define EC_F_COMPUTE_WNAF 143
#define EC_F_EC_GFP_MONT_FIELD_DECODE 133 #define EC_F_EC_GFP_MONT_FIELD_DECODE 133
#define EC_F_EC_GFP_MONT_FIELD_ENCODE 134 #define EC_F_EC_GFP_MONT_FIELD_ENCODE 134
#define EC_F_EC_GFP_MONT_FIELD_MUL 131 #define EC_F_EC_GFP_MONT_FIELD_MUL 131

View File

@ -66,6 +66,7 @@
#ifndef OPENSSL_NO_ERR #ifndef OPENSSL_NO_ERR
static ERR_STRING_DATA EC_str_functs[]= static ERR_STRING_DATA EC_str_functs[]=
{ {
{ERR_PACK(0,EC_F_COMPUTE_WNAF,0), "COMPUTE_WNAF"},
{ERR_PACK(0,EC_F_EC_GFP_MONT_FIELD_DECODE,0), "ec_GFp_mont_field_decode"}, {ERR_PACK(0,EC_F_EC_GFP_MONT_FIELD_DECODE,0), "ec_GFp_mont_field_decode"},
{ERR_PACK(0,EC_F_EC_GFP_MONT_FIELD_ENCODE,0), "ec_GFp_mont_field_encode"}, {ERR_PACK(0,EC_F_EC_GFP_MONT_FIELD_ENCODE,0), "ec_GFp_mont_field_encode"},
{ERR_PACK(0,EC_F_EC_GFP_MONT_FIELD_MUL,0), "ec_GFp_mont_field_mul"}, {ERR_PACK(0,EC_F_EC_GFP_MONT_FIELD_MUL,0), "ec_GFp_mont_field_mul"},

View File

@ -58,11 +58,369 @@
#include "ec_lcl.h" #include "ec_lcl.h"
/* TODO: width-m NAFs */
/* TODO: optional precomputation of multiples of the generator */ /* TODO: optional precomputation of multiples of the generator */
#if 1
/*
* wNAF-based interleaving multi-exponentation method
*/
/* Determine the width-(w+1) Non-Adjacent Form 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.
*/
static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len, BN_CTX *ctx)
{
BIGNUM *c;
int ok = 0;
signed char *r = NULL;
int sign = 1;
int bit, next_bit, mask;
size_t len, j;
BN_CTX_start(ctx);
c = BN_CTX_get(ctx);
if (c == NULL) goto err;
if (w <= 0 || w > 7) /* 'unsigned 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 (!BN_copy(c, scalar)) goto err;
if (c->neg)
{
sign = -1;
c->neg = 0;
}
len = BN_num_bits(c) + 1; /* wNAF may be one digit longer than binary representation */
r = OPENSSL_malloc(len);
if (r == NULL) goto err;
j = 0;
while (!BN_is_zero(c))
{
int u = 0;
if (BN_is_odd(c))
{
if (c->d == NULL || c->top == 0)
{
ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
goto err;
}
u = c->d[0] & mask;
if (u & bit)
{
u -= next_bit;
/* u < 0 */
if (!BN_add_word(c, -u)) goto err;
}
else
{
/* u > 0 */
if (!BN_sub_word(c, u)) goto err;
}
if (u <= -bit || u >= bit || !(u & 1) || c->neg)
{
ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
goto err;
}
}
r[j++] = sign * u;
if (BN_is_odd(c))
{
ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
goto err;
}
if (!BN_rshift1(c, c)) goto err;
}
if (j > len)
{
ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
goto err;
}
len = j;
ok = 1;
err:
BN_CTX_end(ctx);
if (!ok)
{
OPENSSL_free(r);
r = NULL;
}
if (ok)
*ret_len = len;
return r;
}
/* TODO: table should be optimised for the wNAF-based implementation */
#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
* \sum scalars[i]*points[i],
* also including
* scalar*generator
* in the addition if scalar != 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)
{
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 */
size_t *wNAF_len = NULL;
size_t max_len = 0;
signed char **wNAF = NULL; /* individual wNAFs */
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_POINTS_MUL, EC_R_UNDEFINED_GENERATOR);
return 0;
}
}
for (i = 0; i < num; i++)
{
if (group->meth != points[i]->meth)
{
ECerr(EC_F_EC_POINTS_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 * sizeof wNAF[0] + 1);
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_POINTS_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], ctx);
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] > 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;
}
#else
/*
* Basic interleaving multi-exponentation method
*/
#define EC_window_bits_for_scalar_size(b) \ #define EC_window_bits_for_scalar_size(b) \
((b) >= 2000 ? 6 : \ ((b) >= 2000 ? 6 : \
(b) >= 800 ? 5 : \ (b) >= 800 ? 5 : \
@ -143,14 +501,6 @@
* w = 1 if 19 >= b * w = 1 if 19 >= b
*/ */
/* Compute
* \sum scalars[i]*points[i],
* also including
* scalar*generator
* in the addition if scalar != NULL
*/
int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, 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) size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx)
{ {
@ -369,6 +719,7 @@ int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
} }
return ret; return ret;
} }
#endif
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) 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)