malachite_nz/natural/arithmetic/mod_pow.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MP Library.
4//
5// `getbits`, `MPN_REDC_1`, `win_size`, `redcify`, `mpn_powm`, and `mpz_powm` contributed to
6// the GNU project by Torbjörn Granlund.
7//
8// Copyright (C) 2000-2002, 2004, 2007–2012 Free Software Foundation, Inc.
9//
10// This file is part of Malachite.
11//
12// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
13// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
14// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
15
16use crate::natural::InnerNatural::Small;
17use crate::natural::arithmetic::add::{
18 limbs_add_same_length_to_out, limbs_add_to_out_aliased,
19 limbs_slice_add_same_length_in_place_left,
20};
21use crate::natural::arithmetic::add_mul::limbs_slice_add_mul_limb_same_length_in_place_left;
22use crate::natural::arithmetic::div_exact::{
23 limbs_modular_invert, limbs_modular_invert_limb, limbs_modular_invert_scratch_len,
24};
25use crate::natural::arithmetic::div_mod::limbs_div_limb_to_out_mod;
26use crate::natural::arithmetic::mod_op::limbs_mod_to_out;
27use crate::natural::arithmetic::mod_power_of_2_pow::limbs_pow_low;
28use crate::natural::arithmetic::mul::mul_low::limbs_mul_low_same_length;
29use crate::natural::arithmetic::mul::mul_mod::{
30 limbs_mul_mod_base_pow_n_minus_1, limbs_mul_mod_base_pow_n_minus_1_next_size,
31 limbs_mul_mod_base_pow_n_minus_1_scratch_len,
32};
33use crate::natural::arithmetic::mul::{
34 limbs_mul_greater_to_out_basecase, limbs_mul_same_length_to_out,
35 limbs_mul_same_length_to_out_scratch_len, limbs_mul_to_out, limbs_mul_to_out_scratch_len,
36};
37use crate::natural::arithmetic::shr::limbs_shr_to_out;
38use crate::natural::arithmetic::square::{
39 limbs_square_to_out, limbs_square_to_out_basecase, limbs_square_to_out_scratch_len,
40};
41use crate::natural::arithmetic::sub::{
42 limbs_sub_greater_in_place_left, limbs_sub_limb_in_place, limbs_sub_same_length_in_place_left,
43 limbs_sub_same_length_to_out,
44};
45use crate::natural::comparison::cmp::limbs_cmp_same_length;
46use crate::natural::logic::bit_access::limbs_get_bit;
47use crate::natural::logic::significant_bits::limbs_significant_bits;
48use crate::natural::{Natural, bit_to_limb_count_floor, limb_to_bit_count};
49use crate::platform::{Limb, MUL_TOOM22_THRESHOLD, SQR_BASECASE_THRESHOLD, SQR_TOOM2_THRESHOLD};
50use alloc::vec::Vec;
51use core::cmp::{Ordering::*, max, min};
52use malachite_base::fail_on_untested_path;
53use malachite_base::num::arithmetic::traits::{
54 ModPow, ModPowAssign, ModPowerOf2, ModPowerOf2Assign, Parity, PowerOf2, WrappingNegAssign,
55};
56use malachite_base::num::basic::integers::PrimitiveInt;
57use malachite_base::num::basic::traits::{One, Zero};
58use malachite_base::num::conversion::traits::{ConvertibleFrom, ExactFrom, WrappingFrom};
59use malachite_base::num::logic::traits::TrailingZeros;
60use malachite_base::slices::{slice_leading_zeros, slice_set_zero};
61
62// Equivalent to limbs_slice_get_bits(xs, end.saturating_sub(len), end)[0]
63//
64// # Worst-case complexity
65// Constant time and additional memory.
66//
67// This is equivalent to `getbits` from `mpn/generic/powm.c` and `mpn/generic/powlo.c`, GMP 6.2.1.
68// Investigate changes from 6.1.2?
69pub(crate) fn get_bits(xs: &[Limb], mut end: u64, len: u64) -> usize {
70 usize::exact_from(if end < len {
71 xs[0].mod_power_of_2(end)
72 } else {
73 end -= len;
74 let i = bit_to_limb_count_floor(end);
75 end &= Limb::WIDTH_MASK;
76 let mut bits = xs[i] >> end;
77 let coend = Limb::WIDTH - end;
78 if coend < len {
79 bits += xs[i + 1] << coend;
80 }
81 bits.mod_power_of_2(len)
82 })
83}
84
85// # Worst-case complexity
86// $T(n) = O(n^2)$
87//
88// $M(n) = O(1)$
89//
90// where $T$ is time, $M$ is additional memory, and $n$ is `ms.len()`.
91//
92// This is equivalent to `mpn_redc_1` from `mpn/generic/redc_1.c`, GMP 6.2.1.
93#[allow(clippy::redundant_slicing)]
94fn limbs_redc_limb_raw(out: &mut [Limb], xs: &mut [Limb], ms: &[Limb], m_inv: Limb) -> bool {
95 let len = ms.len();
96 assert_ne!(len, 0);
97 let xs = &mut xs[..len << 1];
98 let mut xs_tail = &mut xs[..]; // force borrow rather than move
99 for _ in 0..len {
100 let product = xs_tail[0].wrapping_mul(m_inv);
101 let carry =
102 limbs_slice_add_mul_limb_same_length_in_place_left(&mut xs_tail[..len], ms, product);
103 assert_eq!(xs_tail[0], 0);
104 xs_tail[0] = carry;
105 xs_tail = &mut xs_tail[1..];
106 }
107 let (xs_lo, xs_hi) = xs.split_at(len);
108 limbs_add_same_length_to_out(out, xs_hi, xs_lo)
109}
110
111// # Worst-case complexity
112// $T(n) = O(n^2)$
113//
114// $M(n) = O(1)$
115//
116// where $T$ is time, $M$ is additional memory, and $n$ is `ms.len()`.
117//
118// This is equivalent to `MPN_REDC_1` from `mpn/generic/powm.c`, GMP 6.2.1. Investigate changes from
119// 6.1.2?
120fn limbs_redc_limb(out: &mut [Limb], xs: &mut [Limb], ms: &[Limb], m_inv: Limb) {
121 if limbs_redc_limb_raw(out, xs, ms, m_inv) {
122 limbs_sub_same_length_in_place_left(&mut out[..ms.len()], ms);
123 }
124}
125
126const WIDTH_LIMITS: [u64; 10] = [7, 25, 81, 241, 673, 1793, 4609, 11521, 28161, u64::MAX];
127
128// # Worst-case complexity
129// Constant time and additional memory.
130//
131// This is equivalent to `win_size` from `mpn/generic/powm.c`, 6.2.1. Investigate changes from
132// 6.1.2?
133pub(crate) fn get_window_size(width: u64) -> u64 {
134 u64::wrapping_from(
135 WIDTH_LIMITS
136 .iter()
137 .position(|&limit| width <= limit)
138 .unwrap()
139 + 1,
140 )
141}
142
143// # Worst-case complexity
144// $T(n) = O(n \log n \log\log n)$
145//
146// $M(n) = O(n \log n)$
147//
148// where $T$ is time, $M$ is additional memory, and $n$ is `ms.len()`.
149//
150// This is equivalent to `mpn_redc_n` from `mpn/generic/redc_n.c`, GMP 6.2.1.
151fn limbs_redc(out: &mut [Limb], xs: &[Limb], ms: &[Limb], is: &[Limb]) {
152 let ms_len = ms.len();
153 assert!(ms_len > 8);
154 let n = limbs_mul_mod_base_pow_n_minus_1_next_size(ms_len);
155 let mut scratch =
156 vec![0; limbs_mul_mod_base_pow_n_minus_1_scratch_len(n, ms_len, ms_len) + ms_len + n];
157 let (scratch_0, scratch) = scratch.split_at_mut(ms_len);
158 limbs_mul_low_same_length(scratch_0, &xs[..ms_len], &is[..ms_len]);
159 let (scratch_1, scratch_2) = scratch.split_at_mut(n);
160 limbs_mul_mod_base_pow_n_minus_1(scratch_1, n, scratch_0, ms, scratch_2);
161 let two_ms_len = ms_len << 1;
162 assert!(two_ms_len > n);
163 let m = two_ms_len - n;
164 let carry = limbs_sub_same_length_to_out(scratch_2, &scratch_1[..m], &xs[..m]);
165 let scratch = &mut scratch[..two_ms_len];
166 if carry {
167 assert!(!limbs_sub_limb_in_place(&mut scratch[m..], 1));
168 }
169 if limbs_sub_same_length_to_out(out, &xs[ms_len..two_ms_len], &scratch[ms_len..]) {
170 limbs_slice_add_same_length_in_place_left(&mut out[..ms_len], ms);
171 }
172}
173
174// Convert U to REDC form, U_r = B^n * U mod M
175//
176// # Worst-case complexity
177// $T(n) = O(n \log n \log\log n)$
178//
179// $M(n) = O(n \log n)$
180//
181// where $T$ is time, $M$ is additional memory, and $n$ is `ms.len()`.
182//
183// This is equivalent to `redcify` from `mpn/generic/powm.c`, 6.2.1. Investigate changes from 6.1.2?
184fn to_redc(out: &mut [Limb], xs: &[Limb], ms: &[Limb]) {
185 let xs_len = xs.len();
186 let ms_len = ms.len();
187 if ms_len == 1 {
188 let mut scratch = vec![0; (xs_len << 1) + ms_len + 1];
189 let (scratch, qs) = scratch.split_at_mut(xs_len + ms_len);
190 scratch[ms_len..].copy_from_slice(xs);
191 out[0] = limbs_div_limb_to_out_mod(qs, scratch, ms[0]);
192 } else {
193 let mut scratch = vec![0; xs_len + ms_len];
194 scratch[ms_len..].copy_from_slice(xs);
195 limbs_mod_to_out(out, &scratch, ms);
196 }
197}
198
199// TODO tune
200const REDC_1_TO_REDC_N_THRESHOLD: usize = 100;
201
202// # Worst-case complexity
203// Constant time and additional memory.
204pub_test! {limbs_mod_pow_odd_scratch_len(n: usize) -> usize {
205 max(limbs_modular_invert_scratch_len(n), n << 1)
206}}
207
208// # Worst-case complexity
209// $T(n) = O(n \log n \log\log n)$
210//
211// $M(n) = O(n \log n)$
212//
213// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
214fn square_using_basecase_mul(out: &mut [Limb], xs: &[Limb]) {
215 limbs_mul_greater_to_out_basecase(out, xs, xs);
216}
217
218// # Worst-case complexity
219// $T(n) = O(n^2)$
220//
221// $M(n) = O(1)$
222//
223// where $T$ is time, $M$ is additional memory, and $n$ is `ms.len()`.
224fn limbs_redc_limb_helper(out: &mut [Limb], xs: &mut [Limb], ms: &[Limb], is: &[Limb]) {
225 limbs_redc_limb(out, xs, ms, is[0]);
226}
227
228// # Worst-case complexity
229// $T(n) = O(n \log n \log\log n)$
230//
231// $M(n) = O(n \log n)$
232//
233// where $T$ is time, $M$ is additional memory, and $n$ is `ms.len()`.
234fn limbs_redc_helper(out: &mut [Limb], xs: &mut [Limb], ms: &[Limb], is: &[Limb]) {
235 limbs_redc(out, xs, ms, is);
236}
237
238// # Worst-case complexity
239// Constant time and additional memory.
240#[allow(clippy::absurd_extreme_comparisons, clippy::type_complexity)]
241fn select_fns(
242 ms_len: usize,
243) -> (
244 &'static dyn Fn(&mut [Limb], &[Limb], &[Limb]),
245 &'static dyn Fn(&mut [Limb], &[Limb]),
246 &'static dyn Fn(&mut [Limb], &mut [Limb], &[Limb], &[Limb]),
247) {
248 if REDC_1_TO_REDC_N_THRESHOLD < MUL_TOOM22_THRESHOLD {
249 if ms_len < REDC_1_TO_REDC_N_THRESHOLD {
250 (
251 &limbs_mul_greater_to_out_basecase,
252 if REDC_1_TO_REDC_N_THRESHOLD < SQR_BASECASE_THRESHOLD
253 || !(SQR_BASECASE_THRESHOLD..=SQR_TOOM2_THRESHOLD).contains(&ms_len)
254 {
255 &square_using_basecase_mul
256 } else {
257 &limbs_square_to_out_basecase
258 },
259 &limbs_redc_limb_helper,
260 )
261 } else if ms_len < MUL_TOOM22_THRESHOLD {
262 (
263 &limbs_mul_greater_to_out_basecase,
264 if MUL_TOOM22_THRESHOLD < SQR_BASECASE_THRESHOLD
265 || !(SQR_BASECASE_THRESHOLD..=SQR_TOOM2_THRESHOLD).contains(&ms_len)
266 {
267 &square_using_basecase_mul
268 } else {
269 &limbs_square_to_out_basecase
270 },
271 &limbs_redc_helper,
272 )
273 } else {
274 (
275 &|out, xs, ys| {
276 let mut mul_scratch =
277 vec![0; limbs_mul_same_length_to_out_scratch_len(xs.len())];
278 limbs_mul_same_length_to_out(out, xs, ys, &mut mul_scratch);
279 },
280 &|out, xs| {
281 let mut square_scratch = vec![0; limbs_square_to_out_scratch_len(xs.len())];
282 limbs_square_to_out(out, xs, &mut square_scratch);
283 },
284 &limbs_redc_helper,
285 )
286 }
287 } else if ms_len < MUL_TOOM22_THRESHOLD {
288 (
289 &limbs_mul_greater_to_out_basecase,
290 if MUL_TOOM22_THRESHOLD < SQR_BASECASE_THRESHOLD
291 || !(SQR_BASECASE_THRESHOLD..=SQR_TOOM2_THRESHOLD).contains(&ms_len)
292 {
293 &square_using_basecase_mul
294 } else {
295 &limbs_square_to_out_basecase
296 },
297 &limbs_redc_limb_helper,
298 )
299 } else {
300 (
301 &|out, xs, ys| {
302 let mut mul_scratch = vec![0; limbs_mul_same_length_to_out_scratch_len(xs.len())];
303 limbs_mul_same_length_to_out(out, xs, ys, &mut mul_scratch);
304 },
305 &|out, xs| {
306 let mut square_scratch = vec![0; limbs_square_to_out_scratch_len(xs.len())];
307 limbs_square_to_out(out, xs, &mut square_scratch);
308 },
309 if ms_len < REDC_1_TO_REDC_N_THRESHOLD {
310 &limbs_redc_limb_helper
311 } else {
312 &limbs_redc_helper
313 },
314 )
315 }
316}
317
318// Given the limbs of $x$, $E$, and odd $m$, writes the limbs of $x^E \mod m$ to an output slice.
319//
320// `xs`, `es`, and `ms` must be nonempty and their last elements must be nonzero. $m$ must be odd,
321// $E$ must be greater than 1, and `out` must be at least as long as `ms`. It is not required than
322// `xs` be less than `ms`.
323//
324// # Worst-case complexity
325// $T(n, m) = O(mn \log n \log\log n)$
326//
327// $M(n) = O(n \log n)$
328//
329// where $T$ is time, $M$ is additional memory, $n$ is `ms.len()`, and $m$ is `es.len()`.
330//
331// # Panics
332// Panics if `xs`, `es`, or `ms` are empty, if `xs` is longer than `ms`, if the first element of
333// `ms` is even, or if $E$ less than 2.
334//
335// This is equivalent to `mpn_powm` from `mpn/generic/powm.c`, GMP 6.2.1.
336pub_test! {limbs_mod_pow_odd(
337 out: &mut [Limb],
338 xs: &[Limb],
339 es: &[Limb],
340 ms: &[Limb],
341 scratch: &mut [Limb],
342) {
343 let xs_len = xs.len();
344 let es_len = es.len();
345 let ms_len = ms.len();
346 assert_ne!(xs_len, 0);
347 assert_ne!(es_len, 0);
348 if es_len == 1 {
349 assert!(es[0] > 1);
350 }
351 assert!(ms[0].odd());
352 let out = &mut out[..ms_len];
353 let width = limbs_significant_bits(es);
354 let window_size = get_window_size(width);
355 let mut small_is = [0; 2];
356 let mut is_vec;
357 let is: &mut [Limb];
358 let redc_fn: &dyn Fn(&mut [Limb], &mut [Limb], &[Limb], &[Limb]);
359 if ms_len < REDC_1_TO_REDC_N_THRESHOLD {
360 is = &mut small_is;
361 is[0] = limbs_modular_invert_limb(ms[0]);
362 is[0].wrapping_neg_assign();
363 redc_fn = &limbs_redc_limb_helper;
364 } else {
365 is_vec = vec![0; ms_len];
366 is = &mut is_vec;
367 limbs_modular_invert(is, ms, scratch);
368 redc_fn = &limbs_redc_helper;
369 }
370 let mut powers = vec![0; ms_len << (window_size - 1)];
371 let mut powers: Vec<&mut [Limb]> = powers.chunks_mut(ms_len).collect();
372 to_redc(powers[0], xs, ms);
373 // Store x ^ 2 at `out`.
374 let mut square_scratch = vec![0; limbs_square_to_out_scratch_len(powers[0].len())];
375 limbs_square_to_out(scratch, powers[0], &mut square_scratch);
376 redc_fn(out, scratch, ms, is);
377 // Precompute odd powers of x and put them in `powers`.
378 let mut mul_scratch = vec![0; limbs_mul_same_length_to_out_scratch_len(out.len())];
379 for i in 1..usize::power_of_2(window_size - 1) {
380 let (powers_lo, powers_hi) = powers.split_at_mut(i);
381 limbs_mul_same_length_to_out(scratch, powers_lo[i - 1], out, &mut mul_scratch);
382 redc_fn(powers_hi[0], scratch, ms, is);
383 }
384 let exp_bits = get_bits(es, width, window_size);
385 let mut bit_index = if width < window_size {
386 fail_on_untested_path("limbs_mod_pow_odd, width < window_size");
387 0
388 } else {
389 width - window_size
390 };
391 let trailing_zeros = TrailingZeros::trailing_zeros(Limb::exact_from(exp_bits));
392 bit_index += trailing_zeros;
393 out.copy_from_slice(powers[exp_bits >> trailing_zeros >> 1]);
394 let (mul_fn, square_fn, reduce_fn) = select_fns(ms_len);
395 'outer: while bit_index != 0 {
396 while !limbs_get_bit(es, bit_index - 1) {
397 square_fn(scratch, out);
398 reduce_fn(out, scratch, ms, is);
399 bit_index -= 1;
400 if bit_index == 0 {
401 break 'outer;
402 }
403 }
404 // The next bit of the exponent is 1. Now extract the largest block of bits <= window_size,
405 // and such that the least significant bit is 1.
406 let exp_bits = get_bits(es, bit_index, window_size);
407 let mut this_window_size = window_size;
408 if bit_index < window_size {
409 this_window_size -= window_size - bit_index;
410 bit_index = 0;
411 } else {
412 bit_index -= window_size;
413 }
414 let trailing_zeros = TrailingZeros::trailing_zeros(Limb::exact_from(exp_bits));
415 bit_index += trailing_zeros;
416 for _ in 0..this_window_size - trailing_zeros {
417 square_fn(scratch, out);
418 reduce_fn(out, scratch, ms, is);
419 }
420 mul_fn(scratch, out, powers[exp_bits >> trailing_zeros >> 1]);
421 reduce_fn(out, scratch, ms, is);
422 }
423 let (scratch_lo, scratch_hi) = scratch.split_at_mut(ms_len);
424 scratch_lo.copy_from_slice(out);
425 slice_set_zero(&mut scratch_hi[..ms_len]);
426 redc_fn(out, scratch, ms, is);
427 if limbs_cmp_same_length(out, ms) != Less {
428 limbs_sub_same_length_in_place_left(out, ms);
429 }
430}}
431
432// Interpreting a `Vec<Limb>` and two `&[Limb]` as the limbs (in ascending order) of three
433// `Natural`s, `x`, `exp`, and `m`, writes the limbs of `x ^ exp` mod `2 ^ m` to an output slice.
434// Assumes the input is already reduced mod `m`. No input may be empty or have trailing zeros, the
435// exponent must be greater than 1, and the output slice must be at least as long as `ms`.
436//
437// # Worst-case complexity
438// $T(n, m) = O(mn \log n \log\log n)$
439//
440// $M(n) = O(n \log n)$
441//
442// where $T$ is time, $M$ is additional memory, $n$ is `ms.len()`, and $m$ is `es.len()`.
443//
444// # Panics
445// Panics if the exponent has trailing zeros or is 1.
446//
447// This is equivalent to `mpz_powm` from `mpn/generic/powm.c`, GMP 6.2.1, where `b`, `e`, and `m`
448// are non-negative. Investigate changes from 6.1.2?
449pub_test! {limbs_mod_pow(out: &mut [Limb], xs: &[Limb], es: &[Limb], ms: &[Limb]) {
450 let ms_len = ms.len();
451 let es_len = es.len();
452 let xs_len = xs.len();
453 let mut ms_zero_len = slice_leading_zeros(ms);
454 let mut ms = &ms[ms_zero_len..];
455 let mut ms_nonzero_len = ms_len - ms_zero_len;
456 let mut ms_vec;
457 let mut ms_twos = 0;
458 if ms[0].even() {
459 ms_vec = vec![0; ms_nonzero_len];
460 ms_twos = TrailingZeros::trailing_zeros(ms[0]);
461 limbs_shr_to_out(&mut ms_vec, &ms[..ms_nonzero_len], ms_twos);
462 if ms_vec[ms_nonzero_len - 1] == 0 {
463 ms_nonzero_len -= 1;
464 }
465 ms = &ms_vec;
466 ms_zero_len += 1;
467 }
468 let scratch_len = if ms_zero_len != 0 {
469 // We will call both `limbs_mod_pow_odd` and `limbs_pow_low`.
470 let max_invert_len = max(ms_zero_len, ms_nonzero_len);
471 let invert_scratch_len = limbs_modular_invert_scratch_len(max_invert_len);
472 (ms_len << 1) + max(invert_scratch_len, ms_len << 1)
473 } else {
474 // We will call just `limbs_mod_pow_odd`.
475 let invert_scratch_len = limbs_modular_invert_scratch_len(ms_nonzero_len);
476 max(invert_scratch_len, ms_len << 1)
477 };
478 let mut scratch = vec![0; scratch_len];
479 limbs_mod_pow_odd(out, xs, es, &ms[..ms_nonzero_len], &mut scratch);
480 let mut xs_vec;
481 let mut xs = xs;
482 if ms_zero_len != 0 {
483 if xs_len < ms_zero_len {
484 xs_vec = vec![0; ms_zero_len];
485 xs_vec[..xs_len].copy_from_slice(xs);
486 xs = &xs_vec;
487 }
488 let mut do_pow_low = true;
489 let (scratch_lo, scratch_hi) = scratch.split_at_mut(ms_zero_len);
490 if xs[0].even() {
491 if es_len > 1 {
492 slice_set_zero(scratch_lo);
493 do_pow_low = false;
494 } else {
495 assert_eq!(es_len, 1);
496 let t = if ms_twos == 0 {
497 limb_to_bit_count(ms_zero_len)
498 } else {
499 limb_to_bit_count(ms_zero_len - 1) + ms_twos
500 };
501 // Count number of low zero bits in `xs`, up to 3.
502 let bits =
503 (Limb::exact_from(0x1213) >> (xs[0].mod_power_of_2(3) << 1)).mod_power_of_2(2);
504 // Note that es[0] * bits might overflow, but that just results in a missed
505 // optimization.
506 #[cfg(feature = "32_bit_limbs")]
507 if let Ok(t) = Limb::try_from(t)
508 && es[0].wrapping_mul(bits) >= t
509 {
510 slice_set_zero(scratch_lo);
511 do_pow_low = false;
512 }
513 #[cfg(not(feature = "32_bit_limbs"))]
514 if es[0].wrapping_mul(bits) >= t {
515 slice_set_zero(scratch_lo);
516 do_pow_low = false;
517 }
518 }
519 }
520 if do_pow_low {
521 scratch_lo.copy_from_slice(&xs[..ms_zero_len]);
522 limbs_pow_low(scratch_lo, &es[..es_len], scratch_hi);
523 }
524 let mut ms_vec;
525 if ms_nonzero_len < ms_zero_len {
526 ms_vec = vec![0; ms_zero_len];
527 ms_vec[..ms_nonzero_len].copy_from_slice(&ms[..ms_nonzero_len]);
528 ms = &ms_vec;
529 }
530 let (scratch_0_1, scratch_2) = scratch.split_at_mut(ms_len << 1);
531 let (scratch_0, scratch_1) = scratch_0_1.split_at_mut(ms_len);
532 let scratch_0 = &mut scratch_0[..ms_zero_len];
533 limbs_modular_invert(scratch_1, &ms[..ms_zero_len], scratch_2);
534 limbs_sub_greater_in_place_left(scratch_0, &out[..min(ms_zero_len, ms_nonzero_len)]);
535 limbs_mul_low_same_length(scratch_2, &scratch_1[..ms_zero_len], scratch_0);
536 if ms_twos != 0 {
537 scratch_2[ms_zero_len - 1].mod_power_of_2_assign(ms_twos);
538 }
539 let mut mul_scratch = vec![0; limbs_mul_to_out_scratch_len(ms_zero_len, ms_nonzero_len)];
540 limbs_mul_to_out(
541 scratch_0_1,
542 &scratch_2[..ms_zero_len],
543 &ms[..ms_nonzero_len],
544 &mut mul_scratch,
545 );
546 limbs_add_to_out_aliased(out, ms_nonzero_len, &scratch_0_1[..ms_len]);
547 }
548}}
549
550impl ModPow<Self, Self> for Natural {
551 type Output = Self;
552
553 /// Raises a [`Natural`] to a [`Natural`] power modulo a third [`Natural`] $m$. The base must be
554 /// already reduced modulo $m$. All three [`Natural`]s are taken by value.
555 ///
556 /// $f(x, n, m) = y$, where $x, y < m$ and $x^n \equiv y \mod m$.
557 ///
558 /// # Worst-case complexity
559 /// $T(n, m) = O(mn \log n \log\log n)$
560 ///
561 /// $M(n) = O(n \log n)$
562 ///
563 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$ is
564 /// `exp.significant_bits()`.
565 ///
566 /// # Panics
567 /// Panics if `self` is greater than or equal to `m`.
568 ///
569 /// # Examples
570 /// ```
571 /// use malachite_base::num::arithmetic::traits::ModPow;
572 /// use malachite_nz::natural::Natural;
573 ///
574 /// assert_eq!(
575 /// Natural::from(4u32).mod_pow(Natural::from(13u32), Natural::from(497u32)),
576 /// 445
577 /// );
578 /// assert_eq!(
579 /// Natural::from(10u32).mod_pow(Natural::from(1000u32), Natural::from(30u32)),
580 /// 10
581 /// );
582 /// ```
583 #[inline]
584 fn mod_pow(mut self, exp: Self, m: Self) -> Self {
585 self.mod_pow_assign(exp, m);
586 self
587 }
588}
589
590impl<'a> ModPow<Self, &'a Self> for Natural {
591 type Output = Self;
592
593 /// Raises a [`Natural`] to a [`Natural`] power modulo a third [`Natural`] $m$. The base must be
594 /// already reduced modulo $m$. The first two [`Natural`]s are taken by value and the third by
595 /// reference.
596 ///
597 /// $f(x, n, m) = y$, where $x, y < m$ and $x^n \equiv y \mod m$.
598 ///
599 /// # Worst-case complexity
600 /// $T(n, m) = O(mn \log n \log\log n)$
601 ///
602 /// $M(n) = O(n \log n)$
603 ///
604 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$ is
605 /// `exp.significant_bits()`.
606 ///
607 /// # Panics
608 /// Panics if `self` is greater than or equal to `m`.
609 ///
610 /// # Examples
611 /// ```
612 /// use malachite_base::num::arithmetic::traits::ModPow;
613 /// use malachite_nz::natural::Natural;
614 ///
615 /// assert_eq!(
616 /// Natural::from(4u32).mod_pow(Natural::from(13u32), &Natural::from(497u32)),
617 /// 445
618 /// );
619 /// assert_eq!(
620 /// Natural::from(10u32).mod_pow(Natural::from(1000u32), &Natural::from(30u32)),
621 /// 10
622 /// );
623 /// ```
624 #[inline]
625 fn mod_pow(mut self, exp: Self, m: &'a Self) -> Self {
626 self.mod_pow_assign(exp, m);
627 self
628 }
629}
630
631impl<'a> ModPow<&'a Self, Self> for Natural {
632 type Output = Self;
633
634 /// Raises a [`Natural`] to a [`Natural`] power modulo a third [`Natural`] $m$. The base must be
635 /// already reduced modulo $m$. The first and third [`Natural`]s are taken by value and the
636 /// second by reference.
637 ///
638 /// $f(x, n, m) = y$, where $x, y < m$ and $x^n \equiv y \mod m$.
639 ///
640 /// # Worst-case complexity
641 /// $T(n, m) = O(mn \log n \log\log n)$
642 ///
643 /// $M(n) = O(n \log n)$
644 ///
645 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$ is
646 /// `exp.significant_bits()`.
647 ///
648 /// # Panics
649 /// Panics if `self` is greater than or equal to `m`.
650 ///
651 /// # Examples
652 /// ```
653 /// use malachite_base::num::arithmetic::traits::ModPow;
654 /// use malachite_nz::natural::Natural;
655 ///
656 /// assert_eq!(
657 /// Natural::from(4u32).mod_pow(&Natural::from(13u32), Natural::from(497u32)),
658 /// 445
659 /// );
660 /// assert_eq!(
661 /// Natural::from(10u32).mod_pow(&Natural::from(1000u32), Natural::from(30u32)),
662 /// 10
663 /// );
664 /// ```
665 #[inline]
666 fn mod_pow(mut self, exp: &'a Self, m: Self) -> Self {
667 self.mod_pow_assign(exp, m);
668 self
669 }
670}
671
672impl<'a, 'b> ModPow<&'a Self, &'b Self> for Natural {
673 type Output = Self;
674
675 /// Raises a [`Natural`] to a [`Natural`] power modulo a third [`Natural`] $m$. The base must be
676 /// already reduced modulo $m$. The first [`Natural`] is taken by value and the second and third
677 /// by reference.
678 ///
679 /// $f(x, n, m) = y$, where $x, y < m$ and $x^n \equiv y \mod m$.
680 ///
681 /// # Worst-case complexity
682 /// $T(n, m) = O(mn \log n \log\log n)$
683 ///
684 /// $M(n) = O(n \log n)$
685 ///
686 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$ is
687 /// `exp.significant_bits()`.
688 ///
689 /// # Panics
690 /// Panics if `self` is greater than or equal to `m`.
691 ///
692 /// # Examples
693 /// ```
694 /// use malachite_base::num::arithmetic::traits::ModPow;
695 /// use malachite_nz::natural::Natural;
696 ///
697 /// assert_eq!(
698 /// Natural::from(4u32).mod_pow(&Natural::from(13u32), &Natural::from(497u32)),
699 /// 445
700 /// );
701 /// assert_eq!(
702 /// Natural::from(10u32).mod_pow(&Natural::from(1000u32), &Natural::from(30u32)),
703 /// 10
704 /// );
705 /// ```
706 #[inline]
707 fn mod_pow(mut self, exp: &'a Self, m: &'b Self) -> Self {
708 self.mod_pow_assign(exp, m);
709 self
710 }
711}
712
713impl ModPow<Natural, Natural> for &Natural {
714 type Output = Natural;
715
716 /// Raises a [`Natural`] to a [`Natural`] power modulo a third [`Natural`]$m$. The base must be
717 /// already reduced modulo $m$. The first [`Natural`] is taken by reference and the second and
718 /// third by value.
719 ///
720 /// $f(x, n, m) = y$, where $x, y < m$ and $x^n \equiv y \mod m$.
721 ///
722 /// # Worst-case complexity
723 /// $T(n, m) = O(mn \log n \log\log n)$
724 ///
725 /// $M(n) = O(n \log n)$
726 ///
727 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$ is
728 /// `exp.significant_bits()`.
729 ///
730 /// # Panics
731 /// Panics if `self` is greater than or equal to `m`.
732 ///
733 /// # Examples
734 /// ```
735 /// use malachite_base::num::arithmetic::traits::ModPow;
736 /// use malachite_nz::natural::Natural;
737 ///
738 /// assert_eq!(
739 /// (&Natural::from(4u32)).mod_pow(Natural::from(13u32), Natural::from(497u32)),
740 /// 445
741 /// );
742 /// assert_eq!(
743 /// (&Natural::from(10u32)).mod_pow(Natural::from(1000u32), Natural::from(30u32)),
744 /// 10
745 /// );
746 /// ```
747 #[allow(clippy::match_same_arms)] // matches are order-dependent
748 fn mod_pow(self, mut exp: Natural, mut m: Natural) -> Natural {
749 assert!(*self < m, "self must be reduced mod m, but {self} >= {m}");
750 match (self, &exp, &m) {
751 (_, _, &Natural::ONE) => Natural::ZERO,
752 (_, &Natural::ZERO, _) => Natural::ONE,
753 (&Natural::ZERO, _, _) => Natural::ZERO,
754 (x, &Natural::ONE, _) => x.clone(),
755 (&Natural::ONE, _, _) => Natural::ONE,
756 (Natural(Small(x)), Natural(Small(e)), Natural(Small(m)))
757 if u64::convertible_from(*e) =>
758 {
759 Natural::from(x.mod_pow(u64::wrapping_from(*e), *m))
760 }
761 _ => {
762 let ms = m.promote_in_place();
763 let mut out = vec![0; ms.len()];
764 limbs_mod_pow(&mut out, self.as_limbs_asc(), exp.promote_in_place(), ms);
765 Natural::from_owned_limbs_asc(out)
766 }
767 }
768 }
769}
770
771impl ModPow<Natural, &Natural> for &Natural {
772 type Output = Natural;
773
774 /// Raises a [`Natural`] to a [`Natural`] power modulo a third [`Natural`] $m$. The base must be
775 /// already reduced modulo $m$. The first and third [`Natural`]s are taken by reference and the
776 /// second by value.
777 ///
778 /// $f(x, n, m) = y$, where $x, y < m$ and $x^n \equiv y \mod m$.
779 ///
780 /// # Worst-case complexity
781 /// $T(n, m) = O(mn \log n \log\log n)$
782 ///
783 /// $M(n) = O(n \log n)$
784 ///
785 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$ is
786 /// `exp.significant_bits()`.
787 ///
788 /// # Panics
789 /// Panics if `self` is greater than or equal to `m`.
790 ///
791 /// # Examples
792 /// ```
793 /// use malachite_base::num::arithmetic::traits::ModPow;
794 /// use malachite_nz::natural::Natural;
795 ///
796 /// assert_eq!(
797 /// (&Natural::from(4u32)).mod_pow(Natural::from(13u32), &Natural::from(497u32)),
798 /// 445
799 /// );
800 /// assert_eq!(
801 /// (&Natural::from(10u32)).mod_pow(Natural::from(1000u32), &Natural::from(30u32)),
802 /// 10
803 /// );
804 /// ```
805 #[allow(clippy::match_same_arms)] // matches are order-dependent
806 fn mod_pow(self, mut exp: Natural, m: &Natural) -> Natural {
807 assert!(self < m, "self must be reduced mod m, but {self} >= {m}");
808 match (self, &exp, m) {
809 (_, _, &Natural::ONE) => Natural::ZERO,
810 (_, &Natural::ZERO, _) => Natural::ONE,
811 (&Natural::ZERO, _, _) => Natural::ZERO,
812 (x, &Natural::ONE, _) => x.clone(),
813 (&Natural::ONE, _, _) => Natural::ONE,
814 (Natural(Small(x)), Natural(Small(e)), Natural(Small(m)))
815 if u64::convertible_from(*e) =>
816 {
817 Natural::from(x.mod_pow(u64::wrapping_from(*e), *m))
818 }
819 _ => {
820 let ms = m.as_limbs_asc();
821 let mut out = vec![0; ms.len()];
822 limbs_mod_pow(&mut out, self.as_limbs_asc(), exp.promote_in_place(), ms);
823 Natural::from_owned_limbs_asc(out)
824 }
825 }
826 }
827}
828
829impl ModPow<&Natural, Natural> for &Natural {
830 type Output = Natural;
831
832 /// Raises a [`Natural`] to a [`Natural`] power modulo a third [`Natural`] $m$. The base must be
833 /// already reduced modulo $m$. The first two [`Natural`]s are taken by reference and the third
834 /// by value.
835 ///
836 /// $f(x, n, m) = y$, where $x, y < m$ and $x^n \equiv y \mod m$.
837 ///
838 /// # Worst-case complexity
839 /// $T(n, m) = O(mn \log n \log\log n)$
840 ///
841 /// $M(n) = O(n \log n)$
842 ///
843 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$ is
844 /// `exp.significant_bits()`.
845 ///
846 /// # Panics
847 /// Panics if `self` is greater than or equal to `m`.
848 ///
849 /// # Examples
850 /// ```
851 /// use malachite_base::num::arithmetic::traits::ModPow;
852 /// use malachite_nz::natural::Natural;
853 ///
854 /// assert_eq!(
855 /// (&Natural::from(4u32)).mod_pow(&Natural::from(13u32), Natural::from(497u32)),
856 /// 445
857 /// );
858 /// assert_eq!(
859 /// (&Natural::from(10u32)).mod_pow(&Natural::from(1000u32), Natural::from(30u32)),
860 /// 10
861 /// );
862 /// ```
863 #[allow(clippy::match_same_arms)] // matches are order-dependent
864 fn mod_pow(self, exp: &Natural, mut m: Natural) -> Natural {
865 assert!(*self < m, "self must be reduced mod m, but {self} >= {m}");
866 match (self, exp, &m) {
867 (_, _, &Natural::ONE) => Natural::ZERO,
868 (_, &Natural::ZERO, _) => Natural::ONE,
869 (&Natural::ZERO, _, _) => Natural::ZERO,
870 (x, &Natural::ONE, _) => x.clone(),
871 (&Natural::ONE, _, _) => Natural::ONE,
872 (Natural(Small(x)), Natural(Small(e)), Natural(Small(m)))
873 if u64::convertible_from(*e) =>
874 {
875 Natural::from(x.mod_pow(u64::wrapping_from(*e), *m))
876 }
877 _ => {
878 let ms = m.promote_in_place();
879 let mut out = vec![0; ms.len()];
880 limbs_mod_pow(&mut out, self.as_limbs_asc(), exp.as_limbs_asc(), ms);
881 Natural::from_owned_limbs_asc(out)
882 }
883 }
884 }
885}
886
887impl ModPow<&Natural, &Natural> for &Natural {
888 type Output = Natural;
889
890 /// Raises a [`Natural`] to a [`Natural`] power modulo a third [`Natural`] $m$. The base must be
891 /// already reduced modulo $m$. All three [`Natural`]s are taken by reference.
892 ///
893 /// $f(x, n, m) = y$, where $x, y < m$ and $x^n \equiv y \mod m$.
894 ///
895 /// # Worst-case complexity
896 /// $T(n, m) = O(mn \log n \log\log n)$
897 ///
898 /// $M(n) = O(n \log n)$
899 ///
900 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$ is
901 /// `exp.significant_bits()`.
902 ///
903 /// # Panics
904 /// Panics if `self` is greater than or equal to `m`.
905 ///
906 /// # Examples
907 /// ```
908 /// use malachite_base::num::arithmetic::traits::ModPow;
909 /// use malachite_nz::natural::Natural;
910 ///
911 /// assert_eq!(
912 /// (&Natural::from(4u32)).mod_pow(&Natural::from(13u32), &Natural::from(497u32)),
913 /// 445
914 /// );
915 /// assert_eq!(
916 /// (&Natural::from(10u32)).mod_pow(&Natural::from(1000u32), &Natural::from(30u32)),
917 /// 10
918 /// );
919 /// ```
920 #[allow(clippy::match_same_arms)] // matches are order-dependent
921 fn mod_pow(self, exp: &Natural, m: &Natural) -> Natural {
922 assert!(self < m, "self must be reduced mod m, but {self} >= {m}");
923 match (self, exp, m) {
924 (_, _, &Natural::ONE) => Natural::ZERO,
925 (_, &Natural::ZERO, _) => Natural::ONE,
926 (&Natural::ZERO, _, _) => Natural::ZERO,
927 (x, &Natural::ONE, _) => x.clone(),
928 (&Natural::ONE, _, _) => Natural::ONE,
929 (Natural(Small(x)), Natural(Small(e)), Natural(Small(m)))
930 if u64::convertible_from(*e) =>
931 {
932 Natural::from(x.mod_pow(u64::wrapping_from(*e), *m))
933 }
934 _ => {
935 let ms = m.as_limbs_asc();
936 let mut out = vec![0; ms.len()];
937 limbs_mod_pow(&mut out, self.as_limbs_asc(), exp.as_limbs_asc(), ms);
938 Natural::from_owned_limbs_asc(out)
939 }
940 }
941 }
942}
943
944impl ModPowAssign<Self, Self> for Natural {
945 /// Raises a [`Natural`] to a [`Natural`] power modulo a third [`Natural`] $m$, in place. The
946 /// base must be already reduced modulo $m$. Both [`Natural`]s on the right-hand side are taken
947 /// by value.
948 ///
949 /// $x \gets y$, where $x, y < m$ and $x^n \equiv y \mod m$.
950 ///
951 /// # Worst-case complexity
952 /// $T(n, m) = O(mn \log n \log\log n)$
953 ///
954 /// $M(n) = O(n \log n)$
955 ///
956 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$ is
957 /// `exp.significant_bits()`.
958 ///
959 /// # Panics
960 /// Panics if `self` is greater than or equal to `m`.
961 ///
962 /// # Examples
963 /// ```
964 /// use malachite_base::num::arithmetic::traits::ModPowAssign;
965 /// use malachite_nz::natural::Natural;
966 ///
967 /// let mut x = Natural::from(4u32);
968 /// x.mod_pow_assign(Natural::from(13u32), Natural::from(497u32));
969 /// assert_eq!(x, 445);
970 ///
971 /// let mut x = Natural::from(10u32);
972 /// x.mod_pow_assign(Natural::from(1000u32), Natural::from(30u32));
973 /// assert_eq!(x, 10);
974 /// ```
975 #[allow(clippy::match_same_arms)] // matches are order-dependent
976 fn mod_pow_assign(&mut self, mut exp: Self, mut m: Self) {
977 assert!(*self < m, "self must be reduced mod m, but {self} >= {m}");
978 match (&mut *self, &exp, &m) {
979 (_, _, &Self::ONE) => *self = Self::ZERO,
980 (_, &Self::ZERO, _) => *self = Self::ONE,
981 (&mut (Self::ZERO | Self::ONE), _, _) | (_, &Self::ONE, _) => {}
982 (Self(Small(x)), Self(Small(e)), Self(Small(m))) if u64::convertible_from(*e) => {
983 x.mod_pow_assign(u64::wrapping_from(*e), *m);
984 }
985 _ => {
986 let ms = m.promote_in_place();
987 let mut out = vec![0; ms.len()];
988 limbs_mod_pow(
989 &mut out,
990 self.promote_in_place(),
991 exp.promote_in_place(),
992 ms,
993 );
994 *self = Self::from_owned_limbs_asc(out);
995 }
996 }
997 }
998}
999
1000impl<'a> ModPowAssign<Self, &'a Self> for Natural {
1001 /// Raises a [`Natural`] to a [`Natural`] power modulo a third [`Natural`] $m$, in place. The
1002 /// base must be already reduced modulo $m$. The first [`Natural`] on the right-hand side is
1003 /// taken by value and the second by reference.
1004 ///
1005 /// $x \gets y$, where $x, y < m$ and $x^n \equiv y \mod m$.
1006 ///
1007 /// # Worst-case complexity
1008 /// $T(n, m) = O(mn \log n \log\log n)$
1009 ///
1010 /// $M(n) = O(n \log n)$
1011 ///
1012 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$ is
1013 /// `exp.significant_bits()`.
1014 ///
1015 /// # Panics
1016 /// Panics if `self` is greater than or equal to `m`.
1017 ///
1018 /// # Examples
1019 /// ```
1020 /// use malachite_base::num::arithmetic::traits::ModPowAssign;
1021 /// use malachite_nz::natural::Natural;
1022 ///
1023 /// let mut x = Natural::from(4u32);
1024 /// x.mod_pow_assign(Natural::from(13u32), &Natural::from(497u32));
1025 /// assert_eq!(x, 445);
1026 ///
1027 /// let mut x = Natural::from(10u32);
1028 /// x.mod_pow_assign(Natural::from(1000u32), &Natural::from(30u32));
1029 /// assert_eq!(x, 10);
1030 /// ```
1031 #[allow(clippy::match_same_arms)] // matches are order-dependent
1032 fn mod_pow_assign(&mut self, mut exp: Self, m: &'a Self) {
1033 assert!(&*self < m, "self must be reduced mod m, but {self} >= {m}");
1034 match (&mut *self, &exp, m) {
1035 (_, _, &Self::ONE) => *self = Self::ZERO,
1036 (_, &Self::ZERO, _) => *self = Self::ONE,
1037 (&mut (Self::ZERO | Self::ONE), _, _) | (_, &Self::ONE, _) => {}
1038 (Self(Small(x)), Self(Small(e)), Self(Small(m))) if u64::convertible_from(*e) => {
1039 x.mod_pow_assign(u64::wrapping_from(*e), *m);
1040 }
1041 _ => {
1042 let ms = m.as_limbs_asc();
1043 let mut out = vec![0; ms.len()];
1044 limbs_mod_pow(
1045 &mut out,
1046 self.promote_in_place(),
1047 exp.promote_in_place(),
1048 ms,
1049 );
1050 *self = Self::from_owned_limbs_asc(out);
1051 }
1052 }
1053 }
1054}
1055
1056impl<'a> ModPowAssign<&'a Self, Self> for Natural {
1057 /// Raises a [`Natural`] to a [`Natural`] power modulo a third [`Natural`] $m$, in place. The
1058 /// base must be already reduced modulo $m$. The first [`Natural`] on the right-hand side is
1059 /// taken by reference and the second by value.
1060 ///
1061 /// $x \gets y$, where $x, y < m$ and $x^n \equiv y \mod m$.
1062 ///
1063 /// # Worst-case complexity
1064 /// $T(n, m) = O(mn \log n \log\log n)$
1065 ///
1066 /// $M(n) = O(n \log n)$
1067 ///
1068 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$ is
1069 /// `exp.significant_bits()`.
1070 ///
1071 /// # Panics
1072 /// Panics if `self` is greater than or equal to `m`.
1073 ///
1074 /// # Examples
1075 /// ```
1076 /// use malachite_base::num::arithmetic::traits::ModPowAssign;
1077 /// use malachite_nz::natural::Natural;
1078 ///
1079 /// let mut x = Natural::from(4u32);
1080 /// x.mod_pow_assign(&Natural::from(13u32), Natural::from(497u32));
1081 /// assert_eq!(x, 445);
1082 ///
1083 /// let mut x = Natural::from(10u32);
1084 /// x.mod_pow_assign(&Natural::from(1000u32), Natural::from(30u32));
1085 /// assert_eq!(x, 10);
1086 /// ```
1087 #[allow(clippy::match_same_arms)] // matches are order-dependent
1088 fn mod_pow_assign(&mut self, exp: &'a Self, mut m: Self) {
1089 assert!(*self < m, "self must be reduced mod m, but {self} >= {m}");
1090 match (&mut *self, exp, &m) {
1091 (_, _, &Self::ONE) => *self = Self::ZERO,
1092 (_, &Self::ZERO, _) => *self = Self::ONE,
1093 (&mut (Self::ZERO | Self::ONE), _, _) | (_, &Self::ONE, _) => {}
1094 (Self(Small(x)), Self(Small(e)), Self(Small(m))) if u64::convertible_from(*e) => {
1095 x.mod_pow_assign(u64::wrapping_from(*e), *m);
1096 }
1097 _ => {
1098 let ms = m.promote_in_place();
1099 let mut out = vec![0; ms.len()];
1100 limbs_mod_pow(&mut out, self.promote_in_place(), exp.as_limbs_asc(), ms);
1101 *self = Self::from_owned_limbs_asc(out);
1102 }
1103 }
1104 }
1105}
1106
1107impl<'a, 'b> ModPowAssign<&'a Self, &'b Self> for Natural {
1108 /// Raises a [`Natural`] to a [`Natural`] power modulo a third [`Natural`] $m$, in place. The
1109 /// base must be already reduced modulo $m$. Both [`Natural`]s on the right-hand side are taken
1110 /// by reference.
1111 ///
1112 /// $x \gets y$, where $x, y < m$ and $x^n \equiv y \mod m$.
1113 ///
1114 /// # Worst-case complexity
1115 /// $T(n, m) = O(mn \log n \log\log n)$
1116 ///
1117 /// $M(n) = O(n \log n)$
1118 ///
1119 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$ is
1120 /// `exp.significant_bits()`.
1121 ///
1122 /// # Panics
1123 /// Panics if `self` is greater than or equal to `m`.
1124 ///
1125 /// # Examples
1126 /// ```
1127 /// use malachite_base::num::arithmetic::traits::ModPowAssign;
1128 /// use malachite_nz::natural::Natural;
1129 ///
1130 /// let mut x = Natural::from(4u32);
1131 /// x.mod_pow_assign(&Natural::from(13u32), &Natural::from(497u32));
1132 /// assert_eq!(x, 445);
1133 ///
1134 /// let mut x = Natural::from(10u32);
1135 /// x.mod_pow_assign(&Natural::from(1000u32), &Natural::from(30u32));
1136 /// assert_eq!(x, 10);
1137 /// ```
1138 #[allow(clippy::match_same_arms)] // matches are order-dependent
1139 fn mod_pow_assign(&mut self, exp: &'a Self, m: &'b Self) {
1140 assert!(&*self < m, "self must be reduced mod m, but {self} >= {m}");
1141 match (&mut *self, exp, m) {
1142 (_, _, &Self::ONE) => *self = Self::ZERO,
1143 (_, &Self::ZERO, _) => *self = Self::ONE,
1144 (&mut (Self::ZERO | Self::ONE), _, _) | (_, &Self::ONE, _) => {}
1145 (Self(Small(x)), Self(Small(e)), Self(Small(m))) if u64::convertible_from(*e) => {
1146 x.mod_pow_assign(u64::wrapping_from(*e), *m);
1147 }
1148 _ => {
1149 let ms = m.as_limbs_asc();
1150 let mut out = vec![0; ms.len()];
1151 limbs_mod_pow(&mut out, self.promote_in_place(), exp.as_limbs_asc(), ms);
1152 *self = Self::from_owned_limbs_asc(out);
1153 }
1154 }
1155 }
1156}