1use crate::{CtOption, Int, ShlVartime, Uint, WrappingShl};
4use core::ops::{Shl, ShlAssign};
5
6impl<const LIMBS: usize> Int<LIMBS> {
7 #[inline]
12 #[must_use]
13 #[track_caller]
14 pub const fn shl(&self, shift: u32) -> Self {
15 Self(Uint::shl(&self.0, shift))
16 }
17
18 #[inline(always)]
27 #[must_use]
28 #[track_caller]
29 pub const fn shl_vartime(&self, shift: u32) -> Self {
30 Self(Uint::shl_vartime(&self.0, shift))
31 }
32
33 #[inline(always)]
37 #[must_use]
38 pub const fn overflowing_shl(&self, shift: u32) -> CtOption<Self> {
39 Self::from_uint_opt(self.0.overflowing_shl(shift))
40 }
41
42 #[inline(always)]
51 #[must_use]
52 pub const fn overflowing_shl_vartime(&self, shift: u32) -> Option<Self> {
53 if let Some(uint) = self.0.overflowing_shl_vartime(shift) {
54 Some(*uint.as_int())
55 } else {
56 None
57 }
58 }
59
60 #[inline(always)]
63 #[must_use]
64 pub const fn unbounded_shl(&self, shift: u32) -> Self {
65 Self(self.0.unbounded_shl(shift))
66 }
67
68 #[inline(always)]
75 #[must_use]
76 pub const fn unbounded_shl_vartime(&self, shift: u32) -> Self {
77 Self(self.0.unbounded_shl_vartime(shift))
78 }
79
80 #[inline(always)]
82 #[must_use]
83 pub const fn wrapping_shl(&self, shift: u32) -> Self {
84 Self(self.0.wrapping_shl(shift))
85 }
86
87 #[inline(always)]
94 #[must_use]
95 pub const fn wrapping_shl_vartime(&self, shift: u32) -> Self {
96 Self(self.0.wrapping_shl_vartime(shift))
97 }
98}
99
100macro_rules! impl_shl {
101 ($($shift:ty),+) => {
102 $(
103 impl<const LIMBS: usize> Shl<$shift> for Int<LIMBS> {
104 type Output = Int<LIMBS>;
105
106 #[inline]
107 fn shl(self, shift: $shift) -> Int<LIMBS> {
108 <&Self>::shl(&self, shift)
109 }
110 }
111
112 impl<const LIMBS: usize> Shl<$shift> for &Int<LIMBS> {
113 type Output = Int<LIMBS>;
114
115 #[inline]
116 fn shl(self, shift: $shift) -> Int<LIMBS> {
117 Int::<LIMBS>::shl(self, u32::try_from(shift).expect("invalid shift"))
118 }
119 }
120
121 impl<const LIMBS: usize> ShlAssign<$shift> for Int<LIMBS> {
122 fn shl_assign(&mut self, shift: $shift) {
123 *self = self.shl(shift)
124 }
125 }
126 )+
127 };
128}
129
130impl_shl!(i32, u32, usize);
131
132impl<const LIMBS: usize> WrappingShl for Int<LIMBS> {
133 fn wrapping_shl(&self, shift: u32) -> Int<LIMBS> {
134 self.wrapping_shl(shift)
135 }
136}
137
138impl<const LIMBS: usize> ShlVartime for Int<LIMBS> {
139 fn overflowing_shl_vartime(&self, shift: u32) -> Option<Self> {
140 self.overflowing_shl_vartime(shift)
141 }
142
143 fn unbounded_shl_vartime(&self, shift: u32) -> Self {
144 self.unbounded_shl_vartime(shift)
145 }
146
147 fn wrapping_shl_vartime(&self, shift: u32) -> Self {
148 self.wrapping_shl_vartime(shift)
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use crate::{I256, ShlVartime};
155
156 const N: I256 =
157 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
158
159 const TWO_N: I256 =
160 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD755DB9CD5E9140777FA4BD19A06C8282");
161
162 const FOUR_N: I256 =
163 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAEABB739ABD2280EEFF497A3340D90504");
164
165 const SIXTY_FIVE: I256 =
166 I256::from_be_hex("FFFFFFFFFFFFFFFD755DB9CD5E9140777FA4BD19A06C82820000000000000000");
167
168 const EIGHTY_EIGHT: I256 =
169 I256::from_be_hex("FFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD03641410000000000000000000000");
170
171 const SIXTY_FOUR: I256 =
172 I256::from_be_hex("FFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD03641410000000000000000");
173
174 #[test]
175 fn shl_simple() {
176 let mut t = I256::from(1i8);
177 assert_eq!(t << 1, I256::from(2i8));
178 t = I256::from(3i8);
179 assert_eq!(t << 8, I256::from(0x300i16));
180 }
181
182 #[test]
183 fn shl1() {
184 assert_eq!(N << 1, TWO_N);
185 assert_eq!(ShlVartime::overflowing_shl_vartime(&N, 1), Some(TWO_N));
186 assert_eq!(ShlVartime::wrapping_shl_vartime(&N, 1), TWO_N);
187 }
188
189 #[test]
190 fn shl2() {
191 assert_eq!(N << 2, FOUR_N);
192 }
193
194 #[test]
195 fn shl65() {
196 assert_eq!(N << 65, SIXTY_FIVE);
197 }
198
199 #[test]
200 fn shl88() {
201 assert_eq!(N << 88, EIGHTY_EIGHT);
202 }
203
204 #[test]
205 fn shl256_const() {
206 assert!(N.overflowing_shl(256).is_none().to_bool_vartime());
207 assert!(ShlVartime::overflowing_shl_vartime(&N, 256).is_none());
208 }
209
210 #[test]
211 #[should_panic(expected = "`shift` exceeds upper bound")]
212 fn shl_bounds_panic() {
213 let _ = N << 256;
214 }
215
216 #[test]
217 fn shl64() {
218 assert_eq!(N << 64, SIXTY_FOUR);
219 }
220
221 #[test]
222 fn unbounded_shl() {
223 assert_eq!(I256::MAX.unbounded_shl(257), I256::ZERO);
224 assert_eq!(I256::MIN.unbounded_shl(257), I256::ZERO);
225 assert_eq!(
226 ShlVartime::unbounded_shl_vartime(&I256::MAX, 257),
227 I256::ZERO
228 );
229 assert_eq!(
230 ShlVartime::unbounded_shl_vartime(&I256::MIN, 257),
231 I256::ZERO
232 );
233 }
234
235 #[test]
236 fn wrapping_shl() {
237 assert_eq!(I256::MAX.wrapping_shl(257), I256::MAX.shl(1));
238 assert_eq!(I256::MIN.wrapping_shl(257), I256::MIN.shl(1));
239 assert_eq!(
240 ShlVartime::wrapping_shl_vartime(&I256::MAX, 257),
241 I256::MAX.shl(1)
242 );
243 assert_eq!(
244 ShlVartime::wrapping_shl_vartime(&I256::MIN, 257),
245 I256::MIN.shl(1)
246 );
247 }
248}