Align |BN_div| with its documentation.

Change-Id: Idd0dc9dafb4ea9adbf22257018138c49f7980fee
Reviewed-on: https://boringssl-review.googlesource.com/22604
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
This commit is contained in:
Daniel Hirche 2017-11-03 21:06:33 +01:00 committed by CQ bot account: commit-bot@chromium.org
parent b1cbe19790
commit d5dda9b803

View File

@ -178,28 +178,33 @@ static inline void bn_div_rem_words(BN_ULONG *quotient_out, BN_ULONG *rem_out,
#endif #endif
} }
// BN_div computes dv := num / divisor, rounding towards // BN_div computes "quotient := numerator / divisor", rounding towards zero,
// zero, and sets up rm such that dv*divisor + rm = num holds. // and sets up |rem| such that "quotient * divisor + rem = numerator" holds.
//
// Thus: // Thus:
// dv->neg == num->neg ^ divisor->neg (unless the result is zero) //
// rm->neg == num->neg (unless the remainder is zero) // quotient->neg == numerator->neg ^ divisor->neg
// If 'dv' or 'rm' is NULL, the respective value is not returned. // (unless the result is zero)
// rem->neg == numerator->neg
// (unless the remainder is zero)
//
// If |quotient| or |rem| is NULL, the respective value is not returned.
// //
// This was specifically designed to contain fewer branches that may leak // This was specifically designed to contain fewer branches that may leak
// sensitive information; see "New Branch Prediction Vulnerabilities in OpenSSL // sensitive information; see "New Branch Prediction Vulnerabilities in OpenSSL
// and Necessary Software Countermeasures" by Onur Acıçmez, Shay Gueron, and // and Necessary Software Countermeasures" by Onur Acıçmez, Shay Gueron, and
// Jean-Pierre Seifert. // Jean-Pierre Seifert.
int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
BN_CTX *ctx) { const BIGNUM *divisor, BN_CTX *ctx) {
int norm_shift, i, loop; int norm_shift, loop;
BIGNUM *tmp, wnum, *snum, *sdiv, *res; BIGNUM wnum;
BN_ULONG *resp, *wnump; BN_ULONG *resp, *wnump;
BN_ULONG d0, d1; BN_ULONG d0, d1;
int num_n, div_n; int num_n, div_n;
// Invalid zero-padding would have particularly bad consequences // Invalid zero-padding would have particularly bad consequences
// so don't just rely on bn_check_top() here // so don't just rely on bn_check_top() here
if ((num->top > 0 && num->d[num->top - 1] == 0) || if ((numerator->top > 0 && numerator->d[numerator->top - 1] == 0) ||
(divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) { (divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) {
OPENSSL_PUT_ERROR(BN, BN_R_NOT_INITIALIZED); OPENSSL_PUT_ERROR(BN, BN_R_NOT_INITIALIZED);
return 0; return 0;
@ -211,26 +216,27 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
} }
BN_CTX_start(ctx); BN_CTX_start(ctx);
tmp = BN_CTX_get(ctx); BIGNUM *tmp = BN_CTX_get(ctx);
snum = BN_CTX_get(ctx); BIGNUM *snum = BN_CTX_get(ctx);
sdiv = BN_CTX_get(ctx); BIGNUM *sdiv = BN_CTX_get(ctx);
if (dv == NULL) { BIGNUM *res = NULL;
if (quotient == NULL) {
res = BN_CTX_get(ctx); res = BN_CTX_get(ctx);
} else { } else {
res = dv; res = quotient;
} }
if (sdiv == NULL || res == NULL || tmp == NULL || snum == NULL) { if (sdiv == NULL || res == NULL) {
goto err; goto err;
} }
// First we normalise the numbers // First we normalise the numbers
norm_shift = BN_BITS2 - ((BN_num_bits(divisor)) % BN_BITS2); norm_shift = BN_BITS2 - (BN_num_bits(divisor) % BN_BITS2);
if (!(BN_lshift(sdiv, divisor, norm_shift))) { if (!BN_lshift(sdiv, divisor, norm_shift)) {
goto err; goto err;
} }
sdiv->neg = 0; sdiv->neg = 0;
norm_shift += BN_BITS2; norm_shift += BN_BITS2;
if (!(BN_lshift(snum, num, norm_shift))) { if (!BN_lshift(snum, numerator, norm_shift)) {
goto err; goto err;
} }
snum->neg = 0; snum->neg = 0;
@ -242,7 +248,7 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
if (!bn_wexpand(snum, sdiv->top + 2)) { if (!bn_wexpand(snum, sdiv->top + 2)) {
goto err; goto err;
} }
for (i = snum->top; i < sdiv->top + 2; i++) { for (int i = snum->top; i < sdiv->top + 2; i++) {
snum->d[i] = 0; snum->d[i] = 0;
} }
snum->top = sdiv->top + 2; snum->top = sdiv->top + 2;
@ -275,15 +281,15 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
wnump = &(snum->d[num_n - 1]); wnump = &(snum->d[num_n - 1]);
// Setup to 'res' // Setup to 'res'
res->neg = (num->neg ^ divisor->neg); res->neg = (numerator->neg ^ divisor->neg);
if (!bn_wexpand(res, (loop + 1))) { if (!bn_wexpand(res, loop + 1)) {
goto err; goto err;
} }
res->top = loop - 1; res->top = loop - 1;
resp = &(res->d[loop - 1]); resp = &(res->d[loop - 1]);
// space for temp // space for temp
if (!bn_wexpand(tmp, (div_n + 1))) { if (!bn_wexpand(tmp, div_n + 1)) {
goto err; goto err;
} }
@ -295,11 +301,11 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
resp--; resp--;
} }
for (i = 0; i < loop - 1; i++, wnump--, resp--) { for (int i = 0; i < loop - 1; i++, wnump--, resp--) {
BN_ULONG q, l0; BN_ULONG q, l0;
// the first part of the loop uses the top two words of snum and sdiv to // the first part of the loop uses the top two words of snum and sdiv to
// calculate a BN_ULONG q such that | wnum - sdiv * q | < sdiv // calculate a BN_ULONG q such that | wnum - sdiv * q | < sdiv
BN_ULONG n0, n1, rem = 0; BN_ULONG n0, n1, rm = 0;
n0 = wnump[0]; n0 = wnump[0];
n1 = wnump[-1]; n1 = wnump[-1];
@ -307,18 +313,18 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
q = BN_MASK2; q = BN_MASK2;
} else { } else {
// n0 < d0 // n0 < d0
bn_div_rem_words(&q, &rem, n0, n1, d0); bn_div_rem_words(&q, &rm, n0, n1, d0);
#ifdef BN_ULLONG #ifdef BN_ULLONG
BN_ULLONG t2 = (BN_ULLONG)d1 * q; BN_ULLONG t2 = (BN_ULLONG)d1 * q;
for (;;) { for (;;) {
if (t2 <= ((((BN_ULLONG)rem) << BN_BITS2) | wnump[-2])) { if (t2 <= ((((BN_ULLONG)rm) << BN_BITS2) | wnump[-2])) {
break; break;
} }
q--; q--;
rem += d0; rm += d0;
if (rem < d0) { if (rm < d0) {
break; // don't let rem overflow break; // don't let rm overflow
} }
t2 -= d1; t2 -= d1;
} }
@ -326,13 +332,14 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
BN_ULONG t2l, t2h; BN_ULONG t2l, t2h;
BN_UMULT_LOHI(t2l, t2h, d1, q); BN_UMULT_LOHI(t2l, t2h, d1, q);
for (;;) { for (;;) {
if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2]))) { if (t2h < rm ||
(t2h == rm && t2l <= wnump[-2])) {
break; break;
} }
q--; q--;
rem += d0; rm += d0;
if (rem < d0) { if (rm < d0) {
break; // don't let rem overflow break; // don't let rm overflow
} }
if (t2l < d1) { if (t2l < d1) {
t2h--; t2h--;
@ -363,18 +370,21 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
// store part of the result // store part of the result
*resp = q; *resp = q;
} }
bn_correct_top(snum); bn_correct_top(snum);
if (rm != NULL) {
// Keep a copy of the neg flag in num because if rm==num if (rem != NULL) {
// BN_rshift() will overwrite it. // Keep a copy of the neg flag in numerator because if |rem| == |numerator|
int neg = num->neg; // |BN_rshift| will overwrite it.
if (!BN_rshift(rm, snum, norm_shift)) { int neg = numerator->neg;
if (!BN_rshift(rem, snum, norm_shift)) {
goto err; goto err;
} }
if (!BN_is_zero(rm)) { if (!BN_is_zero(rem)) {
rm->neg = neg; rem->neg = neg;
} }
} }
bn_correct_top(res); bn_correct_top(res);
BN_CTX_end(ctx); BN_CTX_end(ctx);
return 1; return 1;