Skip to main content

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);