1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Diagnostics; 6 7 namespace System.Numerics 8 { 9 internal static partial class BigIntegerCalculator 10 { 11 // Executes different exponentiation algorithms, which are 12 // based on the classic square-and-multiply method. 13 14 // https://en.wikipedia.org/wiki/Exponentiation_by_squaring 15 Pow(uint value, uint power)16 public static uint[] Pow(uint value, uint power) 17 { 18 // The basic pow method for a 32-bit integer. 19 // To spare memory allocations we first roughly 20 // estimate an upper bound for our buffers. 21 22 int size = PowBound(power, 1, 1); 23 BitsBuffer v = new BitsBuffer(size, value); 24 return PowCore(power, ref v); 25 } 26 Pow(uint[] value, uint power)27 public static uint[] Pow(uint[] value, uint power) 28 { 29 Debug.Assert(value != null); 30 31 // The basic pow method for a big integer. 32 // To spare memory allocations we first roughly 33 // estimate an upper bound for our buffers. 34 35 int size = PowBound(power, value.Length, 1); 36 BitsBuffer v = new BitsBuffer(size, value); 37 return PowCore(power, ref v); 38 } 39 PowCore(uint power, ref BitsBuffer value)40 private static uint[] PowCore(uint power, ref BitsBuffer value) 41 { 42 // Executes the basic pow algorithm. 43 44 int size = value.GetSize(); 45 46 BitsBuffer temp = new BitsBuffer(size, 0); 47 BitsBuffer result = new BitsBuffer(size, 1); 48 49 PowCore(power, ref value, ref result, ref temp); 50 51 return result.GetBits(); 52 } 53 PowBound(uint power, int valueLength, int resultLength)54 private static int PowBound(uint power, int valueLength, 55 int resultLength) 56 { 57 // The basic pow algorithm, but instead of squaring 58 // and multiplying we just sum up the lengths. 59 60 while (power != 0) 61 { 62 checked 63 { 64 if ((power & 1) == 1) 65 resultLength += valueLength; 66 if (power != 1) 67 valueLength += valueLength; 68 } 69 power = power >> 1; 70 } 71 72 return resultLength; 73 } 74 PowCore(uint power, ref BitsBuffer value, ref BitsBuffer result, ref BitsBuffer temp)75 private static void PowCore(uint power, ref BitsBuffer value, 76 ref BitsBuffer result, ref BitsBuffer temp) 77 { 78 // The basic pow algorithm using square-and-multiply. 79 80 while (power != 0) 81 { 82 if ((power & 1) == 1) 83 result.MultiplySelf(ref value, ref temp); 84 if (power != 1) 85 value.SquareSelf(ref temp); 86 power = power >> 1; 87 } 88 } 89 Pow(uint value, uint power, uint modulus)90 public static uint Pow(uint value, uint power, uint modulus) 91 { 92 // The 32-bit modulus pow method for a 32-bit integer 93 // raised by a 32-bit integer... 94 95 return PowCore(power, modulus, value, 1); 96 } 97 Pow(uint[] value, uint power, uint modulus)98 public static uint Pow(uint[] value, uint power, uint modulus) 99 { 100 Debug.Assert(value != null); 101 102 // The 32-bit modulus pow method for a big integer 103 // raised by a 32-bit integer... 104 105 uint v = Remainder(value, modulus); 106 return PowCore(power, modulus, v, 1); 107 } 108 Pow(uint value, uint[] power, uint modulus)109 public static uint Pow(uint value, uint[] power, uint modulus) 110 { 111 Debug.Assert(power != null); 112 113 // The 32-bit modulus pow method for a 32-bit integer 114 // raised by a big integer... 115 116 return PowCore(power, modulus, value, 1); 117 } 118 Pow(uint[] value, uint[] power, uint modulus)119 public static uint Pow(uint[] value, uint[] power, uint modulus) 120 { 121 Debug.Assert(value != null); 122 Debug.Assert(power != null); 123 124 // The 32-bit modulus pow method for a big integer 125 // raised by a big integer... 126 127 uint v = Remainder(value, modulus); 128 return PowCore(power, modulus, v, 1); 129 } 130 PowCore(uint[] power, uint modulus, ulong value, ulong result)131 private static uint PowCore(uint[] power, uint modulus, 132 ulong value, ulong result) 133 { 134 // The 32-bit modulus pow algorithm for all but 135 // the last power limb using square-and-multiply. 136 137 for (int i = 0; i < power.Length - 1; i++) 138 { 139 uint p = power[i]; 140 for (int j = 0; j < 32; j++) 141 { 142 if ((p & 1) == 1) 143 result = (result * value) % modulus; 144 value = (value * value) % modulus; 145 p = p >> 1; 146 } 147 } 148 149 return PowCore(power[power.Length - 1], modulus, value, result); 150 } 151 PowCore(uint power, uint modulus, ulong value, ulong result)152 private static uint PowCore(uint power, uint modulus, 153 ulong value, ulong result) 154 { 155 // The 32-bit modulus pow algorithm for the last or 156 // the only power limb using square-and-multiply. 157 158 while (power != 0) 159 { 160 if ((power & 1) == 1) 161 result = (result * value) % modulus; 162 if (power != 1) 163 value = (value * value) % modulus; 164 power = power >> 1; 165 } 166 167 return (uint)(result % modulus); 168 } 169 Pow(uint value, uint power, uint[] modulus)170 public static uint[] Pow(uint value, uint power, uint[] modulus) 171 { 172 Debug.Assert(modulus != null); 173 174 // The big modulus pow method for a 32-bit integer 175 // raised by a 32-bit integer... 176 177 int size = modulus.Length + modulus.Length; 178 BitsBuffer v = new BitsBuffer(size, value); 179 return PowCore(power, modulus, ref v); 180 } 181 Pow(uint[] value, uint power, uint[] modulus)182 public static uint[] Pow(uint[] value, uint power, uint[] modulus) 183 { 184 Debug.Assert(value != null); 185 Debug.Assert(modulus != null); 186 187 // The big modulus pow method for a big integer 188 // raised by a 32-bit integer... 189 190 if (value.Length > modulus.Length) 191 value = Remainder(value, modulus); 192 193 int size = modulus.Length + modulus.Length; 194 BitsBuffer v = new BitsBuffer(size, value); 195 return PowCore(power, modulus, ref v); 196 } 197 Pow(uint value, uint[] power, uint[] modulus)198 public static uint[] Pow(uint value, uint[] power, uint[] modulus) 199 { 200 Debug.Assert(power != null); 201 Debug.Assert(modulus != null); 202 203 // The big modulus pow method for a 32-bit integer 204 // raised by a big integer... 205 206 int size = modulus.Length + modulus.Length; 207 BitsBuffer v = new BitsBuffer(size, value); 208 return PowCore(power, modulus, ref v); 209 } 210 Pow(uint[] value, uint[] power, uint[] modulus)211 public static uint[] Pow(uint[] value, uint[] power, uint[] modulus) 212 { 213 Debug.Assert(value != null); 214 Debug.Assert(power != null); 215 Debug.Assert(modulus != null); 216 217 // The big modulus pow method for a big integer 218 // raised by a big integer... 219 220 if (value.Length > modulus.Length) 221 value = Remainder(value, modulus); 222 223 int size = modulus.Length + modulus.Length; 224 BitsBuffer v = new BitsBuffer(size, value); 225 return PowCore(power, modulus, ref v); 226 } 227 228 // Mutable for unit testing... 229 private static int ReducerThreshold = 32; 230 PowCore(uint[] power, uint[] modulus, ref BitsBuffer value)231 private static uint[] PowCore(uint[] power, uint[] modulus, 232 ref BitsBuffer value) 233 { 234 // Executes the big pow algorithm. 235 236 int size = value.GetSize(); 237 238 BitsBuffer temp = new BitsBuffer(size, 0); 239 BitsBuffer result = new BitsBuffer(size, 1); 240 241 if (modulus.Length < ReducerThreshold) 242 { 243 PowCore(power, modulus, ref value, ref result, ref temp); 244 } 245 else 246 { 247 FastReducer reducer = new FastReducer(modulus); 248 PowCore(power, ref reducer, ref value, ref result, ref temp); 249 } 250 251 return result.GetBits(); 252 } 253 PowCore(uint power, uint[] modulus, ref BitsBuffer value)254 private static uint[] PowCore(uint power, uint[] modulus, 255 ref BitsBuffer value) 256 { 257 // Executes the big pow algorithm. 258 259 int size = value.GetSize(); 260 261 BitsBuffer temp = new BitsBuffer(size, 0); 262 BitsBuffer result = new BitsBuffer(size, 1); 263 264 if (modulus.Length < ReducerThreshold) 265 { 266 PowCore(power, modulus, ref value, ref result, ref temp); 267 } 268 else 269 { 270 FastReducer reducer = new FastReducer(modulus); 271 PowCore(power, ref reducer, ref value, ref result, ref temp); 272 } 273 274 return result.GetBits(); 275 } 276 PowCore(uint[] power, uint[] modulus, ref BitsBuffer value, ref BitsBuffer result, ref BitsBuffer temp)277 private static void PowCore(uint[] power, uint[] modulus, 278 ref BitsBuffer value, ref BitsBuffer result, 279 ref BitsBuffer temp) 280 { 281 // The big modulus pow algorithm for all but 282 // the last power limb using square-and-multiply. 283 284 // NOTE: we're using an ordinary remainder here, 285 // since the reducer overhead doesn't pay off. 286 287 for (int i = 0; i < power.Length - 1; i++) 288 { 289 uint p = power[i]; 290 for (int j = 0; j < 32; j++) 291 { 292 if ((p & 1) == 1) 293 { 294 result.MultiplySelf(ref value, ref temp); 295 result.Reduce(modulus); 296 } 297 value.SquareSelf(ref temp); 298 value.Reduce(modulus); 299 p = p >> 1; 300 } 301 } 302 303 PowCore(power[power.Length - 1], modulus, ref value, ref result, 304 ref temp); 305 } 306 PowCore(uint power, uint[] modulus, ref BitsBuffer value, ref BitsBuffer result, ref BitsBuffer temp)307 private static void PowCore(uint power, uint[] modulus, 308 ref BitsBuffer value, ref BitsBuffer result, 309 ref BitsBuffer temp) 310 { 311 // The big modulus pow algorithm for the last or 312 // the only power limb using square-and-multiply. 313 314 // NOTE: we're using an ordinary remainder here, 315 // since the reducer overhead doesn't pay off. 316 317 while (power != 0) 318 { 319 if ((power & 1) == 1) 320 { 321 result.MultiplySelf(ref value, ref temp); 322 result.Reduce(modulus); 323 } 324 if (power != 1) 325 { 326 value.SquareSelf(ref temp); 327 value.Reduce(modulus); 328 } 329 power = power >> 1; 330 } 331 } 332 PowCore(uint[] power, ref FastReducer reducer, ref BitsBuffer value, ref BitsBuffer result, ref BitsBuffer temp)333 private static void PowCore(uint[] power, ref FastReducer reducer, 334 ref BitsBuffer value, ref BitsBuffer result, 335 ref BitsBuffer temp) 336 { 337 // The big modulus pow algorithm for all but 338 // the last power limb using square-and-multiply. 339 340 // NOTE: we're using a special reducer here, 341 // since it's additional overhead does pay off. 342 343 for (int i = 0; i < power.Length - 1; i++) 344 { 345 uint p = power[i]; 346 for (int j = 0; j < 32; j++) 347 { 348 if ((p & 1) == 1) 349 { 350 result.MultiplySelf(ref value, ref temp); 351 result.Reduce(ref reducer); 352 } 353 value.SquareSelf(ref temp); 354 value.Reduce(ref reducer); 355 p = p >> 1; 356 } 357 } 358 359 PowCore(power[power.Length - 1], ref reducer, ref value, ref result, 360 ref temp); 361 } 362 PowCore(uint power, ref FastReducer reducer, ref BitsBuffer value, ref BitsBuffer result, ref BitsBuffer temp)363 private static void PowCore(uint power, ref FastReducer reducer, 364 ref BitsBuffer value, ref BitsBuffer result, 365 ref BitsBuffer temp) 366 { 367 // The big modulus pow algorithm for the last or 368 // the only power limb using square-and-multiply. 369 370 // NOTE: we're using a special reducer here, 371 // since it's additional overhead does pay off. 372 373 while (power != 0) 374 { 375 if ((power & 1) == 1) 376 { 377 result.MultiplySelf(ref value, ref temp); 378 result.Reduce(ref reducer); 379 } 380 if (power != 1) 381 { 382 value.SquareSelf(ref temp); 383 value.Reduce(ref reducer); 384 } 385 power = power >> 1; 386 } 387 } 388 ActualLength(uint[] value)389 private static int ActualLength(uint[] value) 390 { 391 // Since we're reusing memory here, the actual length 392 // of a given value may be less then the array's length 393 394 return ActualLength(value, value.Length); 395 } 396 ActualLength(uint[] value, int length)397 private static int ActualLength(uint[] value, int length) 398 { 399 Debug.Assert(value != null); 400 Debug.Assert(length <= value.Length); 401 402 while (length > 0 && value[length - 1] == 0) 403 --length; 404 return length; 405 } 406 } 407 } 408