Skip to content

Commit 153176a

Browse files
committed
Add BoxedUint::shl_vartime
1 parent 162c91a commit 153176a

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

src/uint/boxed.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod cmp;
88
pub(crate) mod encoding;
99
mod modular;
1010
mod mul;
11+
mod shl;
1112
mod sub;
1213
mod sub_mod;
1314

src/uint/boxed/shl.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//! [`BoxedUint`] bitwise left shift operations.
2+
3+
use crate::{BoxedUint, Limb, Word};
4+
5+
impl BoxedUint {
6+
/// Computes `self << shift` where `0 <= shift < Limb::BITS`,
7+
/// returning the result and the carry.
8+
#[inline(always)]
9+
pub(crate) fn shl_limb(&self, n: usize) -> (Self, Limb) {
10+
let nlimbs = self.nlimbs();
11+
let mut limbs = vec![Limb::ZERO; nlimbs].into_boxed_slice();
12+
13+
let nz = Limb(n as Word).ct_is_nonzero();
14+
let lshift = n as Word;
15+
let rshift = Limb::ct_select(Limb::ZERO, Limb((Limb::BITS - n) as Word), nz).0;
16+
let carry = Limb::ct_select(
17+
Limb::ZERO,
18+
Limb(self.limbs[nlimbs - 1].0.wrapping_shr(Word::BITS - n as u32)),
19+
nz,
20+
);
21+
22+
let mut i = nlimbs - 1;
23+
while i > 0 {
24+
let mut limb = self.limbs[i].0 << lshift;
25+
let hi = self.limbs[i - 1].0 >> rshift;
26+
limb |= nz.if_true(hi);
27+
limbs[i] = Limb(limb);
28+
i -= 1
29+
}
30+
limbs[0] = Limb(self.limbs[0].0 << lshift);
31+
32+
(Self { limbs }, carry)
33+
}
34+
35+
/// Computes `self << shift`.
36+
///
37+
/// NOTE: this operation is variable time with respect to `n` *ONLY*.
38+
///
39+
/// When used with a fixed `n`, this function is constant-time with respect
40+
/// to `self`.
41+
#[inline(always)]
42+
pub fn shl_vartime(&self, n: usize) -> Self {
43+
let nlimbs = self.nlimbs();
44+
let mut limbs = vec![Limb::ZERO; nlimbs].into_boxed_slice();
45+
46+
if n >= Limb::BITS * nlimbs {
47+
return Self { limbs };
48+
}
49+
50+
let shift_num = n / Limb::BITS;
51+
let rem = n % Limb::BITS;
52+
53+
let mut i = nlimbs;
54+
while i > shift_num {
55+
i -= 1;
56+
limbs[i] = self.limbs[i - shift_num];
57+
}
58+
59+
let (new_lower, _carry) = (Self { limbs }).shl_limb(rem);
60+
new_lower
61+
}
62+
}
63+
64+
#[cfg(test)]
65+
mod tests {
66+
use super::BoxedUint;
67+
68+
#[test]
69+
fn shl_vartime() {
70+
let one = BoxedUint::one_with_precision(128);
71+
72+
assert_eq!(BoxedUint::from(2u8), one.shl_vartime(1));
73+
assert_eq!(BoxedUint::from(4u8), one.shl_vartime(2));
74+
assert_eq!(
75+
BoxedUint::from(0x80000000000000000u128),
76+
one.shl_vartime(67)
77+
);
78+
}
79+
}

0 commit comments

Comments
 (0)