Skip to content

Commit cc3f984

Browse files
authored
BoxedUint: optimize shr_assign (#429)
Allows `shl_assign` to operate in-place on `self` (although it still requires a temporary buffer), ala what #423 did for `shl_assign`
1 parent 63a15e0 commit cc3f984

File tree

2 files changed

+22
-11
lines changed

2 files changed

+22
-11
lines changed

src/uint/boxed/shl.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@ impl BoxedUint {
1717

1818
/// Computes `self <<= shift`.
1919
///
20-
/// Returns a zero and a truthy `Choice` if `shift >= self.bits_precision()`,
21-
/// or a falsy `Choice` otherwise.
22-
fn overflowing_shl_assign(&mut self, shift: u32) -> Choice {
20+
/// Returns a truthy `Choice` if `shift >= self.bits_precision()` or a falsy `Choice` otherwise.
21+
pub fn overflowing_shl_assign(&mut self, shift: u32) -> Choice {
2322
// `floor(log2(bits_precision - 1))` is the number of bits in the representation of `shift`
2423
// (which lies in range `0 <= shift < bits_precision`).
2524
let shift_bits = u32::BITS - (self.bits_precision() - 1).leading_zeros();

src/uint/boxed/shr.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,36 @@ impl BoxedUint {
1010
/// Returns a zero and a truthy `Choice` if `shift >= self.bits_precision()`,
1111
/// or the result and a falsy `Choice` otherwise.
1212
pub fn shr(&self, shift: u32) -> (Self, Choice) {
13+
let mut result = self.clone();
14+
let overflow = result.overflowing_shr_assign(shift);
15+
(result, overflow)
16+
}
17+
18+
/// Computes `self >>= shift`.
19+
///
20+
/// Returns a truthy `Choice` if `shift >= self.bits_precision()` or a falsy `Choice` otherwise.
21+
pub fn overflowing_shr_assign(&mut self, shift: u32) -> Choice {
1322
// `floor(log2(bits_precision - 1))` is the number of bits in the representation of `shift`
1423
// (which lies in range `0 <= shift < bits_precision`).
1524
let shift_bits = u32::BITS - (self.bits_precision() - 1).leading_zeros();
1625
let overflow = !shift.ct_lt(&self.bits_precision());
1726
let shift = shift % self.bits_precision();
18-
let mut result = self.clone();
1927
let mut temp = self.clone();
2028

2129
for i in 0..shift_bits {
2230
let bit = Choice::from(((shift >> i) & 1) as u8);
2331
temp.set_zero();
2432
// Will not overflow by construction
25-
result
26-
.shr_vartime_into(&mut temp, 1 << i)
33+
self.shr_vartime_into(&mut temp, 1 << i)
2734
.expect("shift within range");
28-
result.conditional_assign(&temp, bit);
35+
self.conditional_assign(&temp, bit);
2936
}
3037

31-
result.conditional_set_zero(overflow);
38+
#[cfg(feature = "zeroize")]
39+
zeroize::Zeroize::zeroize(&mut temp);
3240

33-
(result, overflow)
41+
self.conditional_set_zero(overflow);
42+
overflow
3443
}
3544

3645
/// Computes `self >> shift`.
@@ -131,8 +140,11 @@ impl Shr<u32> for &BoxedUint {
131140

132141
impl ShrAssign<u32> for BoxedUint {
133142
fn shr_assign(&mut self, shift: u32) {
134-
// TODO(tarcieri): in-place implementation that avoids clone
135-
*self = self.clone().shr(shift);
143+
let overflow = self.overflowing_shr_assign(shift);
144+
assert!(
145+
!bool::from(overflow),
146+
"attempt to shift right with overflow"
147+
);
136148
}
137149
}
138150

0 commit comments

Comments
 (0)