-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Speedup Uint::shr
#753
base: master
Are you sure you want to change the base?
Speedup Uint::shr
#753
Changes from 5 commits
509c51c
3b78bd5
16f59fc
068b054
dd28ce4
a5dbc74
6858e22
fb15f24
88f1972
d24b299
a49f889
271eadb
3d7c87e
6949c33
81de22d
d438508
aeb0f73
b138396
fb01e75
ada14bc
3a1eb7a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,112 @@ impl<const LIMBS: usize> Uint<LIMBS> { | |
ConstCtOption::new(Uint::select(&result, &Self::ZERO, overflow), overflow.not()) | ||
} | ||
|
||
/// Computes `self >> shift`. | ||
/// | ||
/// Returns `None` if `shift >= Self::BITS`. | ||
pub const fn split_overflowing_shr(&self, shift: u32) -> ConstCtOption<Self> { | ||
let (intra_limb_shift, limb_shift) = (shift % Limb::BITS, shift / Limb::BITS); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI: clippy has an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
self.intra_limb_carrying_shr_internal(intra_limb_shift) | ||
.full_limb_shr(limb_shift) | ||
} | ||
|
||
/// Computes `self >> shift`, for `shift < Limb::BITS`. | ||
/// | ||
/// Returns `None` if `shift >= Limb::BITS`. | ||
pub const fn intra_limb_overflowing_shr(&self, shift: u32) -> ConstCtOption<Self> { | ||
let overflow = ConstChoice::from_u32_lt(shift, Limb::BITS).not(); | ||
let result = self.intra_limb_carrying_shr_internal(shift % Limb::BITS); | ||
ConstCtOption::new(Uint::select(&result, &Self::ZERO, overflow), overflow.not()) | ||
} | ||
|
||
/// Computes `self >> shift`, for `shift < Limb::BITS`. | ||
/// | ||
/// Panics if `shift >= Limb::BITS`. | ||
#[inline(always)] | ||
const fn intra_limb_carrying_shr_internal(&self, shift: u32) -> Self { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: not being There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. |
||
debug_assert!(shift < Limb::BITS); | ||
|
||
let (mut result, mut carry) = (*self, Limb::ZERO); | ||
|
||
let limbs = result.as_limbs_mut(); | ||
let mut i = limbs.len(); | ||
while i > 0 { | ||
i -= 1; | ||
let (shifted, new_carry) = limbs[i].carrying_shr(shift); | ||
limbs[i] = shifted.bitxor(carry); | ||
carry = new_carry; | ||
} | ||
|
||
result | ||
} | ||
|
||
/// Compute `self >> (Limb::BITS * limb_shift)`, for `limb_shift < Self::LIMBS`. | ||
/// | ||
/// Returns `None` if `limb_shift >= Self::LIMBS`. | ||
#[inline(always)] | ||
pub const fn full_limb_shr(&self, limb_shift: u32) -> ConstCtOption<Self> { | ||
let shift_bits = u32::BITS - (LIMBS as u32 - 1).leading_zeros(); | ||
let overflow = ConstChoice::from_u32_lt(limb_shift, LIMBS as u32).not(); | ||
let limb_shift = limb_shift % LIMBS as u32; | ||
|
||
let mut result = *self; | ||
let mut i = 0; | ||
while i < shift_bits { | ||
let bit = ConstChoice::from_u32_lsb((limb_shift >> i) & 1); | ||
result = Uint::select( | ||
&result, | ||
&result | ||
.overflowing_shr_vartime(Limb::BITS << i) | ||
.expect("shift within range"), | ||
bit, | ||
); | ||
i += 1; | ||
} | ||
|
||
ConstCtOption::new(Uint::select(&result, &Self::ZERO, overflow), overflow.not()) | ||
} | ||
|
||
/// Computes `self >> shift`. | ||
/// | ||
/// Returns `None` if `shift >= Self::BITS`. | ||
pub const fn fast_split_overflowing_shr(&self, shift: u32) -> ConstCtOption<Self> { | ||
let (intra_limb_shift, limb_shift) = (shift % Limb::BITS, shift / Limb::BITS); | ||
self.intra_limb_carrying_shr_internal(intra_limb_shift) | ||
.fast_full_limb_shr(limb_shift) | ||
} | ||
|
||
/// Compute `self >> (Limb::BITS * limb_shift)`, for `limb_shift < Self::LIMBS`. | ||
/// | ||
/// Returns `None` if `limb_shift >= Self::LIMBS`. | ||
#[inline(always)] | ||
pub const fn fast_full_limb_shr(&self, limb_shift: u32) -> ConstCtOption<Self> { | ||
let shift_bits = u32::BITS - (LIMBS as u32 - 1).leading_zeros(); | ||
let overflow = ConstChoice::from_u32_lt(limb_shift, LIMBS as u32).not(); | ||
let limb_shift = limb_shift % LIMBS as u32; | ||
|
||
let mut result = *self; | ||
let mut i = 0; | ||
while i < shift_bits { | ||
let bit = ConstChoice::from_u32_lsb((limb_shift >> i) & 1); | ||
|
||
let mut j = 0; | ||
let limbs = result.as_limbs_mut(); | ||
let offset = 1 << i; | ||
while j < Self::LIMBS.saturating_sub(offset) { | ||
limbs[j] = Limb::select(limbs[j], limbs[j + offset], bit); | ||
j += 1; | ||
} | ||
while j < Self::LIMBS { | ||
limbs[j] = Limb::select(limbs[j], Limb::ZERO, bit); | ||
j += 1; | ||
} | ||
|
||
i += 1; | ||
} | ||
|
||
ConstCtOption::new(Uint::select(&result, &Self::ZERO, overflow), overflow.not()) | ||
} | ||
|
||
/// Computes `self >> shift`. | ||
/// | ||
/// Returns `None` if `shift >= Self::BITS`. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
use crypto_bigint::{Limb, Word}; | ||
use proptest::prelude::*; | ||
|
||
prop_compose! { | ||
fn limb()(x in any::<Word>()) -> Limb { | ||
Limb::from(x) | ||
} | ||
} | ||
proptest! { | ||
#[test] | ||
fn carrying_shr_doesnt_panic(limb in limb(), shift in 0..32u32) { | ||
limb.carrying_shr(shift); | ||
} | ||
|
||
#[test] | ||
fn carrying_shr(limb in limb(), shift in 0..32u32) { | ||
if shift == 0 { | ||
assert_eq!(limb.carrying_shr(shift), (limb, Limb::ZERO)); | ||
} else { | ||
assert_eq!(limb.carrying_shr(shift), (limb.shr(shift), limb.shl(Limb::BITS - shift))); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!