diff options
author | tb <> | 2024-11-22 14:59:40 +0000 |
---|---|---|
committer | tb <> | 2024-11-22 14:59:40 +0000 |
commit | d25ca6829fcb33e9080bb5d7d5de5e01694d1cb7 (patch) | |
tree | 7790d27abad19186023db781852d4eb280ca3aa5 /src | |
parent | aa15470973d1fcdb50d16c63b9cff3c9367ce30c (diff) | |
download | openbsd-d25ca6829fcb33e9080bb5d7d5de5e01694d1cb7.tar.gz openbsd-d25ca6829fcb33e9080bb5d7d5de5e01694d1cb7.tar.bz2 openbsd-d25ca6829fcb33e9080bb5d7d5de5e01694d1cb7.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 | } |