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