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;
    public BigInteger modPow(BigInteger exponent, BigInteger m) throws ArithmeticException    {        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        boolean useMonty = ((m.magnitude[m.magnitude.length - 1] & 1) == 1);        long mQ = 0;        if (useMonty)        {            mQ = m.getMQuote();            // tmp = this * R mod m            BigInteger tmp = this.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];                    System.arraycopy(zVal, 0, longZ, longZ.length - zVal.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];                System.arraycopy(magnitude, 0, zVal, zVal.length - magnitude.length,                        magnitude.length);            }            else            {                //                // in normal practice we'll never see this...                //                BigInteger tmp = this.remainder(m);                //zAccum = new int[m.magnitude.length * 2];                zVal = new int[m.magnitude.length];                System.arraycopy(tmp.magnitude, 0, zVal, zVal.length - tmp.magnitude.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                //                System.arraycopy(zVal, 0, yVal, 0, zVal.length);                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);                    System.arraycopy(yAccum, yAccum.length - yVal.length, yVal, 0, yVal.length);                    zero(yAccum);                }                bits++;                if (v < 0)                {                    if (useMonty)                    {                        multiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ);                    }                    else                    {                        multiply(yAccum, yVal, zVal);                        remainder(yAccum, m.magnitude);                        System.arraycopy(yAccum, yAccum.length - yVal.length, yVal, 0,                                yVal.length);                        zero(yAccum);                    }                }                v <<= 1;            }            while (bits < 32)            {                if (useMonty)                {                    multiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ);                }                else                {                    square(yAccum, yVal);                    remainder(yAccum, m.magnitude);                    System.arraycopy(yAccum, yAccum.length - yVal.length, yVal, 0, yVal.length);                    zero(yAccum);                }                bits++;            }        }        if (useMonty)        {            // Return y * R^(-1) mod m by doing y * 1 * R^(-1) mod m            zero(zVal);            zVal[zVal.length - 1] = 1;            multiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ);        }        return new BigInteger(1, yVal);    }