Skip to main content

crypto_bigint/limb/
shl.rs

1//! Limb left bitshift
2
3use crate::{Choice, CtOption, Limb, Shl, ShlAssign, ShlVartime, WrappingShl};
4
5impl Limb {
6    /// Computes `self << shift`.
7    ///
8    /// # Panics
9    /// - if `shift` overflows `Limb::BITS`.
10    #[inline(always)]
11    #[must_use]
12    #[track_caller]
13    pub const fn shl(self, shift: u32) -> Self {
14        Limb(self.0 << shift)
15    }
16
17    /// Computes `self << shift`, returning `CtOption::none()` if the shift exceeds the capacity.
18    #[inline(always)]
19    #[must_use]
20    pub const fn overflowing_shl(self, shift: u32) -> CtOption<Self> {
21        CtOption::new(
22            self.wrapping_shl(shift),
23            Choice::from_u32_lt(shift, Limb::BITS),
24        )
25    }
26
27    /// Computes `self << shift`, returning `None` if the shift exceeds the capacity.
28    ///
29    /// This method is variable time in `shift` only.
30    #[inline(always)]
31    #[must_use]
32    pub const fn overflowing_shl_vartime(self, shift: u32) -> Option<Self> {
33        if shift < Limb::BITS {
34            Some(self.shl(shift))
35        } else {
36            None
37        }
38    }
39
40    /// Computes `self << shift`, returning `Limb::ZERO` if the shift exceeds the capacity.
41    #[inline(always)]
42    #[must_use]
43    pub const fn unbounded_shl(self, shift: u32) -> Self {
44        Limb::select(
45            Limb::ZERO,
46            self.wrapping_shl(shift),
47            Choice::from_u32_lt(shift, Limb::BITS),
48        )
49    }
50
51    /// Computes `self << shift`, returning `Limb::ZERO` if the shift exceeds the capacity.
52    ///
53    /// This method is variable time in `shift` only.
54    #[inline(always)]
55    #[must_use]
56    pub const fn unbounded_shl_vartime(self, shift: u32) -> Self {
57        if shift < Limb::BITS {
58            self.shl(shift)
59        } else {
60            Self::ZERO
61        }
62    }
63
64    /// Computes `self << shift` in a panic-free manner, masking off bits of `shift`
65    /// which would cause the shift to exceed the type's width.
66    #[inline(always)]
67    #[must_use]
68    pub const fn wrapping_shl(self, shift: u32) -> Self {
69        Limb(self.0 << (shift & (Limb::BITS - 1)))
70    }
71}
72
73macro_rules! impl_shl {
74    ($($shift:ty),+) => {
75        $(
76            impl Shl<$shift> for Limb {
77                type Output = Limb;
78
79                #[inline]
80                fn shl(self, shift: $shift) -> Limb {
81                     Self::shl(self, u32::try_from(shift).expect("invalid shift"))
82                }
83            }
84
85            impl Shl<$shift> for &Limb {
86                type Output = Limb;
87
88                #[inline]
89                fn shl(self, shift: $shift) -> Limb {
90                   *self << shift
91                }
92            }
93
94            impl ShlAssign<$shift> for Limb {
95                #[inline]
96                fn shl_assign(&mut self, shift: $shift) {
97                    *self = *self << shift;
98                }
99            }
100        )+
101    };
102}
103
104impl_shl!(i32, u32, usize);
105
106impl ShlVartime for Limb {
107    #[inline]
108    fn overflowing_shl_vartime(&self, shift: u32) -> Option<Self> {
109        (*self).overflowing_shl_vartime(shift)
110    }
111
112    #[inline]
113    fn unbounded_shl_vartime(&self, shift: u32) -> Self {
114        (*self).unbounded_shl_vartime(shift)
115    }
116
117    #[inline]
118    fn wrapping_shl_vartime(&self, shift: u32) -> Self {
119        (*self).wrapping_shl(shift)
120    }
121}
122
123impl WrappingShl for Limb {
124    #[inline]
125    fn wrapping_shl(&self, shift: u32) -> Limb {
126        (*self).wrapping_shl(shift)
127    }
128}
129
130#[cfg(test)]
131mod tests {
132    use crate::{Limb, ShlVartime, WrappingShl};
133
134    #[test]
135    fn shl1() {
136        assert_eq!(Limb(1) << 1, Limb(2));
137    }
138
139    #[test]
140    fn shl2() {
141        assert_eq!(Limb(1) << 2, Limb(4));
142    }
143
144    #[test]
145    fn shl_assign1() {
146        let mut l = Limb(1);
147        l <<= 1;
148        assert_eq!(l, Limb(2));
149    }
150
151    #[test]
152    fn shl_assign2() {
153        let mut l = Limb(1);
154        l <<= 2;
155        assert_eq!(l, Limb(4));
156    }
157
158    #[test]
159    fn overflowing_shl() {
160        assert_eq!(Limb::ONE.overflowing_shl(2).into_option(), Some(Limb(4)));
161        assert_eq!(Limb::ONE.overflowing_shl(Limb::BITS).into_option(), None);
162        assert_eq!(
163            ShlVartime::overflowing_shl_vartime(&Limb::ONE, 2),
164            Some(Limb(4))
165        );
166        assert_eq!(
167            ShlVartime::overflowing_shl_vartime(&Limb::ONE, Limb::BITS),
168            None
169        );
170    }
171
172    #[test]
173    fn unbounded_shl() {
174        assert_eq!(Limb::ONE.unbounded_shl(2), Limb(4));
175        assert_eq!(Limb::ONE.unbounded_shl(Limb::BITS), Limb::ZERO);
176        assert_eq!(ShlVartime::unbounded_shl_vartime(&Limb::ONE, 2), Limb(4));
177        assert_eq!(
178            ShlVartime::unbounded_shl_vartime(&Limb::ONE, Limb::BITS),
179            Limb::ZERO
180        );
181    }
182
183    #[test]
184    fn wrapping_shl() {
185        assert_eq!(WrappingShl::wrapping_shl(&Limb::ONE, 2), Limb(4));
186        assert_eq!(WrappingShl::wrapping_shl(&Limb::ONE, Limb::BITS), Limb::ONE);
187        assert_eq!(ShlVartime::wrapping_shl_vartime(&Limb::ONE, 2), Limb(4));
188        assert_eq!(
189            ShlVartime::wrapping_shl_vartime(&Limb::ONE, Limb::BITS),
190            Limb::ONE
191        );
192    }
193}