Esempio n. 1
0
        public BigInteger ModPow(
            BigInteger exponent,
            BigInteger m) {
            if (m.sign < 1)
                throw new ArithmeticException("Modulus must be positive");

            if (m.Equals(One))
                return Zero;

            if (exponent.sign == 0)
                return One;

            if (sign == 0)
                return Zero;

            int[] zVal = null;
            int[] yAccum = null;
            int[] yVal;

            // Montgomery exponentiation is only possible if the modulus is odd,
            // but AFAIK, this is always the case for crypto algo's
            bool useMonty = ((m.magnitude[m.magnitude.Length - 1] & 1) == 1);
            long mQ = 0;
            if (useMonty) {
                mQ = m.GetMQuote();

                // tmp = this * R mod m
                BigInteger tmp = ShiftLeft(32 * m.magnitude.Length).Mod(m);
                zVal = tmp.magnitude;

                useMonty = (zVal.Length <= m.magnitude.Length);

                if (useMonty) {
                    yAccum = new int[m.magnitude.Length + 1];
                    if (zVal.Length < m.magnitude.Length) {
                        int[] longZ = new int[m.magnitude.Length];
                        zVal.CopyTo(longZ, longZ.Length - zVal.Length);
                        zVal = longZ;
                    }
                }
            }

            if (!useMonty) {
                if (magnitude.Length <= m.magnitude.Length) {
                    //zAccum = new int[m.magnitude.Length * 2];
                    zVal = new int[m.magnitude.Length];
                    magnitude.CopyTo(zVal, zVal.Length - magnitude.Length);
                }
                else {
                    //
                    // in normal practice we'll never see this...
                    //
                    BigInteger tmp = Remainder(m);

                    //zAccum = new int[m.magnitude.Length * 2];
                    zVal = new int[m.magnitude.Length];
                    tmp.magnitude.CopyTo(zVal, zVal.Length - tmp.magnitude.Length);
                }

                yAccum = new int[m.magnitude.Length * 2];
            }

            yVal = new int[m.magnitude.Length];

            //
            // from LSW to MSW
            //
            for (int i = 0; i < exponent.magnitude.Length; i++) {
                int v = exponent.magnitude[i];
                int bits = 0;

                if (i == 0) {
                    while (v > 0) {
                        v <<= 1;
                        bits++;
                    }

                    //
                    // first time in initialise y
                    //
                    zVal.CopyTo(yVal, 0);

                    v <<= 1;
                    bits++;
                }

                while (v != 0) {
                    if (useMonty) {
                        // Montgomery square algo doesn't exist, and a normal
                        // square followed by a Montgomery reduction proved to
                        // be almost as heavy as a Montgomery mulitply.
                        MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ);
                    }
                    else {
                        Square(yAccum, yVal);
                        Remainder(yAccum, m.magnitude);
                        Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length);
                        ZeroOut(yAccum);
                    }
                    bits++;

                    if (v < 0) {
                        if (useMonty) {
                            MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ);
                        }
                        else {
                            Multiply(yAccum, yVal, zVal);
                            Remainder(yAccum, m.magnitude);
                            Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0,
                                yVal.Length);
                            ZeroOut(yAccum);
                        }
                    }

                    v <<= 1;
                }

                while (bits < 32) {
                    if (useMonty) {
                        MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ);
                    }
                    else {
                        Square(yAccum, yVal);
                        Remainder(yAccum, m.magnitude);
                        Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length);
                        ZeroOut(yAccum);
                    }
                    bits++;
                }
            }

            if (useMonty) {
                // Return y * R^(-1) mod m by doing y * 1 * R^(-1) mod m
                ZeroOut(zVal);
                zVal[zVal.Length - 1] = 1;
                MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ);
            }

            BigInteger result = new BigInteger(1, yVal, true);

            return exponent.sign > 0
                ? result
                : result.ModInverse(m);
        }