Skip to content

Commit 8263c76

Browse files
authored
BoxedUint: use Limbs in montgomery_mul (#410)
This was previously written using raw `Word`s to ensure maximum performance, however it precludes access to the constant-time helper functions implemented on `Limb`. This carefully rewrites the implementation to using `Limb` instead of `Word` while avoiding any performance impacts.
1 parent b02bfc7 commit 8263c76

File tree

1 file changed

+27
-26
lines changed
  • src/modular/boxed_residue

1 file changed

+27
-26
lines changed

src/modular/boxed_residue/mul.rs

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
//! Originally (c) 2014 The Rust Project Developers, dual licensed Apache 2.0+MIT.
77
88
use super::{BoxedResidue, BoxedResidueParams};
9-
use crate::{traits::Square, BoxedUint, Limb, WideWord, Word};
9+
use crate::{traits::Square, BoxedUint, Limb, WideWord, Word, Zero};
1010
use core::{
1111
borrow::Borrow,
1212
ops::{Mul, MulAssign},
1313
};
14-
use subtle::{ConditionallySelectable, ConstantTimeEq};
14+
use subtle::ConditionallySelectable;
1515

1616
#[cfg(feature = "zeroize")]
1717
use zeroize::Zeroize;
@@ -129,11 +129,11 @@ impl<'a> MontgomeryMultiplier<'a> {
129129

130130
self.clear_product();
131131
montgomery_mul(
132-
self.product.as_words_mut(),
133-
a.as_words(),
134-
b.as_words(),
135-
self.modulus.as_words(),
136-
self.mod_neg_inv.into(),
132+
self.product.as_limbs_mut(),
133+
a.as_limbs(),
134+
b.as_limbs(),
135+
self.modulus.as_limbs(),
136+
self.mod_neg_inv,
137137
);
138138
a.limbs
139139
.copy_from_slice(&self.product.limbs[..a.limbs.len()]);
@@ -152,11 +152,11 @@ impl<'a> MontgomeryMultiplier<'a> {
152152

153153
self.clear_product();
154154
montgomery_mul(
155-
self.product.as_words_mut(),
156-
a.as_words(),
157-
a.as_words(),
158-
self.modulus.as_words(),
159-
self.mod_neg_inv.into(),
155+
self.product.as_limbs_mut(),
156+
a.as_limbs(),
157+
a.as_limbs(),
158+
self.modulus.as_limbs(),
159+
self.mod_neg_inv,
160160
);
161161
a.limbs
162162
.copy_from_slice(&self.product.limbs[..a.limbs.len()]);
@@ -192,7 +192,7 @@ impl Drop for MontgomeryMultiplier<'_> {
192192
/// Note: this was adapted from an implementation in `num-bigint`'s `monty.rs`.
193193
// TODO(tarcieri): refactor into `reduction.rs`, share impl with `(Dyn)Residue`?
194194
#[cfg(feature = "alloc")]
195-
fn montgomery_mul(z: &mut [Word], x: &[Word], y: &[Word], m: &[Word], k: Word) {
195+
fn montgomery_mul(z: &mut [Limb], x: &[Limb], y: &[Limb], m: &[Limb], k: Limb) {
196196
// This code assumes x, y, m are all the same length (required by addMulVVW and the for loop).
197197
// It also assumes that x, y are already reduced mod m, or else the result will not be properly
198198
// reduced.
@@ -202,7 +202,7 @@ fn montgomery_mul(z: &mut [Word], x: &[Word], y: &[Word], m: &[Word], k: Word) {
202202
debug_assert_eq!(y.len(), n);
203203
debug_assert_eq!(m.len(), n);
204204

205-
let mut c: Word = 0;
205+
let mut c = Limb::ZERO;
206206

207207
for i in 0..n {
208208
let c2 = add_mul_vvw(&mut z[i..n + i], x, y[i]);
@@ -213,24 +213,24 @@ fn montgomery_mul(z: &mut [Word], x: &[Word], y: &[Word], m: &[Word], k: Word) {
213213
z[n + i] = cy;
214214

215215
// TODO(tarcieri): eliminate data-dependent branches
216-
c = (cx < c2 || cy < c3) as Word;
216+
c = Limb((cx.0 < c2.0 || cy.0 < c3.0) as Word);
217217
}
218218

219219
let (lower, upper) = z.split_at_mut(n);
220220
sub_vv(lower, upper, m);
221221

222-
let is_zero = c.ct_eq(&0);
222+
let is_zero = c.is_zero();
223223
for (a, b) in lower.iter_mut().zip(upper.iter()) {
224224
a.conditional_assign(b, is_zero);
225225
}
226226
}
227227

228228
#[inline]
229-
fn add_mul_vvw(z: &mut [Word], x: &[Word], y: Word) -> Word {
230-
let mut c = 0;
229+
fn add_mul_vvw(z: &mut [Limb], x: &[Limb], y: Limb) -> Limb {
230+
let mut c = Limb::ZERO;
231231
for (zi, xi) in z.iter_mut().zip(x.iter()) {
232232
let (z1, z0) = mul_add_www(*xi, y, *zi);
233-
let (c_, zi_) = add_ww(z0, c, 0);
233+
let (c_, zi_) = add_ww(Limb(z0.0), c, Limb::ZERO);
234234
*zi = zi_;
235235
c = c_.wrapping_add(z1);
236236
}
@@ -240,8 +240,8 @@ fn add_mul_vvw(z: &mut [Word], x: &[Word], y: Word) -> Word {
240240

241241
/// The resulting carry c is either 0 or 1.
242242
#[inline(always)]
243-
fn sub_vv(z: &mut [Word], x: &[Word], y: &[Word]) -> Word {
244-
let mut c = 0;
243+
fn sub_vv(z: &mut [Limb], x: &[Limb], y: &[Limb]) -> Limb {
244+
let mut c = Limb::ZERO;
245245
for (i, (&xi, &yi)) in x.iter().zip(y.iter()).enumerate().take(z.len()) {
246246
let zi = xi.wrapping_sub(yi).wrapping_sub(c);
247247
z[i] = zi;
@@ -254,16 +254,17 @@ fn sub_vv(z: &mut [Word], x: &[Word], y: &[Word]) -> Word {
254254

255255
/// z1<<_W + z0 = x+y+c, with c == 0 or 1
256256
#[inline(always)]
257-
fn add_ww(x: Word, y: Word, c: Word) -> (Word, Word) {
257+
fn add_ww(x: Limb, y: Limb, c: Limb) -> (Limb, Limb) {
258258
let yc = y.wrapping_add(c);
259259
let z0 = x.wrapping_add(yc);
260-
let z1 = (z0 < x || yc < y) as Word;
260+
// TODO(tarcieri): eliminate data-dependent branches
261+
let z1 = Limb((z0.0 < x.0 || yc.0 < y.0) as Word);
261262
(z1, z0)
262263
}
263264

264265
/// z1 << _W + z0 = x * y + c
265266
#[inline]
266-
fn mul_add_www(x: Word, y: Word, c: Word) -> (Word, Word) {
267-
let z = x as WideWord * y as WideWord + c as WideWord;
268-
((z >> Word::BITS) as Word, z as Word)
267+
fn mul_add_www(x: Limb, y: Limb, c: Limb) -> (Limb, Limb) {
268+
let z = x.0 as WideWord * y.0 as WideWord + c.0 as WideWord;
269+
(Limb((z >> Word::BITS) as Word), Limb(z as Word))
269270
}

0 commit comments

Comments
 (0)