use crate::{CtOption, Int, ShlVartime, Uint, WrappingShl};
use core::ops::{Shl, ShlAssign};
impl<const LIMBS: usize> Int<LIMBS> {
#[inline]
#[must_use]
#[track_caller]
pub const fn shl(&self, shift: u32) -> Self {
Self(Uint::shl(&self.0, shift))
}
#[inline(always)]
#[must_use]
#[track_caller]
pub const fn shl_vartime(&self, shift: u32) -> Self {
Self(Uint::shl_vartime(&self.0, shift))
}
#[inline(always)]
#[must_use]
pub const fn overflowing_shl(&self, shift: u32) -> CtOption<Self> {
Self::from_uint_opt(self.0.overflowing_shl(shift))
}
#[inline(always)]
#[must_use]
pub const fn overflowing_shl_vartime(&self, shift: u32) -> Option<Self> {
if let Some(uint) = self.0.overflowing_shl_vartime(shift) {
Some(*uint.as_int())
} else {
None
}
}
#[inline(always)]
#[must_use]
pub const fn unbounded_shl(&self, shift: u32) -> Self {
Self(self.0.unbounded_shl(shift))
}
#[inline(always)]
#[must_use]
pub const fn unbounded_shl_vartime(&self, shift: u32) -> Self {
Self(self.0.unbounded_shl_vartime(shift))
}
#[inline(always)]
#[must_use]
pub const fn wrapping_shl(&self, shift: u32) -> Self {
Self(self.0.wrapping_shl(shift))
}
#[inline(always)]
#[must_use]
pub const fn wrapping_shl_vartime(&self, shift: u32) -> Self {
Self(self.0.wrapping_shl_vartime(shift))
}
}
macro_rules! impl_shl {
($($shift:ty),+) => {
$(
impl<const LIMBS: usize> Shl<$shift> for Int<LIMBS> {
type Output = Int<LIMBS>;
#[inline]
fn shl(self, shift: $shift) -> Int<LIMBS> {
<&Self>::shl(&self, shift)
}
}
impl<const LIMBS: usize> Shl<$shift> for &Int<LIMBS> {
type Output = Int<LIMBS>;
#[inline]
fn shl(self, shift: $shift) -> Int<LIMBS> {
Int::<LIMBS>::shl(self, u32::try_from(shift).expect("invalid shift"))
}
}
impl<const LIMBS: usize> ShlAssign<$shift> for Int<LIMBS> {
fn shl_assign(&mut self, shift: $shift) {
*self = self.shl(shift)
}
}
)+
};
}
impl_shl!(i32, u32, usize);
impl<const LIMBS: usize> WrappingShl for Int<LIMBS> {
fn wrapping_shl(&self, shift: u32) -> Int<LIMBS> {
self.wrapping_shl(shift)
}
}
impl<const LIMBS: usize> ShlVartime for Int<LIMBS> {
fn overflowing_shl_vartime(&self, shift: u32) -> Option<Self> {
self.overflowing_shl_vartime(shift)
}
fn unbounded_shl_vartime(&self, shift: u32) -> Self {
self.unbounded_shl_vartime(shift)
}
fn wrapping_shl_vartime(&self, shift: u32) -> Self {
self.wrapping_shl_vartime(shift)
}
}
#[cfg(test)]
mod tests {
use crate::{I256, ShlVartime};
const N: I256 =
I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
const TWO_N: I256 =
I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD755DB9CD5E9140777FA4BD19A06C8282");
const FOUR_N: I256 =
I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAEABB739ABD2280EEFF497A3340D90504");
const SIXTY_FIVE: I256 =
I256::from_be_hex("FFFFFFFFFFFFFFFD755DB9CD5E9140777FA4BD19A06C82820000000000000000");
const EIGHTY_EIGHT: I256 =
I256::from_be_hex("FFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD03641410000000000000000000000");
const SIXTY_FOUR: I256 =
I256::from_be_hex("FFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD03641410000000000000000");
#[test]
fn shl_simple() {
let mut t = I256::from(1i8);
assert_eq!(t << 1, I256::from(2i8));
t = I256::from(3i8);
assert_eq!(t << 8, I256::from(0x300i16));
}
#[test]
fn shl1() {
assert_eq!(N << 1, TWO_N);
assert_eq!(ShlVartime::overflowing_shl_vartime(&N, 1), Some(TWO_N));
assert_eq!(ShlVartime::wrapping_shl_vartime(&N, 1), TWO_N);
}
#[test]
fn shl2() {
assert_eq!(N << 2, FOUR_N);
}
#[test]
fn shl65() {
assert_eq!(N << 65, SIXTY_FIVE);
}
#[test]
fn shl88() {
assert_eq!(N << 88, EIGHTY_EIGHT);
}
#[test]
fn shl256_const() {
assert!(N.overflowing_shl(256).is_none().to_bool_vartime());
assert!(ShlVartime::overflowing_shl_vartime(&N, 256).is_none());
}
#[test]
#[should_panic(expected = "`shift` exceeds upper bound")]
fn shl_bounds_panic() {
let _ = N << 256;
}
#[test]
fn shl64() {
assert_eq!(N << 64, SIXTY_FOUR);
}
#[test]
fn unbounded_shl() {
assert_eq!(I256::MAX.unbounded_shl(257), I256::ZERO);
assert_eq!(I256::MIN.unbounded_shl(257), I256::ZERO);
assert_eq!(
ShlVartime::unbounded_shl_vartime(&I256::MAX, 257),
I256::ZERO
);
assert_eq!(
ShlVartime::unbounded_shl_vartime(&I256::MIN, 257),
I256::ZERO
);
}
#[test]
fn wrapping_shl() {
assert_eq!(I256::MAX.wrapping_shl(257), I256::MAX.shl(1));
assert_eq!(I256::MIN.wrapping_shl(257), I256::MIN.shl(1));
assert_eq!(
ShlVartime::wrapping_shl_vartime(&I256::MAX, 257),
I256::MAX.shl(1)
);
assert_eq!(
ShlVartime::wrapping_shl_vartime(&I256::MIN, 257),
I256::MIN.shl(1)
);
}
}