diff options
author | jsing <> | 2023-02-28 12:29:57 +0000 |
---|---|---|
committer | jsing <> | 2023-02-28 12:29:57 +0000 |
commit | dead64e34c09a337929e371eeb84a00392b8fea1 (patch) | |
tree | 4e300f7db1e4faab027e65e22bf14a65c1edc9f5 | |
parent | a1eb3dcae5de5d83cba3a495bb56b031d126748a (diff) | |
download | openbsd-dead64e34c09a337929e371eeb84a00392b8fea1.tar.gz openbsd-dead64e34c09a337929e371eeb84a00392b8fea1.tar.bz2 openbsd-dead64e34c09a337929e371eeb84a00392b8fea1.zip |
Rewrite/simplify BN_from_montgomery_word() and BN_from_montgomery().
Rename BN_from_montgomery_word() to bn_montgomery_reduce() and rewrite it
to be simpler and clearer, moving further towards constant time in the
process. Clean up BN_from_montgomery() in the process.
ok tb@
-rw-r--r-- | src/lib/libcrypto/bn/bn_mont.c | 177 |
1 files changed, 85 insertions, 92 deletions
diff --git a/src/lib/libcrypto/bn/bn_mont.c b/src/lib/libcrypto/bn/bn_mont.c index c368e07e22..15c9c4a00e 100644 --- a/src/lib/libcrypto/bn/bn_mont.c +++ b/src/lib/libcrypto/bn/bn_mont.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: bn_mont.c,v 1.46 2023/02/22 06:00:24 jsing Exp $ */ | 1 | /* $OpenBSD: bn_mont.c,v 1.47 2023/02/28 12:29:57 jsing Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -356,22 +356,22 @@ bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, | |||
356 | #endif /* !OPENSSL_BN_ASM_MONT */ | 356 | #endif /* !OPENSSL_BN_ASM_MONT */ |
357 | #endif /* OPENSSL_NO_ASM */ | 357 | #endif /* OPENSSL_NO_ASM */ |
358 | 358 | ||
359 | static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont); | 359 | static int bn_montgomery_reduce(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mctx); |
360 | 360 | ||
361 | int | 361 | int |
362 | BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, | 362 | BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, |
363 | BN_MONT_CTX *mont, BN_CTX *ctx) | 363 | BN_MONT_CTX *mctx, BN_CTX *ctx) |
364 | { | 364 | { |
365 | BIGNUM *tmp; | 365 | BIGNUM *tmp; |
366 | int ret = 0; | 366 | int ret = 0; |
367 | 367 | ||
368 | #if defined(OPENSSL_BN_ASM_MONT) | 368 | #if defined(OPENSSL_BN_ASM_MONT) |
369 | int num = mont->N.top; | 369 | int num = mctx->N.top; |
370 | 370 | ||
371 | if (num > 1 && a->top == num && b->top == num) { | 371 | if (num > 1 && a->top == num && b->top == num) { |
372 | if (!bn_wexpand(r, num)) | 372 | if (!bn_wexpand(r, num)) |
373 | return (0); | 373 | return (0); |
374 | if (bn_mul_mont(r->d, a->d, b->d, mont->N.d, mont->n0, num)) { | 374 | if (bn_mul_mont(r->d, a->d, b->d, mctx->N.d, mctx->n0, num)) { |
375 | r->top = num; | 375 | r->top = num; |
376 | bn_correct_top(r); | 376 | bn_correct_top(r); |
377 | BN_set_negative(r, a->neg ^ b->neg); | 377 | BN_set_negative(r, a->neg ^ b->neg); |
@@ -381,6 +381,7 @@ BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, | |||
381 | #endif | 381 | #endif |
382 | 382 | ||
383 | BN_CTX_start(ctx); | 383 | BN_CTX_start(ctx); |
384 | |||
384 | if ((tmp = BN_CTX_get(ctx)) == NULL) | 385 | if ((tmp = BN_CTX_get(ctx)) == NULL) |
385 | goto err; | 386 | goto err; |
386 | 387 | ||
@@ -388,16 +389,19 @@ BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, | |||
388 | if (!BN_sqr(tmp, a, ctx)) | 389 | if (!BN_sqr(tmp, a, ctx)) |
389 | goto err; | 390 | goto err; |
390 | } else { | 391 | } else { |
391 | if (!BN_mul(tmp, a,b, ctx)) | 392 | if (!BN_mul(tmp, a, b, ctx)) |
392 | goto err; | 393 | goto err; |
393 | } | 394 | } |
394 | /* reduce from aRR to aR */ | 395 | |
395 | if (!BN_from_montgomery_word(r, tmp, mont)) | 396 | /* Reduce from aRR to aR. */ |
397 | if (!bn_montgomery_reduce(r, tmp, mctx)) | ||
396 | goto err; | 398 | goto err; |
399 | |||
397 | ret = 1; | 400 | ret = 1; |
398 | err: | 401 | err: |
399 | BN_CTX_end(ctx); | 402 | BN_CTX_end(ctx); |
400 | return (ret); | 403 | |
404 | return ret; | ||
401 | } | 405 | } |
402 | 406 | ||
403 | int | 407 | int |
@@ -407,106 +411,95 @@ BN_to_montgomery(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mont, BN_CTX *ctx) | |||
407 | return BN_mod_mul_montgomery(r, a, &mont->RR, mont, ctx); | 411 | return BN_mod_mul_montgomery(r, a, &mont->RR, mont, ctx); |
408 | } | 412 | } |
409 | 413 | ||
414 | /* | ||
415 | * bn_montgomery_reduce() performs Montgomery reduction, reducing the input | ||
416 | * from its Montgomery form aR to a, returning the result in r. Note that the | ||
417 | * input is mutated in the process of performing the reduction, destroying its | ||
418 | * original value. | ||
419 | */ | ||
410 | static int | 420 | static int |
411 | BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont) | 421 | bn_montgomery_reduce(BIGNUM *r, BIGNUM *a, BN_MONT_CTX *mctx) |
412 | { | 422 | { |
413 | BIGNUM *n; | 423 | BIGNUM *n; |
414 | BN_ULONG *ap, *np, *rp, n0, v, carry; | 424 | BN_ULONG *ap, *rp, n0, v, carry, mask; |
415 | int nl, max, i; | 425 | int i, max, n_len; |
416 | |||
417 | n = &(mont->N); | ||
418 | nl = n->top; | ||
419 | if (nl == 0) { | ||
420 | ret->top = 0; | ||
421 | return (1); | ||
422 | } | ||
423 | 426 | ||
424 | max = (2 * nl); /* carry is stored separately */ | 427 | n = &mctx->N; |
425 | if (!bn_wexpand(r, max)) | 428 | n_len = mctx->N.top; |
426 | return (0); | ||
427 | 429 | ||
428 | BN_set_negative(r, r->neg ^ n->neg); | 430 | if (n_len == 0) { |
429 | np = n->d; | 431 | BN_zero(r); |
430 | rp = r->d; | 432 | return 1; |
433 | } | ||
431 | 434 | ||
432 | /* clear the top words of T */ | 435 | if (!bn_wexpand(r, n_len)) |
433 | #if 1 | 436 | return 0; |
434 | for (i=r->top; i<max; i++) /* memset? XXX */ | 437 | |
435 | rp[i] = 0; | 438 | /* |
436 | #else | 439 | * Expand a to twice the length of the modulus, zero if necessary. |
437 | memset(&(rp[r->top]), 0, (max - r->top) * sizeof(BN_ULONG)); | 440 | * XXX - make this a requirement of the caller. |
438 | #endif | 441 | */ |
442 | if ((max = 2 * n_len) < n_len) | ||
443 | return 0; | ||
444 | if (!bn_wexpand(a, max)) | ||
445 | return 0; | ||
446 | for (i = a->top; i < max; i++) | ||
447 | a->d[i] = 0; | ||
439 | 448 | ||
440 | r->top = max; | 449 | carry = 0; |
441 | n0 = mont->n0[0]; | 450 | n0 = mctx->n0[0]; |
442 | 451 | ||
443 | for (carry = 0, i = 0; i < nl; i++, rp++) { | 452 | /* Add multiples of the modulus, so that it becomes divisable by R. */ |
444 | v = bn_mul_add_words(rp, np, nl, (rp[0] * n0) & BN_MASK2); | 453 | for (i = 0; i < n_len; i++) { |
445 | v = (v + carry + rp[nl]) & BN_MASK2; | 454 | v = bn_mul_add_words(&a->d[i], n->d, n_len, a->d[i] * n0); |
446 | carry |= (v != rp[nl]); | 455 | bn_addw_addw(v, a->d[i + n_len], carry, &carry, |
447 | carry &= (v <= rp[nl]); | 456 | &a->d[i + n_len]); |
448 | rp[nl] = v; | ||
449 | } | 457 | } |
450 | 458 | ||
451 | if (!bn_wexpand(ret, nl)) | 459 | /* Divide by R (this is the equivalent of right shifting by n_len). */ |
452 | return (0); | 460 | ap = &a->d[n_len]; |
453 | ret->top = nl; | 461 | |
454 | BN_set_negative(ret, r->neg); | 462 | /* |
455 | 463 | * The output is now in the range of [0, 2N). Attempt to reduce once by | |
456 | rp = ret->d; | 464 | * subtracting the modulus. If the reduction was necessary then the |
457 | ap = &(r->d[nl]); | 465 | * result is already in r, otherwise copy the value prior to reduction |
458 | 466 | * from the top half of a. | |
459 | #define BRANCH_FREE 1 | 467 | */ |
460 | #if BRANCH_FREE | 468 | mask = carry - bn_sub_words(r->d, ap, n->d, n_len); |
461 | { | 469 | |
462 | BN_ULONG *nrp; | 470 | rp = r->d; |
463 | size_t m; | 471 | for (i = 0; i < n_len; i++) { |
464 | 472 | *rp = (*rp & ~mask) | (*ap & mask); | |
465 | v = bn_sub_words(rp, ap, np, nl) - carry; | 473 | rp++; |
466 | /* if subtraction result is real, then | 474 | ap++; |
467 | * trick unconditional memcpy below to perform in-place | ||
468 | * "refresh" instead of actual copy. */ | ||
469 | m = (0 - (size_t)v); | ||
470 | nrp = (BN_ULONG *)(((uintptr_t)rp & ~m)|((uintptr_t)ap & m)); | ||
471 | |||
472 | for (i = 0, nl -= 4; i < nl; i += 4) { | ||
473 | BN_ULONG t1, t2, t3, t4; | ||
474 | |||
475 | t1 = nrp[i + 0]; | ||
476 | t2 = nrp[i + 1]; | ||
477 | t3 = nrp[i + 2]; | ||
478 | ap[i + 0] = 0; | ||
479 | t4 = nrp[i + 3]; | ||
480 | ap[i + 1] = 0; | ||
481 | rp[i + 0] = t1; | ||
482 | ap[i + 2] = 0; | ||
483 | rp[i + 1] = t2; | ||
484 | ap[i + 3] = 0; | ||
485 | rp[i + 2] = t3; | ||
486 | rp[i + 3] = t4; | ||
487 | } | ||
488 | for (nl += 4; i < nl; i++) | ||
489 | rp[i] = nrp[i], ap[i] = 0; | ||
490 | } | 475 | } |
491 | #else | 476 | r->top = n_len; |
492 | if (bn_sub_words (rp, ap, np, nl) - carry) | 477 | |
493 | memcpy(rp, ap, nl*sizeof(BN_ULONG)); | ||
494 | #endif | ||
495 | bn_correct_top(r); | 478 | bn_correct_top(r); |
496 | bn_correct_top(ret); | ||
497 | 479 | ||
498 | return (1); | 480 | BN_set_negative(r, a->neg ^ n->neg); |
481 | |||
482 | return 1; | ||
499 | } | 483 | } |
500 | 484 | ||
501 | int | 485 | int |
502 | BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, BN_MONT_CTX *mont, BN_CTX *ctx) | 486 | BN_from_montgomery(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mctx, BN_CTX *ctx) |
503 | { | 487 | { |
504 | int retn = 0; | 488 | BIGNUM *tmp; |
505 | BIGNUM *t; | 489 | int ret = 0; |
506 | 490 | ||
507 | BN_CTX_start(ctx); | 491 | BN_CTX_start(ctx); |
508 | if ((t = BN_CTX_get(ctx)) && BN_copy(t, a)) | 492 | |
509 | retn = BN_from_montgomery_word(ret, t, mont); | 493 | if ((tmp = BN_CTX_get(ctx)) == NULL) |
494 | goto err; | ||
495 | if (BN_copy(tmp, a) == NULL) | ||
496 | goto err; | ||
497 | if (!bn_montgomery_reduce(r, tmp, mctx)) | ||
498 | goto err; | ||
499 | |||
500 | ret = 1; | ||
501 | err: | ||
510 | BN_CTX_end(ctx); | 502 | BN_CTX_end(ctx); |
511 | return (retn); | 503 | |
504 | return ret; | ||
512 | } | 505 | } |