private static BigInteger ModPowMonty(BigInteger b, BigInteger e, BigInteger m, bool convert) { int n = m.magnitude.Length; int powR = 32 * n; bool smallMontyModulus = m.BitLength + 2 <= powR; uint mDash = (uint)m.GetMQuote(); // tmp = this * R mod m if (convert) { b = b.ShiftLeft(powR).Remainder(m); } int[] yAccum = new int[n + 1]; int[] zVal = b.magnitude; Debug.Assert(zVal.Length <= n); if (zVal.Length < n) { int[] tmp = new int[n]; zVal.CopyTo(tmp, n - zVal.Length); zVal = tmp; } // Sliding window from MSW to LSW int extraBits = 0; // Filter the common case of small RSA exponents with few bits set if (e.magnitude.Length > 1 || e.BitCount > 2) { int expLength = e.BitLength; while (expLength > ExpWindowThresholds[extraBits]) { ++extraBits; } } int numPowers = 1 << extraBits; int[][] oddPowers = new int[numPowers][]; oddPowers[0] = zVal; int[] zSquared = Arrays.Clone(zVal); SquareMonty(yAccum, zSquared, m.magnitude, mDash, smallMontyModulus); for (int i = 1; i < numPowers; ++i) { oddPowers[i] = Arrays.Clone(oddPowers[i - 1]); MultiplyMonty(yAccum, oddPowers[i], zSquared, m.magnitude, mDash, smallMontyModulus); } int[] windowList = GetWindowList(e.magnitude, extraBits); Debug.Assert(windowList.Length > 1); int window = windowList[0]; int mult = window & 0xFF, lastZeroes = window >> 8; int[] yVal; if (mult == 1) { yVal = zSquared; --lastZeroes; } else { yVal = Arrays.Clone(oddPowers[mult >> 1]); } int windowPos = 1; while ((window = windowList[windowPos++]) != -1) { mult = window & 0xFF; int bits = lastZeroes + BitLengthTable[mult]; for (int j = 0; j < bits; ++j) { SquareMonty(yAccum, yVal, m.magnitude, mDash, smallMontyModulus); } MultiplyMonty(yAccum, yVal, oddPowers[mult >> 1], m.magnitude, mDash, smallMontyModulus); lastZeroes = window >> 8; } for (int i = 0; i < lastZeroes; ++i) { SquareMonty(yAccum, yVal, m.magnitude, mDash, smallMontyModulus); } if (convert) { // Return y * R^(-1) mod m MontgomeryReduce(yVal, m.magnitude, mDash); } else if (smallMontyModulus && CompareTo(0, yVal, 0, m.magnitude) >= 0) { Subtract(0, yVal, 0, m.magnitude); } return new BigInteger(1, yVal, true); }