Skip to main content

malachite_nz/natural/arithmetic/
mod_inverse.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::natural::InnerNatural::Small;
10use crate::natural::Natural;
11use crate::natural::arithmetic::gcd::extended_gcd::limbs_extended_gcd;
12use crate::natural::arithmetic::sub::limbs_sub_same_length_in_place_right;
13use malachite_base::num::arithmetic::traits::ModInverse;
14use malachite_base::num::basic::traits::One;
15
16fn mod_inverse_helper(x: Natural, m: Natural) -> Option<Natural> {
17    let mut xs = x.into_limbs_asc();
18    let mut ys = m.to_limbs_asc();
19    let len = ys.len();
20    xs.resize(len, 0);
21    let mut gs = vec![0; len];
22    let mut ss = vec![0; len + 1];
23    let (g_len, ss_sign) = limbs_extended_gcd(&mut gs, &mut ss, &mut xs, &mut ys);
24    gs.truncate(g_len);
25    if Natural::from_owned_limbs_asc(gs) != 1u32 {
26        return None;
27    }
28    if !ss_sign {
29        assert_eq!(ss.pop(), Some(0));
30        limbs_sub_same_length_in_place_right(&m.into_limbs_asc(), &mut ss);
31    }
32    Some(Natural::from_owned_limbs_asc(ss))
33}
34
35impl ModInverse for Natural {
36    type Output = Self;
37
38    /// Computes the multiplicative inverse of a [`Natural`] modulo another [`Natural`] $m$. The
39    /// input must be already reduced modulo $m$. Both [`Natural`]s are taken by value.
40    ///
41    /// Returns `None` if $x$ and $m$ are not coprime.
42    ///
43    /// $f(x, m) = y$, where $x, y < m$, $\gcd(x, y) = 1$, and $xy \equiv 1 \mod m$.
44    ///
45    /// # Worst-case complexity
46    /// $T(n) = O(n (\log n)^2 \log\log n)$
47    ///
48    /// $M(n) = O(n \log n)$
49    ///
50    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
51    /// m.significant_bits())`.
52    ///
53    /// # Panics
54    /// Panics if `self` is 0 or if `self` is greater than or equal to `m`.
55    ///
56    /// # Examples
57    /// ```
58    /// use malachite_base::num::arithmetic::traits::ModInverse;
59    /// use malachite_nz::natural::Natural;
60    ///
61    /// assert_eq!(
62    ///     Natural::from(3u32).mod_inverse(Natural::from(10u32)),
63    ///     Some(Natural::from(7u32))
64    /// );
65    /// assert_eq!(Natural::from(4u32).mod_inverse(Natural::from(10u32)), None);
66    /// ```
67    fn mod_inverse(self, m: Self) -> Option<Self> {
68        assert_ne!(self, 0u32);
69        assert!(self < m, "self must be reduced mod m, but {self} >= {m}");
70        match (self, m) {
71            (x @ Self::ONE, _) => Some(x),
72            (Self(Small(x)), Self(Small(y))) => x.mod_inverse(y).map(Self::from),
73            (a, b) => mod_inverse_helper(a, b),
74        }
75    }
76}
77
78impl<'a> ModInverse<&'a Self> for Natural {
79    type Output = Self;
80
81    /// Computes the multiplicative inverse of a [`Natural`] modulo another [`Natural`] $m$. The
82    /// input must be already reduced modulo $m$. The first [`Natural`] is taken by value and the
83    /// second by reference.
84    ///
85    /// Returns `None` if $x$ and $m$ are not coprime.
86    ///
87    /// $f(x, m) = y$, where $x, y < m$, $\gcd(x, y) = 1$, and $xy \equiv 1 \mod m$.
88    ///
89    /// # Worst-case complexity
90    /// $T(n) = O(n (\log n)^2 \log\log n)$
91    ///
92    /// $M(n) = O(n \log n)$
93    ///
94    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
95    /// m.significant_bits())`.
96    ///
97    /// # Panics
98    /// Panics if `self` is 0 or if `self` is greater than or equal to `m`.
99    ///
100    /// # Examples
101    /// ```
102    /// use malachite_base::num::arithmetic::traits::ModInverse;
103    /// use malachite_nz::natural::Natural;
104    ///
105    /// assert_eq!(
106    ///     Natural::from(3u32).mod_inverse(&Natural::from(10u32)),
107    ///     Some(Natural::from(7u32))
108    /// );
109    /// assert_eq!(Natural::from(4u32).mod_inverse(&Natural::from(10u32)), None);
110    /// ```
111    fn mod_inverse(self, m: &'a Self) -> Option<Self> {
112        assert_ne!(self, 0u32);
113        assert!(self < *m, "self must be reduced mod m, but {self} >= {m}");
114        match (self, m) {
115            (x @ Self::ONE, _) => Some(x),
116            (Self(Small(x)), Self(Small(y))) => x.mod_inverse(*y).map(Self::from),
117            (a, b) => mod_inverse_helper(a, b.clone()),
118        }
119    }
120}
121
122impl ModInverse<Natural> for &Natural {
123    type Output = Natural;
124
125    /// Computes the multiplicative inverse of a [`Natural`] modulo another [`Natural`] $m$. The
126    /// input must be already reduced modulo $m$. The first [`Natural`]s is taken by reference and
127    /// the second by value.
128    ///
129    /// Returns `None` if $x$ and $m$ are not coprime.
130    ///
131    /// $f(x, m) = y$, where $x, y < m$, $\gcd(x, y) = 1$, and $xy \equiv 1 \mod m$.
132    ///
133    /// # Worst-case complexity
134    /// $T(n) = O(n (\log n)^2 \log\log n)$
135    ///
136    /// $M(n) = O(n \log n)$
137    ///
138    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
139    /// m.significant_bits())`.
140    ///
141    /// # Panics
142    /// Panics if `self` is 0 or if `self` is greater than or equal to `m`.
143    ///
144    /// # Examples
145    /// ```
146    /// use malachite_base::num::arithmetic::traits::ModInverse;
147    /// use malachite_nz::natural::Natural;
148    ///
149    /// assert_eq!(
150    ///     (&Natural::from(3u32)).mod_inverse(Natural::from(10u32)),
151    ///     Some(Natural::from(7u32))
152    /// );
153    /// assert_eq!(
154    ///     (&Natural::from(4u32)).mod_inverse(Natural::from(10u32)),
155    ///     None
156    /// );
157    /// ```
158    fn mod_inverse(self, m: Natural) -> Option<Natural> {
159        assert_ne!(*self, 0u32);
160        assert!(*self < m, "self must be reduced mod m, but {self} >= {m}");
161        match (self, m) {
162            (&Natural::ONE, _) => Some(Natural::ONE),
163            (Natural(Small(x)), Natural(Small(y))) => x.mod_inverse(y).map(Natural::from),
164            (a, b) => mod_inverse_helper(a.clone(), b),
165        }
166    }
167}
168
169impl ModInverse<&Natural> for &Natural {
170    type Output = Natural;
171
172    /// Computes the multiplicative inverse of a [`Natural`] modulo another [`Natural`] $m$. The
173    /// input must be already reduced modulo $m$. Both [`Natural`]s are taken by reference.
174    ///
175    /// Returns `None` if $x$ and $m$ are not coprime.
176    ///
177    /// $f(x, m) = y$, where $x, y < m$, $\gcd(x, y) = 1$, and $xy \equiv 1 \mod m$.
178    ///
179    /// # Worst-case complexity
180    /// $T(n) = O(n (\log n)^2 \log\log n)$
181    ///
182    /// $M(n) = O(n \log n)$
183    ///
184    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
185    /// m.significant_bits())`.
186    ///
187    /// # Panics
188    /// Panics if `self` is 0 or if `self` is greater than or equal to `m`.
189    ///
190    /// # Examples
191    /// ```
192    /// use malachite_base::num::arithmetic::traits::ModInverse;
193    /// use malachite_nz::natural::Natural;
194    ///
195    /// assert_eq!(
196    ///     (&Natural::from(3u32)).mod_inverse(&Natural::from(10u32)),
197    ///     Some(Natural::from(7u32))
198    /// );
199    /// assert_eq!(
200    ///     (&Natural::from(4u32)).mod_inverse(&Natural::from(10u32)),
201    ///     None
202    /// );
203    /// ```
204    fn mod_inverse(self, m: &Natural) -> Option<Natural> {
205        assert_ne!(*self, 0u32);
206        assert!(self < m, "self must be reduced mod m, but {self} >= {m}");
207        match (self, m) {
208            (&Natural::ONE, _) => Some(Natural::ONE),
209            (Natural(Small(x)), Natural(Small(y))) => x.mod_inverse(*y).map(Natural::from),
210            (a, b) => mod_inverse_helper(a.clone(), b.clone()),
211        }
212    }
213}