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    #[inline]
61    fn div_rem_limb_with_reciprocal(&self, rhs: &Reciprocal) -> (Self, Limb) {
62        self.div_rem_with_reciprocal(rhs)
63    }
64}
65
66impl Div<Limb> for Limb {
67    type Output = Limb;
68
69    #[inline]
70    fn div(self, rhs: Limb) -> Self {
71        self.checked_div(rhs).expect("division by zero")
72    }
73}
74
75impl Div<&Limb> for Limb {
76    type Output = Limb;
77
78    #[inline]
79    fn div(self, rhs: &Limb) -> Self {
80        self / (*rhs)
81    }
82}
83
84impl Div<Limb> for &Limb {
85    type Output = Limb;
86
87    #[inline]
88    fn div(self, rhs: Limb) -> Limb {
89        (*self) / rhs
90    }
91}
92
93impl Div<&Limb> for &Limb {
94    type Output = Limb;
95
96    #[inline]
97    fn div(self, rhs: &Limb) -> Limb {
98        (*self) / (*rhs)
99    }
100}
101
102impl Div<NonZero<Limb>> for Limb {
103    type Output = Limb;
104
105    #[inline]
106    fn div(self, rhs: NonZero<Limb>) -> Self {
107        self.div_rem(rhs).0
108    }
109}
110
111impl Div<&NonZero<Limb>> for Limb {
112    type Output = Limb;
113
114    #[inline]
115    fn div(self, rhs: &NonZero<Limb>) -> Self {
116        self / (*rhs)
117    }
118}
119
120impl Div<NonZero<Limb>> for &Limb {
121    type Output = Limb;
122
123    #[inline]
124    fn div(self, rhs: NonZero<Limb>) -> Limb {
125        (*self) / rhs
126    }
127}
128
129impl Div<&NonZero<Limb>> for &Limb {
130    type Output = Limb;
131
132    #[inline]
133    fn div(self, rhs: &NonZero<Limb>) -> Limb {
134        (*self) / (*rhs)
135    }
136}
137
138impl RemLimb for Limb {
139    #[inline]
140    fn rem_limb(&self, rhs: NonZero<Limb>) -> Limb {
141        self.div_rem(rhs).1
142    }
143
144    fn rem_limb_with_reciprocal(&self, rhs: &Reciprocal) -> Limb {
145        self.div_rem_with_reciprocal(rhs).1
146    }
147}
148
149impl Rem<Limb> for Limb {
150    type Output = Limb;
151
152    #[inline]
153    fn rem(self, rhs: Limb) -> Self {
154        self.checked_rem(rhs).expect("division by zero")
155    }
156}
157
158impl Rem<&Limb> for Limb {
159    type Output = Limb;
160
161    #[inline]
162    fn rem(self, rhs: &Limb) -> Self {
163        self % (*rhs)
164    }
165}
166
167impl Rem<Limb> for &Limb {
168    type Output = Limb;
169
170    #[inline]
171    fn rem(self, rhs: Limb) -> Limb {
172        (*self) % rhs
173    }
174}
175
176impl Rem<&Limb> for &Limb {
177    type Output = Limb;
178
179    #[inline]
180    fn rem(self, rhs: &Limb) -> Limb {
181        (*self) % (*rhs)
182    }
183}
184
185impl Rem<NonZero<Limb>> for Limb {
186    type Output = Limb;
187
188    #[inline]
189    fn rem(self, rhs: NonZero<Limb>) -> Self {
190        self.div_rem(rhs).1
191    }
192}
193
194impl Rem<&NonZero<Limb>> for Limb {
195    type Output = Limb;
196
197    #[inline]
198    fn rem(self, rhs: &NonZero<Limb>) -> Self {
199        self % (*rhs)
200    }
201}
202
203impl Rem<NonZero<Limb>> for &Limb {
204    type Output = Limb;
205
206    #[inline]
207    fn rem(self, rhs: NonZero<Limb>) -> Limb {
208        (*self) % rhs
209    }
210}
211
212impl Rem<&NonZero<Limb>> for &Limb {
213    type Output = Limb;
214
215    #[inline]
216    fn rem(self, rhs: &NonZero<Limb>) -> Limb {
217        (*self) % (*rhs)
218    }
219}
220
221impl DivAssign<Limb> for Limb {
222    #[inline]
223    fn div_assign(&mut self, rhs: Limb) {
224        *self = (*self) / rhs;
225    }
226}
227
228impl DivAssign<&Limb> for Limb {
229    #[inline]
230    fn div_assign(&mut self, rhs: &Limb) {
231        *self = (*self) / (*rhs);
232    }
233}
234
235impl DivAssign<NonZero<Limb>> for Limb {
236    #[inline]
237    fn div_assign(&mut self, rhs: NonZero<Limb>) {
238        *self = (*self) / rhs;
239    }
240}
241
242impl DivAssign<&NonZero<Limb>> for Limb {
243    #[inline]
244    fn div_assign(&mut self, rhs: &NonZero<Limb>) {
245        *self = (*self) / (*rhs);
246    }
247}
248
249impl RemAssign<Limb> for Limb {
250    #[inline]
251    fn rem_assign(&mut self, rhs: Limb) {
252        *self = (*self) % rhs;
253    }
254}
255
256impl RemAssign<&Limb> for Limb {
257    #[inline]
258    fn rem_assign(&mut self, rhs: &Limb) {
259        *self = (*self) % (*rhs);
260    }
261}
262
263impl RemAssign<NonZero<Limb>> for Limb {
264    #[inline]
265    fn rem_assign(&mut self, rhs: NonZero<Limb>) {
266        *self = (*self) % rhs;
267    }
268}
269
270impl RemAssign<&NonZero<Limb>> for Limb {
271    #[inline]
272    fn rem_assign(&mut self, rhs: &NonZero<Limb>) {
273        *self = (*self) % (*rhs);
274    }
275}
276
277#[cfg(test)]
278#[allow(clippy::op_ref)]
279mod tests {
280    use super::{CheckedDiv, Limb};
281    use crate::NonZero;
282
283    #[test]
284    fn div_rem_ok() {
285        let n = Limb::from_u32(0xffff_ffff);
286        let d = NonZero::new(Limb::from_u32(0xfffe)).expect("ensured non-zero");
287        assert_eq!(n.div_rem(d), (Limb::from_u32(0x10002), Limb::from_u32(0x3)));
288    }
289
290    #[test]
291    fn checked_div() {
292        assert_eq!(
293            CheckedDiv::checked_div(&Limb::ONE, &Limb::ONE).into_option(),
294            Some(Limb::ONE)
295        );
296        assert_eq!(
297            CheckedDiv::checked_div(&Limb::MAX, &Limb::ZERO).into_option(),
298            None
299        );
300    }
301
302    #[test]
303    fn checked_rem() {
304        assert_eq!(
305            Limb::ONE.checked_rem(Limb::ONE).into_option(),
306            Some(Limb::ZERO)
307        );
308        assert_eq!(Limb::MAX.checked_rem(Limb::ZERO).into_option(), None);
309    }
310
311    #[test]
312    fn div_trait() {
313        let a = Limb::from(10u64);
314        let b = NonZero::new(Limb::from(2u64)).unwrap();
315        let c = Limb::from(5u64);
316
317        assert_eq!(a / b, c);
318        assert_eq!(a / &b, c);
319        assert_eq!(&a / b, c);
320        assert_eq!(&a / &b, c);
321        assert_eq!(a / &b.0, c);
322        assert_eq!(&a / b.0, c);
323    }
324
325    #[test]
326    fn div_assign_trait() {
327        let a = Limb::from(10u64);
328        let b = NonZero::new(Limb::from(2u64)).unwrap();
329        let c = Limb::from(5u64);
330
331        let mut res = a;
332        res /= b;
333        assert_eq!(res, c);
334        let mut res = a;
335        res /= &b;
336        assert_eq!(res, c);
337        let mut res = a;
338        res /= b.0;
339        assert_eq!(res, c);
340        let mut res = a;
341        res /= &b.0;
342        assert_eq!(res, c);
343    }
344
345    #[should_panic]
346    #[test]
347    fn div_zero() {
348        let _ = Limb::ONE / Limb::ZERO;
349    }
350
351    #[should_panic]
352    #[test]
353    fn div_ref_zero() {
354        let _ = &Limb::ONE / Limb::ZERO;
355    }
356
357    #[test]
358    fn rem_trait() {
359        let a = Limb::from(10u64);
360        let b = NonZero::new(Limb::from(3u64)).unwrap();
361        let c = Limb::from(1u64);
362
363        assert_eq!(a % b, c);
364        assert_eq!(a % &b, c);
365        assert_eq!(&a % b, c);
366        assert_eq!(&a % &b, c);
367        assert_eq!(a % &b.0, c);
368        assert_eq!(&a % b.0, c);
369    }
370
371    #[test]
372    fn rem_assign_trait() {
373        let a = Limb::from(10u64);
374        let b = NonZero::new(Limb::from(3u64)).unwrap();
375        let c = Limb::from(1u64);
376
377        let mut res = a;
378        res %= b;
379        assert_eq!(res, c);
380        let mut res = a;
381        res %= &b;
382        assert_eq!(res, c);
383        let mut res = a;
384        res %= b.0;
385        assert_eq!(res, c);
386        let mut res = a;
387        res %= &b.0;
388        assert_eq!(res, c);
389    }
390
391    #[should_panic]
392    #[test]
393    fn rem_zero() {
394        let _ = Limb::ONE % Limb::ZERO;
395    }
396
397    #[should_panic]
398    #[test]
399    fn rem_ref_zero() {
400        let _ = &Limb::ONE % Limb::ZERO;
401    }
402}