div.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. use crate::arch::word::Word;
  2. use crate::ibig::IBig;
  3. use crate::modular::modulo::{Modulo, ModuloLarge, ModuloRepr, ModuloSmall, ModuloSmallRaw};
  4. use crate::ops::RemEuclid;
  5. use crate::ubig::UBig;
  6. use core::convert::TryInto;
  7. use core::ops::{Div, DivAssign};
  8. impl<'a> Modulo<'a> {
  9. /// Inverse.
  10. ///
  11. /// Returns `None` if there is no unique inverse.
  12. ///
  13. /// # Examples
  14. ///
  15. /// ```
  16. /// # use ibig::{modular::ModuloRing, ubig};
  17. /// let ring = ModuloRing::new(&ubig!(10));
  18. /// assert_eq!(ring.from(7).inverse(), Some(ring.from(3)));
  19. /// assert_eq!(ring.from(2).inverse(), None);
  20. /// ```
  21. pub fn inverse(&self) -> Option<Modulo<'a>> {
  22. match self.repr() {
  23. ModuloRepr::Small(self_small) => self_small.inverse().map(Into::into),
  24. ModuloRepr::Large(self_large) => self_large.inverse().map(Into::into),
  25. }
  26. }
  27. }
  28. impl<'a> Div<Modulo<'a>> for Modulo<'a> {
  29. type Output = Modulo<'a>;
  30. #[inline]
  31. fn div(self, rhs: Modulo<'a>) -> Modulo<'a> {
  32. (&self).div(&rhs)
  33. }
  34. }
  35. impl<'a> Div<&Modulo<'a>> for Modulo<'a> {
  36. type Output = Modulo<'a>;
  37. #[inline]
  38. fn div(self, rhs: &Modulo<'a>) -> Modulo<'a> {
  39. (&self).div(rhs)
  40. }
  41. }
  42. impl<'a> Div<Modulo<'a>> for &Modulo<'a> {
  43. type Output = Modulo<'a>;
  44. #[inline]
  45. fn div(self, rhs: Modulo<'a>) -> Modulo<'a> {
  46. self.div(&rhs)
  47. }
  48. }
  49. impl<'a> Div<&Modulo<'a>> for &Modulo<'a> {
  50. type Output = Modulo<'a>;
  51. #[inline]
  52. fn div(self, rhs: &Modulo<'a>) -> Modulo<'a> {
  53. // Clippy doesn't like that division is implemented using multiplication.
  54. #[allow(clippy::suspicious_arithmetic_impl)]
  55. match rhs.inverse() {
  56. None => panic!("Division by a non-invertible Modulo"),
  57. Some(inv_rhs) => self * inv_rhs,
  58. }
  59. }
  60. }
  61. impl<'a> DivAssign<Modulo<'a>> for Modulo<'a> {
  62. #[inline]
  63. fn div_assign(&mut self, rhs: Modulo<'a>) {
  64. self.div_assign(&rhs)
  65. }
  66. }
  67. impl<'a> DivAssign<&Modulo<'a>> for Modulo<'a> {
  68. #[inline]
  69. fn div_assign(&mut self, rhs: &Modulo<'a>) {
  70. *self = (&*self).div(rhs)
  71. }
  72. }
  73. impl<'a> ModuloSmall<'a> {
  74. /// Inverse.
  75. fn inverse(&self) -> Option<ModuloSmall<'a>> {
  76. let a = self.residue();
  77. let b = self.ring().modulus();
  78. // TODO: Optimized `extended_gcd` for `Word`s.
  79. // x * a + _ * b == gcd
  80. let (gcd, x, _) = UBig::from(a).extended_gcd(&UBig::from(b));
  81. if gcd == UBig::from_word(1) {
  82. let res: Word = x
  83. .rem_euclid(IBig::from(b))
  84. .try_into()
  85. .unwrap_or_else(|err| {
  86. panic!(
  87. "Panicked with {err:?} at {}:{} (git sha: {:?})",
  88. file!(),
  89. line!(),
  90. option_env!("GIT_SHA")
  91. )
  92. });
  93. Some(ModuloSmall::new(
  94. ModuloSmallRaw::from_word(res, self.ring()),
  95. self.ring(),
  96. ))
  97. } else {
  98. None
  99. }
  100. }
  101. }
  102. impl<'a> ModuloLarge<'a> {
  103. /// Inverse.
  104. fn inverse(&self) -> Option<ModuloLarge<'a>> {
  105. let a = self.residue();
  106. let b = self.ring().modulus();
  107. let (gcd, x, _) = a.extended_gcd(&b);
  108. if gcd == UBig::from_word(1) {
  109. // TODO: Get rid of redundant remainder computations.
  110. let res: UBig = x
  111. .rem_euclid(IBig::from(b))
  112. .try_into()
  113. .unwrap_or_else(|err| {
  114. panic!(
  115. "Panicked with err: {err:?} at {}:{} (git sha: {:?})",
  116. file!(),
  117. line!(),
  118. option_env!("GIT_SHA")
  119. )
  120. });
  121. Some(ModuloLarge::from_ubig(res, self.ring()))
  122. } else {
  123. None
  124. }
  125. }
  126. }