1use super::div_limb::Reciprocal;
4use crate::{
5 CheckedDiv, CtOption, Div, DivAssign, DivRemLimb, DivVartime, Limb, NonZero, Rem, RemAssign,
6 RemLimb, RemMixed, ToUnsigned, Uint, UintRef, Unsigned, Wrapping,
7};
8
9impl<const LIMBS: usize> Uint<LIMBS> {
10 #[must_use]
13 pub const fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) {
14 let mut quo = *self;
15 let rem = quo
16 .as_mut_uint_ref()
17 .div_rem_limb_with_reciprocal(reciprocal);
18 (quo, rem)
19 }
20
21 #[must_use]
23 pub const fn div_rem_limb(&self, rhs: NonZero<Limb>) -> (Self, Limb) {
24 let mut quo = *self;
25 let rem = quo.as_mut_uint_ref().div_rem_limb(rhs);
26 (quo, rem)
27 }
28
29 #[must_use]
31 pub const fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb {
32 self.as_uint_ref()
33 .rem_limb_with_reciprocal(reciprocal, Limb::ZERO)
34 }
35
36 #[must_use]
38 pub const fn rem_limb(&self, rhs: NonZero<Limb>) -> Limb {
39 self.as_uint_ref().rem_limb(rhs)
40 }
41
42 #[must_use]
46 pub const fn div_rem<const RHS_LIMBS: usize>(
47 &self,
48 rhs: &NonZero<Uint<RHS_LIMBS>>,
49 ) -> (Self, Uint<RHS_LIMBS>) {
50 let (mut x, mut y) = (*self, *rhs.as_ref());
51 UintRef::div_rem(x.as_mut_uint_ref(), y.as_mut_uint_ref());
52 (x, y)
53 }
54
55 #[inline]
62 #[must_use]
63 pub const fn div_rem_vartime<const RHS_LIMBS: usize>(
64 &self,
65 rhs: &NonZero<Uint<RHS_LIMBS>>,
66 ) -> (Self, Uint<RHS_LIMBS>) {
67 let (mut x, mut y) = (*self, *rhs.as_ref());
68 UintRef::div_rem_vartime(x.as_mut_uint_ref(), y.as_mut_uint_ref());
69 (x, y)
70 }
71
72 #[must_use]
74 pub(crate) fn div_rem_assign<Rhs: Unsigned>(&mut self, rhs: NonZero<Rhs>) -> Rhs {
75 let mut rem = rhs.get();
76 self.as_mut_uint_ref().div_rem(rem.as_mut_uint_ref());
77 rem
78 }
79
80 #[must_use]
82 pub const fn rem<const RHS_LIMBS: usize>(
83 &self,
84 rhs: &NonZero<Uint<RHS_LIMBS>>,
85 ) -> Uint<RHS_LIMBS> {
86 let (mut x, mut y) = (*self, *rhs.as_ref());
87 UintRef::div_rem(x.as_mut_uint_ref(), y.as_mut_uint_ref());
88 y
89 }
90
91 #[inline]
96 #[must_use]
97 pub const fn rem_vartime<const RHS_LIMBS: usize>(
98 &self,
99 rhs: &NonZero<Uint<RHS_LIMBS>>,
100 ) -> Uint<RHS_LIMBS> {
101 let (mut x, mut y) = (*self, *rhs.as_ref());
102 UintRef::div_rem_vartime(x.as_mut_uint_ref(), y.as_mut_uint_ref());
103 y
104 }
105
106 #[inline]
108 #[must_use]
109 pub const fn rem_wide(mut lower_upper: (Self, Self), rhs: &NonZero<Self>) -> Self {
110 let mut y = *rhs.as_ref();
111 UintRef::rem_wide(
112 (
113 lower_upper.0.as_mut_uint_ref(),
114 lower_upper.1.as_mut_uint_ref(),
115 ),
116 y.as_mut_uint_ref(),
117 );
118 y
119 }
120
121 #[inline]
128 #[must_use]
129 pub const fn rem_wide_vartime(mut lower_upper: (Self, Self), rhs: &NonZero<Self>) -> Self {
130 let mut y = *rhs.as_ref();
131 UintRef::rem_wide_vartime(
132 (
133 lower_upper.0.as_mut_uint_ref(),
134 lower_upper.1.as_mut_uint_ref(),
135 ),
136 y.as_mut_uint_ref(),
137 );
138 y
139 }
140
141 #[must_use]
156 pub const fn rem2k_vartime(&self, k: u32) -> Self {
157 self.restrict_bits(k)
158 }
159
160 #[must_use]
165 pub const fn wrapping_div(&self, rhs: &NonZero<Self>) -> Self {
166 self.div_rem(rhs).0
167 }
168
169 #[must_use]
174 pub const fn wrapping_div_vartime<const RHS: usize>(&self, rhs: &NonZero<Uint<RHS>>) -> Self {
175 self.div_rem_vartime(rhs).0
176 }
177
178 #[must_use]
197 pub fn checked_div<const RHS_LIMBS: usize>(&self, rhs: &Uint<RHS_LIMBS>) -> CtOption<Self> {
198 NonZero::new(*rhs).map(|rhs| self.div_rem(&rhs).0)
199 }
200
201 #[must_use]
217 pub const fn wrapping_rem_vartime(&self, rhs: &Self) -> Self {
218 let nz_rhs = rhs.to_nz().expect_copied("non-zero divisor");
219 self.rem_vartime(&nz_rhs)
220 }
221
222 #[must_use]
241 pub fn checked_rem<const RHS_LIMBS: usize>(
242 &self,
243 rhs: &Uint<RHS_LIMBS>,
244 ) -> CtOption<Uint<RHS_LIMBS>> {
245 NonZero::new(*rhs).map(|rhs| self.rem(&rhs))
246 }
247}
248
249impl<const LIMBS: usize, const RHS_LIMBS: usize> CheckedDiv<Uint<RHS_LIMBS>> for Uint<LIMBS> {
250 fn checked_div(&self, rhs: &Uint<RHS_LIMBS>) -> CtOption<Self> {
251 self.checked_div(rhs)
252 }
253}
254
255impl<const LIMBS: usize, Rhs: Unsigned> Div<Rhs> for &Uint<LIMBS> {
256 type Output = Uint<LIMBS>;
257
258 #[inline]
259 fn div(self, rhs: Rhs) -> Self::Output {
260 *self / rhs
261 }
262}
263
264impl<const LIMBS: usize, Rhs: Unsigned> Div<Rhs> for Uint<LIMBS> {
265 type Output = Uint<LIMBS>;
266
267 #[inline]
268 fn div(self, rhs: Rhs) -> Self::Output {
269 self / NonZero::new(rhs).expect("attempt to divide with a divisor of zero")
270 }
271}
272
273impl<const LIMBS: usize, Rhs: ToUnsigned + ?Sized> Div<&NonZero<Rhs>> for &Uint<LIMBS> {
274 type Output = Uint<LIMBS>;
275
276 fn div(self, rhs: &NonZero<Rhs>) -> Self::Output {
277 let mut quo = *self;
278 let _rem = quo.div_rem_assign(rhs.to_unsigned());
279 quo
280 }
281}
282
283impl<const LIMBS: usize, Rhs: ToUnsigned + ?Sized> Div<&NonZero<Rhs>> for Uint<LIMBS> {
284 type Output = Self;
285
286 fn div(mut self, rhs: &NonZero<Rhs>) -> Self::Output {
287 let _rem = self.div_rem_assign(rhs.to_unsigned());
288 self
289 }
290}
291
292impl<const LIMBS: usize, Rhs: Unsigned> Div<NonZero<Rhs>> for &Uint<LIMBS> {
293 type Output = Uint<LIMBS>;
294
295 fn div(self, rhs: NonZero<Rhs>) -> Self::Output {
296 let mut quo = *self;
297 let _rem = quo.div_rem_assign(rhs);
298 quo
299 }
300}
301
302impl<const LIMBS: usize, Rhs: Unsigned> Div<NonZero<Rhs>> for Uint<LIMBS> {
303 type Output = Self;
304
305 fn div(mut self, rhs: NonZero<Rhs>) -> Self::Output {
306 let _rem = self.div_rem_assign(rhs);
307 self
308 }
309}
310
311impl<const LIMBS: usize, Rhs: ToUnsigned + ?Sized> DivAssign<&NonZero<Rhs>> for Uint<LIMBS> {
312 fn div_assign(&mut self, rhs: &NonZero<Rhs>) {
313 let _rem = self.div_rem_assign(rhs.to_unsigned());
314 }
315}
316
317impl<const LIMBS: usize, Rhs: Unsigned> DivAssign<NonZero<Rhs>> for Uint<LIMBS> {
318 fn div_assign(&mut self, rhs: NonZero<Rhs>) {
319 let _rem = self.div_rem_assign(rhs);
320 }
321}
322
323impl<const LIMBS: usize, Rhs: Unsigned> Div<NonZero<Rhs>> for Wrapping<Uint<LIMBS>> {
324 type Output = Self;
325
326 fn div(self, rhs: NonZero<Rhs>) -> Self::Output {
327 Wrapping(self.0 / rhs)
328 }
329}
330
331impl<const LIMBS: usize, Rhs: Unsigned> Div<NonZero<Rhs>> for &Wrapping<Uint<LIMBS>> {
332 type Output = Wrapping<Uint<LIMBS>>;
333
334 fn div(self, rhs: NonZero<Rhs>) -> Self::Output {
335 Wrapping(self.0 / rhs)
336 }
337}
338
339impl<const LIMBS: usize, Rhs: ToUnsigned + ?Sized> Div<&NonZero<Rhs>> for &Wrapping<Uint<LIMBS>> {
340 type Output = Wrapping<Uint<LIMBS>>;
341
342 fn div(self, rhs: &NonZero<Rhs>) -> Self::Output {
343 Wrapping(self.0 / rhs)
344 }
345}
346
347impl<const LIMBS: usize, Rhs: ToUnsigned + ?Sized> Div<&NonZero<Rhs>> for Wrapping<Uint<LIMBS>> {
348 type Output = Self;
349
350 fn div(self, rhs: &NonZero<Rhs>) -> Self::Output {
351 Wrapping(self.0 / rhs)
352 }
353}
354
355impl<const LIMBS: usize, Rhs: ToUnsigned + ?Sized> DivAssign<&NonZero<Rhs>>
356 for Wrapping<Uint<LIMBS>>
357{
358 fn div_assign(&mut self, rhs: &NonZero<Rhs>) {
359 self.0 /= rhs;
360 }
361}
362
363impl<const LIMBS: usize, Rhs: Unsigned> DivAssign<NonZero<Rhs>> for Wrapping<Uint<LIMBS>> {
364 fn div_assign(&mut self, rhs: NonZero<Rhs>) {
365 self.0 /= rhs;
366 }
367}
368
369impl<const LIMBS: usize> DivVartime for Uint<LIMBS> {
370 fn div_vartime(&self, rhs: &NonZero<Uint<LIMBS>>) -> Self {
371 self.div_rem_vartime(rhs).0
372 }
373}
374
375impl<const LIMBS: usize, Rhs: Unsigned> Rem<Rhs> for &Uint<LIMBS> {
376 type Output = Rhs;
377
378 #[inline]
379 fn rem(self, rhs: Rhs) -> Self::Output {
380 *self % rhs
381 }
382}
383
384impl<const LIMBS: usize, Rhs: Unsigned> Rem<Rhs> for Uint<LIMBS> {
385 type Output = Rhs;
386
387 #[inline]
388 fn rem(self, rhs: Rhs) -> Self::Output {
389 self % NonZero::new(rhs).expect("attempt to calculate the remainder with a divisor of zero")
390 }
391}
392
393impl<const LIMBS: usize, Rhs: ToUnsigned + ?Sized> Rem<&NonZero<Rhs>> for &Uint<LIMBS> {
394 type Output = Rhs::Unsigned;
395
396 #[inline]
397 fn rem(self, rhs: &NonZero<Rhs>) -> Self::Output {
398 (*self).rem(rhs)
399 }
400}
401
402impl<const LIMBS: usize, Rhs: ToUnsigned + ?Sized> Rem<&NonZero<Rhs>> for Uint<LIMBS> {
403 type Output = Rhs::Unsigned;
404
405 #[inline]
406 fn rem(mut self, rhs: &NonZero<Rhs>) -> Self::Output {
407 self.div_rem_assign(rhs.to_unsigned())
408 }
409}
410
411impl<const LIMBS: usize, Rhs: Unsigned> Rem<NonZero<Rhs>> for &Uint<LIMBS> {
412 type Output = Rhs;
413
414 #[inline]
415 fn rem(self, rhs: NonZero<Rhs>) -> Self::Output {
416 (*self).rem(rhs)
417 }
418}
419
420impl<const LIMBS: usize, Rhs: Unsigned> Rem<NonZero<Rhs>> for Uint<LIMBS> {
421 type Output = Rhs;
422
423 #[inline]
424 fn rem(mut self, rhs: NonZero<Rhs>) -> Self::Output {
425 self.div_rem_assign(rhs)
426 }
427}
428
429impl<const LIMBS: usize, Rhs: Unsigned> Rem<NonZero<Rhs>> for Wrapping<Uint<LIMBS>> {
430 type Output = Wrapping<Rhs>;
431
432 fn rem(self, rhs: NonZero<Rhs>) -> Self::Output {
433 Wrapping(self.0 % rhs)
434 }
435}
436
437impl<const LIMBS: usize, Rhs: Unsigned> Rem<NonZero<Rhs>> for &Wrapping<Uint<LIMBS>> {
438 type Output = Wrapping<Rhs>;
439
440 fn rem(self, rhs: NonZero<Rhs>) -> Self::Output {
441 *self % rhs
442 }
443}
444
445impl<const LIMBS: usize, Rhs: ToUnsigned + ?Sized> Rem<&NonZero<Rhs>> for &Wrapping<Uint<LIMBS>> {
446 type Output = Wrapping<Rhs::Unsigned>;
447
448 fn rem(self, rhs: &NonZero<Rhs>) -> Self::Output {
449 *self % rhs.to_unsigned()
450 }
451}
452
453impl<const LIMBS: usize, Rhs: ToUnsigned + ?Sized> Rem<&NonZero<Rhs>> for Wrapping<Uint<LIMBS>> {
454 type Output = Wrapping<Rhs::Unsigned>;
455
456 fn rem(self, rhs: &NonZero<Rhs>) -> Self::Output {
457 self % rhs.to_unsigned()
458 }
459}
460
461impl<const LIMBS: usize, Rhs: Unsigned> RemAssign<NonZero<Rhs>> for Uint<LIMBS> {
462 fn rem_assign(&mut self, rhs: NonZero<Rhs>) {
463 let rem = *self % rhs;
464 *self = rem.as_uint_ref().to_uint_resize();
465 }
466}
467
468impl<const LIMBS: usize, Rhs: ToUnsigned + ?Sized> RemAssign<&NonZero<Rhs>> for Uint<LIMBS> {
469 fn rem_assign(&mut self, rhs: &NonZero<Rhs>) {
470 *self %= rhs.to_unsigned();
471 }
472}
473
474impl<const LIMBS: usize, Rhs: Unsigned> RemAssign<NonZero<Rhs>> for Wrapping<Uint<LIMBS>> {
475 fn rem_assign(&mut self, rhs: NonZero<Rhs>) {
476 *self %= &rhs;
477 }
478}
479
480impl<const LIMBS: usize, Rhs: ToUnsigned + ?Sized> RemAssign<&NonZero<Rhs>>
481 for Wrapping<Uint<LIMBS>>
482{
483 fn rem_assign(&mut self, rhs: &NonZero<Rhs>) {
484 self.0 %= rhs;
485 }
486}
487
488impl<const LIMBS: usize> DivRemLimb for Uint<LIMBS> {
489 fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) {
490 Self::div_rem_limb_with_reciprocal(self, reciprocal)
491 }
492}
493
494impl<const LIMBS: usize> RemLimb for Uint<LIMBS> {
495 fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb {
496 Self::rem_limb_with_reciprocal(self, reciprocal)
497 }
498}
499
500impl<const LIMBS: usize, Rhs: Unsigned> RemMixed<Rhs> for Uint<LIMBS> {
501 fn rem_mixed(&self, reductor: &NonZero<Rhs>) -> Rhs {
502 let (mut quo, mut rem) = (*self, reductor.as_ref().clone());
503 quo.as_mut_uint_ref().div_rem(rem.as_mut_uint_ref());
504 rem
505 }
506}
507
508#[cfg(test)]
509#[allow(clippy::integer_division_remainder_used, reason = "test")]
510mod tests {
511 use crate::{
512 CtAssign, DivVartime, Limb, NonZero, One, RemMixed, U64, U128, U256, U512, U896, U1024,
513 Uint, Word, Wrapping, Zero,
514 };
515
516 #[cfg(feature = "rand_core")]
517 use {crate::Random, chacha20::ChaCha8Rng, rand_core::Rng, rand_core::SeedableRng};
518
519 #[test]
520 fn div_word() {
521 for (n, d, e, ee) in &[
522 (200u64, 2u64, 100u64, 0),
523 (100u64, 25u64, 4u64, 0),
524 (100u64, 10u64, 10u64, 0),
525 (1024u64, 8u64, 128u64, 0),
526 (27u64, 13u64, 2u64, 1u64),
527 (26u64, 13u64, 2u64, 0u64),
528 (14u64, 13u64, 1u64, 1u64),
529 (13u64, 13u64, 1u64, 0u64),
530 (12u64, 13u64, 0u64, 12u64),
531 (1u64, 13u64, 0u64, 1u64),
532 ] {
533 let lhs = U256::from(*n);
534 let rhs = NonZero::new(U256::from(*d)).unwrap();
535 let (q, r) = lhs.div_rem(&rhs);
536 assert_eq!(U256::from(*e), q);
537 assert_eq!(U256::from(*ee), r);
538 let (q, r) = lhs.div_rem_vartime(&rhs);
539 assert_eq!(U256::from(*e), q);
540 assert_eq!(U256::from(*ee), r);
541 }
542 }
543
544 #[cfg(feature = "rand_core")]
545 #[test]
546 fn div() {
547 let mut rng = ChaCha8Rng::from_seed([7u8; 32]);
548 for _ in 0..25 {
549 let num = U256::random_from_rng(&mut rng)
550 .overflowing_shr_vartime(128)
551 .unwrap();
552 let den = NonZero::new(
553 U256::random_from_rng(&mut rng)
554 .overflowing_shr_vartime(128)
555 .unwrap(),
556 )
557 .unwrap();
558 let n = num.checked_mul(den.as_ref());
559 if n.is_some().into() {
560 let n = n.unwrap();
561 let (q, _) = n.div_rem(&den);
562 assert_eq!(q, num);
563 let (q, _) = n.div_rem_vartime(&den);
564 assert_eq!(q, num);
565 }
566 }
567 }
568
569 #[test]
570 fn div_max() {
571 let mut a = U256::ZERO;
572 let mut b = U256::ZERO;
573 b.limbs[b.limbs.len() - 1] = Limb(Word::MAX);
574 let q = a.wrapping_div(&NonZero::new(b).unwrap());
575 assert_eq!(q, Uint::ZERO);
576 a.limbs[a.limbs.len() - 1] = Limb(1 << (Limb::HI_BIT - 7));
577 b.limbs[b.limbs.len() - 1] = Limb(0x82 << (Limb::HI_BIT - 7));
578 let b = NonZero::new(b).unwrap();
579 let q = a.wrapping_div(&b);
580 assert_eq!(q, Uint::ZERO);
581 }
582
583 #[test]
584 fn div_one() {
585 let (q, r) = U256::from(10u8).div_rem(&NonZero::new(U256::ONE).unwrap());
586 assert_eq!(q, U256::from(10u8));
587 assert_eq!(r, U256::ZERO);
588 let (q, r) = U256::from(10u8).div_rem_vartime(&NonZero::new(U256::ONE).unwrap());
589 assert_eq!(q, U256::from(10u8));
590 assert_eq!(r, U256::ZERO);
591 }
592
593 #[test]
594 fn div_edge() {
595 let lo = U128::from_be_hex("00000000000000000000000000000001");
596 let hi = U128::from_be_hex("00000000000000000000000000000001");
597 let y = U128::from_be_hex("00000000000000010000000000000001");
598 let x = U256::from((lo, hi));
599 let expect = (U64::MAX.resize::<{ U256::LIMBS }>(), U256::from(2u64));
600
601 let (q1, r1) = Uint::div_rem(&x, &NonZero::new(y.resize()).unwrap());
602 assert_eq!((q1, r1), expect);
603 let (q2, r2) = Uint::div_rem_vartime(&x, &NonZero::new(y).unwrap());
604 assert_eq!((q2, r2.resize()), expect);
605 let r3 = Uint::rem(&x, &NonZero::new(y.resize()).unwrap());
606 assert_eq!(r3, expect.1);
607 let r4 = Uint::rem_vartime(&x, &NonZero::new(y.resize()).unwrap());
608 assert_eq!(r4, expect.1);
609 let r5 = Uint::rem_wide((lo, hi), &NonZero::new(y).unwrap());
610 assert_eq!(r5.resize(), expect.1);
611 let r6 = Uint::rem_wide_vartime((lo, hi), &NonZero::new(y).unwrap());
612 assert_eq!(r6.resize(), expect.1);
613 }
614
615 #[test]
616 fn div_rem_larger_denominator() {
617 let x = U64::from_be_hex("8000000000000000");
619 let y = U128::from_be_hex("00000000000000010000000000000000")
620 .to_nz()
621 .unwrap();
622 let (quo, rem) = x.div_rem(&y);
623 assert_eq!(quo, Uint::ZERO);
624 assert_eq!(rem, x.resize());
625
626 let x = U64::from_be_hex("8000000000000000");
628 let y = U128::from_be_hex("00000000000000000000000000001000")
629 .to_nz()
630 .unwrap();
631 let (quo, rem) = x.div_rem(&y);
632 assert_eq!(quo, U64::from_be_hex("0008000000000000"));
633 assert_eq!(rem, U128::ZERO);
634
635 let x = U128::from_be_hex("80000000000000008000000000000000");
637 let y =
638 U256::from_be_hex("0000000000000001000000000000000000000000000000010000000000000000")
639 .to_nz()
640 .unwrap();
641 let (quo, rem) = x.div_rem(&y);
642 assert_eq!(quo, U128::ZERO);
643 assert_eq!(rem, x.resize());
644
645 let x = U128::from_be_hex("80000000000000008000000000000000");
647 let y =
648 U256::from_be_hex("0000000000000000000000000000000000000000000000000000000000110000")
649 .to_nz()
650 .unwrap();
651 let (quo, rem) = x.div_rem(&y);
652 assert_eq!(quo, U128::from_be_hex("000007878787878787878f0f0f0f0f0f"));
653 assert_eq!(
654 rem,
655 U256::from_be_hex("0000000000000000000000000000000000000000000000000000000000010000",)
656 );
657 }
658
659 #[test]
660 fn div_rem_larger_numerator() {
661 let denom = U128::from_be_hex("AAAA0000FFFF11117777333344449999");
662 let (full_q, full_r) =
663 U1024::MAX.div_rem(&denom.resize::<{ U1024::LIMBS }>().to_nz().unwrap());
664
665 let (q, r) = U1024::MAX.div_rem(&denom.to_nz().unwrap());
666 assert_eq!(full_q, q);
667 assert_eq!(full_r.resize(), r);
668 }
669
670 #[allow(clippy::op_ref)]
671 #[test]
672 fn div_trait() {
673 let a = U256::from(10u64);
674 let b = NonZero::new(U256::from(2u64)).unwrap();
675 let c = U256::from(5u64);
676
677 assert_eq!(a / b, c);
678 assert_eq!(a / &b, c);
679 assert_eq!(&a / b, c);
680 assert_eq!(&a / &b, c);
681 assert_eq!(Wrapping(a) / b, Wrapping(c));
682 assert_eq!(Wrapping(a) / &b, Wrapping(c));
683 assert_eq!(&Wrapping(a) / b, Wrapping(c));
684 assert_eq!(&Wrapping(a) / &b, Wrapping(c));
685 }
686
687 #[allow(clippy::op_ref)]
688 #[test]
689 fn div_assign_trait() {
690 let a = U256::from(10u64);
691 let b = NonZero::new(U256::from(2u64)).unwrap();
692 let c = U256::from(5u64);
693
694 let mut res = a;
695 res /= b;
696 assert_eq!(res, c);
697 let mut res = a;
698 res /= &b;
699 assert_eq!(res, c);
700
701 let mut res = Wrapping(a);
702 res /= b;
703 assert_eq!(res, Wrapping(c));
704 let mut res = Wrapping(a);
705 res /= &b;
706 assert_eq!(res, Wrapping(c));
707 }
708
709 #[should_panic]
710 #[test]
711 fn div_zero() {
712 let _ = U256::ONE / U256::ZERO;
713 }
714
715 #[should_panic]
716 #[test]
717 #[allow(clippy::op_ref)]
718 fn div_ref_zero() {
719 let _ = &U256::ONE / U256::ZERO;
720 }
721
722 #[test]
723 fn reduce_one() {
724 let r = U256::from(10u8).rem_vartime(&NonZero::new(U256::ONE).unwrap());
725 assert_eq!(r, U256::ZERO);
726 }
727
728 #[test]
729 fn reduce_tests() {
730 let tests = [
731 (U256::from(2u8), 0u8),
732 (U256::from(3u8), 1u8),
733 (U256::from(7u8), 3u8),
734 (U256::MAX, 10u8),
735 ];
736 for (divisor, expect) in tests {
737 let r1 = U256::from(10u8).rem(&NonZero::new(divisor).unwrap());
738 let r2 = U256::from(10u8).rem_vartime(&NonZero::new(divisor).unwrap());
739 assert_eq!(r1, U256::from(expect));
740 assert_eq!(r1, r2);
741 }
742 }
743
744 #[test]
745 fn reduce_tests_wide_zero_padded() {
746 let tests = [
747 (U256::from(2u8), 0u8),
748 (U256::from(3u8), 1u8),
749 (U256::from(7u8), 3u8),
750 (U256::MAX, 10u8),
751 ];
752 for (divisor, expect) in tests {
753 let r1 = U256::rem_wide(
754 (U256::from(10u8), U256::ZERO),
755 &NonZero::new(divisor).unwrap(),
756 );
757 let r2 = U256::rem_wide_vartime(
758 (U256::from(10u8), U256::ZERO),
759 &NonZero::new(divisor).unwrap(),
760 );
761 assert_eq!(r1, U256::from(expect));
762 assert_eq!(r1, r2);
763 }
764 }
765
766 #[test]
767 fn rem_wide_corner_case() {
768 let modulus = "0000000000000000000000000000000081000000000000000000000000000001";
769 let modulus = NonZero::new(U256::from_be_hex(modulus)).expect("it's odd and not zero");
770 let lo_hi = (
771 U256::from_be_hex("1000000000000000000000000000000000000000000000000000000000000001"),
772 U256::ZERO,
773 );
774 let rem = U256::rem_wide(lo_hi, &modulus);
775 assert_eq!(
777 &rem.to_be_bytes().as_ref()[0..16],
778 U128::ZERO.to_be_bytes().as_ref()
779 );
780 let expected = U128::from_be_hex("203F80FE03F80FE03F80FE03F80FE041");
782 assert_eq!(
783 &rem.to_be_bytes().as_ref()[16..],
784 expected.to_be_bytes().as_ref()
785 );
786
787 let remv = U256::rem_wide_vartime(lo_hi, &modulus);
788 assert_eq!(rem, remv);
789 }
790
791 #[test]
792 fn reduce_max() {
793 let mut a = U256::ZERO;
794 let mut b = U256::ZERO;
795 b.limbs[b.limbs.len() - 1] = Limb(Word::MAX);
796 let r = a.wrapping_rem_vartime(&b);
797 assert_eq!(r, Uint::ZERO);
798 a.limbs[a.limbs.len() - 1] = Limb(1 << (Limb::HI_BIT - 7));
799 b.limbs[b.limbs.len() - 1] = Limb(0x82 << (Limb::HI_BIT - 7));
800 let r = a.wrapping_rem_vartime(&b);
801 assert_eq!(r, a);
802 }
803
804 #[cfg(feature = "rand_core")]
805 #[test]
806 fn rem2krand() {
807 let mut rng = ChaCha8Rng::from_seed([7u8; 32]);
808 for _ in 0..25 {
809 let num = U256::random_from_rng(&mut rng);
810 let k = rng.next_u32() % 256;
811 let den = U256::ONE.overflowing_shl_vartime(k).unwrap();
812
813 let a = num.rem2k_vartime(k);
814 let e = num.wrapping_rem_vartime(&den);
815 assert_eq!(a, e);
816 }
817 }
818
819 #[allow(clippy::op_ref)]
820 #[test]
821 fn rem_trait() {
822 let a = U256::from(10u64);
823 let b = NonZero::new(U256::from(3u64)).unwrap();
824 let c = U256::from(1u64);
825
826 assert_eq!(a % b, c);
827 assert_eq!(a % &b, c);
828 assert_eq!(&a % b, c);
829 assert_eq!(&a % &b, c);
830 assert_eq!(Wrapping(a) % b, Wrapping(c));
831 assert_eq!(Wrapping(a) % &b, Wrapping(c));
832 assert_eq!(&Wrapping(a) % b, Wrapping(c));
833 assert_eq!(&Wrapping(a) % &b, Wrapping(c));
834 }
835
836 #[allow(clippy::op_ref)]
837 #[test]
838 fn rem_assign_trait() {
839 let a = U256::from(10u64);
840 let b = NonZero::new(U256::from(3u64)).unwrap();
841 let c = U256::from(1u64);
842
843 let mut res = a;
844 res %= b;
845 assert_eq!(res, c);
846 let mut res = a;
847 res %= &b;
848 assert_eq!(res, c);
849
850 let mut res = Wrapping(a);
851 res %= b;
852 assert_eq!(res, Wrapping(c));
853 let mut res = Wrapping(a);
854 res %= &b;
855 assert_eq!(res, Wrapping(c));
856 }
857
858 #[should_panic]
859 #[test]
860 fn rem_zero() {
861 let _ = U256::ONE % U256::ZERO;
862 }
863
864 #[should_panic]
865 #[test]
866 #[allow(clippy::op_ref)]
867 fn rem_ref_zero() {
868 let _ = &U256::ONE % U256::ZERO;
869 }
870
871 #[test]
872 fn rem_mixed() {
873 let x = U1024::from_be_hex(concat![
874 "3740C11DB8F260753BC6B97DD2B8746D3E2694412772AC6ABD975119EE0A6190",
875 "F27F6F0969BCA069D8D151031AF83EE2283CC2E3E4FADBBDB9EEDBF0B8F4C1FD",
876 "51912C0D329FDC37D49176DB0A1A2D17E5E6D4F9F6B217FE9412EAA2F881F702",
877 "7A831C1B06D31D3618D218D6E667DBD85BFC7B6B6B93422D52516989376AA29A",
878 ]);
879 let y = U128::from_u64(1234567890987654321);
880 let rem = x.rem_mixed(&y.to_nz().unwrap());
881
882 let y2: U1024 = U128::concat_mixed(&y, &U896::ZERO);
883 let rem_control = x.rem(&NonZero::new(y2).unwrap());
884
885 assert_eq!(rem.bits(), rem_control.bits());
886 assert_eq!(rem.as_words(), &rem_control.as_words()[0..U128::LIMBS]);
887 assert!(
888 rem_control.as_words()[U128::LIMBS..]
889 .iter()
890 .all(|w| *w == 0)
891 );
892 }
893
894 #[test]
895 fn rem_mixed_even() {
896 let x = U1024::from_be_hex(concat![
897 "3740C11DB8F260753BC6B97DD2B8746D3E2694412772AC6ABD975119EE0A6190",
898 "F27F6F0969BCA069D8D151031AF83EE2283CC2E3E4FADBBDB9EEDBF0B8F4C1FD",
899 "51912C0D329FDC37D49176DB0A1A2D17E5E6D4F9F6B217FE9412EAA2F881F702",
900 "7A831C1B06D31D3618D218D6E667DBD85BFC7B6B6B93422D52516989376AA29A",
901 ]);
902 let y = U512::from_u64(1234567890987654321);
903 let rem: U512 = x.rem_mixed(&y.to_nz().unwrap());
904
905 let y_wide = U512::concat_mixed(&y, &U512::ZERO);
906 let rem_control: U1024 = x.rem(&NonZero::new(y_wide).unwrap());
907
908 assert_eq!(rem.bits(), rem_control.bits());
909 assert_eq!(rem.as_words(), &rem_control.as_words()[0..U512::LIMBS]);
910 assert!(
911 rem_control.as_words()[U512::LIMBS..]
912 .iter()
913 .all(|w| *w == 0)
914 );
915 }
916
917 #[test]
918 fn rem_mixed_through_traits() {
919 struct A<T, U> {
920 t: T,
921 u: U,
922 }
923 impl<T, U> A<T, U>
924 where
925 T: RemMixed<U>,
926 U: Clone + Zero + One + CtAssign,
927 {
928 fn reduce_t_by_u(&self) -> U {
929 let rhs = &NonZero::new(self.u.clone()).unwrap();
930 self.t.rem_mixed(rhs)
931 }
932 }
933
934 let a = A {
935 t: U1024::from(1234567890u64),
936 u: U128::from(456u64),
937 };
938 assert_eq!(a.reduce_t_by_u(), U128::from(330u64));
939 }
940
941 #[test]
942 fn div_vartime_through_traits() {
943 struct A<T> {
944 x: T,
945 y: T,
946 }
947 impl<T> A<T>
948 where
949 T: DivVartime + Clone + Zero + One + CtAssign,
950 {
951 fn divide_x_by_y(&self) -> T {
952 let rhs = &NonZero::new(self.y.clone()).unwrap();
953 self.x.div_vartime(rhs)
954 }
955 }
956
957 let a = A {
958 x: U1024::from(1234567890u64),
959 y: U1024::from(456u64),
960 };
961 assert_eq!(a.divide_x_by_y(), U1024::from(2707385u64));
962 }
963}