Skip to content

Commit 9d7f946

Browse files
committed
Some simplifications of vartime division
1 parent edf1f46 commit 9d7f946

File tree

3 files changed

+224
-190
lines changed

3 files changed

+224
-190
lines changed

src/uint/boxed/div.rs

Lines changed: 64 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,42 @@ impl RemLimb for BoxedUint {
310310
}
311311
}
312312

313+
/// Computes `limbs << shift` inplace, where `0 <= shift < Limb::BITS`, returning the carry.
314+
fn shl_limb_vartime(limbs: &mut [Limb], shift: u32) -> Limb {
315+
if shift == 0 {
316+
return Limb::ZERO;
317+
}
318+
319+
let lshift = shift;
320+
let rshift = Limb::BITS - shift;
321+
let limbs_num = limbs.len();
322+
323+
let carry = limbs[limbs_num - 1] >> rshift;
324+
for i in (1..limbs_num).rev() {
325+
limbs[i] = (limbs[i] << lshift) | (limbs[i - 1] >> rshift);
326+
}
327+
limbs[0] <<= lshift;
328+
329+
carry
330+
}
331+
332+
/// Computes `limbs >> shift` inplace, where `0 <= shift < Limb::BITS`.
333+
fn shr_limb_vartime(limbs: &mut [Limb], shift: u32) {
334+
if shift == 0 {
335+
return;
336+
}
337+
338+
let lshift = Limb::BITS - shift;
339+
let rshift = shift;
340+
341+
let limbs_num = limbs.len();
342+
343+
for i in 0..limbs_num - 1 {
344+
limbs[i] = (limbs[i] >> rshift) | (limbs[i + 1] << lshift);
345+
}
346+
limbs[limbs_num - 1] >>= rshift;
347+
}
348+
313349
/// Computes `x` / `y`, returning the quotient in `x` and the remainder in `y`.
314350
///
315351
/// This function operates in variable-time. It will panic if the divisor is zero
@@ -336,51 +372,44 @@ pub(crate) fn div_rem_vartime_in_place(x: &mut [Limb], y: &mut [Limb]) {
336372
}
337373

338374
let lshift = y[yc - 1].leading_zeros();
339-
let rshift = if lshift == 0 { 0 } else { Limb::BITS - lshift };
340-
let mut x_hi = Limb::ZERO;
341-
let mut carry;
342-
343-
if lshift != 0 {
344-
// Shift divisor such that it has no leading zeros
345-
// This means that div2by1 requires no extra shifts, and ensures that the high word >= b/2
346-
carry = Limb::ZERO;
347-
for i in 0..yc {
348-
(y[i], carry) = (Limb((y[i].0 << lshift) | carry.0), Limb(y[i].0 >> rshift));
349-
}
350375

351-
// Shift the dividend to match
352-
carry = Limb::ZERO;
353-
for i in 0..xc {
354-
(x[i], carry) = (Limb((x[i].0 << lshift) | carry.0), Limb(x[i].0 >> rshift));
355-
}
356-
x_hi = carry;
357-
}
376+
// Shift divisor such that it has no leading zeros
377+
// This means that div2by1 requires no extra shifts, and ensures that the high word >= b/2
378+
shl_limb_vartime(y, lshift);
379+
380+
// Shift the dividend to match
381+
let mut x_hi = shl_limb_vartime(x, lshift);
358382

359383
let reciprocal = Reciprocal::new(y[yc - 1].to_nz().expect("zero divisor"));
360384

361385
for xi in (yc - 1..xc).rev() {
362386
// Divide high dividend words by the high divisor word to estimate the quotient word
363-
let (mut quo, _) = div3by2(x_hi.0, x[xi].0, x[xi - 1].0, &reciprocal, y[yc - 2].0);
387+
let mut quo = div3by2(x_hi.0, x[xi].0, x[xi - 1].0, &reciprocal, y[yc - 2].0);
364388

365389
// Subtract q*divisor from the dividend
366-
carry = Limb::ZERO;
367-
let mut borrow = Limb::ZERO;
368-
let mut tmp;
369-
for i in 0..yc {
370-
(tmp, carry) = Limb::ZERO.mac(y[i], Limb(quo), carry);
371-
(x[xi + i + 1 - yc], borrow) = x[xi + i + 1 - yc].sbb(tmp, borrow);
372-
}
373-
(_, borrow) = x_hi.sbb(carry, borrow);
390+
let borrow = {
391+
let mut carry = Limb::ZERO;
392+
let mut borrow = Limb::ZERO;
393+
let mut tmp;
394+
for i in 0..yc {
395+
(tmp, carry) = Limb::ZERO.mac(y[i], Limb(quo), carry);
396+
(x[xi + i + 1 - yc], borrow) = x[xi + i + 1 - yc].sbb(tmp, borrow);
397+
}
398+
(_, borrow) = x_hi.sbb(carry, borrow);
399+
borrow
400+
};
374401

375402
// If the subtraction borrowed, then decrement q and add back the divisor
376403
// The probability of this being needed is very low, about 2/(Limb::MAX+1)
377-
let ct_borrow = ConstChoice::from_word_mask(borrow.0);
378-
carry = Limb::ZERO;
379-
for i in 0..yc {
380-
(x[xi + i + 1 - yc], carry) =
381-
x[xi + i + 1 - yc].adc(Limb::select(Limb::ZERO, y[i], ct_borrow), carry);
382-
}
383-
quo = ct_borrow.select_word(quo, quo.saturating_sub(1));
404+
quo = {
405+
let ct_borrow = ConstChoice::from_word_mask(borrow.0);
406+
let mut carry = Limb::ZERO;
407+
for i in 0..yc {
408+
(x[xi + i + 1 - yc], carry) =
409+
x[xi + i + 1 - yc].adc(Limb::select(Limb::ZERO, y[i], ct_borrow), carry);
410+
}
411+
ct_borrow.select_word(quo, quo.saturating_sub(1))
412+
};
384413

385414
// Store the quotient within dividend and set x_hi to the current highest word
386415
x_hi = x[xi];
@@ -392,12 +421,7 @@ pub(crate) fn div_rem_vartime_in_place(x: &mut [Limb], y: &mut [Limb]) {
392421
y[yc - 1] = x_hi;
393422

394423
// Unshift the remainder from the earlier adjustment
395-
if lshift != 0 {
396-
carry = Limb::ZERO;
397-
for i in (0..yc).rev() {
398-
(y[i], carry) = (Limb((y[i].0 >> lshift) | carry.0), Limb(y[i].0 << rshift));
399-
}
400-
}
424+
shr_limb_vartime(y, lshift);
401425

402426
// Shift the quotient to the low limbs within dividend
403427
// let x_size = xc - yc + 1;

0 commit comments

Comments
 (0)