mirror of
https://github.com/moparisthebest/mailiverse
synced 2024-11-13 12:45:09 -05:00
1014 lines
32 KiB
Java
1014 lines
32 KiB
Java
|
/*
|
||
|
* 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:
|
||
|
*
|
||
|
* <ul type="circle"> <li><b>Division</b> <ul type="circle"> <li>
|
||
|
* {@link BigInteger} division and remainder by {@link BigInteger}.</li> <li>
|
||
|
* {@link BigInteger} division and remainder by {@code int}.</li> <li><i>gcd</i>
|
||
|
* between {@link BigInteger} numbers.</li> </ul> </li> <li><b>Modular
|
||
|
* arithmetic </b> <ul type="circle"> <li>Modular exponentiation between
|
||
|
* {@link BigInteger} numbers.</li> <li>Modular inverse of a {@link BigInteger}
|
||
|
* numbers.</li> </ul> </li> </ul>
|
||
|
*/
|
||
|
class Division {
|
||
|
|
||
|
/**
|
||
|
* Divides the array 'a' by the array 'b' and gets the quotient and the
|
||
|
* remainder. Implements the Knuth's division algorithm. See D. Knuth, The Art
|
||
|
* of Computer Programming, vol. 2. Steps D1-D8 correspond the steps in the
|
||
|
* algorithm description.
|
||
|
*
|
||
|
* @param quot the quotient
|
||
|
* @param quotLength the quotient's length
|
||
|
* @param a the dividend
|
||
|
* @param aLength the dividend's length
|
||
|
* @param b the divisor
|
||
|
* @param bLength the divisor's length
|
||
|
* @return the remainder
|
||
|
*/
|
||
|
static int[] divide(int quot[], int quotLength, int a[], int aLength,
|
||
|
int b[], int bLength) {
|
||
|
|
||
|
int normA[] = new int[aLength + 1]; // the normalized dividend
|
||
|
// an extra byte is needed for correct shift
|
||
|
int normB[] = new int[bLength + 1]; // the normalized divisor;
|
||
|
int normBLength = bLength;
|
||
|
/*
|
||
|
* Step D1: normalize a and b and put the results to a1 and b1 the
|
||
|
* normalized divisor's first digit must be >= 2^31
|
||
|
*/
|
||
|
int divisorShift = Integer.numberOfLeadingZeros(b[bLength - 1]);
|
||
|
if (divisorShift != 0) {
|
||
|
BitLevel.shiftLeft(normB, b, 0, divisorShift);
|
||
|
BitLevel.shiftLeft(normA, a, 0, divisorShift);
|
||
|
} else {
|
||
|
System.arraycopy(a, 0, normA, 0, aLength);
|
||
|
System.arraycopy(b, 0, normB, 0, bLength);
|
||
|
}
|
||
|
int firstDivisorDigit = normB[normBLength - 1];
|
||
|
// Step D2: set the quotient index
|
||
|
int i = quotLength - 1;
|
||
|
int j = aLength;
|
||
|
|
||
|
while (i >= 0) {
|
||
|
// Step D3: calculate a guess digit guessDigit
|
||
|
int guessDigit = 0;
|
||
|
if (normA[j] == firstDivisorDigit) {
|
||
|
// set guessDigit to the largest unsigned int value
|
||
|
guessDigit = -1;
|
||
|
} else {
|
||
|
long product = (((normA[j] & 0xffffffffL) << 32) + (normA[j - 1] & 0xffffffffL));
|
||
|
long res = Division.divideLongByInt(product, firstDivisorDigit);
|
||
|
guessDigit = (int) res; // the quotient of divideLongByInt
|
||
|
int rem = (int) (res >> 32); // the remainder of
|
||
|
// divideLongByInt
|
||
|
// decrease guessDigit by 1 while leftHand > rightHand
|
||
|
if (guessDigit != 0) {
|
||
|
long leftHand = 0;
|
||
|
long rightHand = 0;
|
||
|
boolean rOverflowed = false;
|
||
|
guessDigit++; // to have the proper value in the loop
|
||
|
// below
|
||
|
do {
|
||
|
guessDigit--;
|
||
|
if (rOverflowed) {
|
||
|
break;
|
||
|
}
|
||
|
// leftHand always fits in an unsigned long
|
||
|
leftHand = (guessDigit & 0xffffffffL)
|
||
|
* (normB[normBLength - 2] & 0xffffffffL);
|
||
|
/*
|
||
|
* rightHand can overflow; in this case the loop condition will be
|
||
|
* true in the next step of the loop
|
||
|
*/
|
||
|
rightHand = ((long) rem << 32) + (normA[j - 2] & 0xffffffffL);
|
||
|
long longR = (rem & 0xffffffffL)
|
||
|
+ (firstDivisorDigit & 0xffffffffL);
|
||
|
/*
|
||
|
* checks that longR does not fit in an unsigned int; this ensures
|
||
|
* that rightHand will overflow unsigned long in the next step
|
||
|
*/
|
||
|
if (Integer.numberOfLeadingZeros((int) (longR >>> 32)) < 32) {
|
||
|
rOverflowed = true;
|
||
|
} else {
|
||
|
rem = (int) longR;
|
||
|
}
|
||
|
} while (((leftHand ^ 0x8000000000000000L) > (rightHand ^ 0x8000000000000000L)));
|
||
|
}
|
||
|
}
|
||
|
// Step D4: multiply normB by guessDigit and subtract the production
|
||
|
// from normA.
|
||
|
if (guessDigit != 0) {
|
||
|
int borrow = Division.multiplyAndSubtract(normA, j - normBLength,
|
||
|
normB, normBLength, guessDigit);
|
||
|
// Step D5: check the borrow
|
||
|
if (borrow != 0) {
|
||
|
// Step D6: compensating addition
|
||
|
guessDigit--;
|
||
|
long carry = 0;
|
||
|
for (int k = 0; k < normBLength; k++) {
|
||
|
carry += (normA[j - normBLength + k] & 0xffffffffL)
|
||
|
+ (normB[k] & 0xffffffffL);
|
||
|
normA[j - normBLength + k] = (int) carry;
|
||
|
carry >>>= 32;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (quot != null) {
|
||
|
quot[i] = guessDigit;
|
||
|
}
|
||
|
// Step D7
|
||
|
j--;
|
||
|
i--;
|
||
|
}
|
||
|
/*
|
||
|
* Step D8: we got the remainder in normA. Denormalize it id needed
|
||
|
*/
|
||
|
if (divisorShift != 0) {
|
||
|
// reuse normB
|
||
|
BitLevel.shiftRight(normB, normBLength, normA, 0, divisorShift);
|
||
|
return normB;
|
||
|
}
|
||
|
System.arraycopy(normA, 0, normB, 0, bLength);
|
||
|
return normA;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Computes the quotient and the remainder after a division by an {@code int}
|
||
|
* number.
|
||
|
*
|
||
|
* @return an array of the form {@code [quotient, remainder]}.
|
||
|
*/
|
||
|
static BigInteger[] divideAndRemainderByInteger(BigInteger val, int divisor,
|
||
|
int divisorSign) {
|
||
|
// res[0] is a quotient and res[1] is a remainder:
|
||
|
int[] valDigits = val.digits;
|
||
|
int valLen = val.numberLength;
|
||
|
int valSign = val.sign;
|
||
|
if (valLen == 1) {
|
||
|
long a = (valDigits[0] & 0xffffffffL);
|
||
|
long b = (divisor & 0xffffffffL);
|
||
|
long quo = a / b;
|
||
|
long rem = a % b;
|
||
|
if (valSign != divisorSign) {
|
||
|
quo = -quo;
|
||
|
}
|
||
|
if (valSign < 0) {
|
||
|
rem = -rem;
|
||
|
}
|
||
|
return new BigInteger[] {BigInteger.valueOf(quo), BigInteger.valueOf(rem)};
|
||
|
}
|
||
|
int quotientLength = valLen;
|
||
|
int quotientSign = ((valSign == divisorSign) ? 1 : -1);
|
||
|
int quotientDigits[] = new int[quotientLength];
|
||
|
int remainderDigits[];
|
||
|
remainderDigits = new int[] {Division.divideArrayByInt(quotientDigits,
|
||
|
valDigits, valLen, divisor)};
|
||
|
BigInteger result0 = new BigInteger(quotientSign, quotientLength,
|
||
|
quotientDigits);
|
||
|
BigInteger result1 = new BigInteger(valSign, 1, remainderDigits);
|
||
|
result0.cutOffLeadingZeroes();
|
||
|
result1.cutOffLeadingZeroes();
|
||
|
return new BigInteger[] {result0, result1};
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Divides an array by an integer value. Implements the Knuth's division
|
||
|
* algorithm. See D. Knuth, The Art of Computer Programming, vol. 2.
|
||
|
*
|
||
|
* @param dest the quotient
|
||
|
* @param src the dividend
|
||
|
* @param srcLength the length of the dividend
|
||
|
* @param divisor the divisor
|
||
|
* @return remainder
|
||
|
*/
|
||
|
static int divideArrayByInt(int dest[], int src[], final int srcLength,
|
||
|
final int divisor) {
|
||
|
|
||
|
long rem = 0;
|
||
|
long bLong = divisor & 0xffffffffL;
|
||
|
|
||
|
for (int i = srcLength - 1; i >= 0; i--) {
|
||
|
long temp = (rem << 32) | (src[i] & 0xffffffffL);
|
||
|
long quot;
|
||
|
if (temp >= 0) {
|
||
|
quot = (temp / bLong);
|
||
|
rem = (temp % bLong);
|
||
|
} else {
|
||
|
/*
|
||
|
* make the dividend positive shifting it right by 1 bit then get the
|
||
|
* quotient an remainder and correct them properly
|
||
|
*/
|
||
|
long aPos = temp >>> 1;
|
||
|
long bPos = divisor >>> 1;
|
||
|
quot = aPos / bPos;
|
||
|
rem = aPos % bPos;
|
||
|
// double the remainder and add 1 if a is odd
|
||
|
rem = (rem << 1) + (temp & 1);
|
||
|
if ((divisor & 1) != 0) {
|
||
|
// the divisor is odd
|
||
|
if (quot <= rem) {
|
||
|
rem -= quot;
|
||
|
} else {
|
||
|
if (quot - rem <= bLong) {
|
||
|
rem += bLong - quot;
|
||
|
quot -= 1;
|
||
|
} else {
|
||
|
rem += (bLong << 1) - quot;
|
||
|
quot -= 2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
dest[i] = (int) (quot & 0xffffffffL);
|
||
|
}
|
||
|
return (int) rem;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Divides an unsigned long a by an unsigned int b. It is supposed that the
|
||
|
* most significant bit of b is set to 1, i.e. b < 0
|
||
|
*
|
||
|
* @param a the dividend
|
||
|
* @param b the divisor
|
||
|
* @return the long value containing the unsigned integer remainder in the
|
||
|
* left half and the unsigned integer quotient in the right half
|
||
|
*/
|
||
|
static long divideLongByInt(long a, int b) {
|
||
|
long quot;
|
||
|
long rem;
|
||
|
long bLong = b & 0xffffffffL;
|
||
|
|
||
|
if (a >= 0) {
|
||
|
quot = (a / bLong);
|
||
|
rem = (a % bLong);
|
||
|
} else {
|
||
|
/*
|
||
|
* Make the dividend positive shifting it right by 1 bit then get the
|
||
|
* quotient an remainder and correct them properly
|
||
|
*/
|
||
|
long aPos = a >>> 1;
|
||
|
long bPos = b >>> 1;
|
||
|
quot = aPos / bPos;
|
||
|
rem = aPos % bPos;
|
||
|
// double the remainder and add 1 if a is odd
|
||
|
rem = (rem << 1) + (a & 1);
|
||
|
if ((b & 1) != 0) { // the divisor is odd
|
||
|
if (quot <= rem) {
|
||
|
rem -= quot;
|
||
|
} else {
|
||
|
if (quot - rem <= bLong) {
|
||
|
rem += bLong - quot;
|
||
|
quot -= 1;
|
||
|
} else {
|
||
|
rem += (bLong << 1) - quot;
|
||
|
quot -= 2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return (rem << 32) | (quot & 0xffffffffL);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Performs modular exponentiation using the Montgomery Reduction. It requires
|
||
|
* that all parameters be positive and the modulus be even. Based <i>The
|
||
|
* square and multiply algorithm and the Montgomery Reduction C. K. Koc -
|
||
|
* Montgomery Reduction with Even Modulus</i>. The square and multiply
|
||
|
* algorithm and the Montgomery Reduction.
|
||
|
*
|
||
|
* @ar.org.fitc.ref "C. K. Koc - Montgomery Reduction with Even Modulus"
|
||
|
* @see BigInteger#modPow(BigInteger, BigInteger)
|
||
|
*/
|
||
|
static BigInteger evenModPow(BigInteger base, BigInteger exponent,
|
||
|
BigInteger modulus) {
|
||
|
// PRE: (base > 0), (exponent > 0), (modulus > 0) and (modulus even)
|
||
|
// STEP 1: Obtain the factorization 'modulus'= q * 2^j.
|
||
|
int j = modulus.getLowestSetBit();
|
||
|
BigInteger q = modulus.shiftRight(j);
|
||
|
|
||
|
// STEP 2: Compute x1 := base^exponent (mod q).
|
||
|
BigInteger x1 = oddModPow(base, exponent, q);
|
||
|
|
||
|
// STEP 3: Compute x2 := base^exponent (mod 2^j).
|
||
|
BigInteger x2 = pow2ModPow(base, exponent, j);
|
||
|
|
||
|
// STEP 4: Compute q^(-1) (mod 2^j) and y := (x2-x1) * q^(-1) (mod 2^j)
|
||
|
BigInteger qInv = modPow2Inverse(q, j);
|
||
|
BigInteger y = (x2.subtract(x1)).multiply(qInv);
|
||
|
inplaceModPow2(y, j);
|
||
|
if (y.sign < 0) {
|
||
|
y = y.add(BigInteger.getPowerOfTwo(j));
|
||
|
}
|
||
|
// STEP 5: Compute and return: x1 + q * y
|
||
|
return x1.add(q.multiply(y));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Performs the final reduction of the Montgomery algorithm.
|
||
|
*
|
||
|
* @see #monPro(BigInteger, BigInteger, BigInteger, long)
|
||
|
* @see #monSquare(BigInteger, BigInteger, long)
|
||
|
*/
|
||
|
static BigInteger finalSubtraction(int res[], BigInteger modulus) {
|
||
|
|
||
|
// skipping leading zeros
|
||
|
int modulusLen = modulus.numberLength;
|
||
|
boolean doSub = res[modulusLen] != 0;
|
||
|
if (!doSub) {
|
||
|
int modulusDigits[] = modulus.digits;
|
||
|
doSub = true;
|
||
|
for (int i = modulusLen - 1; i >= 0; i--) {
|
||
|
if (res[i] != modulusDigits[i]) {
|
||
|
doSub = (res[i] != 0)
|
||
|
&& ((res[i] & 0xFFFFFFFFL) > (modulusDigits[i] & 0xFFFFFFFFL));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BigInteger result = new BigInteger(1, modulusLen + 1, res);
|
||
|
|
||
|
// if (res >= modulusDigits) compute (res - modulusDigits)
|
||
|
if (doSub) {
|
||
|
Elementary.inplaceSubtract(result, modulus);
|
||
|
}
|
||
|
|
||
|
result.cutOffLeadingZeroes();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param m a positive modulus Return the greatest common divisor of op1 and
|
||
|
* op2,
|
||
|
*
|
||
|
* @param op1 must be greater than zero
|
||
|
* @param op2 must be greater than zero
|
||
|
* @see BigInteger#gcd(BigInteger)
|
||
|
* @return {@code GCD(op1, op2)}
|
||
|
*/
|
||
|
static BigInteger gcdBinary(BigInteger op1, BigInteger op2) {
|
||
|
// PRE: (op1 > 0) and (op2 > 0)
|
||
|
|
||
|
/*
|
||
|
* Divide both number the maximal possible times by 2 without rounding
|
||
|
* gcd(2*a, 2*b) = 2 * gcd(a,b)
|
||
|
*/
|
||
|
int lsb1 = op1.getLowestSetBit();
|
||
|
int lsb2 = op2.getLowestSetBit();
|
||
|
int pow2Count = Math.min(lsb1, lsb2);
|
||
|
|
||
|
BitLevel.inplaceShiftRight(op1, lsb1);
|
||
|
BitLevel.inplaceShiftRight(op2, lsb2);
|
||
|
|
||
|
BigInteger swap;
|
||
|
// I want op2 > op1
|
||
|
if (op1.compareTo(op2) == BigInteger.GREATER) {
|
||
|
swap = op1;
|
||
|
op1 = op2;
|
||
|
op2 = swap;
|
||
|
}
|
||
|
|
||
|
do { // INV: op2 >= op1 && both are odd unless op1 = 0
|
||
|
|
||
|
// Optimization for small operands
|
||
|
// (op2.bitLength() < 64) implies by INV (op1.bitLength() < 64)
|
||
|
if ((op2.numberLength == 1)
|
||
|
|| ((op2.numberLength == 2) && (op2.digits[1] > 0))) {
|
||
|
op2 = BigInteger.valueOf(Division.gcdBinary(op1.longValue(),
|
||
|
op2.longValue()));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Implements one step of the Euclidean algorithm
|
||
|
// To reduce one operand if it's much smaller than the other one
|
||
|
if (op2.numberLength > op1.numberLength * 1.2) {
|
||
|
op2 = op2.remainder(op1);
|
||
|
if (op2.signum() != 0) {
|
||
|
BitLevel.inplaceShiftRight(op2, op2.getLowestSetBit());
|
||
|
}
|
||
|
} else {
|
||
|
|
||
|
// Use Knuth's algorithm of successive subtract and shifting
|
||
|
do {
|
||
|
Elementary.inplaceSubtract(op2, op1); // both are odd
|
||
|
BitLevel.inplaceShiftRight(op2, op2.getLowestSetBit()); // op2 is even
|
||
|
} while (op2.compareTo(op1) >= BigInteger.EQUALS);
|
||
|
}
|
||
|
// now op1 >= op2
|
||
|
swap = op2;
|
||
|
op2 = op1;
|
||
|
op1 = swap;
|
||
|
} while (op1.sign != 0);
|
||
|
return op2.shiftLeft(pow2Count);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Performs the same as {@link #gcdBinary(BigInteger, BigInteger)}, but with
|
||
|
* numbers of 63 bits, represented in positives values of {@code long} type.
|
||
|
*
|
||
|
* @param op1 a positive number
|
||
|
* @param op2 a positive number
|
||
|
* @see #gcdBinary(BigInteger, BigInteger)
|
||
|
* @return <code>GCD(op1, op2)</code>
|
||
|
*/
|
||
|
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 (2<sup>n</sup>)}.
|
||
|
*
|
||
|
* @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<sup>-1</sup> (mod 2<sup>n</sup>)}.
|
||
|
*/
|
||
|
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 <i>little endian</i> notation.
|
||
|
*
|
||
|
* @param a The first factor of the product.
|
||
|
* @param b The second factor of the product.
|
||
|
* @param modulus The modulus of the operations. Z<sub>modulus</sub>.
|
||
|
* @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 base<sup>exponent</sup> mod (2<sup>j</sup>)}.
|
||
|
* @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 <code>BigInteger</code> by a signed <code>int</code> 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 <i>The sliding
|
||
|
* windows algorithm and the MongomeryReduction</i>.
|
||
|
*
|
||
|
* @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];
|
||
|
}
|
||
|
}
|
||
|
}
|