Skip to content

Commit bc53cfe

Browse files
authored
BoxedResidue: use conditional assignment in pow (#393)
Changes `BoxedUint::conditional_assign` to actually be an in-place operation rather than allocating, and uses it to impl `BoxedResidue::pow`. This leads to a fairly significant performance increase. Montgomery arithmetic/modpow, BoxedUint^BoxedUint time: [27.769 µs 27.798 µs 27.830 µs] change: [-39.063% -38.898% -38.724%] (p = 0.00 < 0.05) Performance has improved.
1 parent 6f71ecb commit bc53cfe

File tree

2 files changed

+12
-14
lines changed

2 files changed

+12
-14
lines changed

src/modular/boxed_residue/pow.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,9 @@ fn pow_montgomery_form(
6161
// powers[i] contains x^i
6262
let mut powers = vec![r.clone(); 1 << WINDOW];
6363
powers[1] = x.clone();
64-
let mut i = 2;
65-
while i < powers.len() {
64+
65+
for i in 2..powers.len() {
6666
powers[i] = mul_montgomery_form(&powers[i - 1], x, modulus, mod_neg_inv);
67-
i += 1;
6867
}
6968

7069
let starting_limb = ((exponent_bits - 1) / Limb::BITS) as usize;
@@ -74,16 +73,15 @@ fn pow_montgomery_form(
7473

7574
let mut z = r.clone(); // 1 in Montgomery form
7675

77-
let mut limb_num = starting_limb + 1;
78-
while limb_num > 0 {
79-
limb_num -= 1;
76+
for limb_num in (0..=starting_limb).rev() {
8077
let w = exponent.as_limbs()[limb_num].0;
8178

8279
let mut window_num = if limb_num == starting_limb {
8380
starting_window + 1
8481
} else {
8582
Limb::BITS / WINDOW
8683
};
84+
8785
while window_num > 0 {
8886
window_num -= 1;
8987

@@ -92,19 +90,15 @@ fn pow_montgomery_form(
9290
if limb_num == starting_limb && window_num == starting_window {
9391
idx &= starting_window_mask;
9492
} else {
95-
let mut i = 0;
96-
while i < WINDOW {
97-
i += 1;
93+
for _ in 1..=WINDOW {
9894
square_montgomery_form_assign(&mut z, modulus, mod_neg_inv);
9995
}
10096
}
10197

10298
// Constant-time lookup in the array of powers
10399
let mut power = powers[0].clone();
104-
let mut i = 1;
105-
while i < 1 << WINDOW {
106-
power = BoxedUint::conditional_select(&power, &powers[i as usize], i.ct_eq(&idx));
107-
i += 1;
100+
for i in 1..(1 << WINDOW) {
101+
power.conditional_assign(&powers[i as usize], i.ct_eq(&idx));
108102
}
109103

110104
mul_montgomery_form_assign(&mut z, &power, modulus, mod_neg_inv);

src/uint/boxed.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,11 @@ impl BoxedUint {
210210
/// This function should execute in constant time.
211211
#[inline]
212212
pub fn conditional_assign(&mut self, other: &Self, choice: Choice) {
213-
*self = Self::conditional_select(self, other, choice);
213+
debug_assert_eq!(self.bits_precision(), other.bits_precision());
214+
215+
for i in 0..self.nlimbs() {
216+
self.limbs[i] = Limb::conditional_select(&self.limbs[i], &other.limbs[i], choice);
217+
}
214218
}
215219

216220
/// Conditionally swap `self` and `other` if `choice == 1`; otherwise,

0 commit comments

Comments
 (0)