/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with this * work for additional information regarding copyright ownership. The ASF * licenses this file to You under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE. */ package java.math; /** * Static library that provides all operations related with division and modular * arithmetic to {@link BigInteger}. Some methods are provided in both mutable * and immutable way. There are several variants provided listed below: * *
GCD(op1, op2)
*/
static long gcdBinary(long op1, long op2) {
// PRE: (op1 > 0) and (op2 > 0)
int lsb1 = Long.numberOfTrailingZeros(op1);
int lsb2 = Long.numberOfTrailingZeros(op2);
int pow2Count = Math.min(lsb1, lsb2);
if (lsb1 != 0) {
op1 >>>= lsb1;
}
if (lsb2 != 0) {
op2 >>>= lsb2;
}
do {
if (op1 >= op2) {
op1 -= op2;
op1 >>>= Long.numberOfTrailingZeros(op1);
} else {
op2 -= op1;
op2 >>>= Long.numberOfTrailingZeros(op2);
}
} while (op1 != 0);
return (op2 << pow2Count);
}
/**
* Performs {@code x = x mod (2n)}.
*
* @param x a positive number, it will store the result.
* @param n a positive exponent of {@code 2}.
*/
static void inplaceModPow2(BigInteger x, int n) {
// PRE: (x > 0) and (n >= 0)
int fd = n >> 5;
int leadingZeros;
if ((x.numberLength < fd) || (x.bitLength() <= n)) {
return;
}
leadingZeros = 32 - (n & 31);
x.numberLength = fd + 1;
x.digits[fd] &= (leadingZeros < 32) ? (-1 >>> leadingZeros) : 0;
x.cutOffLeadingZeroes();
}
/**
*
* Based on "New Algorithm for Classical Modular Inverse" Róbert Lórencz. LNCS
* 2523 (2002)
*
* @return a^(-1) mod m
*/
static BigInteger modInverseLorencz(BigInteger a, BigInteger modulo) {
// PRE: a is coprime with modulo, a < modulo
int max = Math.max(a.numberLength, modulo.numberLength);
int uDigits[] = new int[max + 1]; // enough place to make all the inplace
// operation
int vDigits[] = new int[max + 1];
System.arraycopy(modulo.digits, 0, uDigits, 0, modulo.numberLength);
System.arraycopy(a.digits, 0, vDigits, 0, a.numberLength);
BigInteger u = new BigInteger(modulo.sign, modulo.numberLength, uDigits);
BigInteger v = new BigInteger(a.sign, a.numberLength, vDigits);
BigInteger r = new BigInteger(0, 1, new int[max + 1]); // BigInteger.ZERO;
BigInteger s = new BigInteger(1, 1, new int[max + 1]);
s.digits[0] = 1;
// r == 0 && s == 1, but with enough place
int coefU = 0, coefV = 0;
int n = modulo.bitLength();
int k;
while (!isPowerOfTwo(u, coefU) && !isPowerOfTwo(v, coefV)) {
// modification of original algorithm: I calculate how many times the
// algorithm will enter in the same branch of if
k = howManyIterations(u, n);
if (k != 0) {
BitLevel.inplaceShiftLeft(u, k);
if (coefU >= coefV) {
BitLevel.inplaceShiftLeft(r, k);
} else {
BitLevel.inplaceShiftRight(s, Math.min(coefV - coefU, k));
if (k - (coefV - coefU) > 0) {
BitLevel.inplaceShiftLeft(r, k - coefV + coefU);
}
}
coefU += k;
}
k = howManyIterations(v, n);
if (k != 0) {
BitLevel.inplaceShiftLeft(v, k);
if (coefV >= coefU) {
BitLevel.inplaceShiftLeft(s, k);
} else {
BitLevel.inplaceShiftRight(r, Math.min(coefU - coefV, k));
if (k - (coefU - coefV) > 0) {
BitLevel.inplaceShiftLeft(s, k - coefU + coefV);
}
}
coefV += k;
}
if (u.signum() == v.signum()) {
if (coefU <= coefV) {
Elementary.completeInPlaceSubtract(u, v);
Elementary.completeInPlaceSubtract(r, s);
} else {
Elementary.completeInPlaceSubtract(v, u);
Elementary.completeInPlaceSubtract(s, r);
}
} else {
if (coefU <= coefV) {
Elementary.completeInPlaceAdd(u, v);
Elementary.completeInPlaceAdd(r, s);
} else {
Elementary.completeInPlaceAdd(v, u);
Elementary.completeInPlaceAdd(s, r);
}
}
if (v.signum() == 0 || u.signum() == 0) {
// math.19: BigInteger not invertible
throw new ArithmeticException("BigInteger not invertible.");
}
}
if (isPowerOfTwo(v, coefV)) {
r = s;
if (v.signum() != u.signum()) {
u = u.negate();
}
}
if (u.testBit(n)) {
if (r.signum() < 0) {
r = r.negate();
} else {
r = modulo.subtract(r);
}
}
if (r.signum() < 0) {
r = r.add(modulo);
}
return r;
}
/**
* Calculates a.modInverse(p) Based on: Savas, E; Koc, C "The Montgomery
* Modular Inverse - Revised".
*/
static BigInteger modInverseMontgomery(BigInteger a, BigInteger p) {
if (a.sign == 0) {
// ZERO hasn't inverse
// math.19: BigInteger not invertible
throw new ArithmeticException("BigInteger not invertible.");
}
if (!p.testBit(0)) {
// montgomery inverse require even modulo
return modInverseLorencz(a, p);
}
int m = p.numberLength * 32;
// PRE: a \in [1, p - 1]
BigInteger u, v, r, s;
u = p.copy(); // make copy to use inplace method
v = a.copy();
int max = Math.max(v.numberLength, u.numberLength);
r = new BigInteger(1, 1, new int[max + 1]);
s = new BigInteger(1, 1, new int[max + 1]);
s.digits[0] = 1;
// s == 1 && v == 0
int k = 0;
int lsbu = u.getLowestSetBit();
int lsbv = v.getLowestSetBit();
int toShift;
if (lsbu > lsbv) {
BitLevel.inplaceShiftRight(u, lsbu);
BitLevel.inplaceShiftRight(v, lsbv);
BitLevel.inplaceShiftLeft(r, lsbv);
k += lsbu - lsbv;
} else {
BitLevel.inplaceShiftRight(u, lsbu);
BitLevel.inplaceShiftRight(v, lsbv);
BitLevel.inplaceShiftLeft(s, lsbu);
k += lsbv - lsbu;
}
r.sign = 1;
while (v.signum() > 0) {
// INV v >= 0, u >= 0, v odd, u odd (except last iteration when v is even
// (0))
while (u.compareTo(v) > BigInteger.EQUALS) {
Elementary.inplaceSubtract(u, v);
toShift = u.getLowestSetBit();
BitLevel.inplaceShiftRight(u, toShift);
Elementary.inplaceAdd(r, s);
BitLevel.inplaceShiftLeft(s, toShift);
k += toShift;
}
while (u.compareTo(v) <= BigInteger.EQUALS) {
Elementary.inplaceSubtract(v, u);
if (v.signum() == 0) {
break;
}
toShift = v.getLowestSetBit();
BitLevel.inplaceShiftRight(v, toShift);
Elementary.inplaceAdd(s, r);
BitLevel.inplaceShiftLeft(r, toShift);
k += toShift;
}
}
if (!u.isOne()) {
// in u is stored the gcd
// math.19: BigInteger not invertible.
throw new ArithmeticException("BigInteger not invertible.");
}
if (r.compareTo(p) >= BigInteger.EQUALS) {
Elementary.inplaceSubtract(r, p);
}
r = p.subtract(r);
// Have pair: ((BigInteger)r, (Integer)k) where r == a^(-1) * 2^k mod
// (module)
int n1 = calcN(p);
if (k > m) {
r = monPro(r, BigInteger.ONE, p, n1);
k = k - m;
}
r = monPro(r, BigInteger.getPowerOfTwo(m - k), p, n1);
return r;
}
/**
* @param x an odd positive number.
* @param n the exponent by which 2 is raised.
* @return {@code x-1 (mod 2n)}.
*/
static BigInteger modPow2Inverse(BigInteger x, int n) {
// PRE: (x > 0), (x is odd), and (n > 0)
BigInteger y = new BigInteger(1, new int[1 << n]);
y.numberLength = 1;
y.digits[0] = 1;
y.sign = 1;
for (int i = 1; i < n; i++) {
if (BitLevel.testBit(x.multiply(y), i)) {
// Adding 2^i to y (setting the i-th bit)
y.digits[i >> 5] |= (1 << (i & 31));
}
}
return y;
}
/**
* Implements the Montgomery Product of two integers represented by {@code
* int} arrays. The arrays are supposed in little endian notation.
*
* @param a The first factor of the product.
* @param b The second factor of the product.
* @param modulus The modulus of the operations. Zmodulus.
* @param n2 The digit modulus'[0].
* @ar.org.fitc.ref "C. K. Koc - Analyzing and Comparing Montgomery
* Multiplication Algorithms"
* @see #modPowOdd(BigInteger, BigInteger, BigInteger)
*/
static BigInteger monPro(BigInteger a, BigInteger b, BigInteger modulus,
int n2) {
int modulusLen = modulus.numberLength;
int res[] = new int[(modulusLen << 1) + 1];
Multiplication.multArraysPAP(a.digits,
Math.min(modulusLen, a.numberLength), b.digits, Math.min(modulusLen,
b.numberLength), res);
monReduction(res, modulus, n2);
return finalSubtraction(res, modulus);
}
/**
* Multiplies an array by int and subtracts it from a subarray of another
* array.
*
* @param a the array to subtract from
* @param start the start element of the subarray of a
* @param b the array to be multiplied and subtracted
* @param bLen the length of b
* @param c the multiplier of b
* @return the carry element of subtraction
*/
static int multiplyAndSubtract(int a[], int start, int b[], int bLen, int c) {
long carry0 = 0;
long carry1 = 0;
for (int i = 0; i < bLen; i++) {
carry0 = Multiplication.unsignedMultAddAdd(b[i], c, (int) carry0, 0);
carry1 = (a[start + i] & 0xffffffffL) - (carry0 & 0xffffffffL) + carry1;
a[start + i] = (int) carry1;
carry1 >>= 32; // -1 or 0
carry0 >>>= 32;
}
carry1 = (a[start + bLen] & 0xffffffffL) - carry0 + carry1;
a[start + bLen] = (int) carry1;
return (int) (carry1 >> 32); // -1 or 0
}
/**
* Performs modular exponentiation using the Montgomery Reduction. It requires
* that all parameters be positive and the modulus be odd. >
*
* @see BigInteger#modPow(BigInteger, BigInteger)
* @see #monPro(BigInteger, BigInteger, BigInteger, int)
* @see #slidingWindow(BigInteger, BigInteger, BigInteger, BigInteger, int)
* @see #squareAndMultiply(BigInteger, BigInteger, BigInteger, BigInteger,
* int)
*/
static BigInteger oddModPow(BigInteger base, BigInteger exponent,
BigInteger modulus) {
// PRE: (base > 0), (exponent > 0), (modulus > 0) and (odd modulus)
int k = (modulus.numberLength << 5); // r = 2^k
// n-residue of base [base * r (mod modulus)]
BigInteger a2 = base.shiftLeft(k).mod(modulus);
// n-residue of base [1 * r (mod modulus)]
BigInteger x2 = BigInteger.getPowerOfTwo(k).mod(modulus);
BigInteger res;
// Compute (modulus[0]^(-1)) (mod 2^32) for odd modulus
int n2 = calcN(modulus);
if (modulus.numberLength == 1) {
res = squareAndMultiply(x2, a2, exponent, modulus, n2);
} else {
res = slidingWindow(x2, a2, exponent, modulus, n2);
}
return monPro(res, BigInteger.ONE, modulus, n2);
}
/**
* It requires that all parameters be positive.
*
* @return {@code baseexponent mod (2j)}.
* @see BigInteger#modPow(BigInteger, BigInteger)
*/
static BigInteger pow2ModPow(BigInteger base, BigInteger exponent, int j) {
// PRE: (base > 0), (exponent > 0) and (j > 0)
BigInteger res = BigInteger.ONE;
BigInteger e = exponent.copy();
BigInteger baseMod2toN = base.copy();
BigInteger res2;
/*
* If 'base' is odd then it's coprime with 2^j and phi(2^j) = 2^(j-1); so we
* can reduce reduce the exponent (mod 2^(j-1)).
*/
if (base.testBit(0)) {
inplaceModPow2(e, j - 1);
}
inplaceModPow2(baseMod2toN, j);
for (int i = e.bitLength() - 1; i >= 0; i--) {
res2 = res.copy();
inplaceModPow2(res2, j);
res = res.multiply(res2);
if (BitLevel.testBit(e, i)) {
res = res.multiply(baseMod2toN);
inplaceModPow2(res, j);
}
}
inplaceModPow2(res, j);
return res;
}
/**
* Divides a BigInteger
by a signed int
and returns
* the remainder.
*
* @param dividend the BigInteger to be divided. Must be non-negative.
* @param divisor a signed int
* @return divide % divisor
*/
static int remainder(BigInteger dividend, int divisor) {
return remainderArrayByInt(dividend.digits, dividend.numberLength, divisor);
}
/**
* Divides an array by an integer value. Implements the Knuth's division
* algorithm. See D. Knuth, The Art of Computer Programming, vol. 2.
*
* @param src the dividend
* @param srcLength the length of the dividend
* @param divisor the divisor
* @return remainder
*/
static int remainderArrayByInt(int src[], final int srcLength,
final int divisor) {
long result = 0;
for (int i = srcLength - 1; i >= 0; i--) {
long temp = (result << 32) + (src[i] & 0xffffffffL);
long res = divideLongByInt(temp, divisor);
result = (int) (res >> 32);
}
return (int) result;
}
/*
* Implements the Montgomery modular exponentiation based in The sliding
* windows algorithm and the MongomeryReduction.
*
* @ar.org.fitc.ref
* "A. Menezes,P. van Oorschot, S. Vanstone - Handbook of Applied Cryptography"
* ;
*
* @see #oddModPow(BigInteger, BigInteger, BigInteger)
*/
static BigInteger slidingWindow(BigInteger x2, BigInteger a2,
BigInteger exponent, BigInteger modulus, int n2) {
// fill odd low pows of a2
BigInteger pows[] = new BigInteger[8];
BigInteger res = x2;
int lowexp;
BigInteger x3;
int acc3;
pows[0] = a2;
x3 = monPro(a2, a2, modulus, n2);
for (int i = 1; i <= 7; i++) {
pows[i] = monPro(pows[i - 1], x3, modulus, n2);
}
for (int i = exponent.bitLength() - 1; i >= 0; i--) {
if (BitLevel.testBit(exponent, i)) {
lowexp = 1;
acc3 = i;
for (int j = Math.max(i - 3, 0); j <= i - 1; j++) {
if (BitLevel.testBit(exponent, j)) {
if (j < acc3) {
acc3 = j;
lowexp = (lowexp << (i - j)) ^ 1;
} else {
lowexp = lowexp ^ (1 << (j - acc3));
}
}
}
for (int j = acc3; j <= i; j++) {
res = monPro(res, res, modulus, n2);
}
res = monPro(pows[(lowexp - 1) >> 1], res, modulus, n2);
i = acc3;
} else {
res = monPro(res, res, modulus, n2);
}
}
return res;
}
static BigInteger squareAndMultiply(BigInteger x2, BigInteger a2,
BigInteger exponent, BigInteger modulus, int n2) {
BigInteger res = x2;
for (int i = exponent.bitLength() - 1; i >= 0; i--) {
res = monPro(res, res, modulus, n2);
if (BitLevel.testBit(exponent, i)) {
res = monPro(res, a2, modulus, n2);
}
}
return res;
}
/**
* Calculate the first digit of the inverse.
*/
private static int calcN(BigInteger a) {
long m0 = a.digits[0] & 0xFFFFFFFFL;
long n2 = 1L; // this is a'[0]
long powerOfTwo = 2L;
do {
if (((m0 * n2) & powerOfTwo) != 0) {
n2 |= powerOfTwo;
}
powerOfTwo <<= 1;
} while (powerOfTwo < 0x100000000L);
n2 = -n2;
return (int) (n2 & 0xFFFFFFFFL);
}
/**
* Calculate how many iteration of Lorencz's algorithm would perform the same
* operation.
*
* @param bi
* @param n
* @return
*/
private static int howManyIterations(BigInteger bi, int n) {
int i = n - 1;
if (bi.sign > 0) {
while (!bi.testBit(i)) {
i--;
}
return n - 1 - i;
} else {
while (bi.testBit(i)) {
i--;
}
return n - 1 - Math.max(i, bi.getLowestSetBit());
}
}
/**
* Returns {@code bi == abs(2^exp)}.
*/
private static boolean isPowerOfTwo(BigInteger bi, int exp) {
boolean result = false;
result = (exp >> 5 == bi.numberLength - 1)
&& (bi.digits[bi.numberLength - 1] == 1 << (exp & 31));
if (result) {
for (int i = 0; result && i < bi.numberLength - 1; i++) {
result = bi.digits[i] == 0;
}
}
return result;
}
private static void monReduction(int[] res, BigInteger modulus, int n2) {
/* res + m*modulus_digits */
int[] modulusDigits = modulus.digits;
int modulusLen = modulus.numberLength;
long outerCarry = 0;
for (int i = 0; i < modulusLen; i++) {
long innnerCarry = 0;
int m = (int) Multiplication.unsignedMultAddAdd(res[i], n2, 0, 0);
for (int j = 0; j < modulusLen; j++) {
innnerCarry = Multiplication.unsignedMultAddAdd(m, modulusDigits[j],
res[i + j], (int) innnerCarry);
res[i + j] = (int) innnerCarry;
innnerCarry >>>= 32;
}
outerCarry += (res[i + modulusLen] & 0xFFFFFFFFL) + innnerCarry;
res[i + modulusLen] = (int) outerCarry;
outerCarry >>>= 32;
}
res[modulusLen << 1] = (int) outerCarry;
/* res / r */
for (int j = 0; j < modulusLen + 1; j++) {
res[j] = res[j + modulusLen];
}
}
}