1use crate::{CtOption, Limb, Shr, ShrAssign, ShrVartime, Uint, WrappingShr, primitives::u32_rem};
4
5impl<const LIMBS: usize> Uint<LIMBS> {
6 #[inline(never)]
11 #[must_use]
12 #[track_caller]
13 pub const fn shr(&self, shift: u32) -> Self {
14 let mut res = *self;
15 res.as_mut_uint_ref().bounded_shr_assign(shift, Self::BITS);
16 res
17 }
18
19 #[inline(always)]
24 #[must_use]
25 pub const fn shr_vartime(&self, shift: u32) -> Self {
26 self.overflowing_shr_vartime(shift)
27 .expect("`shift` exceeds upper bound")
28 }
29
30 #[inline(never)]
34 #[must_use]
35 pub const fn overflowing_shr(&self, shift: u32) -> CtOption<Self> {
36 let mut res = *self;
37 let overflow = res.as_mut_uint_ref().overflowing_shr_assign(shift);
38 CtOption::new(res, overflow.not())
39 }
40
41 #[inline(always)]
49 #[must_use]
50 pub const fn overflowing_shr_vartime(&self, shift: u32) -> Option<Self> {
51 if shift < Self::BITS {
52 Some(self.unbounded_shr_vartime(shift))
53 } else {
54 None
55 }
56 }
57
58 #[inline(always)]
67 #[must_use]
68 pub const fn overflowing_shr_vartime_wide(
69 lower_upper: (Self, Self),
70 shift: u32,
71 ) -> Option<(Self, Self)> {
72 let (lower, upper) = lower_upper;
73 if shift >= 2 * Self::BITS {
74 None
75 } else if shift >= Self::BITS {
76 let lower = upper.unbounded_shr_vartime(shift - Self::BITS);
77 Some((lower, Self::ZERO))
78 } else {
79 let new_upper = upper.unbounded_shr_vartime(shift);
80 let lower_hi = upper.unbounded_shl_vartime(Self::BITS - shift);
81 let lower_lo = lower.unbounded_shr_vartime(shift);
82 Some((lower_lo.bitor(&lower_hi), new_upper))
83 }
84 }
85
86 #[inline(never)]
94 #[must_use]
95 #[track_caller]
96 pub const fn bounded_shr(&self, shift: u32, shift_upper_bound: u32) -> Self {
97 let mut res = *self;
98 res.as_mut_uint_ref()
99 .bounded_shr_assign(shift, shift_upper_bound);
100 res
101 }
102
103 #[must_use]
111 #[track_caller]
112 pub(crate) const fn bounded_shr_by_limbs(&self, shift: u32, shift_upper_bound: u32) -> Self {
113 let mut res = *self;
114 res.as_mut_uint_ref()
115 .bounded_shr_by_limbs_assign(shift, shift_upper_bound);
116 res
117 }
118
119 #[inline(never)]
122 #[must_use]
123 pub const fn unbounded_shr(&self, shift: u32) -> Self {
124 let mut res = *self;
125 res.as_mut_uint_ref().unbounded_shr_assign(shift);
126 res
127 }
128
129 #[inline(always)]
137 #[must_use]
138 pub const fn unbounded_shr_vartime(&self, shift: u32) -> Self {
139 let mut res = Self::ZERO;
140 self.as_uint_ref()
141 .unbounded_shr_vartime(shift, res.as_mut_uint_ref());
142 res
143 }
144
145 #[inline(always)]
152 #[must_use]
153 pub(crate) const fn unbounded_shr_by_limbs_vartime(&self, shift: u32) -> Self {
154 let mut res = *self;
155 res.as_mut_uint_ref()
156 .unbounded_shr_assign_by_limbs_vartime(shift);
157 res
158 }
159
160 #[inline(always)]
162 #[must_use]
163 pub const fn wrapping_shr(&self, shift: u32) -> Self {
164 self.shr(u32_rem(shift, Self::BITS))
165 }
166
167 #[inline(always)]
174 #[must_use]
175 #[allow(clippy::integer_division_remainder_used, reason = "vartime")]
176 pub const fn wrapping_shr_vartime(&self, shift: u32) -> Self {
177 self.unbounded_shr_vartime(shift % Self::BITS)
178 }
179
180 #[inline(always)]
182 #[must_use]
183 pub(crate) const fn shr1(&self) -> Self {
184 let mut res = *self;
185 res.as_mut_uint_ref().shr1_assign();
186 res
187 }
188
189 #[inline(always)]
195 #[must_use]
196 #[track_caller]
197 pub(crate) const fn shr_limb_with_carry(&self, shift: u32, carry: Limb) -> (Self, Limb) {
198 let mut res = *self;
199 let carry = res
200 .as_mut_uint_ref()
201 .shr_assign_limb_with_carry(shift, carry);
202 (res, carry)
203 }
204}
205
206macro_rules! impl_shr {
207 ($($shift:ty),+) => {
208 $(
209 impl<const LIMBS: usize> Shr<$shift> for Uint<LIMBS> {
210 type Output = Uint<LIMBS>;
211
212 #[inline]
213 fn shr(self, shift: $shift) -> Uint<LIMBS> {
214 <&Self>::shr(&self, shift)
215 }
216 }
217
218 impl<const LIMBS: usize> Shr<$shift> for &Uint<LIMBS> {
219 type Output = Uint<LIMBS>;
220
221 #[inline]
222 fn shr(self, shift: $shift) -> Uint<LIMBS> {
223 Uint::<LIMBS>::shr(self, u32::try_from(shift).expect("invalid shift"))
224 }
225 }
226
227 impl<const LIMBS: usize> ShrAssign<$shift> for Uint<LIMBS> {
228 fn shr_assign(&mut self, shift: $shift) {
229 *self = self.shr(shift)
230 }
231 }
232 )+
233 };
234}
235
236impl_shr!(i32, u32, usize);
237
238impl<const LIMBS: usize> WrappingShr for Uint<LIMBS> {
239 fn wrapping_shr(&self, shift: u32) -> Uint<LIMBS> {
240 self.wrapping_shr(shift)
241 }
242}
243
244impl<const LIMBS: usize> ShrVartime for Uint<LIMBS> {
245 fn overflowing_shr_vartime(&self, shift: u32) -> Option<Self> {
246 self.overflowing_shr_vartime(shift)
247 }
248
249 fn unbounded_shr_vartime(&self, shift: u32) -> Self {
250 self.unbounded_shr_vartime(shift)
251 }
252
253 fn wrapping_shr_vartime(&self, shift: u32) -> Self {
254 self.wrapping_shr_vartime(shift)
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use crate::{Limb, ShrVartime, U128, U192, Uint, WrappingShr};
261
262 const N: U192 = U192::from_be_hex("FFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
263
264 const N_2: U192 = U192::from_be_hex("7FFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0");
265
266 #[test]
267 fn shr1() {
268 assert_eq!(N.shr1(), N_2);
269 assert_eq!(N >> 1, N_2);
270 assert_eq!(N.bounded_shr(1, 2), N_2);
271 assert_eq!(ShrVartime::overflowing_shr_vartime(&N, 1), Some(N_2));
272 assert_eq!(ShrVartime::wrapping_shr_vartime(&N, 1), N_2);
273 }
274
275 #[test]
276 fn shr_bounds() {
277 assert!(N.overflowing_shr(192).is_none().to_bool_vartime());
278 assert!(N.overflowing_shr_vartime(192).is_none());
279 assert_eq!(N.unbounded_shr(192), Uint::ZERO);
280 assert_eq!(N.unbounded_shr_vartime(192), Uint::ZERO);
281 assert_eq!(N.wrapping_shr(192), N);
282 assert_eq!(N.wrapping_shr_vartime(192), N);
283 }
284
285 #[test]
286 #[should_panic(expected = "`shift` exceeds upper bound")]
287 fn shr_bounds_panic() {
288 let _ = N >> 192;
289 }
290
291 #[test]
292 fn shr_wide_1_1_128() {
293 assert_eq!(
294 Uint::overflowing_shr_vartime_wide((U128::ONE, U128::ONE), 128).unwrap(),
295 (U128::ONE, U128::ZERO)
296 );
297 }
298
299 #[test]
300 fn shr_wide_0_max_1() {
301 assert_eq!(
302 Uint::overflowing_shr_vartime_wide((U128::ZERO, U128::MAX), 1).unwrap(),
303 (U128::ONE << 127, U128::MAX >> 1)
304 );
305 }
306
307 #[test]
308 fn shr_wide_max_max_256() {
309 assert!(Uint::overflowing_shr_vartime_wide((U128::MAX, U128::MAX), 256).is_none());
310 }
311
312 #[test]
313 #[should_panic]
314 fn shr_limb_with_carry_shift_too_large() {
315 let _ = U128::ONE.shr_limb_with_carry(Limb::BITS, Limb::ZERO);
316 }
317
318 #[test]
319 fn shr_limb_with_carry() {
320 let val = U128::from_be_hex("876543210FEDCBA90123456FEDCBA987");
321
322 let (res, carry) = val.shr_limb_with_carry(0, Limb::ZERO);
324 assert_eq!(res, val);
325 assert_eq!(carry, Limb::ZERO);
326
327 let (res, carry) = val.shr_limb_with_carry(1, Limb::ZERO);
329 assert_eq!(res, val.shr_vartime(1));
330 assert_eq!(carry, val.limbs[0].shl(Limb::BITS - 1));
331
332 let (res, carry) = val.shr_limb_with_carry(13, Limb::ZERO);
334 assert_eq!(res, val.shr_vartime(13));
335 assert_eq!(carry, val.limbs[0].shl(Limb::BITS - 13));
336
337 let (res, carry) = val.shr_limb_with_carry(Limb::BITS - 1, Limb::ZERO);
339 assert_eq!(res, val.shr_vartime(Limb::BITS - 1));
340 assert_eq!(carry, val.limbs[0].shl(1));
341 }
342
343 #[test]
344 fn shr_by_limbs() {
345 let val = Uint::<2>::from_words([1, 99]);
346 assert_eq!(val.bounded_shr_by_limbs(0, 3).as_words(), &[1, 99]);
347 assert_eq!(val.bounded_shr_by_limbs(1, 3).as_words(), &[99, 0]);
348 assert_eq!(val.bounded_shr_by_limbs(2, 3).as_words(), &[0, 0]);
349 assert_eq!(val.unbounded_shr_by_limbs_vartime(0).as_words(), &[1, 99]);
350 assert_eq!(val.unbounded_shr_by_limbs_vartime(1).as_words(), &[99, 0]);
351 assert_eq!(val.unbounded_shr_by_limbs_vartime(2).as_words(), &[0, 0]);
352 }
353
354 #[test]
355 fn overflowing_shr() {
356 assert_eq!(
357 U192::from_u8(16).overflowing_shr(2).into_option(),
358 Some(U192::from_u8(4))
359 );
360 assert_eq!(U192::ONE.overflowing_shr(U192::BITS).into_option(), None);
361 assert_eq!(
362 ShrVartime::overflowing_shr_vartime(&U192::from_u8(16), 2),
363 Some(U192::from_u8(4))
364 );
365 assert_eq!(
366 ShrVartime::overflowing_shr_vartime(&U192::ONE, U192::BITS),
367 None
368 );
369 }
370
371 #[test]
372 fn unbounded_shr() {
373 assert_eq!(U192::from_u8(16).unbounded_shr(2), U192::from_u8(4));
374 assert_eq!(U192::MAX.unbounded_shr(U192::BITS), U192::ZERO);
375 assert_eq!(
376 ShrVartime::unbounded_shr_vartime(&U192::from_u8(16), 2),
377 U192::from_u8(4)
378 );
379 assert_eq!(
380 ShrVartime::unbounded_shr_vartime(&U192::MAX, U192::BITS),
381 U192::ZERO
382 );
383 }
384
385 #[test]
386 fn wrapping_shr() {
387 assert_eq!(
388 WrappingShr::wrapping_shr(&U192::from_u8(16), 2),
389 U192::from_u8(4)
390 );
391 assert_eq!(WrappingShr::wrapping_shr(&U192::ONE, U192::BITS), U192::ONE);
392 assert_eq!(
393 ShrVartime::wrapping_shr_vartime(&U192::from_u8(16), 2),
394 U192::from_u8(4)
395 );
396 assert_eq!(
397 ShrVartime::wrapping_shr_vartime(&U192::ONE, U192::BITS),
398 U192::ONE
399 );
400 }
401}