crypto_bigint/limb/
shl.rs1use crate::{Choice, CtOption, Limb, Shl, ShlAssign, ShlVartime, WrappingShl};
4
5impl Limb {
6 #[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 #[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 #[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 #[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 #[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 #[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}