1use core::ops::{Shl, ShlAssign};
4
5use subtle::CtOption;
6
7use crate::{ConstCtOption, Int, ShlVartime, Uint, WrappingShl};
8
9impl<const LIMBS: usize> Int<LIMBS> {
10 pub const fn shl(&self, shift: u32) -> Self {
14 Self(Uint::shl(&self.0, shift))
15 }
16
17 pub const fn shl_vartime(&self, shift: u32) -> Self {
21 Self(Uint::shl_vartime(&self.0, shift))
22 }
23
24 pub const fn overflowing_shl(&self, shift: u32) -> ConstCtOption<Self> {
28 self.0.overflowing_shl(shift).as_int()
29 }
30
31 #[inline(always)]
40 pub const fn overflowing_shl_vartime(&self, shift: u32) -> ConstCtOption<Self> {
41 self.0.overflowing_shl_vartime(shift).as_int()
42 }
43
44 pub const fn wrapping_shl(&self, shift: u32) -> Self {
47 Self(self.0.wrapping_shl(shift))
48 }
49
50 pub const fn wrapping_shl_vartime(&self, shift: u32) -> Self {
53 Self(self.0.wrapping_shl_vartime(shift))
54 }
55}
56
57macro_rules! impl_shl {
58 ($($shift:ty),+) => {
59 $(
60 impl<const LIMBS: usize> Shl<$shift> for Int<LIMBS> {
61 type Output = Int<LIMBS>;
62
63 #[inline]
64 fn shl(self, shift: $shift) -> Int<LIMBS> {
65 <&Self>::shl(&self, shift)
66 }
67 }
68
69 impl<const LIMBS: usize> Shl<$shift> for &Int<LIMBS> {
70 type Output = Int<LIMBS>;
71
72 #[inline]
73 fn shl(self, shift: $shift) -> Int<LIMBS> {
74 Int::<LIMBS>::shl(self, u32::try_from(shift).expect("invalid shift"))
75 }
76 }
77
78 impl<const LIMBS: usize> ShlAssign<$shift> for Int<LIMBS> {
79 fn shl_assign(&mut self, shift: $shift) {
80 *self = self.shl(shift)
81 }
82 }
83 )+
84 };
85}
86
87impl_shl!(i32, u32, usize);
88
89impl<const LIMBS: usize> WrappingShl for Int<LIMBS> {
90 fn wrapping_shl(&self, shift: u32) -> Int<LIMBS> {
91 self.wrapping_shl(shift)
92 }
93}
94
95impl<const LIMBS: usize> ShlVartime for Int<LIMBS> {
96 fn overflowing_shl_vartime(&self, shift: u32) -> CtOption<Self> {
97 self.overflowing_shl(shift).into()
98 }
99 fn wrapping_shl_vartime(&self, shift: u32) -> Self {
100 self.wrapping_shl(shift)
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use crate::I256;
107
108 const N: I256 =
109 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
110
111 const TWO_N: I256 =
112 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD755DB9CD5E9140777FA4BD19A06C8282");
113
114 const FOUR_N: I256 =
115 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAEABB739ABD2280EEFF497A3340D90504");
116
117 const SIXTY_FIVE: I256 =
118 I256::from_be_hex("FFFFFFFFFFFFFFFD755DB9CD5E9140777FA4BD19A06C82820000000000000000");
119
120 const EIGHTY_EIGHT: I256 =
121 I256::from_be_hex("FFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD03641410000000000000000000000");
122
123 const SIXTY_FOUR: I256 =
124 I256::from_be_hex("FFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD03641410000000000000000");
125
126 #[test]
127 fn shl_simple() {
128 let mut t = I256::from(1i8);
129 assert_eq!(t << 1, I256::from(2i8));
130 t = I256::from(3i8);
131 assert_eq!(t << 8, I256::from(0x300i16));
132 }
133
134 #[test]
135 fn shl1() {
136 assert_eq!(N << 1, TWO_N);
137 }
138
139 #[test]
140 fn shl2() {
141 assert_eq!(N << 2, FOUR_N);
142 }
143
144 #[test]
145 fn shl65() {
146 assert_eq!(N << 65, SIXTY_FIVE);
147 }
148
149 #[test]
150 fn shl88() {
151 assert_eq!(N << 88, EIGHTY_EIGHT);
152 }
153
154 #[test]
155 fn shl256_const() {
156 assert!(N.overflowing_shl(256).is_none().is_true_vartime());
157 assert!(N.overflowing_shl_vartime(256).is_none().is_true_vartime());
158 }
159
160 #[test]
161 #[should_panic(expected = "`shift` within the bit size of the integer")]
162 fn shl256() {
163 let _ = N << 256;
164 }
165
166 #[test]
167 fn shl64() {
168 assert_eq!(N << 64, SIXTY_FOUR);
169 }
170}