Skip to main content

crypto_bigint/limb/
div.rs

1//! Limb division
2
3use core::slice;
4
5use crate::{
6    CheckedDiv, CtOption, Div, DivAssign, DivRemLimb, Limb, NonZero, Reciprocal, Rem, RemAssign,
7    RemLimb, UintRef,
8};
9
10impl Limb {
11    /// Computes `self / rhs`, returning the quotient and remainder.
12    #[inline(always)]
13    #[must_use]
14    pub const fn div_rem(self, rhs: NonZero<Self>) -> (Limb, Limb) {
15        self.div_rem_with_reciprocal(&Reciprocal::new(rhs))
16    }
17
18    /// Computes `self / rhs` where `recip` is a [`Reciprocal`] created from a non-zero Limb `rhs`.
19    /// Returns the quotient and remainder.
20    #[inline(always)]
21    #[must_use]
22    pub const fn div_rem_with_reciprocal(self, recip: &Reciprocal) -> (Limb, Limb) {
23        let mut quo = self;
24        let rem = UintRef::new_mut(slice::from_mut(&mut quo)).div_rem_limb_with_reciprocal(recip);
25        (quo, rem)
26    }
27
28    /// Computes the checked division `self / rhs`, returning the quotient
29    /// if the divisor is non-zero, and `CtOption::none()` otherwise.
30    #[must_use]
31    pub const fn checked_div(self, rhs: Self) -> CtOption<Limb> {
32        let is_nz = rhs.is_nonzero();
33        let quo = self.div_rem(NonZero(Self::select(Limb::ONE, rhs, is_nz))).0;
34        CtOption::new(quo, is_nz)
35    }
36
37    /// Computes the checked division `self / rhs`, returning the remainder
38    /// if the divisor is non-zero, and `CtOption::none()` otherwise.
39    #[must_use]
40    pub const fn checked_rem(self, rhs: Self) -> CtOption<Limb> {
41        let is_nz = rhs.is_nonzero();
42        let rem = self.div_rem(NonZero(Self::select(Limb::ONE, rhs, is_nz))).1;
43        CtOption::new(rem, is_nz)
44    }
45}
46
47impl CheckedDiv for Limb {
48    #[inline]
49    fn checked_div(&self, rhs: &Self) -> CtOption<Self> {
50        (*self).checked_div(*rhs)
51    }
52}
53
54impl DivRemLimb for Limb {
55    #[inline]
56    fn div_rem_limb(&self, rhs: NonZero<Limb>) -> (Self, Limb) {
57        self.div_rem(rhs)
58    }
59
60    fn div_rem_limb_with_reciprocal(&self, rhs: &Reciprocal) -> (Self, Limb) {
61        self.div_rem_with_reciprocal(rhs)
62    }
63}
64
65impl Div<Limb> for Limb {
66    type Output = Limb;
67
68    #[inline]
69    fn div(self, rhs: Limb) -> Self {
70        self.checked_div(rhs).expect("division by zero")
71    }
72}
73
74impl Div<&Limb> for Limb {
75    type Output = Limb;
76
77    #[inline]
78    fn div(self, rhs: &Limb) -> Self {
79        self / (*rhs)
80    }
81}
82
83impl Div<Limb> for &Limb {
84    type Output = Limb;
85
86    #[inline]
87    fn div(self, rhs: Limb) -> Limb {
88        (*self) / rhs
89    }
90}
91
92impl Div<&Limb> for &Limb {
93    type Output = Limb;
94
95    #[inline]
96    fn div(self, rhs: &Limb) -> Limb {
97        (*self) / (*rhs)
98    }
99}
100
101impl Div<NonZero<Limb>> for Limb {
102    type Output = Limb;
103
104    #[inline]
105    fn div(self, rhs: NonZero<Limb>) -> Self {
106        self.div_rem(rhs).0
107    }
108}
109
110impl Div<&NonZero<Limb>> for Limb {
111    type Output = Limb;
112
113    #[inline]
114    fn div(self, rhs: &NonZero<Limb>) -> Self {
115        self / (*rhs)
116    }
117}
118
119impl Div<NonZero<Limb>> for &Limb {
120    type Output = Limb;
121
122    #[inline]
123    fn div(self, rhs: NonZero<Limb>) -> Limb {
124        (*self) / rhs
125    }
126}
127
128impl Div<&NonZero<Limb>> for &Limb {
129    type Output = Limb;
130
131    #[inline]
132    fn div(self, rhs: &NonZero<Limb>) -> Limb {
133        (*self) / (*rhs)
134    }
135}
136
137impl RemLimb for Limb {
138    #[inline]
139    fn rem_limb(&self, rhs: NonZero<Limb>) -> Limb {
140        self.div_rem(rhs).1
141    }
142
143    fn rem_limb_with_reciprocal(&self, rhs: &Reciprocal) -> Limb {
144        self.div_rem_with_reciprocal(rhs).1
145    }
146}
147
148impl Rem<Limb> for Limb {
149    type Output = Limb;
150
151    #[inline]
152    fn rem(self, rhs: Limb) -> Self {
153        self.checked_rem(rhs).expect("division by zero")
154    }
155}
156
157impl Rem<&Limb> for Limb {
158    type Output = Limb;
159
160    #[inline]
161    fn rem(self, rhs: &Limb) -> Self {
162        self % (*rhs)
163    }
164}
165
166impl Rem<Limb> for &Limb {
167    type Output = Limb;
168
169    #[inline]
170    fn rem(self, rhs: Limb) -> Limb {
171        (*self) % rhs
172    }
173}
174
175impl Rem<&Limb> for &Limb {
176    type Output = Limb;
177
178    #[inline]
179    fn rem(self, rhs: &Limb) -> Limb {
180        (*self) % (*rhs)
181    }
182}
183
184impl Rem<NonZero<Limb>> for Limb {
185    type Output = Limb;
186
187    #[inline]
188    fn rem(self, rhs: NonZero<Limb>) -> Self {
189        self.div_rem(rhs).1
190    }
191}
192
193impl Rem<&NonZero<Limb>> for Limb {
194    type Output = Limb;
195
196    #[inline]
197    fn rem(self, rhs: &NonZero<Limb>) -> Self {
198        self % (*rhs)
199    }
200}
201
202impl Rem<NonZero<Limb>> for &Limb {
203    type Output = Limb;
204
205    #[inline]
206    fn rem(self, rhs: NonZero<Limb>) -> Limb {
207        (*self) % rhs
208    }
209}
210
211impl Rem<&NonZero<Limb>> for &Limb {
212    type Output = Limb;
213
214    #[inline]
215    fn rem(self, rhs: &NonZero<Limb>) -> Limb {
216        (*self) % (*rhs)
217    }
218}
219
220impl DivAssign<Limb> for Limb {
221    #[inline]
222    fn div_assign(&mut self, rhs: Limb) {
223        *self = (*self) / rhs;
224    }
225}
226
227impl DivAssign<&Limb> for Limb {
228    #[inline]
229    fn div_assign(&mut self, rhs: &Limb) {
230        *self = (*self) / (*rhs);
231    }
232}
233
234impl DivAssign<NonZero<Limb>> for Limb {
235    #[inline]
236    fn div_assign(&mut self, rhs: NonZero<Limb>) {
237        *self = (*self) / rhs;
238    }
239}
240
241impl DivAssign<&NonZero<Limb>> for Limb {
242    #[inline]
243    fn div_assign(&mut self, rhs: &NonZero<Limb>) {
244        *self = (*self) / (*rhs);
245    }
246}
247
248impl RemAssign<Limb> for Limb {
249    #[inline]
250    fn rem_assign(&mut self, rhs: Limb) {
251        *self = (*self) % rhs;
252    }
253}
254
255impl RemAssign<&Limb> for Limb {
256    #[inline]
257    fn rem_assign(&mut self, rhs: &Limb) {
258        *self = (*self) % (*rhs);
259    }
260}
261
262impl RemAssign<NonZero<Limb>> for Limb {
263    #[inline]
264    fn rem_assign(&mut self, rhs: NonZero<Limb>) {
265        *self = (*self) % rhs;
266    }
267}
268
269impl RemAssign<&NonZero<Limb>> for Limb {
270    #[inline]
271    fn rem_assign(&mut self, rhs: &NonZero<Limb>) {
272        *self = (*self) % (*rhs);
273    }
274}
275
276#[cfg(test)]
277mod tests {
278    use super::{CheckedDiv, Limb};
279    use crate::NonZero;
280
281    #[test]
282    fn div_rem_ok() {
283        let n = Limb::from_u32(0xffff_ffff);
284        let d = NonZero::new(Limb::from_u32(0xfffe)).expect("ensured non-zero");
285        assert_eq!(n.div_rem(d), (Limb::from_u32(0x10002), Limb::from_u32(0x3)));
286    }
287
288    #[test]
289    fn checked_div() {
290        assert_eq!(
291            CheckedDiv::checked_div(&Limb::ONE, &Limb::ONE).into_option(),
292            Some(Limb::ONE)
293        );
294        assert_eq!(
295            CheckedDiv::checked_div(&Limb::MAX, &Limb::ZERO).into_option(),
296            None
297        );
298    }
299
300    #[test]
301    fn checked_rem() {
302        assert_eq!(
303            Limb::ONE.checked_rem(Limb::ONE).into_option(),
304            Some(Limb::ZERO)
305        );
306        assert_eq!(Limb::MAX.checked_rem(Limb::ZERO).into_option(), None);
307    }
308}