1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

mpint_rshift_safe: stop using variable bit shifts.

I've decided not to trust register-controlled shift operations to be
time-constant after all. They're surely fine on nice fast machines
where everything simple takes one cycle, but stranger machines,
perhaps not. In which case, I should avoid using them in the mpint
shift operation that's supposed not to reveal the shift count.
This commit is contained in:
Simon Tatham 2019-01-13 21:50:15 +00:00
parent ced0f19118
commit c9f673ac12

30
mpint.c
View File

@ -1112,19 +1112,14 @@ mp_int *mp_rshift_safe(mp_int *x, size_t bits)
/*
* That's done the shifting by words; now we do the shifting by
* bits.
*
* I assume here that register-controlled right shifts are
* time-constant. If they're not, I could replace this with
* another loop over bit positions.
*/
size_t upshift = BIGNUM_INT_BITS - bitshift;
size_t no_shift = (upshift >> BIGNUM_INT_BITS_BITS);
upshift &= ~-(size_t)no_shift;
BignumInt upshifted_mask = ~-(BignumInt)no_shift;
for (size_t i = 0; i < r->nw; i++) {
r->w[i] = (r->w[i] >> bitshift) |
((mp_word(r, i+1) << upshift) & upshifted_mask);
for (unsigned bit = 0; bit < BIGNUM_INT_BITS_BITS; bit++) {
unsigned shift = 1 << bit, upshift = BIGNUM_INT_BITS - shift;
BignumInt mask = -(BignumInt)((bitshift >> bit) & 1);
for (size_t i = 0; i < r->nw; i++) {
BignumInt w = ((r->w[i] >> shift) | (mp_word(r, i+1) << upshift));
r->w[i] ^= (r->w[i] ^ w) & mask;
}
}
return r;
@ -1863,12 +1858,11 @@ void mp_divmod_into(mp_int *n, mp_int *d, mp_int *q_out, mp_int *r_out)
* actual input will be close to a fixed power of two regardless
* of where the MSB was.
*
* I do this in another log n individual passes, not so much
* because I'm worried about the time-invariance of the CPU's
* register-controlled shift operation, but in case the compiler
* code-generates uint64_t shifts out of a variable number of
* smaller-word shift instructions, e.g. by splitting up into
* cases.
* I do this in another log n individual passes, partly in case
* the CPU's register-controlled shift operation isn't
* time-constant, and also in case the compiler code-generates
* uint64_t shifts out of a variable number of smaller-word shift
* instructions, e.g. by splitting up into cases.
*/
for (size_t i = BIGNUM_INT_BITS_BITS; i-- > 0;) {
size_t sl = 1 << i; /* left shift count */