use crate::{Limb, Uint};
impl<const LIMBS: usize> Uint<LIMBS> {
#[inline(always)]
#[allow(clippy::cast_possible_truncation)]
pub(super) const fn section_vartime_length<const SECTION_LIMBS: usize>(
&self,
idx: u32,
length: u32,
) -> Uint<SECTION_LIMBS> {
debug_assert!(length <= Uint::<SECTION_LIMBS>::BITS);
debug_assert!(idx + length <= Self::BITS);
if LIMBS > SECTION_LIMBS {
let (shr_limbs, shr_bits) = (idx >> Limb::LOG2_BITS, idx & (Limb::BITS - 1));
let buf = self.bounded_shr_by_limbs(shr_limbs, LIMBS as u32);
buf.resize::<SECTION_LIMBS>()
.shr_limb_with_carry(
shr_bits,
buf.limbs[SECTION_LIMBS].unbounded_shl(Limb::BITS - shr_bits),
)
.0
.restrict_bits(length)
} else {
self.shr(idx)
.resize::<SECTION_LIMBS>()
.restrict_bits(length)
}
}
#[inline(always)]
pub(super) const fn section_vartime<const SECTION_LIMBS: usize>(
&self,
idx: u32,
length: u32,
) -> Uint<SECTION_LIMBS> {
debug_assert!(length <= Uint::<SECTION_LIMBS>::BITS);
debug_assert!(idx + length <= Self::BITS);
self.shr_vartime(idx)
.resize::<SECTION_LIMBS>()
.restrict_bits(length)
}
#[inline(always)]
pub(super) const fn compact<const K: u32, const SUMMARY_LIMBS: usize>(
&self,
n: u32,
) -> Uint<SUMMARY_LIMBS> {
debug_assert!(K <= Uint::<SUMMARY_LIMBS>::BITS);
debug_assert!(n <= Self::BITS);
debug_assert!(n >= 2 * K);
let hi = self.section_vartime_length(n - K, K);
let lo = self.section_vartime(0, K);
hi.shl_vartime(K).bitxor(&lo)
}
#[inline(always)]
pub(crate) const fn compact_vartime<const K: u32, const SUMMARY_LIMBS: usize>(
&self,
n: u32,
) -> Uint<SUMMARY_LIMBS> {
debug_assert!(K <= Uint::<SUMMARY_LIMBS>::BITS);
debug_assert!(n <= Self::BITS);
debug_assert!(n >= 2 * K);
let hi = self.section_vartime(n - K, K);
let lo = self.section_vartime(0, K);
hi.shl_vartime(K).bitxor(&lo)
}
}
#[cfg(test)]
mod tests {
use crate::{U128, U256};
#[test]
fn test_compact() {
let val =
U256::from_be_hex("CFCF1535CEBE19BBF289933AB8645189397450A32BFEC57579FB7EB14E27D101");
let target = U128::from_be_hex("BBF289933AB8645179FB7EB14E27D101");
let compact = val.compact::<64, { U128::LIMBS }>(200);
assert_eq!(compact, target);
}
#[test]
fn test_compact_vartime() {
let val =
U256::from_be_hex("1971BC6285D8CBA9640AA3B3B9C01EF4186D1EBE9A17393A9E43586E0EBAED5B");
let target = U128::from_be_hex("A9640AA3B3B9C01E9E43586E0EBAED5B");
let compact = val.compact_vartime::<64, { U128::LIMBS }>(200);
assert_eq!(compact, target);
}
}