/rust/registry/src/index.crates.io-6f17d22bba15001f/num-bigint-0.4.6/src/biguint/power.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use super::monty::monty_modpow; |
2 | | use super::BigUint; |
3 | | |
4 | | use crate::big_digit::{self, BigDigit}; |
5 | | |
6 | | use num_integer::Integer; |
7 | | use num_traits::{One, Pow, ToPrimitive, Zero}; |
8 | | |
9 | | impl Pow<&BigUint> for BigUint { |
10 | | type Output = BigUint; |
11 | | |
12 | | #[inline] |
13 | 0 | fn pow(self, exp: &BigUint) -> BigUint { |
14 | 0 | if self.is_one() || exp.is_zero() { |
15 | 0 | BigUint::one() |
16 | 0 | } else if self.is_zero() { |
17 | 0 | Self::ZERO |
18 | 0 | } else if let Some(exp) = exp.to_u64() { |
19 | 0 | self.pow(exp) |
20 | 0 | } else if let Some(exp) = exp.to_u128() { |
21 | 0 | self.pow(exp) |
22 | | } else { |
23 | | // At this point, `self >= 2` and `exp >= 2¹²⁸`. The smallest possible result given |
24 | | // `2.pow(2¹²⁸)` would require far more memory than 64-bit targets can address! |
25 | 0 | panic!("memory overflow") |
26 | | } |
27 | 0 | } |
28 | | } |
29 | | |
30 | | impl Pow<BigUint> for BigUint { |
31 | | type Output = BigUint; |
32 | | |
33 | | #[inline] |
34 | 0 | fn pow(self, exp: BigUint) -> BigUint { |
35 | 0 | Pow::pow(self, &exp) |
36 | 0 | } |
37 | | } |
38 | | |
39 | | impl Pow<&BigUint> for &BigUint { |
40 | | type Output = BigUint; |
41 | | |
42 | | #[inline] |
43 | 0 | fn pow(self, exp: &BigUint) -> BigUint { |
44 | 0 | if self.is_one() || exp.is_zero() { |
45 | 0 | BigUint::one() |
46 | 0 | } else if self.is_zero() { |
47 | 0 | BigUint::ZERO |
48 | | } else { |
49 | 0 | self.clone().pow(exp) |
50 | | } |
51 | 0 | } |
52 | | } |
53 | | |
54 | | impl Pow<BigUint> for &BigUint { |
55 | | type Output = BigUint; |
56 | | |
57 | | #[inline] |
58 | 0 | fn pow(self, exp: BigUint) -> BigUint { |
59 | 0 | Pow::pow(self, &exp) |
60 | 0 | } |
61 | | } |
62 | | |
63 | | macro_rules! pow_impl { |
64 | | ($T:ty) => { |
65 | | impl Pow<$T> for BigUint { |
66 | | type Output = BigUint; |
67 | | |
68 | 0 | fn pow(self, mut exp: $T) -> BigUint { |
69 | 0 | if exp == 0 { |
70 | 0 | return BigUint::one(); |
71 | 0 | } |
72 | 0 | let mut base = self; |
73 | | |
74 | 0 | while exp & 1 == 0 { |
75 | 0 | base = &base * &base; |
76 | 0 | exp >>= 1; |
77 | 0 | } |
78 | | |
79 | 0 | if exp == 1 { |
80 | 0 | return base; |
81 | 0 | } |
82 | 0 |
|
83 | 0 | let mut acc = base.clone(); |
84 | 0 | while exp > 1 { |
85 | 0 | exp >>= 1; |
86 | 0 | base = &base * &base; |
87 | 0 | if exp & 1 == 1 { |
88 | 0 | acc *= &base; |
89 | 0 | } |
90 | | } |
91 | 0 | acc |
92 | 0 | } Unexecuted instantiation: <num_bigint::biguint::BigUint as num_traits::pow::Pow<u8>>::pow Unexecuted instantiation: <num_bigint::biguint::BigUint as num_traits::pow::Pow<u16>>::pow Unexecuted instantiation: <num_bigint::biguint::BigUint as num_traits::pow::Pow<u32>>::pow Unexecuted instantiation: <num_bigint::biguint::BigUint as num_traits::pow::Pow<u64>>::pow Unexecuted instantiation: <num_bigint::biguint::BigUint as num_traits::pow::Pow<usize>>::pow Unexecuted instantiation: <num_bigint::biguint::BigUint as num_traits::pow::Pow<u128>>::pow |
93 | | } |
94 | | |
95 | | impl Pow<&$T> for BigUint { |
96 | | type Output = BigUint; |
97 | | |
98 | | #[inline] |
99 | 0 | fn pow(self, exp: &$T) -> BigUint { |
100 | 0 | Pow::pow(self, *exp) |
101 | 0 | } Unexecuted instantiation: <num_bigint::biguint::BigUint as num_traits::pow::Pow<&u8>>::pow Unexecuted instantiation: <num_bigint::biguint::BigUint as num_traits::pow::Pow<&u16>>::pow Unexecuted instantiation: <num_bigint::biguint::BigUint as num_traits::pow::Pow<&u32>>::pow Unexecuted instantiation: <num_bigint::biguint::BigUint as num_traits::pow::Pow<&u64>>::pow Unexecuted instantiation: <num_bigint::biguint::BigUint as num_traits::pow::Pow<&usize>>::pow Unexecuted instantiation: <num_bigint::biguint::BigUint as num_traits::pow::Pow<&u128>>::pow |
102 | | } |
103 | | |
104 | | impl Pow<$T> for &BigUint { |
105 | | type Output = BigUint; |
106 | | |
107 | | #[inline] |
108 | 0 | fn pow(self, exp: $T) -> BigUint { |
109 | 0 | if exp == 0 { |
110 | 0 | return BigUint::one(); |
111 | 0 | } |
112 | 0 | Pow::pow(self.clone(), exp) |
113 | 0 | } Unexecuted instantiation: <&num_bigint::biguint::BigUint as num_traits::pow::Pow<u8>>::pow Unexecuted instantiation: <&num_bigint::biguint::BigUint as num_traits::pow::Pow<u16>>::pow Unexecuted instantiation: <&num_bigint::biguint::BigUint as num_traits::pow::Pow<u64>>::pow Unexecuted instantiation: <&num_bigint::biguint::BigUint as num_traits::pow::Pow<usize>>::pow Unexecuted instantiation: <&num_bigint::biguint::BigUint as num_traits::pow::Pow<u128>>::pow Unexecuted instantiation: <&num_bigint::biguint::BigUint as num_traits::pow::Pow<u32>>::pow |
114 | | } |
115 | | |
116 | | impl Pow<&$T> for &BigUint { |
117 | | type Output = BigUint; |
118 | | |
119 | | #[inline] |
120 | 0 | fn pow(self, exp: &$T) -> BigUint { |
121 | 0 | Pow::pow(self, *exp) |
122 | 0 | } Unexecuted instantiation: <&num_bigint::biguint::BigUint as num_traits::pow::Pow<&u8>>::pow Unexecuted instantiation: <&num_bigint::biguint::BigUint as num_traits::pow::Pow<&u16>>::pow Unexecuted instantiation: <&num_bigint::biguint::BigUint as num_traits::pow::Pow<&u32>>::pow Unexecuted instantiation: <&num_bigint::biguint::BigUint as num_traits::pow::Pow<&u64>>::pow Unexecuted instantiation: <&num_bigint::biguint::BigUint as num_traits::pow::Pow<&usize>>::pow Unexecuted instantiation: <&num_bigint::biguint::BigUint as num_traits::pow::Pow<&u128>>::pow |
123 | | } |
124 | | }; |
125 | | } |
126 | | |
127 | | pow_impl!(u8); |
128 | | pow_impl!(u16); |
129 | | pow_impl!(u32); |
130 | | pow_impl!(u64); |
131 | | pow_impl!(usize); |
132 | | pow_impl!(u128); |
133 | | |
134 | 0 | pub(super) fn modpow(x: &BigUint, exponent: &BigUint, modulus: &BigUint) -> BigUint { |
135 | 0 | assert!( |
136 | 0 | !modulus.is_zero(), |
137 | 0 | "attempt to calculate with zero modulus!" |
138 | | ); |
139 | | |
140 | 0 | if modulus.is_odd() { |
141 | | // For an odd modulus, we can use Montgomery multiplication in base 2^32. |
142 | 0 | monty_modpow(x, exponent, modulus) |
143 | | } else { |
144 | | // Otherwise do basically the same as `num::pow`, but with a modulus. |
145 | 0 | plain_modpow(x, &exponent.data, modulus) |
146 | | } |
147 | 0 | } |
148 | | |
149 | 0 | fn plain_modpow(base: &BigUint, exp_data: &[BigDigit], modulus: &BigUint) -> BigUint { |
150 | 0 | assert!( |
151 | 0 | !modulus.is_zero(), |
152 | 0 | "attempt to calculate with zero modulus!" |
153 | | ); |
154 | | |
155 | 0 | let i = match exp_data.iter().position(|&r| r != 0) { |
156 | 0 | None => return BigUint::one(), |
157 | 0 | Some(i) => i, |
158 | 0 | }; |
159 | 0 |
|
160 | 0 | let mut base = base % modulus; |
161 | 0 | for _ in 0..i { |
162 | 0 | for _ in 0..big_digit::BITS { |
163 | 0 | base = &base * &base % modulus; |
164 | 0 | } |
165 | | } |
166 | | |
167 | 0 | let mut r = exp_data[i]; |
168 | 0 | let mut b = 0u8; |
169 | 0 | while r.is_even() { |
170 | 0 | base = &base * &base % modulus; |
171 | 0 | r >>= 1; |
172 | 0 | b += 1; |
173 | 0 | } |
174 | | |
175 | 0 | let mut exp_iter = exp_data[i + 1..].iter(); |
176 | 0 | if exp_iter.len() == 0 && r.is_one() { |
177 | 0 | return base; |
178 | 0 | } |
179 | 0 |
|
180 | 0 | let mut acc = base.clone(); |
181 | 0 | r >>= 1; |
182 | 0 | b += 1; |
183 | 0 |
|
184 | 0 | { |
185 | 0 | let mut unit = |exp_is_odd| { |
186 | 0 | base = &base * &base % modulus; |
187 | 0 | if exp_is_odd { |
188 | 0 | acc *= &base; |
189 | 0 | acc %= modulus; |
190 | 0 | } |
191 | 0 | }; |
192 | | |
193 | 0 | if let Some(&last) = exp_iter.next_back() { |
194 | | // consume exp_data[i] |
195 | 0 | for _ in b..big_digit::BITS { |
196 | 0 | unit(r.is_odd()); |
197 | 0 | r >>= 1; |
198 | 0 | } |
199 | | |
200 | | // consume all other digits before the last |
201 | 0 | for &r in exp_iter { |
202 | 0 | let mut r = r; |
203 | 0 | for _ in 0..big_digit::BITS { |
204 | 0 | unit(r.is_odd()); |
205 | 0 | r >>= 1; |
206 | 0 | } |
207 | | } |
208 | 0 | r = last; |
209 | 0 | } |
210 | | |
211 | 0 | debug_assert_ne!(r, 0); |
212 | 0 | while !r.is_zero() { |
213 | 0 | unit(r.is_odd()); |
214 | 0 | r >>= 1; |
215 | 0 | } |
216 | | } |
217 | 0 | acc |
218 | 0 | } |
219 | | |
220 | | #[test] |
221 | | fn test_plain_modpow() { |
222 | | let two = &BigUint::from(2u32); |
223 | | let modulus = BigUint::from(0x1100u32); |
224 | | |
225 | | let exp = vec![0, 0b1]; |
226 | | assert_eq!( |
227 | | two.pow(0b1_00000000_u32) % &modulus, |
228 | | plain_modpow(two, &exp, &modulus) |
229 | | ); |
230 | | let exp = vec![0, 0b10]; |
231 | | assert_eq!( |
232 | | two.pow(0b10_00000000_u32) % &modulus, |
233 | | plain_modpow(two, &exp, &modulus) |
234 | | ); |
235 | | let exp = vec![0, 0b110010]; |
236 | | assert_eq!( |
237 | | two.pow(0b110010_00000000_u32) % &modulus, |
238 | | plain_modpow(two, &exp, &modulus) |
239 | | ); |
240 | | let exp = vec![0b1, 0b1]; |
241 | | assert_eq!( |
242 | | two.pow(0b1_00000001_u32) % &modulus, |
243 | | plain_modpow(two, &exp, &modulus) |
244 | | ); |
245 | | let exp = vec![0b1100, 0, 0b1]; |
246 | | assert_eq!( |
247 | | two.pow(0b1_00000000_00001100_u32) % &modulus, |
248 | | plain_modpow(two, &exp, &modulus) |
249 | | ); |
250 | | } |
251 | | |
252 | | #[test] |
253 | | fn test_pow_biguint() { |
254 | | let base = BigUint::from(5u8); |
255 | | let exponent = BigUint::from(3u8); |
256 | | |
257 | | assert_eq!(BigUint::from(125u8), base.pow(exponent)); |
258 | | } |