diff options
| author | tb <> | 2024-11-22 14:59:40 +0000 |
|---|---|---|
| committer | tb <> | 2024-11-22 14:59:40 +0000 |
| commit | 34fb513f2d864d2c5d2801cf2a489943c9b86eb6 (patch) | |
| tree | 7790d27abad19186023db781852d4eb280ca3aa5 /src | |
| parent | 867439fbf4403ba93411cab0150b5821a28d4a40 (diff) | |
| download | openbsd-34fb513f2d864d2c5d2801cf2a489943c9b86eb6.tar.gz openbsd-34fb513f2d864d2c5d2801cf2a489943c9b86eb6.tar.bz2 openbsd-34fb513f2d864d2c5d2801cf2a489943c9b86eb6.zip | |
Split two helpers out of ec_wNAF_mul()
As its name indicates, the first, ec_compute_odd_multiples(), fills
point, 3 * point, 5 * point, ..., (2 * len - 1) * point into row[].
In fact, it first computes doubled = 2 * point and then goes on to
set row[i] = row[i - 1] + doubled. That's straightforward enough. One
change here is that this helper allocates row[i] on the fly rather
than preallocating the entire array of points up front.
The second piece is the actual precomputation, ec_wNAF_precompute().
It first computes the wNAF digits of the two scalars n and m (in this
order for now) with appropriate window size and length. Then the above
mentioned val[] array is allocated and populated with odd multiples
of point and generator. Finally, all points in val[] are made affine
in a single step, which means we only need one modular inversion, and
this then allows us to take fast paths in all the computations in the
one remaining loop in ec_wNAF_mul().
ok jsing
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/libcrypto/ec/ec_mult.c | 211 |
1 files changed, 119 insertions, 92 deletions
diff --git a/src/lib/libcrypto/ec/ec_mult.c b/src/lib/libcrypto/ec/ec_mult.c index 43fab4b83c..9a695a2fb6 100644 --- a/src/lib/libcrypto/ec/ec_mult.c +++ b/src/lib/libcrypto/ec/ec_mult.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: ec_mult.c,v 1.41 2024/11/22 00:54:42 tb Exp $ */ | 1 | /* $OpenBSD: ec_mult.c,v 1.42 2024/11/22 14:59:40 tb Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Originally written by Bodo Moeller and Nils Larsch for the OpenSSL project. | 3 | * Originally written by Bodo Moeller and Nils Larsch for the OpenSSL project. |
| 4 | */ | 4 | */ |
| @@ -219,6 +219,113 @@ compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) | |||
| 219 | (b) >= 20 ? 2 : \ | 219 | (b) >= 20 ? 2 : \ |
| 220 | 1)) | 220 | 1)) |
| 221 | 221 | ||
| 222 | static int | ||
| 223 | ec_compute_odd_multiples(const EC_GROUP *group, const EC_POINT *point, | ||
| 224 | EC_POINT **row, size_t len, BN_CTX *ctx) | ||
| 225 | { | ||
| 226 | EC_POINT *doubled = NULL; | ||
| 227 | size_t i; | ||
| 228 | int ret = 0; | ||
| 229 | |||
| 230 | if (len < 1) | ||
| 231 | goto err; | ||
| 232 | |||
| 233 | if ((row[0] = EC_POINT_dup(point, group)) == NULL) | ||
| 234 | goto err; | ||
| 235 | |||
| 236 | if ((doubled = EC_POINT_new(group)) == NULL) | ||
| 237 | goto err; | ||
| 238 | if (!EC_POINT_dbl(group, doubled, point, ctx)) | ||
| 239 | goto err; | ||
| 240 | for (i = 1; i < len; i++) { | ||
| 241 | if ((row[i] = EC_POINT_new(group)) == NULL) | ||
| 242 | goto err; | ||
| 243 | if (!EC_POINT_add(group, row[i], row[i - 1], doubled, ctx)) | ||
| 244 | goto err; | ||
| 245 | } | ||
| 246 | |||
| 247 | ret = 1; | ||
| 248 | |||
| 249 | err: | ||
| 250 | EC_POINT_free(doubled); | ||
| 251 | |||
| 252 | return ret; | ||
| 253 | } | ||
| 254 | |||
| 255 | /* | ||
| 256 | * This computes the wNAF representation of m and n and uses the window size to | ||
| 257 | * precompute the two rows of odd multiples of point and generator. On success, | ||
| 258 | * out_val owns the out_val_len points in the two rows. | ||
| 259 | * | ||
| 260 | * XXX - the only reason we need a single array is to be able to pass it to | ||
| 261 | * EC_POINTs_make_affine(). Consider writing a suitable variant that doesn't | ||
| 262 | * require such grotesque gymnastics. | ||
| 263 | */ | ||
| 264 | |||
| 265 | static int | ||
| 266 | ec_wNAF_precompute(const EC_GROUP *group, const BIGNUM *m, const EC_POINT *point, | ||
| 267 | const BIGNUM *n, signed char *wNAF[2], size_t wNAF_len[2], EC_POINT **row[2], | ||
| 268 | EC_POINT ***out_val, size_t *out_val_len, BN_CTX *ctx) | ||
| 269 | { | ||
| 270 | EC_POINT **val = NULL; | ||
| 271 | size_t val_len = 0; | ||
| 272 | const EC_POINT *generator; | ||
| 273 | size_t wsize[2] = { 0 }; | ||
| 274 | size_t i, len0, len1; | ||
| 275 | int ret = 0; | ||
| 276 | |||
| 277 | *out_val = NULL; | ||
| 278 | *out_val_len = 0; | ||
| 279 | |||
| 280 | if ((generator = EC_GROUP_get0_generator(group)) == NULL) { | ||
| 281 | ECerror(EC_R_UNDEFINED_GENERATOR); | ||
| 282 | goto err; | ||
| 283 | } | ||
| 284 | |||
| 285 | wsize[0] = EC_window_bits_for_scalar_size(BN_num_bits(n)); | ||
| 286 | if ((wNAF[0] = compute_wNAF(n, wsize[0], &wNAF_len[0])) == NULL) | ||
| 287 | goto err; | ||
| 288 | |||
| 289 | wsize[1] = EC_window_bits_for_scalar_size(BN_num_bits(m)); | ||
| 290 | if ((wNAF[1] = compute_wNAF(m, wsize[1], &wNAF_len[1])) == NULL) | ||
| 291 | goto err; | ||
| 292 | |||
| 293 | len0 = 1 << (wsize[0] - 1); | ||
| 294 | len1 = 1 << (wsize[1] - 1); | ||
| 295 | |||
| 296 | if ((val = calloc(len0 + len1, sizeof(*val))) == NULL) { | ||
| 297 | ECerror(ERR_R_MALLOC_FAILURE); | ||
| 298 | goto err; | ||
| 299 | } | ||
| 300 | val_len = len0 + len1; | ||
| 301 | |||
| 302 | row[0] = &val[0]; | ||
| 303 | row[1] = &val[len0]; | ||
| 304 | |||
| 305 | if (!ec_compute_odd_multiples(group, point, row[0], len0, ctx)) | ||
| 306 | goto err; | ||
| 307 | if (!ec_compute_odd_multiples(group, generator, row[1], len1, ctx)) | ||
| 308 | goto err; | ||
| 309 | |||
| 310 | if (!EC_POINTs_make_affine(group, val_len, val, ctx)) | ||
| 311 | goto err; | ||
| 312 | |||
| 313 | *out_val = val; | ||
| 314 | val = NULL; | ||
| 315 | |||
| 316 | *out_val_len = val_len; | ||
| 317 | val_len = 0; | ||
| 318 | |||
| 319 | ret = 1; | ||
| 320 | |||
| 321 | err: | ||
| 322 | for (i = 0; i < val_len; i++) | ||
| 323 | EC_POINT_free(val[i]); | ||
| 324 | free(val); | ||
| 325 | |||
| 326 | return ret; | ||
| 327 | } | ||
| 328 | |||
| 222 | /* | 329 | /* |
| 223 | * Compute r = generator * m + point * n in non-constant time. | 330 | * Compute r = generator * m + point * n in non-constant time. |
| 224 | */ | 331 | */ |
| @@ -229,17 +336,13 @@ ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *m, | |||
| 229 | { | 336 | { |
| 230 | signed char *wNAF[2] = { 0 }; | 337 | signed char *wNAF[2] = { 0 }; |
| 231 | size_t wNAF_len[2] = { 0 }; | 338 | size_t wNAF_len[2] = { 0 }; |
| 232 | size_t wsize[2] = { 0 }; | ||
| 233 | const EC_POINT *generator = NULL; | ||
| 234 | EC_POINT *tmp = NULL; | ||
| 235 | EC_POINT **row[2] = { 0 }; | 339 | EC_POINT **row[2] = { 0 }; |
| 236 | size_t i, j; | 340 | EC_POINT **val = NULL; |
| 341 | size_t val_len = 0; | ||
| 342 | size_t i; | ||
| 237 | int k; | 343 | int k; |
| 238 | int r_is_inverted = 0; | 344 | int r_is_inverted = 0; |
| 239 | size_t max_len = 0; | 345 | size_t max_len = 0; |
| 240 | size_t num_val; | ||
| 241 | EC_POINT **val = NULL; /* precomputation */ | ||
| 242 | EC_POINT **v; | ||
| 243 | int ret = 0; | 346 | int ret = 0; |
| 244 | 347 | ||
| 245 | if (m == NULL || n == NULL) { | 348 | if (m == NULL || n == NULL) { |
| @@ -251,86 +354,13 @@ ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *m, | |||
| 251 | goto err; | 354 | goto err; |
| 252 | } | 355 | } |
| 253 | 356 | ||
| 254 | if ((generator = EC_GROUP_get0_generator(group)) == NULL) { | 357 | if (!ec_wNAF_precompute(group, m, point, n, wNAF, wNAF_len, row, |
| 255 | ECerror(EC_R_UNDEFINED_GENERATOR); | 358 | &val, &val_len, ctx)) |
| 256 | goto err; | 359 | goto err; |
| 257 | } | ||
| 258 | 360 | ||
| 259 | /* num_val will be the total number of temporarily precomputed points */ | 361 | max_len = wNAF_len[0]; |
| 260 | num_val = 0; | 362 | if (wNAF_len[1] > max_len) |
| 261 | 363 | max_len = wNAF_len[1]; | |
| 262 | for (i = 0; i < 2; i++) { | ||
| 263 | size_t bits; | ||
| 264 | |||
| 265 | bits = i < 1 ? BN_num_bits(n) : BN_num_bits(m); | ||
| 266 | wsize[i] = EC_window_bits_for_scalar_size(bits); | ||
| 267 | num_val += (size_t) 1 << (wsize[i] - 1); | ||
| 268 | wNAF[i] = compute_wNAF(i < 1 ? n : m, wsize[i], &wNAF_len[i]); | ||
| 269 | if (wNAF[i] == NULL) | ||
| 270 | goto err; | ||
| 271 | if (wNAF_len[i] > max_len) | ||
| 272 | max_len = wNAF_len[i]; | ||
| 273 | } | ||
| 274 | |||
| 275 | /* | ||
| 276 | * All points we precompute now go into a single array 'val'. | ||
| 277 | * 'val_sub[i]' is a pointer to the subarray for the i-th point, or | ||
| 278 | * to a subarray of 'pre_comp->points' if we already have | ||
| 279 | * precomputation. | ||
| 280 | */ | ||
| 281 | val = reallocarray(NULL, (num_val + 1), sizeof val[0]); | ||
| 282 | if (val == NULL) { | ||
| 283 | ECerror(ERR_R_MALLOC_FAILURE); | ||
| 284 | goto err; | ||
| 285 | } | ||
| 286 | val[num_val] = NULL; /* pivot element */ | ||
| 287 | |||
| 288 | /* allocate points for precomputation */ | ||
| 289 | v = val; | ||
| 290 | for (i = 0; i < 2; i++) { | ||
| 291 | row[i] = v; | ||
| 292 | for (j = 0; j < ((size_t) 1 << (wsize[i] - 1)); j++) { | ||
| 293 | *v = EC_POINT_new(group); | ||
| 294 | if (*v == NULL) | ||
| 295 | goto err; | ||
| 296 | v++; | ||
| 297 | } | ||
| 298 | } | ||
| 299 | if (!(v == val + num_val)) { | ||
| 300 | ECerror(ERR_R_INTERNAL_ERROR); | ||
| 301 | goto err; | ||
| 302 | } | ||
| 303 | if (!(tmp = EC_POINT_new(group))) | ||
| 304 | goto err; | ||
| 305 | |||
| 306 | /* | ||
| 307 | * prepare precomputed values: | ||
| 308 | * row[i][0] := points[i] | ||
| 309 | * row[i][1] := 3 * points[i] | ||
| 310 | * row[i][2] := 5 * points[i] | ||
| 311 | * ... | ||
| 312 | */ | ||
| 313 | for (i = 0; i < 2; i++) { | ||
| 314 | if (i < 1) { | ||
| 315 | if (!EC_POINT_copy(row[i][0], point)) | ||
| 316 | goto err; | ||
| 317 | } else { | ||
| 318 | if (!EC_POINT_copy(row[i][0], generator)) | ||
| 319 | goto err; | ||
| 320 | } | ||
| 321 | |||
| 322 | if (wsize[i] > 1) { | ||
| 323 | if (!EC_POINT_dbl(group, tmp, row[i][0], ctx)) | ||
| 324 | goto err; | ||
| 325 | for (j = 1; j < ((size_t) 1 << (wsize[i] - 1)); j++) { | ||
| 326 | if (!EC_POINT_add(group, row[i][j], row[i][j - 1], tmp, ctx)) | ||
| 327 | goto err; | ||
| 328 | } | ||
| 329 | } | ||
| 330 | } | ||
| 331 | |||
| 332 | if (!EC_POINTs_make_affine(group, num_val, val, ctx)) | ||
| 333 | goto err; | ||
| 334 | 364 | ||
| 335 | /* | 365 | /* |
| 336 | * Set r to the neutral element. Scan through the wNAF representations | 366 | * Set r to the neutral element. Scan through the wNAF representations |
| @@ -381,14 +411,11 @@ ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *m, | |||
| 381 | ret = 1; | 411 | ret = 1; |
| 382 | 412 | ||
| 383 | err: | 413 | err: |
| 384 | EC_POINT_free(tmp); | ||
| 385 | free(wNAF[0]); | 414 | free(wNAF[0]); |
| 386 | free(wNAF[1]); | 415 | free(wNAF[1]); |
| 387 | if (val != NULL) { | 416 | for (i = 0; i < val_len; i++) |
| 388 | for (v = val; *v != NULL; v++) | 417 | EC_POINT_free(val[i]); |
| 389 | EC_POINT_free(*v); | 418 | free(val); |
| 390 | free(val); | ||
| 391 | } | ||
| 392 | 419 | ||
| 393 | return ret; | 420 | return ret; |
| 394 | } | 421 | } |
