
lowentry.ue4.classes.internal.rsa.RsaMutableBigInteger Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java Show documentation
Show all versions of java Show documentation
A Java library for the Low Entry UE4 plugins.
package lowentry.ue4.classes.internal.rsa;
import java.util.Arrays;
class RsaMutableBigInteger
{
private int[] value;
public int intLen;
private int offset = 0;
private static final RsaMutableBigInteger ONE = new RsaMutableBigInteger(1);
private static final int KNUTH_POW2_THRESH_LEN = 6;
private static final int KNUTH_POW2_THRESH_ZEROS = 3;
private final static long LONG_MASK = 0xffffffffL;
public RsaMutableBigInteger()
{
value = new int[1];
intLen = 0;
}
public RsaMutableBigInteger(int val)
{
value = new int[1];
intLen = 1;
value[0] = val;
}
public RsaMutableBigInteger(int[] val)
{
if(val == null)
{
val = new int[1];
}
value = val;
intLen = val.length;
}
public RsaMutableBigInteger(RsaBigInteger b)
{
if(b == null)
{
value = new int[1];
intLen = 0;
return;
}
intLen = b.mag.length;
value = Arrays.copyOf(b.mag, intLen);
}
public RsaMutableBigInteger(RsaMutableBigInteger val)
{
if(val == null)
{
value = new int[1];
intLen = 0;
return;
}
intLen = val.intLen;
value = Arrays.copyOfRange(val.value, val.offset, val.offset + intLen);
}
private static int si(int a, int b)
{
return (a >>> b);
}
private static long sl(long a, int b)
{
return (a >>> b);
}
private void ones(int n)
{
if(n > value.length)
{
value = new int[n];
}
Arrays.fill(value, -1);
offset = 0;
intLen = n;
}
private int[] getMagnitudeArray()
{
if((offset > 0) || (value.length != intLen))
{
return Arrays.copyOfRange(value, offset, offset + intLen);
}
return value;
}
public RsaBigInteger toBigInteger(int sign)
{
if((intLen == 0) || (sign == 0))
{
return RsaBigInteger.ZERO;
}
return new RsaBigInteger(getMagnitudeArray(), sign);
}
public RsaBigInteger toBigInteger()
{
normalize();
return toBigInteger(isZero() ? 0 : 1);
}
private void clear()
{
offset = intLen = 0;
for(int index = 0, n = value.length; index < n; index++)
{
value[index] = 0;
}
}
private void reset()
{
offset = intLen = 0;
}
private final int compare(RsaMutableBigInteger b)
{
if(b == null)
{
return 0;
}
int blen = b.intLen;
if(intLen < blen)
{
return -1;
}
if(intLen > blen)
{
return 1;
}
int[] bval = b.value;
for(int i = offset, j = b.offset; i < (intLen + offset); i++, j++)
{
int b1 = value[i] + 0x80000000;
int b2 = bval[j] + 0x80000000;
if(b1 < b2)
{
return -1;
}
if(b1 > b2)
{
return 1;
}
}
return 0;
}
private int compareShifted(RsaMutableBigInteger b, int ints)
{
if(b == null)
{
return 0;
}
int blen = b.intLen;
int alen = intLen - ints;
if(alen < blen)
{
return -1;
}
if(alen > blen)
{
return 1;
}
int[] bval = b.value;
for(int i = offset, j = b.offset; i < (alen + offset); i++, j++)
{
int b1 = value[i] + 0x80000000;
int b2 = bval[j] + 0x80000000;
if(b1 < b2)
{
return -1;
}
if(b1 > b2)
{
return 1;
}
}
return 0;
}
private final int getLowestSetBit()
{
if(intLen == 0)
{
return -1;
}
int j = intLen - 1;
while((j > 0) && (value[j + offset] == 0))
{
j--;
}
int b = value[j + offset];
if(b == 0)
{
return -1;
}
return ((intLen - 1 - j) << 5) + integerNumberOfTrailingZeros(b);
}
private final void normalize()
{
if(intLen == 0)
{
offset = 0;
return;
}
int index = offset;
if(value[index] != 0)
{
return;
}
int indexBound = index + intLen;
index++;
while((index < indexBound) && (value[index] == 0))
{
index++;
}
int numZeros = index - offset;
intLen -= numZeros;
offset = (intLen == 0 ? 0 : offset + numZeros);
}
public int[] toIntArray()
{
int[] result = new int[intLen];
for(int i = 0; i < intLen; i++)
{
result[i] = value[offset + i];
}
return result;
}
private void setValue(int[] val, int length)
{
if((val == null) || (val.length <= 0))
{
val = new int[1];
}
value = val;
intLen = length;
offset = 0;
}
private void copyValue(RsaMutableBigInteger src)
{
if(src == null)
{
return;
}
int len = src.intLen;
if(value.length < len)
{
value = new int[len];
}
System.arraycopy(src.value, src.offset, value, 0, len);
intLen = len;
offset = 0;
}
private boolean isOne()
{
return (intLen == 1) && (value[offset] == 1);
}
public boolean isZero()
{
return (intLen == 0);
}
private boolean isEven()
{
return (intLen == 0) || ((value[(offset + intLen) - 1] & 1) == 0);
}
private boolean isOdd()
{
return isZero() ? false : ((value[(offset + intLen) - 1] & 1) == 1);
}
private void safeRightShift(int n)
{
if((n / 32) >= intLen)
{
reset();
}
else
{
rightShift(n);
}
}
private void rightShift(int n)
{
if(intLen == 0)
{
return;
}
int nInts = si(n, 5);
int nBits = n & 0x1F;
this.intLen -= nInts;
if(nBits == 0)
{
return;
}
int bitsInHighWord = bitLengthForInt(value[offset]);
if(nBits >= bitsInHighWord)
{
this.primitiveLeftShift(32 - nBits);
this.intLen--;
}
else
{
primitiveRightShift(nBits);
}
}
private void safeLeftShift(int n)
{
if(n > 0)
{
leftShift(n);
}
}
public void leftShift(int n)
{
if(intLen == 0)
{
return;
}
int nInts = si(n, 5);
int nBits = n & 0x1F;
int bitsInHighWord = bitLengthForInt(value[offset]);
if(n <= (32 - bitsInHighWord))
{
primitiveLeftShift(nBits);
return;
}
int newLen = intLen + nInts + 1;
if(nBits <= (32 - bitsInHighWord))
{
newLen--;
}
if(value.length < newLen)
{
int[] result = new int[newLen];
for(int i = 0; i < intLen; i++)
{
result[i] = value[offset + i];
}
setValue(result, newLen);
}
else if((value.length - offset) >= newLen)
{
for(int i = 0; i < (newLen - intLen); i++)
{
value[offset + intLen + i] = 0;
}
}
else
{
for(int i = 0; i < intLen; i++)
{
value[i] = value[offset + i];
}
for(int i = intLen; i < newLen; i++)
{
value[i] = 0;
}
offset = 0;
}
intLen = newLen;
if(nBits == 0)
{
return;
}
if(nBits <= (32 - bitsInHighWord))
{
primitiveLeftShift(nBits);
}
else
{
primitiveRightShift(32 - nBits);
}
}
private int divadd(int[] a, int[] result, int offset)
{
if((a == null) || (result == null))
{
return 0;
}
long carry = 0;
for(int j = a.length - 1; j >= 0; j--)
{
long sum = (a[j] & LONG_MASK) + (result[j + offset] & LONG_MASK) + carry;
result[j + offset] = (int) sum;
carry = sl(sum, 32);
}
return (int) carry;
}
private int mulsub(int[] q, int[] a, int x, int len, int offset)
{
if((q == null) || (a == null))
{
return 0;
}
long xLong = x & LONG_MASK;
long carry = 0;
offset += len;
for(int j = len - 1; j >= 0; j--)
{
long product = ((a[j] & LONG_MASK) * xLong) + carry;
long difference = q[offset] - product;
q[offset--] = (int) difference;
carry = sl(product, 32) + (((difference & LONG_MASK) > (((~(int) product) & LONG_MASK))) ? 1 : 0);
}
return (int) carry;
}
private int mulsubBorrow(int[] q, int[] a, int x, int len, int offset)
{
if((q == null) || (a == null))
{
return 0;
}
long xLong = x & LONG_MASK;
long carry = 0;
offset += len;
for(int j = len - 1; j >= 0; j--)
{
long product = ((a[j] & LONG_MASK) * xLong) + carry;
long difference = q[offset--] - product;
carry = sl(product, 32) + (((difference & LONG_MASK) > (((~(int) product) & LONG_MASK))) ? 1 : 0);
}
return (int) carry;
}
private final void primitiveRightShift(int n)
{
int n2 = 32 - n;
for(int i = (offset + intLen) - 1, c = value[i]; i > offset; i--)
{
int b = c;
c = value[i - 1];
value[i] = (c << n2) | si(b, n);
}
value[offset] = si(value[offset], n);
}
private final void primitiveLeftShift(int n)
{
int n2 = 32 - n;
for(int i = offset, c = value[i], m = (i + intLen) - 1; i < m; i++)
{
int b = c;
c = value[i + 1];
value[i] = (b << n) | si(c, n2);
}
value[(offset + intLen) - 1] <<= n;
}
private RsaBigInteger getLower(int n)
{
if(isZero())
{
return RsaBigInteger.ZERO;
}
else if(intLen < n)
{
return toBigInteger(1);
}
else
{
int len = n;
while((len > 0) && (value[(offset + intLen) - len] == 0))
{
len--;
}
int sign = len > 0 ? 1 : 0;
return new RsaBigInteger(Arrays.copyOfRange(value, (offset + intLen) - len, offset + intLen), sign);
}
}
private void keepLower(int n)
{
if(intLen >= n)
{
offset += intLen - n;
intLen = n;
}
}
public void add(RsaMutableBigInteger addend)
{
if(addend == null)
{
return;
}
int x = intLen;
int y = addend.intLen;
int resultLen = (intLen > addend.intLen ? intLen : addend.intLen);
int[] result = (value.length < resultLen ? new int[resultLen] : value);
int rstart = result.length - 1;
long sum;
long carry = 0;
while((x > 0) && (y > 0))
{
x--;
y--;
sum = (value[x + offset] & LONG_MASK) + (addend.value[y + addend.offset] & LONG_MASK) + carry;
result[rstart--] = (int) sum;
carry = sl(sum, 32);
}
while(x > 0)
{
x--;
if((carry == 0) && (result == value) && (rstart == (x + offset)))
{
return;
}
sum = (value[x + offset] & LONG_MASK) + carry;
result[rstart--] = (int) sum;
carry = sl(sum, 32);
}
while(y > 0)
{
y--;
sum = (addend.value[y + addend.offset] & LONG_MASK) + carry;
result[rstart--] = (int) sum;
carry = sl(sum, 32);
}
if(carry > 0)
{
resultLen++;
if(result.length < resultLen)
{
int temp[] = new int[resultLen];
System.arraycopy(result, 0, temp, 1, result.length);
temp[0] = 1;
result = temp;
}
else
{
result[rstart--] = 1;
}
}
value = result;
intLen = resultLen;
offset = result.length - resultLen;
}
private void addShifted(RsaMutableBigInteger addend, int n)
{
if(addend == null)
{
return;
}
if(addend.isZero())
{
return;
}
int x = intLen;
int y = addend.intLen + n;
int resultLen = (intLen > y ? intLen : y);
int[] result = (value.length < resultLen ? new int[resultLen] : value);
int rstart = result.length - 1;
long sum;
long carry = 0;
while((x > 0) && (y > 0))
{
x--;
y--;
int bval = (y + addend.offset) < addend.value.length ? addend.value[y + addend.offset] : 0;
sum = (value[x + offset] & LONG_MASK) + (bval & LONG_MASK) + carry;
result[rstart--] = (int) sum;
carry = sl(sum, 32);
}
while(x > 0)
{
x--;
if((carry == 0) && (result == value) && (rstart == (x + offset)))
{
return;
}
sum = (value[x + offset] & LONG_MASK) + carry;
result[rstart--] = (int) sum;
carry = sl(sum, 32);
}
while(y > 0)
{
y--;
int bval = (y + addend.offset) < addend.value.length ? addend.value[y + addend.offset] : 0;
sum = (bval & LONG_MASK) + carry;
result[rstart--] = (int) sum;
carry = sl(sum, 32);
}
if(carry > 0)
{
resultLen++;
if(result.length < resultLen)
{
int temp[] = new int[resultLen];
System.arraycopy(result, 0, temp, 1, result.length);
temp[0] = 1;
result = temp;
}
else
{
result[rstart--] = 1;
}
}
value = result;
intLen = resultLen;
offset = result.length - resultLen;
}
private void addDisjoint(RsaMutableBigInteger addend, int n)
{
if(addend == null)
{
return;
}
if(addend.isZero())
{
return;
}
int x = intLen;
int y = addend.intLen + n;
int resultLen = (intLen > y ? intLen : y);
int[] result;
if(value.length < resultLen)
{
result = new int[resultLen];
}
else
{
result = value;
Arrays.fill(value, offset + intLen, value.length, 0);
}
int rstart = result.length - 1;
System.arraycopy(value, offset, result, (rstart + 1) - x, x);
y -= x;
rstart -= x;
int len = Math.min(y, addend.value.length - addend.offset);
System.arraycopy(addend.value, addend.offset, result, (rstart + 1) - y, len);
for(int i = ((rstart + 1) - y) + len; i < (rstart + 1); i++)
{
result[i] = 0;
}
value = result;
intLen = resultLen;
offset = result.length - resultLen;
}
private void addLower(RsaMutableBigInteger addend, int n)
{
if(addend == null)
{
return;
}
RsaMutableBigInteger a = new RsaMutableBigInteger(addend);
if((a.offset + a.intLen) >= n)
{
a.offset = (a.offset + a.intLen) - n;
a.intLen = n;
}
a.normalize();
add(a);
}
public int subtract(RsaMutableBigInteger b)
{
if(b == null)
{
return 0;
}
RsaMutableBigInteger a = this;
int[] result = value;
int sign = a.compare(b);
if(sign == 0)
{
reset();
return 0;
}
if(sign < 0)
{
RsaMutableBigInteger tmp = a;
a = b;
b = tmp;
}
int resultLen = a.intLen;
if(result.length < resultLen)
{
result = new int[resultLen];
}
long diff = 0;
int x = a.intLen;
int y = b.intLen;
int rstart = result.length - 1;
while(y > 0)
{
x--;
y--;
diff = (a.value[x + a.offset] & LONG_MASK) - (b.value[y + b.offset] & LONG_MASK) - ((int) -(diff >> 32));
result[rstart--] = (int) diff;
}
while(x > 0)
{
x--;
diff = (a.value[x + a.offset] & LONG_MASK) - ((int) -(diff >> 32));
result[rstart--] = (int) diff;
}
value = result;
intLen = resultLen;
offset = value.length - resultLen;
normalize();
return sign;
}
private int difference(RsaMutableBigInteger b)
{
if(b == null)
{
return 0;
}
RsaMutableBigInteger a = this;
int sign = a.compare(b);
if(sign == 0)
{
return 0;
}
if(sign < 0)
{
RsaMutableBigInteger tmp = a;
a = b;
b = tmp;
}
long diff = 0;
int x = a.intLen;
int y = b.intLen;
while(y > 0)
{
x--;
y--;
diff = (a.value[a.offset + x] & LONG_MASK) - (b.value[b.offset + y] & LONG_MASK) - ((int) -(diff >> 32));
a.value[a.offset + x] = (int) diff;
}
while(x > 0)
{
x--;
diff = (a.value[a.offset + x] & LONG_MASK) - ((int) -(diff >> 32));
a.value[a.offset + x] = (int) diff;
}
a.normalize();
return sign;
}
public void multiply(RsaMutableBigInteger y, RsaMutableBigInteger z)
{
if((y == null) || (z == null))
{
return;
}
int xLen = intLen;
int yLen = y.intLen;
int newLen = xLen + yLen;
if(z.value.length < newLen)
{
z.value = new int[newLen];
}
z.offset = 0;
z.intLen = newLen;
long carry = 0;
for(int j = yLen - 1, k = (yLen + xLen) - 1; j >= 0; j--, k--)
{
long product = ((y.value[j + y.offset] & LONG_MASK) * (value[(xLen - 1) + offset] & LONG_MASK)) + carry;
z.value[k] = (int) product;
carry = sl(product, 32);
}
z.value[xLen - 1] = (int) carry;
for(int i = xLen - 2; i >= 0; i--)
{
carry = 0;
for(int j = yLen - 1, k = yLen + i; j >= 0; j--, k--)
{
long product = ((y.value[j + y.offset] & LONG_MASK) * (value[i + offset] & LONG_MASK)) + (z.value[k] & LONG_MASK) + carry;
z.value[k] = (int) product;
carry = sl(product, 32);
}
z.value[i] = (int) carry;
}
z.normalize();
}
private void mul(int y, RsaMutableBigInteger z)
{
if(z == null)
{
return;
}
if(y == 1)
{
z.copyValue(this);
return;
}
if(y == 0)
{
z.clear();
return;
}
long ylong = y & LONG_MASK;
int[] zval = (z.value.length < (intLen + 1) ? new int[intLen + 1] : z.value);
long carry = 0;
for(int i = intLen - 1; i >= 0; i--)
{
long product = (ylong * (value[i + offset] & LONG_MASK)) + carry;
zval[i + 1] = (int) product;
carry = sl(product, 32);
}
if(carry == 0)
{
z.offset = 1;
z.intLen = intLen;
}
else
{
z.offset = 0;
z.intLen = intLen + 1;
zval[0] = (int) carry;
}
z.value = zval;
}
public static int bitLengthForInt(int n)
{
return 32 - integerNumberOfLeadingZeros(n);
}
private static int integerNumberOfTrailingZeros(int i)
{
int y;
if(i == 0)
{
return 32;
}
int n = 31;
y = i << 16;
if(y != 0)
{
n = n - 16;
i = y;
}
y = i << 8;
if(y != 0)
{
n = n - 8;
i = y;
}
y = i << 4;
if(y != 0)
{
n = n - 4;
i = y;
}
y = i << 2;
if(y != 0)
{
n = n - 2;
i = y;
}
return (n - si((i << 1), 31));
}
private static int integerNumberOfLeadingZeros(int i)
{
if(i == 0)
{
return 32;
}
int n = 1;
if(si(i, 16) == 0)
{
n += 16;
i <<= 16;
}
if(si(i, 24) == 0)
{
n += 8;
i <<= 8;
}
if(si(i, 28) == 0)
{
n += 4;
i <<= 4;
}
if(si(i, 30) == 0)
{
n += 2;
i <<= 2;
}
n -= si(i, 31);
return n;
}
public int divideOneWord(int divisor, RsaMutableBigInteger quotient)
{
if(quotient == null)
{
return 0;
}
long divisorLong = divisor & LONG_MASK;
if(intLen == 1)
{
long dividendValue = value[offset] & LONG_MASK;
int q = (int) (dividendValue / divisorLong);
int r = (int) (dividendValue - (q * divisorLong));
quotient.value[0] = q;
quotient.intLen = (q == 0) ? 0 : 1;
quotient.offset = 0;
return r;
}
if(quotient.value.length < intLen)
{
quotient.value = new int[intLen];
}
quotient.offset = 0;
quotient.intLen = intLen;
int shift = integerNumberOfLeadingZeros(divisor);
int rem = value[offset];
long remLong = rem & LONG_MASK;
if(remLong < divisorLong)
{
quotient.value[0] = 0;
}
else
{
quotient.value[0] = (int) (remLong / divisorLong);
rem = (int) (remLong - (quotient.value[0] * divisorLong));
remLong = rem & LONG_MASK;
}
int xlen = intLen;
while(--xlen > 0)
{
long dividendEstimate = (remLong << 32) | (value[(offset + intLen) - xlen] & LONG_MASK);
int q;
if(dividendEstimate >= 0)
{
q = (int) (dividendEstimate / divisorLong);
rem = (int) (dividendEstimate - (q * divisorLong));
}
else
{
long tmp = divWord(dividendEstimate, divisor);
q = (int) (tmp & LONG_MASK);
rem = (int) sl(tmp, 32);
}
quotient.value[intLen - xlen] = q;
remLong = rem & LONG_MASK;
}
quotient.normalize();
if(shift > 0)
{
return rem % divisor;
}
else
{
return rem;
}
}
public RsaMutableBigInteger divide(RsaMutableBigInteger b, RsaMutableBigInteger quotient)
{
if((b == null) || (quotient == null))
{
return null;
}
return divide(b, quotient, true);
}
private RsaMutableBigInteger divide(RsaMutableBigInteger b, RsaMutableBigInteger quotient, boolean needRemainder)
{
if((b == null) || (quotient == null))
{
return null;
}
if((b.intLen < RsaBigInteger.BURNIKEL_ZIEGLER_THRESHOLD) || ((intLen - b.intLen) < RsaBigInteger.BURNIKEL_ZIEGLER_OFFSET))
{
return divideKnuth(b, quotient, needRemainder);
}
else
{
return divideAndRemainderBurnikelZiegler(b, quotient);
}
}
public RsaMutableBigInteger divideKnuth(RsaMutableBigInteger b, RsaMutableBigInteger quotient)
{
if((b == null) || (quotient == null))
{
return null;
}
return divideKnuth(b, quotient, true);
}
private RsaMutableBigInteger divideKnuth(RsaMutableBigInteger b, RsaMutableBigInteger quotient, boolean needRemainder)
{
if((b == null) || (quotient == null))
{
return null;
}
if(b.intLen == 0)
{
//throw new ArithmeticException("BigInteger divide by zero");
return null;
}
if(intLen == 0)
{
quotient.intLen = 0;
quotient.offset = 0;
return needRemainder ? new RsaMutableBigInteger() : null;
}
int cmp = compare(b);
if(cmp < 0)
{
quotient.intLen = 0;
quotient.offset = 0;
return needRemainder ? new RsaMutableBigInteger(this) : null;
}
if(cmp == 0)
{
quotient.value[0] = 1;
quotient.intLen = 1;
quotient.offset = 0;
return needRemainder ? new RsaMutableBigInteger() : null;
}
quotient.clear();
if(b.intLen == 1)
{
int r = divideOneWord(b.value[b.offset], quotient);
if(needRemainder)
{
if(r == 0)
{
return new RsaMutableBigInteger();
}
return new RsaMutableBigInteger(r);
}
else
{
return null;
}
}
if(intLen >= KNUTH_POW2_THRESH_LEN)
{
int trailingZeroBits = Math.min(getLowestSetBit(), b.getLowestSetBit());
if(trailingZeroBits >= (KNUTH_POW2_THRESH_ZEROS * 32))
{
RsaMutableBigInteger a = new RsaMutableBigInteger(this);
b = new RsaMutableBigInteger(b);
a.rightShift(trailingZeroBits);
b.rightShift(trailingZeroBits);
RsaMutableBigInteger r = a.divideKnuth(b, quotient);
if(r == null)
{
return null;
}
r.leftShift(trailingZeroBits);
return r;
}
}
return divideMagnitude(b, quotient, needRemainder);
}
public RsaMutableBigInteger divideAndRemainderBurnikelZiegler(RsaMutableBigInteger b, RsaMutableBigInteger quotient)
{
if((b == null) || (quotient == null))
{
return null;
}
int r = intLen;
int s = b.intLen;
quotient.offset = quotient.intLen = 0;
if(r < s)
{
return this;
}
else
{
int m = 1 << (32 - integerNumberOfLeadingZeros(s / RsaBigInteger.BURNIKEL_ZIEGLER_THRESHOLD));
int j = ((s + m) - 1) / m;
int n = j * m;
long n32 = 32L * n;
int sigma = (int) Math.max(0, n32 - b.bitLength());
RsaMutableBigInteger bShifted = new RsaMutableBigInteger(b);
bShifted.safeLeftShift(sigma);
RsaMutableBigInteger aShifted = new RsaMutableBigInteger(this);
aShifted.safeLeftShift(sigma);
int t = (int) ((aShifted.bitLength() + n32) / n32);
if(t < 2)
{
t = 2;
}
RsaMutableBigInteger a1 = aShifted.getBlock(t - 1, t, n);
if(a1 == null)
{
return null;
}
RsaMutableBigInteger z = aShifted.getBlock(t - 2, t, n);
if(z == null)
{
return null;
}
z.addDisjoint(a1, n);
RsaMutableBigInteger qi = new RsaMutableBigInteger();
RsaMutableBigInteger ri;
for(int i = t - 2; i > 0; i--)
{
ri = z.divide2n1n(bShifted, qi);
if(ri == null)
{
return null;
}
z = aShifted.getBlock(i - 1, t, n);
if(z == null)
{
return null;
}
z.addDisjoint(ri, n);
quotient.addShifted(qi, i * n);
}
ri = z.divide2n1n(bShifted, qi);
if(ri == null)
{
return null;
}
quotient.add(qi);
ri.rightShift(sigma);
return ri;
}
}
private RsaMutableBigInteger divide2n1n(RsaMutableBigInteger b, RsaMutableBigInteger quotient)
{
if((b == null) || (quotient == null))
{
return null;
}
int n = b.intLen;
if(((n % 2) != 0) || (n < RsaBigInteger.BURNIKEL_ZIEGLER_THRESHOLD))
{
return divideKnuth(b, quotient);
}
RsaMutableBigInteger aUpper = new RsaMutableBigInteger(this);
aUpper.safeRightShift(32 * (n / 2));
keepLower(n / 2);
RsaMutableBigInteger q1 = new RsaMutableBigInteger();
RsaMutableBigInteger r1 = aUpper.divide3n2n(b, q1);
if(r1 == null)
{
return null;
}
addDisjoint(r1, n / 2);
RsaMutableBigInteger r2 = divide3n2n(b, quotient);
if(r2 == null)
{
return null;
}
quotient.addDisjoint(q1, n / 2);
return r2;
}
private RsaMutableBigInteger divide3n2n(RsaMutableBigInteger b, RsaMutableBigInteger quotient)
{
if((b == null) || (quotient == null))
{
return null;
}
int n = b.intLen / 2;
RsaMutableBigInteger a12 = new RsaMutableBigInteger(this);
a12.safeRightShift(32 * n);
RsaMutableBigInteger b1 = new RsaMutableBigInteger(b);
b1.safeRightShift(n * 32);
RsaBigInteger b2 = b.getLower(n);
if(b2 == null)
{
return null;
}
RsaMutableBigInteger r;
RsaMutableBigInteger d;
if(compareShifted(b, n) < 0)
{
r = a12.divide2n1n(b1, quotient);
if(r == null)
{
return null;
}
RsaBigInteger qbigint = quotient.toBigInteger();
if(qbigint == null)
{
return null;
}
qbigint = qbigint.multiply(b2);
if(qbigint == null)
{
return null;
}
d = new RsaMutableBigInteger(qbigint);
}
else
{
quotient.ones(n);
a12.add(b1);
b1.leftShift(32 * n);
a12.subtract(b1);
r = a12;
d = new RsaMutableBigInteger(b2);
d.leftShift(32 * n);
d.subtract(new RsaMutableBigInteger(b2));
}
r.leftShift(32 * n);
r.addLower(this, n);
while(r.compare(d) < 0)
{
r.add(b);
quotient.subtract(RsaMutableBigInteger.ONE);
}
r.subtract(d);
return r;
}
private RsaMutableBigInteger getBlock(int index, int numBlocks, int blockLength)
{
int blockStart = index * blockLength;
if(blockStart >= intLen)
{
return new RsaMutableBigInteger();
}
int blockEnd;
if(index == (numBlocks - 1))
{
blockEnd = intLen;
}
else
{
blockEnd = (index + 1) * blockLength;
}
if(blockEnd > intLen)
{
return new RsaMutableBigInteger();
}
int[] newVal = Arrays.copyOfRange(value, (offset + intLen) - blockEnd, (offset + intLen) - blockStart);
return new RsaMutableBigInteger(newVal);
}
private long bitLength()
{
if(intLen == 0)
{
return 0;
}
return (intLen * 32L) - integerNumberOfLeadingZeros(value[offset]);
}
private static void copyAndShift(int[] src, int srcFrom, int srcLen, int[] dst, int dstFrom, int shift)
{
if((src == null) || (dst == null))
{
return;
}
int n2 = 32 - shift;
int c = src[srcFrom];
for(int i = 0; i < (srcLen - 1); i++)
{
int b = c;
c = src[++srcFrom];
dst[dstFrom + i] = (b << shift) | si(c, n2);
}
dst[(dstFrom + srcLen) - 1] = c << shift;
}
private RsaMutableBigInteger divideMagnitude(RsaMutableBigInteger div, RsaMutableBigInteger quotient, boolean needRemainder)
{
if((div == null) || (quotient == null))
{
return null;
}
int shift = integerNumberOfLeadingZeros(div.value[div.offset]);
final int dlen = div.intLen;
int[] divisor;
RsaMutableBigInteger rem;
if(shift > 0)
{
divisor = new int[dlen];
copyAndShift(div.value, div.offset, dlen, divisor, 0, shift);
if(integerNumberOfLeadingZeros(value[offset]) >= shift)
{
int[] remarr = new int[intLen + 1];
copyAndShift(value, offset, intLen, remarr, 1, shift);
rem = new RsaMutableBigInteger(remarr);
rem.intLen = intLen;
rem.offset = 1;
}
else
{
int[] remarr = new int[intLen + 2];
int rFrom = offset;
int c = 0;
int n2 = 32 - shift;
for(int i = 1; i < (intLen + 1); i++, rFrom++)
{
int b = c;
c = value[rFrom];
remarr[i] = (b << shift) | si(c, n2);
}
remarr[intLen + 1] = c << shift;
rem = new RsaMutableBigInteger(remarr);
rem.intLen = intLen + 1;
rem.offset = 1;
}
}
else
{
divisor = Arrays.copyOfRange(div.value, div.offset, div.offset + div.intLen);
rem = new RsaMutableBigInteger(new int[intLen + 1]);
System.arraycopy(value, offset, rem.value, 1, intLen);
rem.intLen = intLen;
rem.offset = 1;
}
int nlen = rem.intLen;
final int limit = (nlen - dlen) + 1;
if(quotient.value.length < limit)
{
quotient.value = new int[limit];
quotient.offset = 0;
}
quotient.intLen = limit;
int[] q = quotient.value;
if(rem.intLen == nlen)
{
rem.offset = 0;
rem.value[0] = 0;
rem.intLen++;
}
int dh = divisor[0];
long dhLong = dh & LONG_MASK;
int dl = divisor[1];
for(int j = 0; j < (limit - 1); j++)
{
int qhat = 0;
int qrem = 0;
boolean skipCorrection = false;
int nh = rem.value[j + rem.offset];
int nh2 = nh + 0x80000000;
int nm = rem.value[j + 1 + rem.offset];
if(nh == dh)
{
qhat = ~0;
qrem = nh + nm;
skipCorrection = (qrem + 0x80000000) < nh2;
}
else
{
long nChunk = (((long) nh) << 32) | (nm & LONG_MASK);
if(nChunk >= 0)
{
qhat = (int) (nChunk / dhLong);
qrem = (int) (nChunk - (qhat * dhLong));
}
else
{
long tmp = divWord(nChunk, dh);
qhat = (int) (tmp & LONG_MASK);
qrem = (int) sl(tmp, 32);
}
}
if(qhat == 0)
{
continue;
}
if(!skipCorrection)
{
long nl = rem.value[j + 2 + rem.offset] & LONG_MASK;
long rs = ((qrem & LONG_MASK) << 32) | nl;
long estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK);
if(unsignedLongCompare(estProduct, rs))
{
qhat--;
qrem = (int) ((qrem & LONG_MASK) + dhLong);
if((qrem & LONG_MASK) >= dhLong)
{
estProduct -= (dl & LONG_MASK);
rs = ((qrem & LONG_MASK) << 32) | nl;
if(unsignedLongCompare(estProduct, rs))
{
qhat--;
}
}
}
}
rem.value[j + rem.offset] = 0;
int borrow = mulsub(rem.value, divisor, qhat, dlen, j + rem.offset);
if((borrow + 0x80000000) > nh2)
{
divadd(divisor, rem.value, j + 1 + rem.offset);
qhat--;
}
q[j] = qhat;
}
int qhat = 0;
int qrem = 0;
boolean skipCorrection = false;
int nh = rem.value[(limit - 1) + rem.offset];
int nh2 = nh + 0x80000000;
int nm = rem.value[limit + rem.offset];
if(nh == dh)
{
qhat = ~0;
qrem = nh + nm;
skipCorrection = (qrem + 0x80000000) < nh2;
}
else
{
long nChunk = (((long) nh) << 32) | (nm & LONG_MASK);
if(nChunk >= 0)
{
qhat = (int) (nChunk / dhLong);
qrem = (int) (nChunk - (qhat * dhLong));
}
else
{
long tmp = divWord(nChunk, dh);
qhat = (int) (tmp & LONG_MASK);
qrem = (int) sl(tmp, 32);
}
}
if(qhat != 0)
{
if(!skipCorrection)
{
long nl = rem.value[limit + 1 + rem.offset] & LONG_MASK;
long rs = ((qrem & LONG_MASK) << 32) | nl;
long estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK);
if(unsignedLongCompare(estProduct, rs))
{
qhat--;
qrem = (int) ((qrem & LONG_MASK) + dhLong);
if((qrem & LONG_MASK) >= dhLong)
{
estProduct -= (dl & LONG_MASK);
rs = ((qrem & LONG_MASK) << 32) | nl;
if(unsignedLongCompare(estProduct, rs))
{
qhat--;
}
}
}
}
int borrow;
rem.value[(limit - 1) + rem.offset] = 0;
if(needRemainder)
{
borrow = mulsub(rem.value, divisor, qhat, dlen, (limit - 1) + rem.offset);
}
else
{
borrow = mulsubBorrow(rem.value, divisor, qhat, dlen, (limit - 1) + rem.offset);
}
if((borrow + 0x80000000) > nh2)
{
if(needRemainder)
{
divadd(divisor, rem.value, (limit - 1) + 1 + rem.offset);
}
qhat--;
}
q[(limit - 1)] = qhat;
}
if(needRemainder)
{
if(shift > 0)
{
rem.rightShift(shift);
}
rem.normalize();
}
quotient.normalize();
return needRemainder ? rem : null;
}
private boolean unsignedLongCompare(long one, long two)
{
return (one + Long.MIN_VALUE) > (two + Long.MIN_VALUE);
}
private static long divWord(long n, int d)
{
long dLong = d & LONG_MASK;
long r;
long q;
if(dLong == 1)
{
q = (int) n;
r = 0;
return (r << 32) | (q & LONG_MASK);
}
q = sl(n, 1) / sl(dLong, 1);
r = n - (q * dLong);
while(r < 0)
{
r += dLong;
q--;
}
while(r >= dLong)
{
r -= dLong;
q++;
}
return (r << 32) | (q & LONG_MASK);
}
public RsaMutableBigInteger hybridGCD(RsaMutableBigInteger b)
{
if(b == null)
{
return null;
}
RsaMutableBigInteger a = this;
RsaMutableBigInteger q = new RsaMutableBigInteger();
while(b.intLen != 0)
{
if(Math.abs(a.intLen - b.intLen) < 2)
{
return a.binaryGCD(b);
}
RsaMutableBigInteger r = a.divide(b, q);
if(r == null)
{
return null;
}
a = b;
b = r;
}
return a;
}
private RsaMutableBigInteger binaryGCD(RsaMutableBigInteger v)
{
if(v == null)
{
return null;
}
RsaMutableBigInteger u = this;
RsaMutableBigInteger r = new RsaMutableBigInteger();
int s1 = u.getLowestSetBit();
int s2 = v.getLowestSetBit();
int k = (s1 < s2) ? s1 : s2;
if(k != 0)
{
u.rightShift(k);
v.rightShift(k);
}
boolean uOdd = (k == s1);
RsaMutableBigInteger t = uOdd ? v : u;
int tsign = uOdd ? -1 : 1;
int lb = t.getLowestSetBit();
while(lb >= 0)
{
t.rightShift(lb);
if(tsign > 0)
{
u = t;
}
else
{
v = t;
}
if((u.intLen < 2) && (v.intLen < 2))
{
int x = u.value[u.offset];
int y = v.value[v.offset];
x = binaryGcd(x, y);
r.value[0] = x;
r.intLen = 1;
r.offset = 0;
if(k > 0)
{
r.leftShift(k);
}
return r;
}
tsign = u.difference(v);
if(tsign == 0)
{
break;
}
t = (tsign >= 0) ? u : v;
lb = t.getLowestSetBit();
}
if(k > 0)
{
u.leftShift(k);
}
return u;
}
private static int binaryGcd(int a, int b)
{
if(b == 0)
{
return a;
}
if(a == 0)
{
return b;
}
int aZeros = integerNumberOfTrailingZeros(a);
int bZeros = integerNumberOfTrailingZeros(b);
a = si(a, aZeros);
b = si(b, bZeros);
int t = (aZeros < bZeros ? aZeros : bZeros);
while(a != b)
{
if((a + 0x80000000) > (b + 0x80000000))
{
a -= b;
a = si(a, integerNumberOfTrailingZeros(a));
}
else
{
b -= a;
b = si(b, integerNumberOfTrailingZeros(b));
}
}
return a << t;
}
public RsaMutableBigInteger mutableModInverse(RsaMutableBigInteger p)
{
if(p == null)
{
return null;
}
if(p.isOdd())
{
return modInverse(p);
}
if(isEven())
{
//throw new ArithmeticException("BigInteger not invertible.");
return null;
}
int powersOf2 = p.getLowestSetBit();
RsaMutableBigInteger oddMod = new RsaMutableBigInteger(p);
oddMod.rightShift(powersOf2);
if(oddMod.isOne())
{
return modInverseMP2(powersOf2);
}
RsaMutableBigInteger oddPart = modInverse(oddMod);
if(oddPart == null)
{
return null;
}
RsaMutableBigInteger evenPart = modInverseMP2(powersOf2);
if(evenPart == null)
{
return null;
}
RsaMutableBigInteger y1 = modInverseBP2(oddMod, powersOf2);
if(y1 == null)
{
return null;
}
RsaMutableBigInteger y2 = oddMod.modInverseMP2(powersOf2);
if(y2 == null)
{
return null;
}
RsaMutableBigInteger temp1 = new RsaMutableBigInteger();
RsaMutableBigInteger temp2 = new RsaMutableBigInteger();
RsaMutableBigInteger result = new RsaMutableBigInteger();
oddPart.leftShift(powersOf2);
oddPart.multiply(y1, result);
evenPart.multiply(oddMod, temp1);
temp1.multiply(y2, temp2);
result.add(temp2);
return result.divide(p, temp1);
}
private RsaMutableBigInteger modInverseMP2(int k)
{
if(isEven())
{
//throw new ArithmeticException("Non-invertible. (GCD != 1)");
return null;
}
if(k > 64)
{
return euclidModInverse(k);
}
int t = inverseMod32(value[(offset + intLen) - 1]);
if(k < 33)
{
t = (k == 32 ? t : t & ((1 << k) - 1));
return new RsaMutableBigInteger(t);
}
long pLong = (value[(offset + intLen) - 1] & LONG_MASK);
if(intLen > 1)
{
pLong |= ((long) value[(offset + intLen) - 2] << 32);
}
long tLong = t & LONG_MASK;
tLong = tLong * (2 - (pLong * tLong));
tLong = (k == 64 ? tLong : tLong & ((1L << k) - 1));
RsaMutableBigInteger result = new RsaMutableBigInteger(new int[2]);
result.value[0] = (int) sl(tLong, 32);
result.value[1] = (int) tLong;
result.intLen = 2;
result.normalize();
return result;
}
public static int inverseMod32(int val)
{
int t = val;
t *= 2 - (val * t);
t *= 2 - (val * t);
t *= 2 - (val * t);
t *= 2 - (val * t);
return t;
}
private static RsaMutableBigInteger modInverseBP2(RsaMutableBigInteger mod, int k)
{
if(mod == null)
{
return null;
}
return fixup(new RsaMutableBigInteger(1), new RsaMutableBigInteger(mod), k);
}
private RsaMutableBigInteger modInverse(RsaMutableBigInteger mod)
{
if(mod == null)
{
return null;
}
RsaMutableBigInteger p = new RsaMutableBigInteger(mod);
RsaMutableBigInteger f = new RsaMutableBigInteger(this);
RsaMutableBigInteger g = new RsaMutableBigInteger(p);
RsaSignedMutableBigInteger c = new RsaSignedMutableBigInteger(1);
RsaSignedMutableBigInteger d = new RsaSignedMutableBigInteger();
RsaMutableBigInteger temp = null;
RsaSignedMutableBigInteger sTemp = null;
int k = 0;
if(f.isEven())
{
int trailingZeros = f.getLowestSetBit();
f.rightShift(trailingZeros);
d.leftShift(trailingZeros);
k = trailingZeros;
}
while(!f.isOne())
{
if(f.isZero())
{
//throw new ArithmeticException("BigInteger not invertible.");
return null;
}
if(f.compare(g) < 0)
{
temp = f;
f = g;
g = temp;
sTemp = d;
d = c;
c = sTemp;
}
if(((f.value[(f.offset + f.intLen) - 1] ^ g.value[(g.offset + g.intLen) - 1]) & 3) == 0)
{
f.subtract(g);
c.signedSubtract(d);
}
else
{
f.add(g);
c.signedAdd(d);
}
int trailingZeros = f.getLowestSetBit();
f.rightShift(trailingZeros);
d.leftShift(trailingZeros);
k += trailingZeros;
}
while(c.sign < 0)
{
c.signedAdd(p);
}
return fixup(c, p, k);
}
private static RsaMutableBigInteger fixup(RsaMutableBigInteger c, RsaMutableBigInteger p, int k)
{
if((c == null) || (p == null))
{
return null;
}
RsaMutableBigInteger temp = new RsaMutableBigInteger();
int r = -inverseMod32(p.value[(p.offset + p.intLen) - 1]);
for(int i = 0, numWords = k >> 5; i < numWords; i++)
{
int v = r * c.value[(c.offset + c.intLen) - 1];
p.mul(v, temp);
c.add(temp);
c.intLen--;
}
int numBits = k & 0x1f;
if(numBits != 0)
{
int v = r * c.value[(c.offset + c.intLen) - 1];
v &= ((1 << numBits) - 1);
p.mul(v, temp);
c.add(temp);
c.rightShift(numBits);
}
while(c.compare(p) >= 0)
{
c.subtract(p);
}
return c;
}
private RsaMutableBigInteger euclidModInverse(int k)
{
RsaMutableBigInteger b = new RsaMutableBigInteger(1);
b.leftShift(k);
RsaMutableBigInteger mod = new RsaMutableBigInteger(b);
RsaMutableBigInteger a = new RsaMutableBigInteger(this);
RsaMutableBigInteger q = new RsaMutableBigInteger();
RsaMutableBigInteger r = b.divide(a, q);
RsaMutableBigInteger swapper = b;
b = r;
r = swapper;
RsaMutableBigInteger t1 = new RsaMutableBigInteger(q);
RsaMutableBigInteger t0 = new RsaMutableBigInteger(1);
RsaMutableBigInteger temp = new RsaMutableBigInteger();
while(!b.isOne())
{
r = a.divide(b, q);
if(r == null)
{
return null;
}
if(r.intLen == 0)
{
//throw new ArithmeticException("BigInteger not invertible.");
return null;
}
swapper = r;
a = swapper;
if(q.intLen == 1)
{
t1.mul(q.value[q.offset], temp);
}
else
{
q.multiply(t1, temp);
}
swapper = q;
q = temp;
temp = swapper;
t0.add(q);
if(a.isOne())
{
return t0;
}
r = b.divide(a, q);
if(r == null)
{
return null;
}
if(r.intLen == 0)
{
//throw new ArithmeticException("BigInteger not invertible.");
return null;
}
swapper = b;
b = r;
if(q.intLen == 1)
{
t0.mul(q.value[q.offset], temp);
}
else
{
q.multiply(t0, temp);
}
swapper = q;
q = temp;
temp = swapper;
t1.add(q);
}
mod.subtract(t1);
return mod;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy