malachite_base/num/arithmetic/mod_pow.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// Uses code adopted from the FLINT Library.
4//
5// Copyright © 2009, 2010, 2012, 2016 William Hart
6//
7// This file is part of Malachite.
8//
9// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
10// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
11// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
12
13use crate::num::arithmetic::mod_mul::{limbs_invert_limb_u32, limbs_invert_limb_u64};
14use crate::num::arithmetic::traits::{
15 ModPow, ModPowAssign, ModPowPrecomputed, ModPowPrecomputedAssign,
16};
17use crate::num::basic::integers::USIZE_IS_U32;
18use crate::num::basic::unsigneds::PrimitiveUnsigned;
19use crate::num::conversion::traits::{HasHalf, JoinHalves, SplitInHalf, WrappingFrom};
20use crate::num::logic::traits::{BitIterable, LeadingZeros};
21
22private_test_fn! {simple_binary_mod_pow<T: PrimitiveUnsigned>(x: T, exp: u64, m: T) -> T {
23 assert!(x < m, "x must be reduced mod m, but {x} >= {m}");
24 if m == T::ONE {
25 return T::ZERO;
26 }
27 let data = T::precompute_mod_mul_data(&m);
28 let mut out = T::ONE;
29 for bit in exp.bits().rev() {
30 out.mod_mul_precomputed_assign(out, m, &data);
31 if bit {
32 out.mod_mul_precomputed_assign(x, m, &data);
33 }
34 }
35 out
36}}
37
38// m.get_highest_bit(), x < m, y < m
39//
40// This is equivalent to `n_mulmod_preinv` from `ulong_extras/mulmod_preinv.c`, FLINT 2.7.1.
41pub(crate) fn mul_mod_helper<
42 T: PrimitiveUnsigned,
43 DT: From<T> + HasHalf<Half = T> + JoinHalves + PrimitiveUnsigned + SplitInHalf,
44>(
45 mut x: T,
46 y: T,
47 m: T,
48 inverse: T,
49 shift: u64,
50) -> T {
51 x >>= shift;
52 let p = DT::from(x) * DT::from(y);
53 let (p_hi, p_lo) = p.split_in_half();
54 let (q_1, q_0) = (DT::from(p_hi) * DT::from(inverse))
55 .wrapping_add(p)
56 .split_in_half();
57 let mut r = p_lo.wrapping_sub(q_1.wrapping_add(T::ONE).wrapping_mul(m));
58 if r > q_0 {
59 r.wrapping_add_assign(m);
60 }
61 if r < m { r } else { r.wrapping_sub(m) }
62}
63
64// m.get_highest_bit(), x < m
65//
66// This is equivalent to `n_powmod_ui_preinv` from ulong_extras/powmod_ui_preinv.c, FLINT 2.7.1.
67pub(crate) fn fast_mod_pow<
68 T: PrimitiveUnsigned,
69 DT: From<T> + HasHalf<Half = T> + JoinHalves + PrimitiveUnsigned + SplitInHalf,
70>(
71 mut x: T,
72 exp: u64,
73 m: T,
74 inverse: T,
75 shift: u64,
76) -> T {
77 assert!(x < m, "x must be reduced mod m, but {x} >= {m}");
78 if exp == 0 {
79 let x = T::power_of_2(shift);
80 if x == m { T::ZERO } else { x }
81 } else if x == T::ZERO {
82 T::ZERO
83 } else {
84 let mut bits = exp.bits();
85 let mut out = if bits.next().unwrap() {
86 x
87 } else {
88 T::power_of_2(shift)
89 };
90 for bit in bits {
91 x = mul_mod_helper::<T, DT>(x, x, m, inverse, shift);
92 if bit {
93 out = mul_mod_helper::<T, DT>(out, x, m, inverse, shift);
94 }
95 }
96 out
97 }
98}
99
100macro_rules! impl_mod_pow_precomputed_fast {
101 ($t:ident, $dt:ident, $invert_limb:ident) => {
102 impl ModPowPrecomputed<u64, $t> for $t {
103 type Output = $t;
104 type Data = ($t, u64);
105
106 /// Precomputes data for modular exponentiation.
107 ///
108 /// See `mod_pow_precomputed` and
109 /// [`mod_pow_precomputed_assign`](super::traits::ModPowPrecomputedAssign).
110 ///
111 /// # Worst-case complexity
112 /// Constant time and additional memory.
113 fn precompute_mod_pow_data(&m: &$t) -> ($t, u64) {
114 let leading_zeros = LeadingZeros::leading_zeros(m);
115 ($invert_limb(m << leading_zeros), leading_zeros)
116 }
117
118 /// Raises a number to a power modulo another number $m$. The base must be already
119 /// reduced modulo $m$.
120 ///
121 /// Some precomputed data is provided; this speeds up computations involving several
122 /// modular exponentiations with the same modulus. The precomputed data should be
123 /// obtained using
124 /// [`precompute_mod_pow_data`](ModPowPrecomputed::precompute_mod_pow_data).
125 ///
126 /// # Worst-case complexity
127 /// $T(n) = O(n)$
128 ///
129 /// $M(n) = O(1)$
130 ///
131 /// where $T$ is time, $M$ is additional memory, and $n$ is `exp.significant_bits()`.
132 /// The square-and-multiply ladder performs one or two modular multiplications per
133 /// exponent bit.
134 ///
135 /// # Panics
136 /// Panics if `self` is greater than or equal to `m`.
137 ///
138 /// # Examples
139 /// See [here](super::mod_pow#mod_pow_precomputed).
140 fn mod_pow_precomputed(self, exp: u64, m: $t, data: &($t, u64)) -> $t {
141 let (inverse, shift) = *data;
142 fast_mod_pow::<$t, $dt>(self << shift, exp, m << shift, inverse, shift) >> shift
143 }
144 }
145 };
146}
147impl_mod_pow_precomputed_fast!(u32, u64, limbs_invert_limb_u32);
148impl_mod_pow_precomputed_fast!(u64, u128, limbs_invert_limb_u64);
149
150macro_rules! impl_mod_pow_precomputed_promoted {
151 ($t:ident) => {
152 impl ModPowPrecomputed<u64, $t> for $t {
153 type Output = $t;
154 type Data = (u32, u64);
155
156 /// Precomputes data for modular exponentiation.
157 ///
158 /// See `mod_pow_precomputed` and
159 /// [`mod_pow_precomputed_assign`](super::traits::ModPowPrecomputedAssign).
160 ///
161 /// # Worst-case complexity
162 /// Constant time and additional memory.
163 fn precompute_mod_pow_data(&m: &$t) -> (u32, u64) {
164 u32::precompute_mod_pow_data(&u32::from(m))
165 }
166
167 /// Raises a number to a power modulo another number $m$. The base must be already
168 /// reduced modulo $m$.
169 ///
170 /// Some precomputed data is provided; this speeds up computations involving several
171 /// modular exponentiations with the same modulus. The precomputed data should be
172 /// obtained using
173 /// [`precompute_mod_pow_data`](ModPowPrecomputed::precompute_mod_pow_data).
174 ///
175 /// # Worst-case complexity
176 /// $T(n) = O(n)$
177 ///
178 /// $M(n) = O(1)$
179 ///
180 /// where $T$ is time, $M$ is additional memory, and $n$ is `exp.significant_bits()`.
181 /// The square-and-multiply ladder performs one or two modular multiplications per
182 /// exponent bit.
183 ///
184 /// # Panics
185 /// Panics if `self` is greater than or equal to `m`.
186 ///
187 /// # Examples
188 /// See [here](super::mod_pow#mod_pow_precomputed).
189 fn mod_pow_precomputed(self, exp: u64, m: $t, data: &(u32, u64)) -> $t {
190 $t::wrapping_from(u32::from(self).mod_pow_precomputed(exp, u32::from(m), data))
191 }
192 }
193 };
194}
195impl_mod_pow_precomputed_promoted!(u8);
196impl_mod_pow_precomputed_promoted!(u16);
197
198impl ModPowPrecomputed<u64, Self> for u128 {
199 type Output = Self;
200 type Data = ();
201
202 /// Precomputes data for modular exponentiation.
203 ///
204 /// See `mod_pow_precomputed` and
205 /// [`mod_pow_precomputed_assign`](super::traits::ModPowPrecomputedAssign).
206 ///
207 /// # Worst-case complexity
208 /// Constant time and additional memory.
209 fn precompute_mod_pow_data(_m: &Self) {}
210
211 /// Raises a number to a power modulo another number $m$. The base must be already reduced
212 /// modulo $m$.
213 ///
214 /// Some precomputed data is provided; this speeds up computations involving several modular
215 /// exponentiations with the same modulus. The precomputed data should be obtained using
216 /// [`precompute_mod_pow_data`](ModPowPrecomputed::precompute_mod_pow_data).
217 ///
218 /// # Worst-case complexity
219 /// $T(n) = O(n)$
220 ///
221 /// $M(n) = O(1)$
222 ///
223 /// where $T$ is time, $M$ is additional memory, and $n$ is `exp.significant_bits()`. The
224 /// square-and-multiply ladder performs one or two modular multiplications per exponent bit.
225 ///
226 /// # Panics
227 /// Panics if `self` is greater than or equal to `m`.
228 ///
229 /// # Examples
230 /// See [here](super::mod_pow#mod_pow_precomputed).
231 #[inline]
232 fn mod_pow_precomputed(self, exp: u64, m: Self, _data: &()) -> Self {
233 simple_binary_mod_pow(self, exp, m)
234 }
235}
236
237impl ModPowPrecomputed<u64, Self> for usize {
238 type Output = Self;
239 type Data = (Self, u64);
240
241 /// Precomputes data for modular exponentiation.
242 ///
243 /// See `mod_pow_precomputed` and
244 /// [`mod_pow_precomputed_assign`](super::traits::ModPowPrecomputedAssign).
245 ///
246 /// # Worst-case complexity
247 /// Constant time and additional memory.
248 fn precompute_mod_pow_data(&m: &Self) -> (Self, u64) {
249 if USIZE_IS_U32 {
250 let (inverse, shift) = u32::precompute_mod_pow_data(&u32::wrapping_from(m));
251 (Self::wrapping_from(inverse), shift)
252 } else {
253 let (inverse, shift) = u64::precompute_mod_pow_data(&u64::wrapping_from(m));
254 (Self::wrapping_from(inverse), shift)
255 }
256 }
257
258 /// Raises a number to a power modulo another number $m$. The base must be already reduced
259 /// modulo $m$.
260 ///
261 /// Some precomputed data is provided; this speeds up computations involving several modular
262 /// exponentiations with the same modulus. The precomputed data should be obtained using
263 /// [`precompute_mod_pow_data`](ModPowPrecomputed::precompute_mod_pow_data).
264 ///
265 /// # Worst-case complexity
266 /// $T(n) = O(n)$
267 ///
268 /// $M(n) = O(1)$
269 ///
270 /// where $T$ is time, $M$ is additional memory, and $n$ is `exp.significant_bits()`. The
271 /// square-and-multiply ladder performs one or two modular multiplications per exponent bit.
272 ///
273 /// # Panics
274 /// Panics if `self` is greater than or equal to `m`.
275 ///
276 /// # Examples
277 /// See [here](super::mod_pow#mod_pow_precomputed).
278 fn mod_pow_precomputed(self, exp: u64, m: Self, data: &(Self, u64)) -> Self {
279 let (inverse, shift) = *data;
280 if USIZE_IS_U32 {
281 Self::wrapping_from(u32::wrapping_from(self).mod_pow_precomputed(
282 exp,
283 u32::wrapping_from(m),
284 &(u32::wrapping_from(inverse), shift),
285 ))
286 } else {
287 Self::wrapping_from(u64::wrapping_from(self).mod_pow_precomputed(
288 exp,
289 u64::wrapping_from(m),
290 &(u64::wrapping_from(inverse), shift),
291 ))
292 }
293 }
294}
295
296macro_rules! impl_mod_pow {
297 ($t:ident) => {
298 impl ModPowPrecomputedAssign<u64, $t> for $t {
299 /// Raises a number to a power modulo another number $m$, in place. The base must be
300 /// already reduced modulo $m$.
301 ///
302 /// Some precomputed data is provided; this speeds up computations involving several
303 /// modular exponentiations with the same modulus. The precomputed data should be
304 /// obtained using
305 /// [`precompute_mod_pow_data`](ModPowPrecomputed::precompute_mod_pow_data).
306 ///
307 /// # Worst-case complexity
308 /// $T(n) = O(n)$
309 ///
310 /// $M(n) = O(1)$
311 ///
312 /// where $T$ is time, $M$ is additional memory, and $n$ is `exp.significant_bits()`.
313 /// The square-and-multiply ladder performs one or two modular multiplications per
314 /// exponent bit.
315 ///
316 /// # Examples
317 /// See [here](super::mod_pow#mod_pow_precomputed_assign).
318 #[inline]
319 fn mod_pow_precomputed_assign(&mut self, exp: u64, m: $t, data: &Self::Data) {
320 *self = self.mod_pow_precomputed(exp, m, data);
321 }
322 }
323
324 impl ModPow<u64> for $t {
325 type Output = $t;
326
327 /// Raises a number to a power modulo another number $m$. The base must be already
328 /// reduced modulo $m$.
329 ///
330 /// $f(x, n, m) = y$, where $x, y < m$ and $x^n \equiv y \mod m$.
331 ///
332 /// # Worst-case complexity
333 /// $T(n) = O(n)$
334 ///
335 /// $M(n) = O(1)$
336 ///
337 /// where $T$ is time, $M$ is additional memory, and $n$ is `exp.significant_bits()`.
338 /// The square-and-multiply ladder performs one or two modular multiplications per
339 /// exponent bit.
340 ///
341 /// # Panics
342 /// Panics if `self` is greater than or equal to `m`.
343 ///
344 /// # Examples
345 /// See [here](super::mod_pow#mod_pow).
346 #[inline]
347 fn mod_pow(self, exp: u64, m: $t) -> $t {
348 simple_binary_mod_pow(self, exp, m)
349 }
350 }
351
352 impl ModPowAssign<u64> for $t {
353 /// Raises a number to a power modulo another number $m$, in place. The base must be
354 /// already reduced modulo $m$.
355 ///
356 /// $x \gets y$, where $x, y < m$ and $x^n \equiv y \mod m$.
357 ///
358 /// # Worst-case complexity
359 /// $T(n) = O(n)$
360 ///
361 /// $M(n) = O(1)$
362 ///
363 /// where $T$ is time, $M$ is additional memory, and $n$ is `exp.significant_bits()`.
364 /// The square-and-multiply ladder performs one or two modular multiplications per
365 /// exponent bit.
366 ///
367 /// # Panics
368 /// Panics if `self` is greater than or equal to `m`.
369 ///
370 /// # Examples
371 /// See [here](super::mod_pow#mod_pow_assign).
372 #[inline]
373 fn mod_pow_assign(&mut self, exp: u64, m: $t) {
374 *self = simple_binary_mod_pow(*self, exp, m);
375 }
376 }
377 };
378}
379apply_to_unsigneds!(impl_mod_pow);