Skip to main content

crypto_bigint/limb/
shr.rs

1//! Limb right bitshift
2
3use crate::{Choice, CtOption, Limb, ShrVartime, WrappingShr};
4use core::ops::{Shr, ShrAssign};
5
6impl Limb {
7    /// Computes `self >> shift`.
8    ///
9    /// # Panics
10    /// - if `shift` overflows `Limb::BITS`.
11    #[inline(always)]
12    #[must_use]
13    #[track_caller]
14    pub const fn shr(self, shift: u32) -> Self {
15        Limb(self.0 >> shift)
16    }
17
18    /// Computes `self >> 1` and return the result and the carry (0 or `1 << HI_BIT`).
19    #[inline(always)]
20    pub(crate) const fn shr1(self) -> (Self, Self) {
21        (Self(self.0 >> 1), Self(self.0 << Self::HI_BIT))
22    }
23
24    /// Computes `self >> shift`, returning `CtOption::none()` if the shift exceeds the capacity.
25    #[inline(always)]
26    #[must_use]
27    pub const fn overflowing_shr(self, shift: u32) -> CtOption<Self> {
28        CtOption::new(
29            self.wrapping_shr(shift),
30            Choice::from_u32_lt(shift, Limb::BITS),
31        )
32    }
33
34    /// Computes `self >> shift`, returning `None` if the shift exceeds the capacity.
35    ///
36    /// This method is variable time in `shift` only.
37    #[inline(always)]
38    #[must_use]
39    pub const fn overflowing_shr_vartime(self, shift: u32) -> Option<Self> {
40        if shift < Limb::BITS {
41            Some(self.shr(shift))
42        } else {
43            None
44        }
45    }
46
47    /// Computes `self >> shift`, returning `Limb::ZERO` if the shift exceeds the capacity.
48    #[inline(always)]
49    #[must_use]
50    pub const fn unbounded_shr(self, shift: u32) -> Self {
51        Limb::select(
52            Limb::ZERO,
53            self.wrapping_shr(shift),
54            Choice::from_u32_lt(shift, Limb::BITS),
55        )
56    }
57
58    /// Computes `self >> shift`, returning `Limb::ZERO` if the shift exceeds the capacity.
59    ///
60    /// This method is variable time in `shift` only.
61    #[inline(always)]
62    #[must_use]
63    pub const fn unbounded_shr_vartime(self, shift: u32) -> Self {
64        if shift < Limb::BITS {
65            self.shr(shift)
66        } else {
67            Self::ZERO
68        }
69    }
70
71    /// Computes `self >> shift` in a panic-free manner, masking off bits of `shift`
72    /// which would cause the shift to exceed the type's width.
73    #[inline(always)]
74    #[must_use]
75    pub const fn wrapping_shr(self, shift: u32) -> Self {
76        Limb(self.0 >> (shift & (Limb::BITS - 1)))
77    }
78}
79
80macro_rules! impl_shr {
81    ($($shift:ty),+) => {
82        $(
83            impl Shr<$shift> for Limb {
84                type Output = Limb;
85
86                #[inline]
87                fn shr(self, shift: $shift) -> Limb {
88                     Self::shr(self, u32::try_from(shift).expect("invalid shift"))
89                }
90            }
91
92            impl Shr<$shift> for &Limb {
93                type Output = Limb;
94
95                #[inline]
96                fn shr(self, shift: $shift) -> Limb {
97                   *self >> shift
98                }
99            }
100
101            impl ShrAssign<$shift> for Limb {
102                #[inline]
103                fn shr_assign(&mut self, shift: $shift) {
104                    *self = *self >> shift;
105                }
106            }
107        )+
108    };
109}
110
111impl_shr!(i32, u32, usize);
112
113impl ShrVartime for Limb {
114    #[inline]
115    fn overflowing_shr_vartime(&self, shift: u32) -> Option<Self> {
116        (*self).overflowing_shr_vartime(shift)
117    }
118
119    #[inline]
120    fn unbounded_shr_vartime(&self, shift: u32) -> Self {
121        (*self).unbounded_shr_vartime(shift)
122    }
123
124    #[inline]
125    fn wrapping_shr_vartime(&self, shift: u32) -> Self {
126        (*self).wrapping_shr(shift)
127    }
128}
129
130impl WrappingShr for Limb {
131    #[inline]
132    fn wrapping_shr(&self, shift: u32) -> Limb {
133        (*self).wrapping_shr(shift)
134    }
135}
136
137#[cfg(test)]
138mod tests {
139    use crate::{Limb, ShrVartime, WrappingShr};
140
141    #[test]
142    fn shr1() {
143        assert_eq!(Limb(2) >> 1, Limb(1));
144    }
145
146    #[test]
147    fn shr2() {
148        assert_eq!(Limb(16) >> 2, Limb(4));
149    }
150
151    #[test]
152    fn shr_assign1() {
153        let mut l = Limb::ONE;
154        l >>= 1;
155        assert_eq!(l, Limb::ZERO);
156    }
157
158    #[test]
159    fn shr_assign2() {
160        let mut l = Limb(32);
161        l >>= 2;
162        assert_eq!(l, Limb(8));
163    }
164
165    #[test]
166    fn overflowing_shr() {
167        assert_eq!(
168            Limb::from(16u8).overflowing_shr(2).into_option(),
169            Some(Limb(4))
170        );
171        assert_eq!(Limb::ONE.overflowing_shr(Limb::BITS).into_option(), None);
172        assert_eq!(
173            ShrVartime::overflowing_shr_vartime(&Limb::from(16u8), 2),
174            Some(Limb(4))
175        );
176        assert_eq!(
177            ShrVartime::overflowing_shr_vartime(&Limb::ONE, Limb::BITS),
178            None
179        );
180    }
181
182    #[test]
183    fn unbounded_shr() {
184        assert_eq!(Limb::from(16u8).unbounded_shr(2), Limb(4));
185        assert_eq!(Limb::ONE.unbounded_shr(Limb::BITS), Limb::ZERO);
186        assert_eq!(
187            ShrVartime::unbounded_shr_vartime(&Limb::from(16u8), 2),
188            Limb(4)
189        );
190        assert_eq!(
191            ShrVartime::unbounded_shr_vartime(&Limb::ONE, Limb::BITS),
192            Limb::ZERO
193        );
194    }
195
196    #[test]
197    fn wrapping_shr() {
198        assert_eq!(WrappingShr::wrapping_shr(&Limb::from(16u8), 2), Limb(4));
199        assert_eq!(WrappingShr::wrapping_shr(&Limb::ONE, Limb::BITS), Limb::ONE);
200        assert_eq!(
201            ShrVartime::wrapping_shr_vartime(&Limb::from(16u8), 2),
202            Limb(4)
203        );
204        assert_eq!(
205            ShrVartime::wrapping_shr_vartime(&Limb::ONE, Limb::BITS),
206            Limb::ONE
207        );
208    }
209}