Remove |EC_POINTs_mul| & simplify p256-x86_64.

Without |EC_POINTs_mul|, there's never more than one variable point
passed to a |EC_METHOD|'s |mul| method. This allows them to be
simplified considerably. In this commit, the p256-x86_64 implementation
has been simplified to eliminate the heap allocation and looping
related that was previously necessary to deal with the possibility of
there being multiple input points. The other implementations were left
mostly as-is; they should be similarly simplified in the future.

Change-Id: I70751d1d5296be2562af0730e7ccefdba7a1acae
Reviewed-on: https://boringssl-review.googlesource.com/6493
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
Brian Smith 2015-11-12 15:05:22 -10:00 committed by Adam Langley
parent 301efc8cea
commit f3376ace43
7 changed files with 174 additions and 230 deletions

View File

@ -837,39 +837,23 @@ int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx) {
} }
int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, 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 *p, const BIGNUM *p_scalar, BN_CTX *ctx) {
/* just a convenient interface to EC_POINTs_mul() */ /* Previously, this function set |r| to the point at infinity if there was
* nothing to multiply. But, nobody should be calling this function with
* nothing to multiply in the first place. */
if ((g_scalar == NULL && p_scalar == NULL) ||
((p == NULL) != (p_scalar == NULL))) {
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
const EC_POINT *points[1]; if (group->meth != r->meth ||
const BIGNUM *scalars[1]; (p != NULL && group->meth != p->meth)) {
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_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 != r->meth) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0; return 0;
} }
size_t i; return group->meth->mul(group, r, g_scalar, p, p_scalar, ctx);
for (i = 0; i < num; i++) {
if (points[i]->meth != r->meth) {
break;
}
}
if (i != num) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
return group->meth->mul(group, r, scalar, num, points, scalars, ctx);
} }
int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,

View File

@ -95,12 +95,13 @@ struct ec_method_st {
int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_POINT *, int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_POINT *,
BIGNUM *x, BIGNUM *y, BN_CTX *); BIGNUM *x, BIGNUM *y, BN_CTX *);
/* used by EC_POINTs_mul, EC_POINT_mul, EC_POINT_precompute_mult, /* Computes |r = g_scalar*generator + p_scalar*p| if |g_scalar| and |p_scalar|
* EC_POINT_have_precompute_mult * are both non-null. Computes |r = g_scalar*generator| if |p_scalar| is null.
* (default implementations are used if the 'mul' pointer is 0): */ * Computes |r = p_scalar*p| if g_scalar is null. At least one of |g_scalar|
int (*mul)(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, * and |p_scalar| must be non-null, and |p| must be non-null if |p_scalar| is
size_t num, const EC_POINT *points[], const BIGNUM *scalars[], * non-null. */
BN_CTX *); int (*mul)(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx);
/* internal functions */ /* internal functions */
@ -164,9 +165,8 @@ int ec_group_copy(EC_GROUP *dest, const EC_GROUP *src);
* a built-in group. */ * a built-in group. */
const BN_MONT_CTX *ec_group_get_mont_data(const EC_GROUP *group); const BN_MONT_CTX *ec_group_get_mont_data(const EC_GROUP *group);
int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
size_t num, const EC_POINT *points[], const BIGNUM *scalars[], const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx);
BN_CTX *);
/* method functions in simple.c */ /* method functions in simple.c */
int ec_GFp_simple_group_init(EC_GROUP *); int ec_GFp_simple_group_init(EC_GROUP *);

View File

@ -1121,12 +1121,16 @@ static void make_points_affine(size_t num, felem points[/*num*/][3],
(void (*)(void *, const void *))felem_contract); (void (*)(void *, const void *))felem_contract);
} }
/* Computes scalar*generator + \sum scalars[i]*points[i], ignoring NULL values
* Result is stored in r (r can equal one of the inputs). */
int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r, int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
const BIGNUM *scalar, size_t num, const BIGNUM *g_scalar, const EC_POINT *p_,
const EC_POINT *points[], const BIGNUM *p_scalar_, BN_CTX *ctx) {
const BIGNUM *scalars[], BN_CTX *ctx) { /* TODO: This function used to take |points| and |scalars| as arrays of
* |num| elements. The code below should be simplified to work in terms of
* |p_| and |p_scalar_|. */
size_t num = p_ != NULL ? 1 : 0;
const EC_POINT **points = p_ != NULL ? &p_ : NULL;
BIGNUM const *const *scalars = p_ != NULL ? &p_scalar_ : NULL;
int ret = 0; int ret = 0;
int j; int j;
unsigned i; unsigned i;
@ -1186,7 +1190,7 @@ int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
if (i == num) { if (i == num) {
/* the generator */ /* the generator */
p = EC_GROUP_get0_generator(group); p = EC_GROUP_get0_generator(group);
p_scalar = scalar; p_scalar = g_scalar;
} else { } else {
/* the i^th point */ /* the i^th point */
p = points[i]; p = points[i];
@ -1194,7 +1198,7 @@ int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
} }
if (p_scalar != NULL && p != NULL) { if (p_scalar != NULL && p != NULL) {
/* reduce scalar to 0 <= scalar < 2^224 */ /* reduce g_scalar to 0 <= g_scalar < 2^224 */
if (BN_num_bits(p_scalar) > 224 || BN_is_negative(p_scalar)) { if (BN_num_bits(p_scalar) > 224 || BN_is_negative(p_scalar)) {
/* this is an unusual input, and we don't guarantee /* this is an unusual input, and we don't guarantee
* constant-timeness */ * constant-timeness */
@ -1239,25 +1243,24 @@ int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
} }
} }
/* the scalar for the generator */ if (g_scalar != NULL) {
if (scalar != NULL) {
memset(g_secret, 0, sizeof(g_secret)); memset(g_secret, 0, sizeof(g_secret));
/* reduce scalar to 0 <= scalar < 2^224 */ /* reduce g_scalar to 0 <= g_scalar < 2^224 */
if (BN_num_bits(scalar) > 224 || BN_is_negative(scalar)) { if (BN_num_bits(g_scalar) > 224 || BN_is_negative(g_scalar)) {
/* this is an unusual input, and we don't guarantee constant-timeness */ /* this is an unusual input, and we don't guarantee constant-timeness */
if (!BN_nnmod(tmp_scalar, scalar, &group->order, ctx)) { if (!BN_nnmod(tmp_scalar, g_scalar, &group->order, ctx)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err; goto err;
} }
num_bytes = BN_bn2bin(tmp_scalar, tmp); num_bytes = BN_bn2bin(tmp_scalar, tmp);
} else { } else {
num_bytes = BN_bn2bin(scalar, tmp); num_bytes = BN_bn2bin(g_scalar, tmp);
} }
flip_endian(g_secret, tmp, num_bytes); flip_endian(g_secret, tmp, num_bytes);
} }
batch_mul(x_out, y_out, z_out, (const felem_bytearray(*))secrets, batch_mul(x_out, y_out, z_out, (const felem_bytearray(*))secrets,
num_points, scalar != NULL ? g_secret : NULL, mixed, num_points, g_scalar != NULL ? g_secret : NULL, mixed,
(const felem(*)[17][3])pre_comp); (const felem(*)[17][3])pre_comp);
/* reduce the output to its unique minimal representation */ /* reduce the output to its unique minimal representation */

View File

@ -1701,12 +1701,16 @@ static void make_points_affine(size_t num, smallfelem points[][3],
(void (*)(void *, const void *))smallfelem_assign); (void (*)(void *, const void *))smallfelem_assign);
} }
/* Computes scalar*generator + \sum scalars[i]*points[i], ignoring NULL
* values Result is stored in r (r can equal one of the inputs). */
int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r, int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
const BIGNUM *scalar, size_t num, const BIGNUM *g_scalar, const EC_POINT *p_,
const EC_POINT *points[], const BIGNUM *p_scalar_, BN_CTX *ctx) {
const BIGNUM *scalars[], BN_CTX *ctx) { /* TODO: This function used to take |points| and |scalars| as arrays of
* |num| elements. The code below should be simplified to work in terms of |p|
* and |p_scalar|. */
size_t num = p_ != NULL ? 1 : 0;
const EC_POINT **points = p_ != NULL ? &p_ : NULL;
BIGNUM const *const *scalars = p_ != NULL ? &p_scalar_ : NULL;
int ret = 0; int ret = 0;
int j; int j;
int mixed = 0; int mixed = 0;
@ -1765,14 +1769,14 @@ int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
if (i == num) { if (i == num) {
/* we didn't have a valid precomputation, so we pick the generator. */ /* we didn't have a valid precomputation, so we pick the generator. */
p = EC_GROUP_get0_generator(group); p = EC_GROUP_get0_generator(group);
p_scalar = scalar; p_scalar = g_scalar;
} else { } else {
/* the i^th point */ /* the i^th point */
p = points[i]; p = points[i];
p_scalar = scalars[i]; p_scalar = scalars[i];
} }
if (p_scalar != NULL && p != NULL) { if (p_scalar != NULL && p != NULL) {
/* reduce scalar to 0 <= scalar < 2^256 */ /* reduce g_scalar to 0 <= g_scalar < 2^256 */
if (BN_num_bits(p_scalar) > 256 || BN_is_negative(p_scalar)) { if (BN_num_bits(p_scalar) > 256 || BN_is_negative(p_scalar)) {
/* this is an unusual input, and we don't guarantee /* this is an unusual input, and we don't guarantee
* constant-timeness. */ * constant-timeness. */
@ -1814,25 +1818,24 @@ int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
} }
} }
/* the scalar for the generator */ if (g_scalar != NULL) {
if (scalar != NULL) {
memset(g_secret, 0, sizeof(g_secret)); memset(g_secret, 0, sizeof(g_secret));
/* reduce scalar to 0 <= scalar < 2^256 */ /* reduce g_scalar to 0 <= g_scalar < 2^256 */
if (BN_num_bits(scalar) > 256 || BN_is_negative(scalar)) { if (BN_num_bits(g_scalar) > 256 || BN_is_negative(g_scalar)) {
/* this is an unusual input, and we don't guarantee /* this is an unusual input, and we don't guarantee
* constant-timeness. */ * constant-timeness. */
if (!BN_nnmod(tmp_scalar, scalar, &group->order, ctx)) { if (!BN_nnmod(tmp_scalar, g_scalar, &group->order, ctx)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err; goto err;
} }
num_bytes = BN_bn2bin(tmp_scalar, tmp); num_bytes = BN_bn2bin(tmp_scalar, tmp);
} else { } else {
num_bytes = BN_bn2bin(scalar, tmp); num_bytes = BN_bn2bin(g_scalar, tmp);
} }
flip_endian(g_secret, tmp, num_bytes); flip_endian(g_secret, tmp, num_bytes);
} }
batch_mul(x_out, y_out, z_out, (const felem_bytearray(*))secrets, batch_mul(x_out, y_out, z_out, (const felem_bytearray(*))secrets,
num_points, scalar != NULL ? g_secret : NULL, mixed, num_points, g_scalar != NULL ? g_secret : NULL, mixed,
(const smallfelem(*)[17][3])pre_comp); (const smallfelem(*)[17][3])pre_comp);
/* reduce the output to its unique minimal representation */ /* reduce the output to its unique minimal representation */

View File

@ -22,6 +22,7 @@
#include <openssl/ec.h> #include <openssl/ec.h>
#include <assert.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@ -44,11 +45,11 @@
#endif #endif
#if defined(__GNUC__) #if defined(__GNUC__)
#define ALIGN32 __attribute((aligned(32))) #define ALIGN(x) __attribute((aligned(x)))
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define ALIGN32 __declspec(align(32)) #define ALIGN(x) __declspec(align(x))
#else #else
#define ALIGN32 #define ALIGN(x)
#endif #endif
#define ALIGNPTR(p, N) ((uint8_t *)p + N - (size_t)p % N) #define ALIGNPTR(p, N) ((uint8_t *)p + N - (size_t)p % N)
@ -254,130 +255,117 @@ static int ecp_nistz256_bignum_to_field_elem(BN_ULONG out[P256_LIMBS],
return 1; return 1;
} }
/* r = sum(scalar[i]*point[i]) */ /* r = p * p_scalar */
static int ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r, static int ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
const BIGNUM **scalar, const EC_POINT *p, const BIGNUM *p_scalar,
const EC_POINT **point, int num,
BN_CTX *ctx) { BN_CTX *ctx) {
assert(p != NULL);
assert(p_scalar != NULL);
static const unsigned kWindowSize = 5; static const unsigned kWindowSize = 5;
static const unsigned kMask = (1 << (5 /* kWindowSize */ + 1)) - 1; static const unsigned kMask = (1 << (5 /* kWindowSize */ + 1)) - 1;
void *table_storage = OPENSSL_malloc(num * 16 * sizeof(P256_POINT) + 64); /* A |P256_POINT| is (3 * 32) = 96 bytes, and the 64-byte alignment should
uint8_t(*p_str)[33] = OPENSSL_malloc(num * 33 * sizeof(uint8_t)); * add no more than 63 bytes of overhead. Thus, |table| should require
const BIGNUM **scalars = OPENSSL_malloc(num * sizeof(BIGNUM *)); * ~1599 ((96 * 16) + 63) bytes of stack space. */
ALIGN(64) P256_POINT table[16];
uint8_t p_str[33];
int ret = 0; int ret = 0;
BN_CTX *new_ctx = NULL; BN_CTX *new_ctx = NULL;
int ctx_started = 0; int ctx_started = 0;
if (table_storage == NULL || if (BN_num_bits(p_scalar) > 256 || BN_is_negative(p_scalar)) {
p_str == NULL || if (ctx == NULL) {
scalars == NULL) { new_ctx = BN_CTX_new();
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); if (new_ctx == NULL) {
goto err;
}
P256_POINT(*table)[16] = (void *)ALIGNPTR(table_storage, 64);
int i;
for (i = 0; i < num; i++) {
P256_POINT *row = table[i];
if (BN_num_bits(scalar[i]) > 256 || BN_is_negative(scalar[i])) {
if (!ctx_started) {
if (ctx == NULL) {
new_ctx = BN_CTX_new();
if (new_ctx == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
goto err;
}
ctx = new_ctx;
}
BN_CTX_start(ctx);
ctx_started = 1;
}
BIGNUM *mod = BN_CTX_get(ctx);
if (mod == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
goto err; goto err;
} }
ctx = new_ctx;
if (!BN_nnmod(mod, scalar[i], &group->order, ctx)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err;
}
scalars[i] = mod;
} else {
scalars[i] = scalar[i];
} }
BN_CTX_start(ctx);
int j; ctx_started = 1;
for (j = 0; j < scalars[i]->top * BN_BYTES; j += BN_BYTES) { BIGNUM *mod = BN_CTX_get(ctx);
BN_ULONG d = scalars[i]->d[j / BN_BYTES]; if (mod == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
p_str[i][j + 0] = d & 0xff;
p_str[i][j + 1] = (d >> 8) & 0xff;
p_str[i][j + 2] = (d >> 16) & 0xff;
p_str[i][j + 3] = (d >>= 24) & 0xff;
if (BN_BYTES == 8) {
d >>= 8;
p_str[i][j + 4] = d & 0xff;
p_str[i][j + 5] = (d >> 8) & 0xff;
p_str[i][j + 6] = (d >> 16) & 0xff;
p_str[i][j + 7] = (d >> 24) & 0xff;
}
}
for (; j < 33; j++) {
p_str[i][j] = 0;
}
/* table[0] is implicitly (0,0,0) (the point at infinity), therefore it is
* not stored. All other values are actually stored with an offset of -1 in
* table. */
if (!ecp_nistz256_bignum_to_field_elem(row[1 - 1].X, &point[i]->X) ||
!ecp_nistz256_bignum_to_field_elem(row[1 - 1].Y, &point[i]->Y) ||
!ecp_nistz256_bignum_to_field_elem(row[1 - 1].Z, &point[i]->Z)) {
OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE);
goto err; goto err;
} }
if (!BN_nnmod(mod, p_scalar, &group->order, ctx)) {
ecp_nistz256_point_double(&row[2 - 1], &row[1 - 1]); OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
ecp_nistz256_point_add(&row[3 - 1], &row[2 - 1], &row[1 - 1]); goto err;
ecp_nistz256_point_double(&row[4 - 1], &row[2 - 1]); }
ecp_nistz256_point_double(&row[6 - 1], &row[3 - 1]); p_scalar = mod;
ecp_nistz256_point_double(&row[8 - 1], &row[4 - 1]);
ecp_nistz256_point_double(&row[12 - 1], &row[6 - 1]);
ecp_nistz256_point_add(&row[5 - 1], &row[4 - 1], &row[1 - 1]);
ecp_nistz256_point_add(&row[7 - 1], &row[6 - 1], &row[1 - 1]);
ecp_nistz256_point_add(&row[9 - 1], &row[8 - 1], &row[1 - 1]);
ecp_nistz256_point_add(&row[13 - 1], &row[12 - 1], &row[1 - 1]);
ecp_nistz256_point_double(&row[14 - 1], &row[7 - 1]);
ecp_nistz256_point_double(&row[10 - 1], &row[5 - 1]);
ecp_nistz256_point_add(&row[15 - 1], &row[14 - 1], &row[1 - 1]);
ecp_nistz256_point_add(&row[11 - 1], &row[10 - 1], &row[1 - 1]);
ecp_nistz256_point_add(&row[16 - 1], &row[15 - 1], &row[1 - 1]);
} }
int j;
for (j = 0; j < p_scalar->top * BN_BYTES; j += BN_BYTES) {
BN_ULONG d = p_scalar->d[j / BN_BYTES];
p_str[j + 0] = d & 0xff;
p_str[j + 1] = (d >> 8) & 0xff;
p_str[j + 2] = (d >> 16) & 0xff;
p_str[j + 3] = (d >>= 24) & 0xff;
if (BN_BYTES == 8) {
d >>= 8;
p_str[j + 4] = d & 0xff;
p_str[j + 5] = (d >> 8) & 0xff;
p_str[j + 6] = (d >> 16) & 0xff;
p_str[j + 7] = (d >> 24) & 0xff;
}
}
for (; j < 33; j++) {
p_str[j] = 0;
}
/* table[0] is implicitly (0,0,0) (the point at infinity), therefore it is
* not stored. All other values are actually stored with an offset of -1 in
* table. */
P256_POINT *row = table;
if (!ecp_nistz256_bignum_to_field_elem(row[1 - 1].X, &p->X) ||
!ecp_nistz256_bignum_to_field_elem(row[1 - 1].Y, &p->Y) ||
!ecp_nistz256_bignum_to_field_elem(row[1 - 1].Z, &p->Z)) {
OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE);
goto err;
}
ecp_nistz256_point_double(&row[2 - 1], &row[1 - 1]);
ecp_nistz256_point_add(&row[3 - 1], &row[2 - 1], &row[1 - 1]);
ecp_nistz256_point_double(&row[4 - 1], &row[2 - 1]);
ecp_nistz256_point_double(&row[6 - 1], &row[3 - 1]);
ecp_nistz256_point_double(&row[8 - 1], &row[4 - 1]);
ecp_nistz256_point_double(&row[12 - 1], &row[6 - 1]);
ecp_nistz256_point_add(&row[5 - 1], &row[4 - 1], &row[1 - 1]);
ecp_nistz256_point_add(&row[7 - 1], &row[6 - 1], &row[1 - 1]);
ecp_nistz256_point_add(&row[9 - 1], &row[8 - 1], &row[1 - 1]);
ecp_nistz256_point_add(&row[13 - 1], &row[12 - 1], &row[1 - 1]);
ecp_nistz256_point_double(&row[14 - 1], &row[7 - 1]);
ecp_nistz256_point_double(&row[10 - 1], &row[5 - 1]);
ecp_nistz256_point_add(&row[15 - 1], &row[14 - 1], &row[1 - 1]);
ecp_nistz256_point_add(&row[11 - 1], &row[10 - 1], &row[1 - 1]);
ecp_nistz256_point_add(&row[16 - 1], &row[15 - 1], &row[1 - 1]);
BN_ULONG tmp[P256_LIMBS]; BN_ULONG tmp[P256_LIMBS];
ALIGN32 P256_POINT h; ALIGN(32) P256_POINT h;
unsigned index = 255; unsigned index = 255;
unsigned wvalue = p_str[0][(index - 1) / 8]; unsigned wvalue = p_str[(index - 1) / 8];
wvalue = (wvalue >> ((index - 1) % 8)) & kMask; wvalue = (wvalue >> ((index - 1) % 8)) & kMask;
ecp_nistz256_select_w5(r, table[0], booth_recode_w5(wvalue) >> 1); ecp_nistz256_select_w5(r, table, booth_recode_w5(wvalue) >> 1);
while (index >= 5) { while (index >= 5) {
for (i = (index == 255 ? 1 : 0); i < num; i++) { if (index != 255) {
unsigned off = (index - 1) / 8; unsigned off = (index - 1) / 8;
wvalue = p_str[i][off] | p_str[i][off + 1] << 8; wvalue = p_str[off] | p_str[off + 1] << 8;
wvalue = (wvalue >> ((index - 1) % 8)) & kMask; wvalue = (wvalue >> ((index - 1) % 8)) & kMask;
wvalue = booth_recode_w5(wvalue); wvalue = booth_recode_w5(wvalue);
ecp_nistz256_select_w5(&h, table[i], wvalue >> 1); ecp_nistz256_select_w5(&h, table, wvalue >> 1);
ecp_nistz256_neg(tmp, h.Y); ecp_nistz256_neg(tmp, h.Y);
copy_conditional(h.Y, tmp, (wvalue & 1)); copy_conditional(h.Y, tmp, (wvalue & 1));
@ -395,26 +383,21 @@ static int ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
} }
/* Final window */ /* Final window */
for (i = 0; i < num; i++) { wvalue = p_str[0];
wvalue = p_str[i][0]; wvalue = (wvalue << 1) & kMask;
wvalue = (wvalue << 1) & kMask;
wvalue = booth_recode_w5(wvalue); wvalue = booth_recode_w5(wvalue);
ecp_nistz256_select_w5(&h, table[i], wvalue >> 1); ecp_nistz256_select_w5(&h, table, wvalue >> 1);
ecp_nistz256_neg(tmp, h.Y); ecp_nistz256_neg(tmp, h.Y);
copy_conditional(h.Y, tmp, wvalue & 1); copy_conditional(h.Y, tmp, wvalue & 1);
ecp_nistz256_point_add(r, r, &h); ecp_nistz256_point_add(r, r, &h);
}
ret = 1; ret = 1;
err: err:
OPENSSL_free(table_storage);
OPENSSL_free(p_str);
OPENSSL_free((BIGNUM**) scalars);
if (ctx_started) { if (ctx_started) {
BN_CTX_end(ctx); BN_CTX_end(ctx);
} }
@ -422,14 +405,15 @@ err:
return ret; return ret;
} }
/* r = scalar*G + sum(scalars[i]*points[i]) */
static int ecp_nistz256_points_mul( static int ecp_nistz256_points_mul(
const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx) { const EC_POINT *p_, const BIGNUM *p_scalar, BN_CTX *ctx) {
assert((p_ != NULL) == (p_scalar != NULL));
static const unsigned kWindowSize = 7; static const unsigned kWindowSize = 7;
static const unsigned kMask = (1 << (7 /* kWindowSize */ + 1)) - 1; static const unsigned kMask = (1 << (7 /* kWindowSize */ + 1)) - 1;
ALIGN32 union { ALIGN(32) union {
P256_POINT p; P256_POINT p;
P256_POINT_AFFINE a; P256_POINT_AFFINE a;
} t, p; } t, p;
@ -438,10 +422,6 @@ static int ecp_nistz256_points_mul(
BN_CTX *new_ctx = NULL; BN_CTX *new_ctx = NULL;
int ctx_started = 0; int ctx_started = 0;
if (scalar == NULL && num == 0) {
return EC_POINT_set_to_infinity(group, r);
}
/* Need 256 bits for space for all coordinates. */ /* Need 256 bits for space for all coordinates. */
if (bn_wexpand(&r->X, P256_LIMBS) == NULL || if (bn_wexpand(&r->X, P256_LIMBS) == NULL ||
bn_wexpand(&r->Y, P256_LIMBS) == NULL || bn_wexpand(&r->Y, P256_LIMBS) == NULL ||
@ -453,36 +433,33 @@ static int ecp_nistz256_points_mul(
r->Y.top = P256_LIMBS; r->Y.top = P256_LIMBS;
r->Z.top = P256_LIMBS; r->Z.top = P256_LIMBS;
if (scalar) { if (g_scalar != NULL) {
if (BN_num_bits(scalar) > 256 || BN_is_negative(scalar)) { if (BN_num_bits(g_scalar) > 256 || BN_is_negative(g_scalar)) {
if (ctx == NULL) { if (ctx == NULL) {
new_ctx = BN_CTX_new(); new_ctx = BN_CTX_new();
if (new_ctx == NULL) { if (new_ctx == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
goto err; goto err;
} }
ctx = new_ctx; ctx = new_ctx;
} }
BN_CTX_start(ctx); BN_CTX_start(ctx);
ctx_started = 1; ctx_started = 1;
BIGNUM *tmp_scalar = BN_CTX_get(ctx); BIGNUM *tmp_scalar = BN_CTX_get(ctx);
if (tmp_scalar == NULL) { if (tmp_scalar == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
goto err; goto err;
} }
if (!BN_nnmod(tmp_scalar, scalar, &group->order, ctx)) { if (!BN_nnmod(tmp_scalar, g_scalar, &group->order, ctx)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err; goto err;
} }
scalar = tmp_scalar; g_scalar = tmp_scalar;
} }
uint8_t p_str[33] = {0}; uint8_t p_str[33] = {0};
int i; int i;
for (i = 0; i < scalar->top * BN_BYTES; i += BN_BYTES) { for (i = 0; i < g_scalar->top * BN_BYTES; i += BN_BYTES) {
BN_ULONG d = scalar->d[i / BN_BYTES]; BN_ULONG d = g_scalar->d[i / BN_BYTES];
p_str[i + 0] = d & 0xff; p_str[i + 0] = d & 0xff;
p_str[i + 1] = (d >> 8) & 0xff; p_str[i + 1] = (d >> 8) & 0xff;
@ -533,14 +510,14 @@ static int ecp_nistz256_points_mul(
} }
} }
const int p_is_infinity = !scalar; const int p_is_infinity = g_scalar == NULL;
if (num) { if (p_scalar != NULL) {
P256_POINT *out = &t.p; P256_POINT *out = &t.p;
if (p_is_infinity) { if (p_is_infinity) {
out = &p.p; out = &p.p;
} }
if (!ecp_nistz256_windowed_mul(group, out, scalars, points, num, ctx)) { if (!ecp_nistz256_windowed_mul(group, out, p_, p_scalar, ctx)) {
goto err; goto err;
} }

View File

@ -224,15 +224,8 @@ err:
? 2 \ ? 2 \
: 1)) : 1))
/* Compute int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
* \sum scalars[i]*points[i], const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx) {
* 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; BN_CTX *new_ctx = NULL;
const EC_POINT *generator = NULL; const EC_POINT *generator = NULL;
EC_POINT *tmp = NULL; EC_POINT *tmp = NULL;
@ -251,22 +244,6 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
EC_POINT ***val_sub = NULL; /* pointers to sub-arrays of 'val' */ EC_POINT ***val_sub = NULL; /* pointers to sub-arrays of 'val' */
int ret = 0; int ret = 0;
if (group->meth != r->meth) {
OPENSSL_PUT_ERROR(EC, 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) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
}
if (ctx == NULL) { if (ctx == NULL) {
ctx = new_ctx = BN_CTX_new(); ctx = new_ctx = BN_CTX_new();
if (ctx == NULL) { if (ctx == NULL) {
@ -274,16 +251,23 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
} }
} }
/* TODO: This function used to take |points| and |scalars| as arrays of
* |num| elements. The code below should be simplified to work in terms of |p|
* and |p_scalar|. */
size_t num = p != NULL ? 1 : 0;
const EC_POINT **points = p != NULL ? &p : NULL;
const BIGNUM **scalars = p != NULL ? &p_scalar : NULL;
total_num = num; total_num = num;
if (scalar != NULL) { if (g_scalar != NULL) {
generator = EC_GROUP_get0_generator(group); generator = EC_GROUP_get0_generator(group);
if (generator == NULL) { if (generator == NULL) {
OPENSSL_PUT_ERROR(EC, EC_R_UNDEFINED_GENERATOR); OPENSSL_PUT_ERROR(EC, EC_R_UNDEFINED_GENERATOR);
goto err; goto err;
} }
++total_num; /* treat 'scalar' like 'num'-th element of 'scalars' */ ++total_num; /* treat 'g_scalar' like 'num'-th element of 'scalars' */
} }
@ -309,12 +293,12 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
for (i = 0; i < total_num; i++) { for (i = 0; i < total_num; i++) {
size_t bits; size_t bits;
bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(scalar); bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(g_scalar);
wsize[i] = EC_window_bits_for_scalar_size(bits); wsize[i] = EC_window_bits_for_scalar_size(bits);
num_val += (size_t)1 << (wsize[i] - 1); num_val += (size_t)1 << (wsize[i] - 1);
wNAF[i + 1] = NULL; /* make sure we always have a pivot */ wNAF[i + 1] = NULL; /* make sure we always have a pivot */
wNAF[i] = wNAF[i] =
compute_wNAF((i < num ? scalars[i] : scalar), wsize[i], &wNAF_len[i]); compute_wNAF((i < num ? scalars[i] : g_scalar), wsize[i], &wNAF_len[i]);
if (wNAF[i] == NULL) { if (wNAF[i] == NULL) {
goto err; goto err;
} }

View File

@ -269,13 +269,6 @@ OPENSSL_EXPORT int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r,
const BIGNUM *n, const EC_POINT *q, const BIGNUM *n, const EC_POINT *q,
const BIGNUM *m, BN_CTX *ctx); const BIGNUM *m, BN_CTX *ctx);
/* EC_POINTs_mul sets r = generator*n + sum(p[i]*m[i]). It returns one on
* success and zero otherwise. If |ctx| is not NULL, it may be used. */
OPENSSL_EXPORT int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r,
const BIGNUM *n, size_t num,
const EC_POINT *p[], const BIGNUM *m[],
BN_CTX *ctx);
/* Deprecated functions. */ /* Deprecated functions. */