crypto_bigint/uint/
shl.rs

1//! [`UInt`] bitwise left shift operations.
2
3use crate::{Limb, UInt, Word};
4use core::ops::{Shl, ShlAssign};
5
6impl<const LIMBS: usize> UInt<LIMBS> {
7    /// Computes `self << shift`.
8    ///
9    /// NOTE: this operation is variable time with respect to `n` *ONLY*.
10    ///
11    /// When used with a fixed `n`, this function is constant-time with respect
12    /// to `self`.
13    #[inline(always)]
14    pub const fn shl_vartime(&self, n: usize) -> Self {
15        let mut limbs = [Limb::ZERO; LIMBS];
16
17        if n >= Limb::BIT_SIZE * LIMBS {
18            return Self { limbs };
19        }
20
21        let shift_num = n / Limb::BIT_SIZE;
22        let rem = n % Limb::BIT_SIZE;
23        let nz = Limb(rem as Word).is_nonzero();
24        let lshift_rem = rem as Word;
25        let rshift_rem = Limb::ct_select(Limb::ZERO, Limb((Limb::BIT_SIZE - rem) as Word), nz).0;
26
27        let mut i = LIMBS - 1;
28        while i > shift_num {
29            let mut limb = self.limbs[i - shift_num].0 << lshift_rem;
30            let hi = self.limbs[i - shift_num - 1].0 >> rshift_rem;
31            limb |= hi & nz;
32            limbs[i] = Limb(limb);
33            i -= 1
34        }
35        limbs[shift_num] = Limb(self.limbs[0].0 << lshift_rem);
36
37        Self { limbs }
38    }
39}
40
41impl<const LIMBS: usize> Shl<usize> for UInt<LIMBS> {
42    type Output = UInt<LIMBS>;
43
44    /// NOTE: this operation is variable time with respect to `rhs` *ONLY*.
45    ///
46    /// When used with a fixed `rhs`, this function is constant-time with respect
47    /// to `self`.
48    fn shl(self, rhs: usize) -> UInt<LIMBS> {
49        self.shl_vartime(rhs)
50    }
51}
52
53impl<const LIMBS: usize> Shl<usize> for &UInt<LIMBS> {
54    type Output = UInt<LIMBS>;
55
56    /// NOTE: this operation is variable time with respect to `rhs` *ONLY*.
57    ///
58    /// When used with a fixed `rhs`, this function is constant-time with respect
59    /// to `self`.
60    fn shl(self, rhs: usize) -> UInt<LIMBS> {
61        self.shl_vartime(rhs)
62    }
63}
64
65impl<const LIMBS: usize> ShlAssign<usize> for UInt<LIMBS> {
66    /// NOTE: this operation is variable time with respect to `rhs` *ONLY*.
67    ///
68    /// When used with a fixed `rhs`, this function is constant-time with respect
69    /// to `self`.
70    fn shl_assign(&mut self, rhs: usize) {
71        *self = self.shl_vartime(rhs)
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use crate::U256;
78
79    const N: U256 =
80        U256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
81
82    const TWO_N: U256 =
83        U256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD755DB9CD5E9140777FA4BD19A06C8282");
84
85    const FOUR_N: U256 =
86        U256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAEABB739ABD2280EEFF497A3340D90504");
87
88    const SIXTY_FIVE: U256 =
89        U256::from_be_hex("FFFFFFFFFFFFFFFD755DB9CD5E9140777FA4BD19A06C82820000000000000000");
90
91    const EIGHTY_EIGHT: U256 =
92        U256::from_be_hex("FFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD03641410000000000000000000000");
93
94    const SIXTY_FOUR: U256 =
95        U256::from_be_hex("FFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD03641410000000000000000");
96
97    #[test]
98    fn shl_simple() {
99        let mut t = U256::from(1u8);
100        assert_eq!(t << 1, U256::from(2u8));
101        t = U256::from(3u8);
102        assert_eq!(t << 8, U256::from(0x300u16));
103    }
104
105    #[test]
106    fn shl1() {
107        assert_eq!(N << 1, TWO_N);
108    }
109
110    #[test]
111    fn shl2() {
112        assert_eq!(N << 2, FOUR_N);
113    }
114
115    #[test]
116    fn shl65() {
117        assert_eq!(N << 65, SIXTY_FIVE);
118    }
119
120    #[test]
121    fn shl88() {
122        assert_eq!(N << 88, EIGHTY_EIGHT);
123    }
124
125    #[test]
126    fn shl256() {
127        assert_eq!(N << 256, U256::default());
128    }
129
130    #[test]
131    fn shl64() {
132        assert_eq!(N << 64, SIXTY_FOUR);
133    }
134}