Add bn_usub_fixed.

There are a number of random subtractions in RSA key generation. Add a
fixed-width version.

Median of 29 RSA keygens: 0m0.859s -> 0m0.811s
(Accuracy beyond 0.1s is questionable.)

Bug: 238
Change-Id: I9fa0771b95a438fd7d2635fd77a332146ccc96d9
Reviewed-on: https://boringssl-review.googlesource.com/25884
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
David Benjamin 2018-02-03 19:43:33 -05:00 committed by Adam Langley
parent d89d65ba12
commit ad066861dd
2 changed files with 34 additions and 54 deletions

View File

@ -223,69 +223,45 @@ int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
return 1;
}
int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
int max, min, dif;
register BN_ULONG t1, t2, *ap, *bp, *rp;
int i, carry;
int bn_usub_fixed(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
// |b| may have more words than |a| given non-minimal inputs, but all words
// beyond |a->width| must then be zero.
int b_width = b->width;
if (b_width > a->width) {
if (!bn_fits_in_words(b, a->width)) {
OPENSSL_PUT_ERROR(BN, BN_R_ARG2_LT_ARG3);
return 0;
}
b_width = a->width;
}
max = bn_minimal_width(a);
min = bn_minimal_width(b);
dif = max - min;
if (!bn_wexpand(r, a->width)) {
return 0;
}
if (dif < 0) // hmm... should not be happening
{
BN_ULONG borrow = bn_sub_words(r->d, a->d, b->d, b_width);
for (int i = b_width; i < a->width; i++) {
// |r| and |a| may alias, so use a temporary.
BN_ULONG tmp = a->d[i];
r->d[i] = a->d[i] - borrow;
borrow = tmp < r->d[i];
}
if (borrow) {
OPENSSL_PUT_ERROR(BN, BN_R_ARG2_LT_ARG3);
return 0;
}
if (!bn_wexpand(r, max)) {
r->width = a->width;
r->neg = 0;
return 1;
}
int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
if (!bn_usub_fixed(r, a, b)) {
return 0;
}
ap = a->d;
bp = b->d;
rp = r->d;
carry = 0;
for (i = min; i != 0; i--) {
t1 = *(ap++);
t2 = *(bp++);
if (carry) {
carry = (t1 <= t2);
t1 -= t2 + 1;
} else {
carry = (t1 < t2);
t1 -= t2;
}
*(rp++) = t1;
}
if (carry) // subtracted
{
if (!dif) {
// error: a < b
return 0;
}
while (dif) {
dif--;
t1 = *(ap++);
t2 = t1 - 1;
*(rp++) = t2;
if (t1) {
break;
}
}
}
if (dif > 0 && rp != ap) {
OPENSSL_memcpy(rp, ap, sizeof(*rp) * dif);
}
r->width = max;
r->neg = 0;
bn_set_minimal_width(r);
return 1;
}

View File

@ -366,6 +366,10 @@ int bn_less_than_montgomery_R(const BIGNUM *bn, const BN_MONT_CTX *mont);
// |r->width| = |a->width| + |b->width| + 1.
int bn_uadd_fixed(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
// bn_usub_fixed behaves like |BN_usub|, but it pessimally sets
// |r->width| = |a->width|.
int bn_usub_fixed(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
// bn_mul_fixed behaves like |BN_mul|, but it rejects negative inputs and
// pessimally sets |r->width| to |a->width| + |b->width|, to avoid leaking
// information about |a| and |b|.