Rework sp_div to work around static analysis error

Fix _sp_exptmod_mont_ext() to handle when number of bits in exponent is
a multiple of the window size.
This commit is contained in:
Sean Parkinson
2022-08-24 12:31:21 +10:00
parent 3b6124cf34
commit d087cbea1b

View File

@ -7008,6 +7008,158 @@ void sp_rshb(sp_int* a, int n, sp_int* r)
#if defined(WOLFSSL_SP_MATH_ALL) || !defined(NO_DH) || defined(HAVE_ECC) || \
(!defined(NO_RSA) && !defined(WOLFSSL_RSA_VERIFY_ONLY) && \
!defined(WOLFSSL_RSA_PUBLIC_ONLY))
/* Divide a by d and return the quotient in r and the remainder in a.
* r = a / d; a = a % d
*
* @param [in, out] a SP integer to be divided and remainder on out.
* @param [in] d SP integer to divide by.
* @param [out] r SP integer that is the quotient.
* @param [out] trial SP integer that is product in trial division.
*
* @return MP_OKAY on success.
* @return MP_VAL when operation fails - only when compiling small code.
*/
static int _sp_div(sp_int* a, sp_int* d, sp_int* r, sp_int* trial)
{
#ifdef WOLFSSL_SP_SMALL
int c;
#else
int j;
int o;
#ifndef SQR_MUL_ASM
sp_int_sword sw;
#else
sp_int_digit sl;
sp_int_digit sh;
sp_int_digit st;
#endif
#endif /* WOLFSSL_SP_SMALL */
int err = MP_OKAY;
int i;
sp_int_digit t;
sp_int_digit dt;
#ifdef WOLFSSL_SP_INT_NEGATIVE
a->sign = MP_ZPOS;
d->sign = MP_ZPOS;
#endif /* WOLFSSL_SP_INT_NEGATIVE */
r->used = a->used - d->used + 1;
sp_clear(r);
r->used = a->used - d->used + 1;
dt = d->dp[d->used-1];
for (i = d->used - 1; i > 0; i--) {
if (a->dp[a->used - d->used + i] != d->dp[i]) {
break;
}
}
if (a->dp[a->used - d->used + i] >= d->dp[i]) {
i = a->used;
_sp_sub_off(a, d, a, a->used - d->used);
/* Keep the same 'used' so that zeros will be put in. */
a->used = i;
r->dp[a->used - d->used] = 1;
}
for (i = a->used - 1; i >= d->used; i--) {
if (a->dp[i] == dt) {
t = SP_DIGIT_MAX;
}
else {
t = sp_div_word(a->dp[i], a->dp[i-1], dt);
}
#ifdef WOLFSSL_SP_SMALL
do {
err = _sp_mul_d(d, t, trial, i - d->used);
if (err != MP_OKAY) {
break;
}
c = _sp_cmp_abs(trial, a);
if (c == MP_GT) {
t--;
}
}
while (c == MP_GT);
if (err != MP_OKAY) {
break;
}
_sp_sub_off(a, trial, a, 0);
r->dp[i - d->used] += t;
if (r->dp[i - d->used] < t) {
r->dp[i + 1 - d->used]++;
}
#else
o = i - d->used;
do {
#ifndef SQR_MUL_ASM
sp_int_word tw = 0;
#else
sp_int_digit tl = 0;
sp_int_digit th = 0;
#endif
for (j = 0; j < d->used; j++) {
#ifndef SQR_MUL_ASM
tw += (sp_int_word)d->dp[j] * t;
trial->dp[j] = (sp_int_digit)tw;
tw >>= SP_WORD_SIZE;
#else
SP_ASM_MUL_ADD_NO(tl, th, d->dp[j], t);
trial->dp[j] = tl;
tl = th;
th = 0;
#endif
}
#ifndef SQR_MUL_ASM
trial->dp[j] = (sp_int_digit)tw;
#else
trial->dp[j] = tl;
#endif
for (j = d->used; j > 0; j--) {
if (trial->dp[j] != a->dp[j + o]) {
break;
}
}
if (trial->dp[j] > a->dp[j + o]) {
t--;
}
}
while (trial->dp[j] > a->dp[j + o]);
#ifndef SQR_MUL_ASM
sw = 0;
#else
sl = 0;
sh = 0;
#endif
for (j = 0; j <= d->used; j++) {
#ifndef SQR_MUL_ASM
sw += a->dp[j + o];
sw -= trial->dp[j];
a->dp[j + o] = (sp_int_digit)sw;
sw >>= SP_WORD_SIZE;
#else
st = a->dp[j + o];
SP_ASM_ADDC(sl, sh, st);
st = trial->dp[j];
SP_ASM_SUBC(sl, sh, st);
a->dp[j + o] = sl;
sl = sh;
sh = (sp_int_digit)0 - (sl >> (SP_WORD_SIZE - 1));
#endif
}
r->dp[o] = t;
#endif /* WOLFSSL_SP_SMALL */
}
a->used = i + 1;
return err;
}
/* Divide a by d and return the quotient in r and the remainder in rem.
* r = a / d; rem = a % d
*
@ -7028,10 +7180,7 @@ int sp_div(sp_int* a, sp_int* d, sp_int* r, sp_int* rem)
int err = MP_OKAY;
int ret;
int done = 0;
int i;
int s = 0;
sp_int_digit dt;
sp_int_digit t;
sp_int* sa = NULL;
sp_int* sd = NULL;
sp_int* tr = NULL;
@ -7121,52 +7270,61 @@ int sp_div(sp_int* a, sp_int* d, sp_int* r, sp_int* rem)
}
}
/* Allocate temprorary 'sp_int's and assign. */
if ((!done) && (err == MP_OKAY)) {
#if (defined(WOLFSSL_SMALL_STACK) || defined(SP_ALLOC)) && \
!defined(WOLFSSL_SP_NO_MALLOC)
#if (defined(WOLFSSL_SMALL_STACK) || defined(SP_ALLOC)) && \
!defined(WOLFSSL_SP_NO_MALLOC)
int cnt = 4;
/* Resuse where possible. */
if ((rem != NULL) && (rem != d) && (rem->size > a->used)) {
sa = rem;
cnt--;
}
if ((r != NULL) && (r != d)) {
tr = r;
cnt--;
}
/* Macro always has code associated with it and checks err first. */
ALLOC_SP_INT_ARRAY(td, a->used + 1, cnt, err, NULL);
#else
#else
ALLOC_SP_INT_ARRAY(td, a->used + 1, 4, err, NULL);
#endif
#endif
}
if ((!done) && (err == MP_OKAY)) {
sd = td[0];
trial = td[1];
#if (defined(WOLFSSL_SMALL_STACK) || defined(SP_ALLOC)) && \
!defined(WOLFSSL_SP_NO_MALLOC)
i = 2;
sa = ((rem != NULL) && (rem != d) && (rem->size > a->used)) ? rem :
td[i++];
tr = ((r != NULL) && (r != d)) ? r : td[i];
#else
#if (defined(WOLFSSL_SMALL_STACK) || defined(SP_ALLOC)) && \
!defined(WOLFSSL_SP_NO_MALLOC)
int i = 2;
/* Set to temporary when not reusing. */
if (sa == NULL) {
sa = td[i++];
}
if (tr == NULL) {
tr = td[i];
}
#else
sa = td[2];
tr = td[3];
#endif
#endif
sd = td[0];
trial = td[1];
sp_init_size(sd, d->used + 1);
sp_init_size(trial, a->used + 1);
#if (defined(WOLFSSL_SMALL_STACK) || defined(SP_ALLOC)) && \
!defined(WOLFSSL_SP_NO_MALLOC)
#if (defined(WOLFSSL_SMALL_STACK) || defined(SP_ALLOC)) && \
!defined(WOLFSSL_SP_NO_MALLOC)
if (sa != rem) {
sp_init_size(sa, a->used + 1);
}
if (tr != r) {
sp_init_size(tr, a->used - d->used + 2);
}
#else
#else
sp_init_size(sa, a->used + 1);
sp_init_size(tr, a->used - d->used + 2);
#endif
#endif
/* Move divisor to top of word. Adjust dividend as well. */
s = sp_count_bits(d);
s = SP_WORD_SIZE - (s & SP_WORD_MASK);
sp_copy(a, sa);
@ -7180,165 +7338,37 @@ int sp_div(sp_int* a, sp_int* d, sp_int* r, sp_int* rem)
}
}
if ((!done) && (err == MP_OKAY) && (d->used > 0)) {
#ifdef WOLFSSL_SP_SMALL
int c;
#else
int j;
int o;
#ifndef SQR_MUL_ASM
sp_int_sword sw;
#else
sp_int_digit sl;
sp_int_digit sh;
sp_int_digit st;
#endif
#endif /* WOLFSSL_SP_SMALL */
#ifdef WOLFSSL_SP_INT_NEGATIVE
sa->sign = MP_ZPOS;
sd->sign = MP_ZPOS;
#endif /* WOLFSSL_SP_INT_NEGATIVE */
tr->used = sa->used - d->used + 1;
sp_clear(tr);
tr->used = sa->used - d->used + 1;
dt = d->dp[d->used-1];
for (i = d->used - 1; i > 0; i--) {
if (sa->dp[sa->used - d->used + i] != d->dp[i]) {
break;
}
}
if (sa->dp[sa->used - d->used + i] >= d->dp[i]) {
i = sa->used;
_sp_sub_off(sa, d, sa, sa->used - d->used);
/* Keep the same used so that 0 zeros will be put in. */
sa->used = i;
if (r != NULL) {
tr->dp[sa->used - d->used] = 1;
}
}
for (i = sa->used - 1; i >= d->used; i--) {
if (sa->dp[i] == dt) {
t = SP_DIGIT_MAX;
}
else {
t = sp_div_word(sa->dp[i], sa->dp[i-1], dt);
}
#ifdef WOLFSSL_SP_SMALL
do {
err = _sp_mul_d(d, t, trial, i - d->used);
if (err != MP_OKAY) {
break;
}
c = _sp_cmp_abs(trial, sa);
if (c == MP_GT) {
t--;
}
}
while (c == MP_GT);
if (err != MP_OKAY) {
break;
}
_sp_sub_off(sa, trial, sa, 0);
tr->dp[i - d->used] += t;
if (tr->dp[i - d->used] < t) {
tr->dp[i + 1 - d->used]++;
}
#else
o = i - d->used;
do {
#ifndef SQR_MUL_ASM
sp_int_word tw = 0;
#else
sp_int_digit tl = 0;
sp_int_digit th = 0;
#endif
for (j = 0; j < d->used; j++) {
#ifndef SQR_MUL_ASM
tw += (sp_int_word)d->dp[j] * t;
trial->dp[j] = (sp_int_digit)tw;
tw >>= SP_WORD_SIZE;
#else
SP_ASM_MUL_ADD_NO(tl, th, d->dp[j], t);
trial->dp[j] = tl;
tl = th;
th = 0;
#endif
}
#ifndef SQR_MUL_ASM
trial->dp[j] = (sp_int_digit)tw;
#else
trial->dp[j] = tl;
#endif
for (j = d->used; j > 0; j--) {
if (trial->dp[j] != sa->dp[j + o]) {
break;
}
}
if (trial->dp[j] > sa->dp[j + o]) {
t--;
}
}
while (trial->dp[j] > sa->dp[j + o]);
#ifndef SQR_MUL_ASM
sw = 0;
#else
sl = 0;
sh = 0;
#endif
for (j = 0; j <= d->used; j++) {
#ifndef SQR_MUL_ASM
sw += sa->dp[j + o];
sw -= trial->dp[j];
sa->dp[j + o] = (sp_int_digit)sw;
sw >>= SP_WORD_SIZE;
#else
st = sa->dp[j + o];
SP_ASM_ADDC(sl, sh, st);
st = trial->dp[j];
SP_ASM_SUBC(sl, sh, st);
sa->dp[j + o] = sl;
sl = sh;
sh = (sp_int_digit)0 - (sl >> (SP_WORD_SIZE - 1));
#endif
}
tr->dp[o] = t;
#endif /* WOLFSSL_SP_SMALL */
}
sa->used = i + 1;
/* Do division: tr = sa / d, sa = sa % d. */
err = _sp_div(sa, d, tr, trial);
/* Return the remainder if required. */
if ((err == MP_OKAY) && (rem != NULL)) {
#ifdef WOLFSSL_SP_INT_NEGATIVE
#ifdef WOLFSSL_SP_INT_NEGATIVE
sa->sign = (sa->used == 0) ? MP_ZPOS : aSign;
#endif /* WOLFSSL_SP_INT_NEGATIVE */
#endif /* WOLFSSL_SP_INT_NEGATIVE */
/* Move result back down if moved up for divisor value. */
if (s != SP_WORD_SIZE) {
sp_rshb(sa, s, sa);
}
sp_copy(sa, rem);
sp_clamp(rem);
#ifdef WOLFSSL_SP_INT_NEGATIVE
#ifdef WOLFSSL_SP_INT_NEGATIVE
if (sp_iszero(rem)) {
rem->sign = MP_ZPOS;
}
#endif
#endif
}
/* Return the quotient if required. */
if ((err == MP_OKAY) && (r != NULL)) {
sp_copy(tr, r);
sp_clamp(r);
#ifdef WOLFSSL_SP_INT_NEGATIVE
#ifdef WOLFSSL_SP_INT_NEGATIVE
if (sp_iszero(r)) {
r->sign = MP_ZPOS;
}
else {
r->sign = (aSign == dSign) ? MP_ZPOS : MP_NEG;
}
#endif /* WOLFSSL_SP_INT_NEGATIVE */
#endif /* WOLFSSL_SP_INT_NEGATIVE */
}
}
@ -11044,7 +11074,12 @@ static int _sp_exptmod_mont_ex(sp_int* b, sp_int* e, int bits, sp_int* m,
if (c == 0) {
c = SP_WORD_SIZE;
}
c -= bits % winBits;
if ((bits % winBits) != 0) {
c -= bits % winBits;
}
else {
c -= winBits;
}
y = (int)(n >> c);
n <<= SP_WORD_SIZE - c;
/* Copy window number for top bits. */