Skip to main content

crypto_bigint/int/
div_unsigned.rs

1//! Operations related to dividing an [`Int`] by a [`Uint`].
2use core::ops::{Div, DivAssign, Rem, RemAssign};
3
4use crate::{Choice, Int, NonZero, Uint, Wrapping};
5
6/// Checked division operations.
7impl<const LIMBS: usize> Int<LIMBS> {
8    #[inline]
9    /// Base `div_rem` operation on dividing an [`Int`] by a [`Uint`].
10    /// Computes the quotient and remainder of `self / rhs`.
11    /// Furthermore, returns the sign of `self`.
12    const fn div_rem_base_unsigned<const RHS_LIMBS: usize>(
13        &self,
14        rhs: &NonZero<Uint<RHS_LIMBS>>,
15    ) -> (Uint<LIMBS>, Uint<RHS_LIMBS>, Choice) {
16        let (lhs_mag, lhs_sgn) = self.abs_sign();
17        let (quotient, remainder) = lhs_mag.div_rem(rhs);
18        (quotient, remainder, lhs_sgn)
19    }
20
21    /// Compute the quotient and remainder of `self / rhs`.
22    ///
23    /// Example:
24    /// ```
25    /// use crypto_bigint::{I128, NonZero, U128};
26    ///
27    /// let (quotient, remainder) = I128::from(8).div_rem_unsigned(&U128::from(3u32).to_nz().unwrap());
28    /// assert_eq!(quotient, I128::from(2));
29    /// assert_eq!(remainder, I128::from(2));
30    ///
31    /// let (quotient, remainder) = I128::from(-8).div_rem_unsigned(&U128::from(3u32).to_nz().unwrap());
32    /// assert_eq!(quotient, I128::from(-2));
33    /// assert_eq!(remainder, I128::from(-2));
34    /// ```
35    #[must_use]
36    pub const fn div_rem_unsigned<const RHS_LIMBS: usize>(
37        &self,
38        rhs: &NonZero<Uint<RHS_LIMBS>>,
39    ) -> (Self, Int<RHS_LIMBS>) {
40        let (quotient, remainder, lhs_sgn) = self.div_rem_base_unsigned(rhs);
41        (
42            Self(quotient).wrapping_neg_if(lhs_sgn),
43            Int::new_from_abs_sign(remainder, lhs_sgn).expect_copied("no overflow; always fits"),
44        )
45    }
46
47    /// Perform division.
48    /// Note: this operation rounds towards zero, truncating any fractional part of the exact result.
49    #[must_use]
50    pub const fn div_unsigned<const RHS_LIMBS: usize>(
51        &self,
52        rhs: &NonZero<Uint<RHS_LIMBS>>,
53    ) -> Self {
54        self.div_rem_unsigned(rhs).0
55    }
56
57    /// Compute the remainder.
58    /// The remainder will have the same sign as `self` (or be zero).
59    #[must_use]
60    pub const fn rem_unsigned<const RHS_LIMBS: usize>(
61        &self,
62        rhs: &NonZero<Uint<RHS_LIMBS>>,
63    ) -> Int<RHS_LIMBS> {
64        self.div_rem_unsigned(rhs).1
65    }
66}
67
68/// Vartime checked division operations.
69impl<const LIMBS: usize> Int<LIMBS> {
70    #[inline]
71    /// Variable time equivalent of [`Self::div_rem_base_unsigned`].
72    ///
73    /// This is variable only with respect to `rhs`.
74    ///
75    /// When used with a fixed `rhs`, this function is constant-time with respect
76    /// to `self`.
77    const fn div_rem_base_unsigned_vartime<const RHS_LIMBS: usize>(
78        &self,
79        rhs: &NonZero<Uint<RHS_LIMBS>>,
80    ) -> (Uint<LIMBS>, Uint<RHS_LIMBS>, Choice) {
81        let (lhs_mag, lhs_sgn) = self.abs_sign();
82        let (quotient, remainder) = lhs_mag.div_rem_vartime(rhs);
83        (quotient, remainder, lhs_sgn)
84    }
85
86    /// Variable time equivalent of [`Self::div_rem_unsigned`].
87    ///
88    /// This is variable only with respect to `rhs`.
89    ///
90    /// When used with a fixed `rhs`, this function is constant-time with respect
91    /// to `self`.
92    #[must_use]
93    pub const fn div_rem_unsigned_vartime<const RHS_LIMBS: usize>(
94        &self,
95        rhs: &NonZero<Uint<RHS_LIMBS>>,
96    ) -> (Self, Int<RHS_LIMBS>) {
97        let (quotient, remainder, lhs_sgn) = self.div_rem_base_unsigned_vartime(rhs);
98        (
99            Self(quotient).wrapping_neg_if(lhs_sgn),
100            remainder.as_int().wrapping_neg_if(lhs_sgn),
101        )
102    }
103
104    /// Variable time equivalent of [`Self::div_unsigned`].
105    ///
106    /// This is variable only with respect to `rhs`.
107    ///
108    /// When used with a fixed `rhs`, this function is constant-time with respect
109    /// to `self`.
110    #[must_use]
111    pub const fn div_unsigned_vartime<const RHS_LIMBS: usize>(
112        &self,
113        rhs: &NonZero<Uint<RHS_LIMBS>>,
114    ) -> Self {
115        self.div_rem_unsigned_vartime(rhs).0
116    }
117
118    /// Variable time equivalent of [`Self::rem_unsigned`].
119    ///
120    /// This is variable only with respect to `rhs`.
121    ///
122    /// When used with a fixed `rhs`, this function is constant-time with respect
123    /// to `self`.
124    #[must_use]
125    pub const fn rem_unsigned_vartime<const RHS_LIMBS: usize>(
126        &self,
127        rhs: &NonZero<Uint<RHS_LIMBS>>,
128    ) -> Int<RHS_LIMBS> {
129        self.div_rem_unsigned_vartime(rhs).1
130    }
131}
132
133/// Checked div-floor operations
134impl<const LIMBS: usize> Int<LIMBS> {
135    /// Perform floored division and mod:
136    /// given `n` and `d`, computes `q` and `r` s.t. `n = qd + r` and `q = ⌊n/d⌋`.
137    /// Note: this operation rounds **down**, not towards zero.
138    ///
139    /// Example:
140    /// ```
141    /// use crypto_bigint::{I128, U128};
142    ///
143    /// let three = U128::from(3u32).to_nz().unwrap();
144    /// assert_eq!(
145    ///     I128::from(8).div_rem_floor_unsigned(&three),
146    ///     (I128::from(2), U128::from(2u32))
147    /// );
148    /// assert_eq!(
149    ///     I128::from(-8).div_rem_floor_unsigned(&three),
150    ///     (I128::from(-3), U128::ONE)
151    /// );
152    /// ```
153    #[must_use]
154    pub fn div_rem_floor_unsigned<const RHS_LIMBS: usize>(
155        &self,
156        rhs: &NonZero<Uint<RHS_LIMBS>>,
157    ) -> (Self, Uint<RHS_LIMBS>) {
158        let (quotient, remainder, lhs_sgn) = self.div_rem_base_unsigned(rhs);
159
160        // Increase the quotient by one when self is negative and there is a non-zero remainder.
161        let modify = remainder.is_nonzero().and(lhs_sgn);
162        let quotient = Uint::select(&quotient, &quotient.wrapping_add(&Uint::ONE), modify);
163
164        // Invert the remainder when self is negative and there is a non-zero remainder.
165        let remainder = Uint::select(&remainder, &rhs.wrapping_sub(&remainder), modify);
166
167        // Negate if applicable
168        let quotient = Self(quotient).wrapping_neg_if(lhs_sgn);
169
170        (quotient, remainder)
171    }
172
173    /// Perform checked division.
174    /// Note: this operation rounds down.
175    ///
176    /// Example:
177    /// ```
178    /// use crypto_bigint::{I128, U128};
179    /// assert_eq!(
180    ///     I128::from(8).div_floor_unsigned(&U128::from(3u32).to_nz().unwrap()),
181    ///     I128::from(2)
182    /// );
183    /// assert_eq!(
184    ///     I128::from(-8).div_floor_unsigned(&U128::from(3u32).to_nz().unwrap()),
185    ///     I128::from(-3)
186    /// );
187    /// ```
188    #[must_use]
189    pub fn div_floor_unsigned<const RHS_LIMBS: usize>(
190        &self,
191        rhs: &NonZero<Uint<RHS_LIMBS>>,
192    ) -> Self {
193        let (q, _) = self.div_rem_floor_unsigned(rhs);
194        q
195    }
196
197    /// Compute `self % rhs` and return the result contained in the interval `[0, rhs)`.
198    ///
199    /// Example:
200    /// ```
201    /// use crypto_bigint::{I128, U128};
202    /// assert_eq!(
203    ///     I128::from(8).normalized_rem(&U128::from(3u32).to_nz().unwrap()),
204    ///     U128::from(2u32)
205    /// );
206    /// assert_eq!(
207    ///     I128::from(-8).normalized_rem(&U128::from(3u32).to_nz().unwrap()),
208    ///     U128::ONE
209    /// );
210    /// ```
211    #[must_use]
212    pub fn normalized_rem<const RHS_LIMBS: usize>(
213        &self,
214        rhs: &NonZero<Uint<RHS_LIMBS>>,
215    ) -> Uint<RHS_LIMBS> {
216        let (_, r) = self.div_rem_floor_unsigned(rhs);
217        r
218    }
219}
220
221/// Vartime checked div-floor operations
222impl<const LIMBS: usize> Int<LIMBS> {
223    /// Variable time equivalent of [`Self::div_rem_floor_unsigned`].
224    ///
225    /// This is variable only with respect to `rhs`.
226    ///
227    /// When used with a fixed `rhs`, this function is constant-time with respect
228    /// to `self`.
229    #[must_use]
230    pub fn div_rem_floor_unsigned_vartime<const RHS_LIMBS: usize>(
231        &self,
232        rhs: &NonZero<Uint<RHS_LIMBS>>,
233    ) -> (Self, Uint<RHS_LIMBS>) {
234        let (quotient, remainder, lhs_sgn) = self.div_rem_base_unsigned_vartime(rhs);
235
236        // Increase the quotient by one when self is negative and there is a non-zero remainder.
237        let modify = remainder.is_nonzero().and(lhs_sgn);
238        let quotient = Uint::select(&quotient, &quotient.wrapping_add(&Uint::ONE), modify);
239
240        // Invert the remainder when self is negative and there is a non-zero remainder.
241        let remainder = Uint::select(&remainder, &rhs.wrapping_sub(&remainder), modify);
242
243        // Negate if applicable
244        let quotient = Self(quotient).wrapping_neg_if(lhs_sgn);
245
246        (quotient, remainder)
247    }
248
249    /// Variable time equivalent of [`Self::div_floor_unsigned`].
250    ///
251    /// This is variable only with respect to `rhs`.
252    ///
253    /// When used with a fixed `rhs`, this function is constant-time with respect
254    /// to `self`.
255    #[must_use]
256    pub fn div_floor_unsigned_vartime<const RHS_LIMBS: usize>(
257        &self,
258        rhs: &NonZero<Uint<RHS_LIMBS>>,
259    ) -> Self {
260        let (q, _) = self.div_rem_floor_unsigned_vartime(rhs);
261        q
262    }
263
264    /// Variable time equivalent of [`Self::normalized_rem`].
265    ///
266    /// This is variable only with respect to `rhs`.
267    ///
268    /// When used with a fixed `rhs`, this function is constant-time with respect
269    /// to `self`.
270    #[must_use]
271    pub fn normalized_rem_vartime<const RHS_LIMBS: usize>(
272        &self,
273        rhs: &NonZero<Uint<RHS_LIMBS>>,
274    ) -> Uint<RHS_LIMBS> {
275        let (_, r) = self.div_rem_floor_unsigned_vartime(rhs);
276        r
277    }
278}
279
280impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<&NonZero<Uint<RHS_LIMBS>>> for &Int<LIMBS> {
281    type Output = Int<LIMBS>;
282
283    fn div(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
284        *self / *rhs
285    }
286}
287
288impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<&NonZero<Uint<RHS_LIMBS>>> for Int<LIMBS> {
289    type Output = Int<LIMBS>;
290
291    fn div(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
292        self / *rhs
293    }
294}
295
296impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<NonZero<Uint<RHS_LIMBS>>> for &Int<LIMBS> {
297    type Output = Int<LIMBS>;
298
299    fn div(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
300        *self / rhs
301    }
302}
303
304impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<NonZero<Uint<RHS_LIMBS>>> for Int<LIMBS> {
305    type Output = Int<LIMBS>;
306
307    fn div(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
308        self.div_unsigned(&rhs)
309    }
310}
311
312impl<const LIMBS: usize> DivAssign<&NonZero<Uint<LIMBS>>> for Int<LIMBS> {
313    fn div_assign(&mut self, rhs: &NonZero<Uint<LIMBS>>) {
314        *self /= *rhs;
315    }
316}
317
318impl<const LIMBS: usize> DivAssign<NonZero<Uint<LIMBS>>> for Int<LIMBS> {
319    fn div_assign(&mut self, rhs: NonZero<Uint<LIMBS>>) {
320        *self = *self / rhs;
321    }
322}
323
324impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<NonZero<Uint<RHS_LIMBS>>>
325    for Wrapping<Int<LIMBS>>
326{
327    type Output = Wrapping<Int<LIMBS>>;
328
329    fn div(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
330        Wrapping(self.0 / rhs)
331    }
332}
333
334impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<NonZero<Uint<RHS_LIMBS>>>
335    for &Wrapping<Int<LIMBS>>
336{
337    type Output = Wrapping<Int<LIMBS>>;
338
339    fn div(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
340        *self / rhs
341    }
342}
343
344impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<&NonZero<Uint<RHS_LIMBS>>>
345    for &Wrapping<Int<LIMBS>>
346{
347    type Output = Wrapping<Int<LIMBS>>;
348
349    fn div(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
350        *self / *rhs
351    }
352}
353
354impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<&NonZero<Uint<RHS_LIMBS>>>
355    for Wrapping<Int<LIMBS>>
356{
357    type Output = Wrapping<Int<LIMBS>>;
358
359    fn div(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
360        self / *rhs
361    }
362}
363
364impl<const LIMBS: usize> DivAssign<&NonZero<Uint<LIMBS>>> for Wrapping<Int<LIMBS>> {
365    fn div_assign(&mut self, rhs: &NonZero<Uint<LIMBS>>) {
366        *self = Wrapping(self.0 / rhs);
367    }
368}
369
370impl<const LIMBS: usize> DivAssign<NonZero<Uint<LIMBS>>> for Wrapping<Int<LIMBS>> {
371    fn div_assign(&mut self, rhs: NonZero<Uint<LIMBS>>) {
372        *self /= &rhs;
373    }
374}
375
376impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<&NonZero<Uint<RHS_LIMBS>>> for &Int<LIMBS> {
377    type Output = Int<RHS_LIMBS>;
378
379    fn rem(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
380        *self % *rhs
381    }
382}
383
384impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<&NonZero<Uint<RHS_LIMBS>>> for Int<LIMBS> {
385    type Output = Int<RHS_LIMBS>;
386
387    fn rem(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
388        self % *rhs
389    }
390}
391
392impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<NonZero<Uint<RHS_LIMBS>>> for &Int<LIMBS> {
393    type Output = Int<RHS_LIMBS>;
394
395    fn rem(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
396        *self % rhs
397    }
398}
399
400impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<NonZero<Uint<RHS_LIMBS>>> for Int<LIMBS> {
401    type Output = Int<RHS_LIMBS>;
402
403    fn rem(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
404        Self::rem_unsigned(&self, &rhs)
405    }
406}
407
408impl<const LIMBS: usize> RemAssign<&NonZero<Uint<LIMBS>>> for Int<LIMBS> {
409    fn rem_assign(&mut self, rhs: &NonZero<Uint<LIMBS>>) {
410        *self %= *rhs;
411    }
412}
413
414impl<const LIMBS: usize> RemAssign<NonZero<Uint<LIMBS>>> for Int<LIMBS> {
415    fn rem_assign(&mut self, rhs: NonZero<Uint<LIMBS>>) {
416        *self = *self % rhs;
417    }
418}
419
420impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<NonZero<Uint<RHS_LIMBS>>>
421    for Wrapping<Int<LIMBS>>
422{
423    type Output = Wrapping<Int<RHS_LIMBS>>;
424
425    fn rem(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
426        Wrapping(self.0 % rhs)
427    }
428}
429
430impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<NonZero<Uint<RHS_LIMBS>>>
431    for &Wrapping<Int<LIMBS>>
432{
433    type Output = Wrapping<Int<RHS_LIMBS>>;
434
435    fn rem(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
436        *self % rhs
437    }
438}
439
440impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<&NonZero<Uint<RHS_LIMBS>>>
441    for &Wrapping<Int<LIMBS>>
442{
443    type Output = Wrapping<Int<RHS_LIMBS>>;
444
445    fn rem(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
446        *self % *rhs
447    }
448}
449
450impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<&NonZero<Uint<RHS_LIMBS>>>
451    for Wrapping<Int<LIMBS>>
452{
453    type Output = Wrapping<Int<RHS_LIMBS>>;
454
455    fn rem(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
456        self % *rhs
457    }
458}
459
460impl<const LIMBS: usize> RemAssign<NonZero<Uint<LIMBS>>> for Wrapping<Int<LIMBS>> {
461    fn rem_assign(&mut self, rhs: NonZero<Uint<LIMBS>>) {
462        *self %= &rhs;
463    }
464}
465
466impl<const LIMBS: usize> RemAssign<&NonZero<Uint<LIMBS>>> for Wrapping<Int<LIMBS>> {
467    fn rem_assign(&mut self, rhs: &NonZero<Uint<LIMBS>>) {
468        *self = Wrapping(self.0 % rhs);
469    }
470}
471
472#[cfg(test)]
473mod tests {
474    #[cfg(feature = "rand_core")]
475    use {
476        crate::{I1024, Random, U512, U1024},
477        chacha20::ChaCha8Rng,
478        rand_core::SeedableRng,
479    };
480
481    use crate::{I128, U128};
482
483    #[test]
484    fn test_div_unsigned() {
485        // lhs = min
486        assert_eq!(I128::MIN / U128::ONE.to_nz().unwrap(), I128::MIN);
487        assert_eq!(I128::MIN / U128::MAX.to_nz().unwrap(), I128::ZERO);
488
489        // lhs = -1
490        assert_eq!(
491            I128::MINUS_ONE / U128::ONE.to_nz().unwrap(),
492            I128::MINUS_ONE
493        );
494        assert_eq!(I128::MINUS_ONE / U128::MAX.to_nz().unwrap(), I128::ZERO);
495
496        // lhs = 0
497        assert_eq!(I128::ZERO / U128::ONE.to_nz().unwrap(), I128::ZERO);
498        assert_eq!(I128::ZERO / U128::MAX.to_nz().unwrap(), I128::ZERO);
499
500        // lhs = 1
501        assert_eq!(I128::ONE / U128::ONE.to_nz().unwrap(), I128::ONE);
502        assert_eq!(I128::ONE / U128::MAX.to_nz().unwrap(), I128::ZERO);
503
504        // lhs = max
505        assert_eq!(I128::MAX / U128::ONE.to_nz().unwrap(), I128::MAX);
506        assert_eq!(I128::MAX / U128::MAX.to_nz().unwrap(), I128::ZERO);
507    }
508
509    // TODO(tarcieri): use proptest
510    #[cfg(feature = "rand_core")]
511    #[test]
512    fn test_div_ct_vs_vt() {
513        let mut rng = ChaCha8Rng::from_seed([7u8; 32]);
514        for _ in 0..50 {
515            let num = I1024::random_from_rng(&mut rng);
516            let denom = U1024::from(&U512::random_from_rng(&mut rng))
517                .to_nz()
518                .unwrap();
519
520            assert_eq!(num.div_unsigned(&denom), num.div_unsigned_vartime(&denom));
521        }
522    }
523
524    #[test]
525    fn test_div_rem_floor_unsigned() {
526        // lhs = min
527        assert_eq!(
528            I128::MIN.div_rem_floor_unsigned(&U128::ONE.to_nz().unwrap()),
529            (I128::MIN, U128::ZERO)
530        );
531        assert_eq!(
532            I128::MIN.div_rem_floor_unsigned(&U128::MAX.to_nz().unwrap()),
533            (
534                I128::MINUS_ONE,
535                I128::MIN.as_uint().wrapping_sub(&U128::ONE)
536            )
537        );
538
539        // lhs = -1
540        assert_eq!(
541            I128::MINUS_ONE.div_rem_floor_unsigned(&U128::ONE.to_nz().unwrap()),
542            (I128::MINUS_ONE, U128::ZERO)
543        );
544        assert_eq!(
545            I128::MINUS_ONE.div_rem_floor_unsigned(&U128::MAX.to_nz().unwrap()),
546            (I128::MINUS_ONE, U128::MAX.wrapping_sub(&U128::ONE))
547        );
548
549        // lhs = 0
550        assert_eq!(
551            I128::ZERO.div_rem_floor_unsigned(&U128::ONE.to_nz().unwrap()),
552            (I128::ZERO, U128::ZERO)
553        );
554        assert_eq!(
555            I128::ZERO.div_rem_floor_unsigned(&U128::MAX.to_nz().unwrap()),
556            (I128::ZERO, U128::ZERO)
557        );
558
559        // lhs = 1
560        assert_eq!(
561            I128::ONE.div_rem_floor_unsigned(&U128::ONE.to_nz().unwrap()),
562            (I128::ONE, U128::ZERO)
563        );
564        assert_eq!(
565            I128::ONE.div_rem_floor_unsigned(&U128::MAX.to_nz().unwrap()),
566            (I128::ZERO, U128::ONE)
567        );
568
569        // lhs = max
570        assert_eq!(
571            I128::MAX.div_rem_floor_unsigned(&U128::ONE.to_nz().unwrap()),
572            (I128::MAX, U128::ZERO)
573        );
574        assert_eq!(
575            I128::MAX.div_rem_floor_unsigned(&U128::MAX.to_nz().unwrap()),
576            (I128::ZERO, *I128::MAX.as_uint())
577        );
578    }
579
580    // TODO(tarcieri): use proptest
581    #[cfg(feature = "rand_core")]
582    #[test]
583    fn test_div_floor_ct_vs_vt() {
584        let mut rng = ChaCha8Rng::from_seed([7u8; 32]);
585        for _ in 0..50 {
586            let num = I1024::random_from_rng(&mut rng);
587            let denom = U1024::from(&U512::random_from_rng(&mut rng))
588                .to_nz()
589                .unwrap();
590
591            assert_eq!(
592                num.div_floor_unsigned(&denom),
593                num.div_floor_unsigned_vartime(&denom)
594            );
595        }
596    }
597}