Commit 17e39e5c by Raif S. Naffah Committed by Tom Tromey

BigInteger.java: Updated notice to include years 2002 and 3.

2003-02-10  Raif S. Naffah <raif@fl.net.au>

	* java/math/BigInteger.java:
	Updated notice to include years 2002 and 3.
	Added 2 private (int) arrays with values from the HAC (Handbook of
	Applied Cryptography -A. Menezes & al): k[] that contains bit lengths
	and t[] that contains nbr. of tests --used in isProbablePrime().

	* java/math/BigInteger.java (make(long)): Merged into valueOf(long).

	* java/math/BigInteger.java (make(int[],int), add(int,int),
	add(BI,BI,int), times(BI,int), divide(long,long,BI,BI,int), gcd(BI),
	isProbablePrime(int), shift(BI,int), valueOf(String,int), neg(BI),
	bitOp(int,BI,BI), and(BI,int)): Use valueOf(long) instead of
	make(long).

	* java/math/BigInteger.java (euclidInv): Reduce number of work vars
	(euclidInv(int,int,int)): Now returns an array of 2 ints instead of 3.
	(euclidInv(BI,BI,BI)): Used to return an array of 2 BIs; now accepts 6
	BIs and returns void.
	(modInverse(BI)): Use new signatures of euclidInv().

	* java/math/BigInteger.java (isProbablePrime(int)): Use divide() with
	static small primes instead of remainder().
	Use pre-computed max nbr of trials based on bitlength of BI to test.
	Use pre-computed small primes for the trial tests instead of random
	numbers.

	* java/math/BigInteger.java (isOdd, isMinusOne, pow): Removed.
	not used.

	* java/math/BigInteger.java (format(int,StringBuffer)): Removed
	invoacation of MPN.chars_per_word().  not used.

	* java/math/BigInteger.java (gcd(int,int)): Declared 'tmp' once as
	local var and used where needed.

	* java/math/BigInteger.java (modPow(BI,BI)): Fixed spelling.
	Combined declaration with initialisation of locals.
	Removed unused var.

	* java/math/BigInteger.java: Style changes
	(pow(int)): Removed 'else' keyword.
	(toString(int)): idem.
	(doubleValue()): idem.
	(bitLength()): idem.
	(equals(Object)): Use static methods name in same class w/o prepending
	class name.
	(doubleValue()): idem.
	(setNegative(BI)): idem.
	(negate()): idem.
	(and(BI,int)): idem.
	(and(BI)): idem.
	(gcd(BI)): idem.
	(byteArrayToIntArray()): Removed casting to (int). this is
	std. behaviour.
	(canonicalize()): idem.
	(alloc(int)): Always instantiate a new BI.

From-SVN: r62656
parent 2a4e6df4
2003-02-10 Raif S. Naffah <raif@fl.net.au>
* java/math/BigInteger.java:
Updated notice to include years 2002 and 3.
Added 2 private (int) arrays with values from the HAC (Handbook of
Applied Cryptography -A. Menezes & al): k[] that contains bit lengths
and t[] that contains nbr. of tests --used in isProbablePrime().
* java/math/BigInteger.java (make(long)): Merged into valueOf(long).
* java/math/BigInteger.java (make(int[],int), add(int,int),
add(BI,BI,int), times(BI,int), divide(long,long,BI,BI,int), gcd(BI),
isProbablePrime(int), shift(BI,int), valueOf(String,int), neg(BI),
bitOp(int,BI,BI), and(BI,int)): Use valueOf(long) instead of
make(long).
* java/math/BigInteger.java (euclidInv): Reduce number of work vars
(euclidInv(int,int,int)): Now returns an array of 2 ints instead of 3.
(euclidInv(BI,BI,BI)): Used to return an array of 2 BIs; now accepts 6
BIs and returns void.
(modInverse(BI)): Use new signatures of euclidInv().
* java/math/BigInteger.java (isProbablePrime(int)): Use divide() with
static small primes instead of remainder().
Use pre-computed max nbr of trials based on bitlength of BI to test.
Use pre-computed small primes for the trial tests instead of random
numbers.
* java/math/BigInteger.java (isOdd, isMinusOne, pow): Removed.
not used.
* java/math/BigInteger.java (format(int,StringBuffer)): Removed
invoacation of MPN.chars_per_word(). not used.
* java/math/BigInteger.java (gcd(int,int)): Declared 'tmp' once as
local var and used where needed.
* java/math/BigInteger.java (modPow(BI,BI)): Fixed spelling.
Combined declaration with initialisation of locals.
Removed unused var.
* java/math/BigInteger.java: Style changes
(pow(int)): Removed 'else' keyword.
(toString(int)): idem.
(doubleValue()): idem.
(bitLength()): idem.
(equals(Object)): Use static methods name in same class w/o prepending
class name.
(doubleValue()): idem.
(setNegative(BI)): idem.
(negate()): idem.
(and(BI,int)): idem.
(and(BI)): idem.
(gcd(BI)): idem.
(byteArrayToIntArray()): Removed casting to (int). this is
std. behaviour.
(canonicalize()): idem.
(alloc(int)): Always instantiate a new BI.
2003-02-10 Tom Tromey <tromey@redhat.com> 2003-02-10 Tom Tromey <tromey@redhat.com>
* java/sql/Timestamp.java (compareTo(Object)): New method. * java/sql/Timestamp.java (compareTo(Object)): New method.
......
/* java.math.BigInteger -- Arbitary precision integers /* java.math.BigInteger -- Arbitary precision integers
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -110,6 +110,12 @@ public class BigInteger extends Number implements Comparable ...@@ -110,6 +110,12 @@ public class BigInteger extends Number implements Comparable
109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181,
191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251 }; 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251 };
/** HAC (Handbook of Applied Cryptography), Alfred Menezes & al. Table 4.4. */
private static final int[] k =
{100,150,200,250,300,350,400,500,600,800,1250, Integer.MAX_VALUE};
private static final int[] t =
{ 27, 18, 15, 12, 9, 8, 7, 6, 5, 4, 3, 2};
private BigInteger() private BigInteger()
{ {
} }
...@@ -218,38 +224,29 @@ public class BigInteger extends Number implements Comparable ...@@ -218,38 +224,29 @@ public class BigInteger extends Number implements Comparable
} }
/** Return a (possibly-shared) BigInteger with a given long value. */ /** Return a (possibly-shared) BigInteger with a given long value. */
private static BigInteger make(long value) public static BigInteger valueOf(long val)
{ {
if (value >= minFixNum && value <= maxFixNum) if (val >= minFixNum && val <= maxFixNum)
return smallFixNums[(int)value - minFixNum]; return smallFixNums[(int) val - minFixNum];
int i = (int) value; int i = (int) val;
if ((long)i == value) if ((long) i == val)
return new BigInteger(i); return new BigInteger(i);
BigInteger result = alloc(2); BigInteger result = alloc(2);
result.ival = 2; result.ival = 2;
result.words[0] = i; result.words[0] = i;
result.words[1] = (int) (value >> 32); result.words[1] = (int)(val >> 32);
return result; return result;
} }
// FIXME: Could simply rename 'make' method above as valueOf while
// changing all instances of 'make'. Don't do this until this class
// is done as the Kawa class this is based on has 'make' methods
// with other parameters; wait to see if they are used in BigInteger.
public static BigInteger valueOf(long val)
{
return make(val);
}
/** Make a canonicalized BigInteger from an array of words. /** Make a canonicalized BigInteger from an array of words.
* The array may be reused (without copying). */ * The array may be reused (without copying). */
private static BigInteger make(int[] words, int len) private static BigInteger make(int[] words, int len)
{ {
if (words == null) if (words == null)
return make(len); return valueOf(len);
len = BigInteger.wordsNeeded(words, len); len = BigInteger.wordsNeeded(words, len);
if (len <= 1) if (len <= 1)
return len == 0 ? ZERO : make(words[0]); return len == 0 ? ZERO : valueOf(words[0]);
BigInteger num = new BigInteger(); BigInteger num = new BigInteger();
num.words = words; num.words = words;
num.ival = len; num.ival = len;
...@@ -267,15 +264,15 @@ public class BigInteger extends Number implements Comparable ...@@ -267,15 +264,15 @@ public class BigInteger extends Number implements Comparable
int bptr = 0; int bptr = 0;
int word = sign; int word = sign;
for (int i = bytes.length % 4; i > 0; --i, bptr++) for (int i = bytes.length % 4; i > 0; --i, bptr++)
word = (word << 8) | (((int) bytes[bptr]) & 0xff); word = (word << 8) | (bytes[bptr] & 0xff);
words[--nwords] = word; words[--nwords] = word;
// Elements remaining in byte[] are a multiple of 4. // Elements remaining in byte[] are a multiple of 4.
while (nwords > 0) while (nwords > 0)
words[--nwords] = bytes[bptr++] << 24 | words[--nwords] = bytes[bptr++] << 24 |
(((int) bytes[bptr++]) & 0xff) << 16 | (bytes[bptr++] & 0xff) << 16 |
(((int) bytes[bptr++]) & 0xff) << 8 | (bytes[bptr++] & 0xff) << 8 |
(((int) bytes[bptr++]) & 0xff); (bytes[bptr++] & 0xff);
return words; return words;
} }
...@@ -284,9 +281,8 @@ public class BigInteger extends Number implements Comparable ...@@ -284,9 +281,8 @@ public class BigInteger extends Number implements Comparable
*/ */
private static BigInteger alloc(int nwords) private static BigInteger alloc(int nwords)
{ {
if (nwords <= 1)
return new BigInteger();
BigInteger result = new BigInteger(); BigInteger result = new BigInteger();
if (nwords > 1)
result.words = new int[nwords]; result.words = new int[nwords];
return result; return result;
} }
...@@ -376,12 +372,6 @@ public class BigInteger extends Number implements Comparable ...@@ -376,12 +372,6 @@ public class BigInteger extends Number implements Comparable
return compareTo(this, val) > 0 ? this : val; return compareTo(this, val) > 0 ? this : val;
} }
private final boolean isOdd()
{
int low = words == null ? ival : words[0];
return (low & 1) != 0;
}
private final boolean isZero() private final boolean isZero()
{ {
return words == null && ival == 0; return words == null && ival == 0;
...@@ -392,11 +382,6 @@ public class BigInteger extends Number implements Comparable ...@@ -392,11 +382,6 @@ public class BigInteger extends Number implements Comparable
return words == null && ival == 1; return words == null && ival == 1;
} }
private final boolean isMinusOne()
{
return words == null && ival == -1;
}
/** Calculate how many words are significant in words[0:len-1]. /** Calculate how many words are significant in words[0:len-1].
* Returns the least value x such that x>0 && words[0:x-1]==words[0:len-1], * Returns the least value x such that x>0 && words[0:x-1]==words[0:len-1],
* when words is viewed as a 2's complement integer. * when words is viewed as a 2's complement integer.
...@@ -433,14 +418,14 @@ public class BigInteger extends Number implements Comparable ...@@ -433,14 +418,14 @@ public class BigInteger extends Number implements Comparable
words = null; words = null;
} }
if (words == null && ival >= minFixNum && ival <= maxFixNum) if (words == null && ival >= minFixNum && ival <= maxFixNum)
return smallFixNums[(int) ival - minFixNum]; return smallFixNums[ival - minFixNum];
return this; return this;
} }
/** Add two ints, yielding a BigInteger. */ /** Add two ints, yielding a BigInteger. */
private static final BigInteger add(int x, int y) private static final BigInteger add(int x, int y)
{ {
return BigInteger.make((long) x + (long) y); return valueOf((long) x + (long) y);
} }
/** Add a BigInteger and an int, yielding a new BigInteger. */ /** Add a BigInteger and an int, yielding a new BigInteger. */
...@@ -526,13 +511,13 @@ public class BigInteger extends Number implements Comparable ...@@ -526,13 +511,13 @@ public class BigInteger extends Number implements Comparable
private static BigInteger add(BigInteger x, BigInteger y, int k) private static BigInteger add(BigInteger x, BigInteger y, int k)
{ {
if (x.words == null && y.words == null) if (x.words == null && y.words == null)
return BigInteger.make((long) k * (long) y.ival + (long) x.ival); return valueOf((long) k * (long) y.ival + (long) x.ival);
if (k != 1) if (k != 1)
{ {
if (k == -1) if (k == -1)
y = BigInteger.neg(y); y = BigInteger.neg(y);
else else
y = BigInteger.times(y, BigInteger.make(k)); y = BigInteger.times(y, valueOf(k));
} }
if (x.words == null) if (x.words == null)
return BigInteger.add(y, x.ival); return BigInteger.add(y, x.ival);
...@@ -580,7 +565,7 @@ public class BigInteger extends Number implements Comparable ...@@ -580,7 +565,7 @@ public class BigInteger extends Number implements Comparable
int[] xwords = x.words; int[] xwords = x.words;
int xlen = x.ival; int xlen = x.ival;
if (xwords == null) if (xwords == null)
return BigInteger.make((long) xlen * (long) y); return valueOf((long) xlen * (long) y);
boolean negative; boolean negative;
BigInteger result = BigInteger.alloc(xlen + 1); BigInteger result = BigInteger.alloc(xlen + 1);
if (xwords[xlen - 1] < 0) if (xwords[xlen - 1] < 0)
...@@ -662,7 +647,7 @@ public class BigInteger extends Number implements Comparable ...@@ -662,7 +647,7 @@ public class BigInteger extends Number implements Comparable
xNegative = true; xNegative = true;
if (x == Long.MIN_VALUE) if (x == Long.MIN_VALUE)
{ {
divide(BigInteger.make(x), BigInteger.make(y), divide(valueOf(x), valueOf(y),
quotient, remainder, rounding_mode); quotient, remainder, rounding_mode);
return; return;
} }
...@@ -684,7 +669,7 @@ public class BigInteger extends Number implements Comparable ...@@ -684,7 +669,7 @@ public class BigInteger extends Number implements Comparable
remainder.set(x); remainder.set(x);
} }
else else
divide(BigInteger.make(x), BigInteger.make(y), divide(valueOf(x), valueOf(y),
quotient, remainder, rounding_mode); quotient, remainder, rounding_mode);
return; return;
} }
...@@ -966,39 +951,6 @@ public class BigInteger extends Number implements Comparable ...@@ -966,39 +951,6 @@ public class BigInteger extends Number implements Comparable
return rem.canonicalize(); return rem.canonicalize();
} }
/** Calculate power for BigInteger exponents.
* @param y exponent assumed to be non-negative. */
private BigInteger pow(BigInteger y)
{
if (isOne())
return this;
if (isMinusOne())
return y.isOdd () ? this : ONE;
if (y.words == null && y.ival >= 0)
return pow(y.ival);
// Assume exponent is non-negative.
if (isZero())
return this;
// Implemented by repeated squaring and multiplication.
BigInteger pow2 = this;
BigInteger r = null;
for (;;) // for (i = 0; ; i++)
{
// pow2 == x**(2**i)
// prod = x**(sum(j=0..i-1, (y>>j)&1))
if (y.isOdd())
r = r == null ? pow2 : times(r, pow2); // r *= pow2
y = BigInteger.shift(y, -1);
if (y.isZero())
break;
// pow2 *= pow2;
pow2 = times(pow2, pow2);
}
return r == null ? ONE : r;
}
/** Calculate the integral power of a BigInteger. /** Calculate the integral power of a BigInteger.
* @param exponent the exponent (must be non-negative) * @param exponent the exponent (must be non-negative)
*/ */
...@@ -1008,7 +960,6 @@ public class BigInteger extends Number implements Comparable ...@@ -1008,7 +960,6 @@ public class BigInteger extends Number implements Comparable
{ {
if (exponent == 0) if (exponent == 0)
return ONE; return ONE;
else
throw new ArithmeticException("negative exponent"); throw new ArithmeticException("negative exponent");
} }
if (isZero()) if (isZero())
...@@ -1051,51 +1002,36 @@ public class BigInteger extends Number implements Comparable ...@@ -1051,51 +1002,36 @@ public class BigInteger extends Number implements Comparable
private static final int[] euclidInv(int a, int b, int prevDiv) private static final int[] euclidInv(int a, int b, int prevDiv)
{ {
// Storage for return values, plus one slot for a temp int (see below).
int[] xy;
if (b == 0) if (b == 0)
throw new ArithmeticException("not invertible"); throw new ArithmeticException("not invertible");
else if (b == 1)
{ if (b == 1)
// Success: values are indeed invertible! // Success: values are indeed invertible!
// Bottom of the recursion reached; start unwinding. // Bottom of the recursion reached; start unwinding.
xy = new int[3]; return new int[] { -prevDiv, 1 };
xy[0] = -prevDiv;
xy[1] = 1;
return xy;
}
xy = euclidInv(b, a % b, a / b); // Recursion happens here.
// xy[2] is just temp storage for intermediate results in the following int[] xy = euclidInv(b, a % b, a / b); // Recursion happens here.
// calculation. This saves us a bit of space over having an int a = xy[0]; // use our local copy of 'a' as a work var
// allocated at every level of this recursive method. xy[0] = a * -prevDiv + xy[1];
xy[2] = xy[0]; xy[1] = a;
xy[0] = xy[2] * -prevDiv + xy[1];
xy[1] = xy[2];
return xy; return xy;
} }
private static final BigInteger[] private static final void euclidInv(BigInteger a, BigInteger b,
euclidInv(BigInteger a, BigInteger b, BigInteger prevDiv) BigInteger prevDiv, BigInteger xy0,
BigInteger xy1, BigInteger xy2)
{ {
// FIXME: This method could be more efficient memory-wise and should be
// modified as such since it is recursive.
// Storage for return values, plus one slot for a temp int (see below).
BigInteger[] xy;
if (b.isZero()) if (b.isZero())
throw new ArithmeticException("not invertible"); throw new ArithmeticException("not invertible");
else if (b.isOne())
if (b.isOne())
{ {
// Success: values are indeed invertible! // Success: values are indeed invertible!
// Bottom of the recursion reached; start unwinding. // Bottom of the recursion reached; start unwinding.
xy = new BigInteger[3]; // WARNING: xy1 is, and xy0 may be, a shared BI!
xy[0] = neg(prevDiv); xy0 = neg(prevDiv);
xy[1] = ONE; xy1 = ONE;
return xy; return;
} }
// Recursion happens in the following conditional! // Recursion happens in the following conditional!
...@@ -1104,9 +1040,8 @@ public class BigInteger extends Number implements Comparable ...@@ -1104,9 +1040,8 @@ public class BigInteger extends Number implements Comparable
if (a.words == null) if (a.words == null)
{ {
int[] xyInt = euclidInv(b.ival, a.ival % b.ival, a.ival / b.ival); int[] xyInt = euclidInv(b.ival, a.ival % b.ival, a.ival / b.ival);
xy = new BigInteger[3]; xy0 = new BigInteger(xyInt[0]); // non-shared BI
xy[0] = new BigInteger(xyInt[0]); xy1 = new BigInteger(xyInt[1]); // non-shared BI
xy[1] = new BigInteger(xyInt[1]);
} }
else else
{ {
...@@ -1116,16 +1051,15 @@ public class BigInteger extends Number implements Comparable ...@@ -1116,16 +1051,15 @@ public class BigInteger extends Number implements Comparable
// quot and rem may not be in canonical form. ensure // quot and rem may not be in canonical form. ensure
rem.canonicalize(); rem.canonicalize();
quot.canonicalize(); quot.canonicalize();
xy = euclidInv(b, rem, quot); euclidInv(b, rem, quot, xy0, xy1, xy2);
} }
// xy[2] is just temp storage for intermediate results in the following // xy2 is just temp storage for intermediate results in the following
// calculation. This saves us a bit of space over having a BigInteger // calculation. This saves us a bit of space over having a BigInteger
// allocated at every level of this recursive method. // allocated at every level of this recursive method.
xy[2] = xy[0]; xy2 = xy0;
xy[0] = add(xy[1], times(xy[2], prevDiv), -1); xy0 = add(xy1, times(xy2, prevDiv), -1);
xy[1] = xy[2]; xy1 = xy2;
return xy;
} }
public BigInteger modInverse(BigInteger y) public BigInteger modInverse(BigInteger y)
...@@ -1136,7 +1070,7 @@ public class BigInteger extends Number implements Comparable ...@@ -1136,7 +1070,7 @@ public class BigInteger extends Number implements Comparable
// Degenerate cases. // Degenerate cases.
if (y.isOne()) if (y.isOne())
return ZERO; return ZERO;
else if (isOne()) if (isOne())
return ONE; return ONE;
// Use Euclid's algorithm as in gcd() but do this recursively // Use Euclid's algorithm as in gcd() but do this recursively
...@@ -1144,8 +1078,6 @@ public class BigInteger extends Number implements Comparable ...@@ -1144,8 +1078,6 @@ public class BigInteger extends Number implements Comparable
// unwind from the recursion. // unwind from the recursion.
// Used http://www.math.nmsu.edu/~crypto/EuclideanAlgo.html as reference. // Used http://www.math.nmsu.edu/~crypto/EuclideanAlgo.html as reference.
BigInteger result = new BigInteger(); BigInteger result = new BigInteger();
int xval = ival;
int yval = y.ival;
boolean swapped = false; boolean swapped = false;
if (y.words == null) if (y.words == null)
...@@ -1156,8 +1088,8 @@ public class BigInteger extends Number implements Comparable ...@@ -1156,8 +1088,8 @@ public class BigInteger extends Number implements Comparable
// math. Note that BigInteger.mod() must be used even if this is // math. Note that BigInteger.mod() must be used even if this is
// already an int as the % operator would provide a negative result if // already an int as the % operator would provide a negative result if
// this is negative, BigInteger.mod() never returns negative values. // this is negative, BigInteger.mod() never returns negative values.
if (words != null || isNegative()) int xval = (words != null || isNegative()) ? mod(y).ival : ival;
xval = mod(y).ival; int yval = y.ival;
// Swap values so x > y. // Swap values so x > y.
if (yval > xval) if (yval > xval)
...@@ -1178,16 +1110,13 @@ public class BigInteger extends Number implements Comparable ...@@ -1178,16 +1110,13 @@ public class BigInteger extends Number implements Comparable
} }
else else
{ {
BigInteger x = this;
// As above, force this to be a positive value via modulo math. // As above, force this to be a positive value via modulo math.
if (isNegative()) BigInteger x = isNegative() ? this.mod(y) : this;
x = mod(y);
// Swap values so x > y. // Swap values so x > y.
if (x.compareTo(y) < 0) if (x.compareTo(y) < 0)
{ {
BigInteger tmp = x; x = y; y = tmp; result = x; x = y; y = result; // use 'result' as a work var
swapped = true; swapped = true;
} }
// As above (for ints), result will be in the 2nd element unless // As above (for ints), result will be in the 2nd element unless
...@@ -1198,7 +1127,10 @@ public class BigInteger extends Number implements Comparable ...@@ -1198,7 +1127,10 @@ public class BigInteger extends Number implements Comparable
// quot and rem may not be in canonical form. ensure // quot and rem may not be in canonical form. ensure
rem.canonicalize(); rem.canonicalize();
quot.canonicalize(); quot.canonicalize();
result = euclidInv(y, rem, quot)[swapped ? 0 : 1]; BigInteger xy0 = new BigInteger();
BigInteger xy1 = new BigInteger();
euclidInv(y, rem, quot, xy0, xy1, result);
result = swapped ? xy0 : xy1;
// Result can't be negative, so make it positive by adding the // Result can't be negative, so make it positive by adding the
// original modulus, y (which is now x if they were swapped). // original modulus, y (which is now x if they were swapped).
...@@ -1222,16 +1154,13 @@ public class BigInteger extends Number implements Comparable ...@@ -1222,16 +1154,13 @@ public class BigInteger extends Number implements Comparable
// To do this naively by first raising this to the power of exponent // To do this naively by first raising this to the power of exponent
// and then performing modulo m would be extremely expensive, especially // and then performing modulo m would be extremely expensive, especially
// for very large numbers. The solution is found in Number Theory // for very large numbers. The solution is found in Number Theory
// where a combination of partial powers and modulos can be done easily. // where a combination of partial powers and moduli can be done easily.
// //
// We'll use the algorithm for Additive Chaining which can be found on // We'll use the algorithm for Additive Chaining which can be found on
// p. 244 of "Applied Cryptography, Second Edition" by Bruce Schneier. // p. 244 of "Applied Cryptography, Second Edition" by Bruce Schneier.
BigInteger s, t, u; BigInteger s = ONE;
int i; BigInteger t = this;
BigInteger u = exponent;
s = ONE;
t = this;
u = exponent;
while (!u.isZero()) while (!u.isZero())
{ {
...@@ -1248,24 +1177,22 @@ public class BigInteger extends Number implements Comparable ...@@ -1248,24 +1177,22 @@ public class BigInteger extends Number implements Comparable
private static final int gcd(int a, int b) private static final int gcd(int a, int b)
{ {
// Euclid's algorithm, copied from libg++. // Euclid's algorithm, copied from libg++.
int tmp;
if (b > a) if (b > a)
{ {
int tmp = a; a = b; b = tmp; tmp = a; a = b; b = tmp;
} }
for(;;) for(;;)
{ {
if (b == 0) if (b == 0)
return a; return a;
else if (b == 1) if (b == 1)
return b; return b;
else tmp = b;
{
int tmp = b;
b = a % b; b = a % b;
a = tmp; a = tmp;
} }
} }
}
public BigInteger gcd(BigInteger y) public BigInteger gcd(BigInteger y)
{ {
...@@ -1274,7 +1201,7 @@ public class BigInteger extends Number implements Comparable ...@@ -1274,7 +1201,7 @@ public class BigInteger extends Number implements Comparable
if (words == null) if (words == null)
{ {
if (xval == 0) if (xval == 0)
return BigInteger.abs(y); return abs(y);
if (y.words == null if (y.words == null
&& xval != Integer.MIN_VALUE && yval != Integer.MIN_VALUE) && xval != Integer.MIN_VALUE && yval != Integer.MIN_VALUE)
{ {
...@@ -1282,14 +1209,14 @@ public class BigInteger extends Number implements Comparable ...@@ -1282,14 +1209,14 @@ public class BigInteger extends Number implements Comparable
xval = -xval; xval = -xval;
if (yval < 0) if (yval < 0)
yval = -yval; yval = -yval;
return BigInteger.make(BigInteger.gcd(xval, yval)); return valueOf(gcd(xval, yval));
} }
xval = 1; xval = 1;
} }
if (y.words == null) if (y.words == null)
{ {
if (yval == 0) if (yval == 0)
return BigInteger.abs(this); return abs(this);
yval = 1; yval = 1;
} }
int len = (xval > yval ? xval : yval) + 1; int len = (xval > yval ? xval : yval) + 1;
...@@ -1304,8 +1231,24 @@ public class BigInteger extends Number implements Comparable ...@@ -1304,8 +1231,24 @@ public class BigInteger extends Number implements Comparable
return result.canonicalize(); return result.canonicalize();
} }
/**
* <p>Returns <code>true</code> if this BigInteger is probably prime,
* <code>false</code> if it's definitely composite. If <code>certainty</code>
* is <code><= 0</code>, <code>true</code> is returned.</p>
*
* @param certainty a measure of the uncertainty that the caller is willing
* to tolerate: if the call returns <code>true</code> the probability that
* this BigInteger is prime exceeds <code>(1 - 1/2<sup>certainty</sup>)</code>.
* The execution time of this method is proportional to the value of this
* parameter.
* @return <code>true</code> if this BigInteger is probably prime,
* <code>false</code> if it's definitely composite.
*/
public boolean isProbablePrime(int certainty) public boolean isProbablePrime(int certainty)
{ {
if (certainty < 1)
return true;
/** We'll use the Rabin-Miller algorithm for doing a probabilistic /** We'll use the Rabin-Miller algorithm for doing a probabilistic
* primality test. It is fast, easy and has faster decreasing odds of a * primality test. It is fast, easy and has faster decreasing odds of a
* composite passing than with other tests. This means that this * composite passing than with other tests. This means that this
...@@ -1317,19 +1260,20 @@ public class BigInteger extends Number implements Comparable ...@@ -1317,19 +1260,20 @@ public class BigInteger extends Number implements Comparable
* Cryptography, Second Edition" by Bruce Schneier. * Cryptography, Second Edition" by Bruce Schneier.
*/ */
// First rule out small prime factors and assure the number is odd. // First rule out small prime factors
for (int i = 0; i < primes.length; i++) BigInteger rem = new BigInteger();
int i;
for (i = 0; i < primes.length; i++)
{ {
if (words == null && ival == primes[i]) if (words == null && ival == primes[i])
return true; return true;
if (remainder(make(primes[i])).isZero())
divide(this, smallFixNums[primes[i] - minFixNum], null, rem, TRUNCATE);
if (rem.canonicalize().isZero())
return false; return false;
} }
// Now perform the Rabin-Miller test. // Now perform the Rabin-Miller test.
// NB: I know that this can be simplified programatically, but
// I have tried to keep it as close as possible to the algorithm
// as written in the Schneier book for reference purposes.
// Set b to the number of times 2 evenly divides (this - 1). // Set b to the number of times 2 evenly divides (this - 1).
// I.e. 2^b is the largest power of 2 that divides (this - 1). // I.e. 2^b is the largest power of 2 that divides (this - 1).
...@@ -1337,22 +1281,31 @@ public class BigInteger extends Number implements Comparable ...@@ -1337,22 +1281,31 @@ public class BigInteger extends Number implements Comparable
int b = pMinus1.getLowestSetBit(); int b = pMinus1.getLowestSetBit();
// Set m such that this = 1 + 2^b * m. // Set m such that this = 1 + 2^b * m.
BigInteger m = pMinus1.divide(make(2L << b - 1)); BigInteger m = pMinus1.divide(valueOf(2L << b - 1));
Random rand = new Random(); // The HAC (Handbook of Applied Cryptography), Alfred Menezes & al. Note
while (certainty-- > 0) // 4.49 (controlling the error probability) gives the number of trials
{ // for an error probability of 1/2**80, given the number of bits in the
// Pick a random number greater than 1 and less than this. // number to test. we shall use these numbers as is if/when 'certainty'
// The algorithm says to pick a small number to make the calculations // is less or equal to 80, and twice as much if it's greater.
// go faster, but it doesn't say how small; we'll use 2 to 1024. int bits = this.bitLength();
int a = rand.nextInt(); for (i = 0; i < k.length; i++)
a = (a < 0 ? -a : a) % 1023 + 2; if (bits <= k[i])
break;
BigInteger z = make(a).modPow(m, this); int trials = t[i];
if (certainty > 80)
trials *= 2;
BigInteger z;
for (int t = 0; t < trials; t++)
{
// The HAC (Handbook of Applied Cryptography), Alfred Menezes & al.
// Remark 4.28 states: "...A strategy that is sometimes employed
// is to fix the bases a to be the first few primes instead of
// choosing them at random.
z = smallFixNums[primes[t] - minFixNum].modPow(m, this);
if (z.isOne() || z.equals(pMinus1)) if (z.isOne() || z.equals(pMinus1))
continue; // Passes the test; may be prime. continue; // Passes the test; may be prime.
int i;
for (i = 0; i < b; ) for (i = 0; i < b; )
{ {
if (z.isOne()) if (z.isOne())
...@@ -1361,7 +1314,7 @@ public class BigInteger extends Number implements Comparable ...@@ -1361,7 +1314,7 @@ public class BigInteger extends Number implements Comparable
if (z.equals(pMinus1)) if (z.equals(pMinus1))
break; // Passes the test; may be prime. break; // Passes the test; may be prime.
z = z.modPow(make(2), this); z = z.modPow(valueOf(2), this);
} }
if (i == b && !z.equals(pMinus1)) if (i == b && !z.equals(pMinus1))
...@@ -1462,9 +1415,9 @@ public class BigInteger extends Number implements Comparable ...@@ -1462,9 +1415,9 @@ public class BigInteger extends Number implements Comparable
if (x.words == null) if (x.words == null)
{ {
if (count <= 0) if (count <= 0)
return make(count > -32 ? x.ival >> (-count) : x.ival < 0 ? -1 : 0); return valueOf(count > -32 ? x.ival >> (-count) : x.ival < 0 ? -1 : 0);
if (count < 32) if (count < 32)
return make((long) x.ival << count); return valueOf((long) x.ival << count);
} }
if (count == 0) if (count == 0)
return x; return x;
...@@ -1502,7 +1455,6 @@ public class BigInteger extends Number implements Comparable ...@@ -1502,7 +1455,6 @@ public class BigInteger extends Number implements Comparable
work = words; work = words;
int len = ival; int len = ival;
int buf_size = len * (MPN.chars_per_word(radix) + 1);
if (radix == 16) if (radix == 16)
{ {
if (neg) if (neg)
...@@ -1555,7 +1507,7 @@ public class BigInteger extends Number implements Comparable ...@@ -1555,7 +1507,7 @@ public class BigInteger extends Number implements Comparable
{ {
if (words == null) if (words == null)
return Integer.toString(ival, radix); return Integer.toString(ival, radix);
else if (ival <= 2) if (ival <= 2)
return Long.toString(longValue(), radix); return Long.toString(longValue(), radix);
int buf_size = ival * (MPN.chars_per_word(radix) + 1); int buf_size = ival * (MPN.chars_per_word(radix) + 1);
StringBuffer buffer = new StringBuffer(buf_size); StringBuffer buffer = new StringBuffer(buf_size);
...@@ -1605,7 +1557,7 @@ public class BigInteger extends Number implements Comparable ...@@ -1605,7 +1557,7 @@ public class BigInteger extends Number implements Comparable
{ {
if (obj == null || ! (obj instanceof BigInteger)) if (obj == null || ! (obj instanceof BigInteger))
return false; return false;
return BigInteger.equals(this, (BigInteger) obj); return equals(this, (BigInteger) obj);
} }
private static BigInteger valueOf(String s, int radix) private static BigInteger valueOf(String s, int radix)
...@@ -1615,7 +1567,7 @@ public class BigInteger extends Number implements Comparable ...@@ -1615,7 +1567,7 @@ public class BigInteger extends Number implements Comparable
// Testing (len < MPN.chars_per_word(radix)) would be more accurate, // Testing (len < MPN.chars_per_word(radix)) would be more accurate,
// but slightly more expensive, for little practical gain. // but slightly more expensive, for little practical gain.
if (len <= 15 && radix <= 16) if (len <= 15 && radix <= 16)
return BigInteger.make(Long.parseLong(s, radix)); return valueOf(Long.parseLong(s, radix));
int byte_len = 0; int byte_len = 0;
byte[] bytes = new byte[len]; byte[] bytes = new byte[len];
...@@ -1660,8 +1612,7 @@ public class BigInteger extends Number implements Comparable ...@@ -1660,8 +1612,7 @@ public class BigInteger extends Number implements Comparable
if (ival <= 2) if (ival <= 2)
return (double) longValue(); return (double) longValue();
if (isNegative()) if (isNegative())
return BigInteger.neg(this).roundToDouble(0, true, false); return neg(this).roundToDouble(0, true, false);
else
return roundToDouble(0, false, false); return roundToDouble(0, false, false);
} }
...@@ -1769,7 +1720,6 @@ public class BigInteger extends Number implements Comparable ...@@ -1769,7 +1720,6 @@ public class BigInteger extends Number implements Comparable
* Assumes words.length >= (this.words == null ? 1 : this.ival). * Assumes words.length >= (this.words == null ? 1 : this.ival).
* Result is zero-extended, but need not be a valid 2's complement number. * Result is zero-extended, but need not be a valid 2's complement number.
*/ */
private void getAbsolute(int[] words) private void getAbsolute(int[] words)
{ {
int len; int len;
...@@ -1820,7 +1770,7 @@ public class BigInteger extends Number implements Comparable ...@@ -1820,7 +1770,7 @@ public class BigInteger extends Number implements Comparable
return; return;
} }
realloc(len + 1); realloc(len + 1);
if (BigInteger.negate(words, x.words, len)) if (negate(words, x.words, len))
words[len++] = 0; words[len++] = 0;
ival = len; ival = len;
} }
...@@ -1844,7 +1794,7 @@ public class BigInteger extends Number implements Comparable ...@@ -1844,7 +1794,7 @@ public class BigInteger extends Number implements Comparable
private static BigInteger neg(BigInteger x) private static BigInteger neg(BigInteger x)
{ {
if (x.words == null && x.ival != Integer.MIN_VALUE) if (x.words == null && x.ival != Integer.MIN_VALUE)
return make(- x.ival); return valueOf(- x.ival);
BigInteger result = new BigInteger(0); BigInteger result = new BigInteger(0);
result.setNegative(x); result.setNegative(x);
return result.canonicalize(); return result.canonicalize();
...@@ -1852,7 +1802,7 @@ public class BigInteger extends Number implements Comparable ...@@ -1852,7 +1802,7 @@ public class BigInteger extends Number implements Comparable
public BigInteger negate() public BigInteger negate()
{ {
return BigInteger.neg(this); return neg(this);
} }
/** Calculates ceiling(log2(this < 0 ? -this : this+1)) /** Calculates ceiling(log2(this < 0 ? -this : this+1))
...@@ -1862,7 +1812,6 @@ public class BigInteger extends Number implements Comparable ...@@ -1862,7 +1812,6 @@ public class BigInteger extends Number implements Comparable
{ {
if (words == null) if (words == null)
return MPN.intLength(ival); return MPN.intLength(ival);
else
return MPN.intLength(words, ival); return MPN.intLength(words, ival);
} }
...@@ -1913,7 +1862,7 @@ public class BigInteger extends Number implements Comparable ...@@ -1913,7 +1862,7 @@ public class BigInteger extends Number implements Comparable
case 1: return x.and(y); case 1: return x.and(y);
case 3: return x; case 3: return x;
case 5: return y; case 5: return y;
case 15: return make(-1); case 15: return valueOf(-1);
} }
BigInteger result = new BigInteger(); BigInteger result = new BigInteger();
setBitOp(result, op, x, y); setBitOp(result, op, x, y);
...@@ -2111,15 +2060,15 @@ public class BigInteger extends Number implements Comparable ...@@ -2111,15 +2060,15 @@ public class BigInteger extends Number implements Comparable
private static BigInteger and(BigInteger x, int y) private static BigInteger and(BigInteger x, int y)
{ {
if (x.words == null) if (x.words == null)
return BigInteger.make(x.ival & y); return valueOf(x.ival & y);
if (y >= 0) if (y >= 0)
return BigInteger.make(x.words[0] & y); return valueOf(x.words[0] & y);
int len = x.ival; int len = x.ival;
int[] words = new int[len]; int[] words = new int[len];
words[0] = x.words[0] & y; words[0] = x.words[0] & y;
while (--len > 0) while (--len > 0)
words[len] = x.words[len]; words[len] = x.words[len];
return BigInteger.make(words, x.ival); return make(words, x.ival);
} }
/** Return the logical (bit-wise) "and" of two BigIntegers. */ /** Return the logical (bit-wise) "and" of two BigIntegers. */
...@@ -2142,7 +2091,7 @@ public class BigInteger extends Number implements Comparable ...@@ -2142,7 +2091,7 @@ public class BigInteger extends Number implements Comparable
words[i] = x.words[i] & y.words[i]; words[i] = x.words[i] & y.words[i];
for ( ; i < len; i++) for ( ; i < len; i++)
words[i] = x.words[i]; words[i] = x.words[i];
return BigInteger.make(words, len); return make(words, len);
} }
/** Return the logical (bit-wise) "(inclusive) or" of two BigIntegers. */ /** Return the logical (bit-wise) "(inclusive) or" of two BigIntegers. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment