package java.math.test; import java.math.BigInteger; import java.security.SecureRandom; import org.bouncycastle.util.test.*; public class BigIntegerTest extends SimpleTest { private static BigInteger VALUE1 = new BigInteger("1234"); private static BigInteger VALUE2 = new BigInteger("1234567890"); private static BigInteger VALUE3 = new BigInteger("12345678901234567890123"); private static BigInteger zero = BigInteger.ZERO; private static BigInteger one = BigInteger.ONE; private static BigInteger two = BigInteger.valueOf(2); public String getName() { return "BigInteger"; } private void clearBitTest() { BigInteger value = VALUE1.clearBit(3); BigInteger result = new BigInteger("1234"); if (!value.equals(result)) { fail("clearBit - expected: " + result + " got: " + value); } value = VALUE2.clearBit(3); result = new BigInteger("1234567890"); if (!value.equals(result)) { fail("clearBit - expected: " + result + " got: " + value); } value = VALUE3.clearBit(3); result = new BigInteger("12345678901234567890115"); if (!value.equals(result)) { fail("clearBit - expected: " + result + " got: " + value); } value = VALUE2.clearBit(55); result = new BigInteger("1234567890"); if (!value.equals(result)) { fail("clearBit - expected: " + result + " got: " + value); } value = VALUE3.clearBit(55); result = new BigInteger("12345642872437548926155"); if (!value.equals(result)) { fail("clearBit - expected: " + result + " got: " + value); } } private void flipBitTest() { BigInteger value = VALUE1.flipBit(3); BigInteger result = new BigInteger("1242"); if (!value.equals(result)) { fail("flipBit - expected: " + result + " got: " + value); } value = VALUE2.flipBit(3); result = new BigInteger("1234567898"); if (!value.equals(result)) { fail("flipBit - expected: " + result + " got: " + value); } value = VALUE3.flipBit(3); result = new BigInteger("12345678901234567890115"); if (!value.equals(result)) { fail("flipBit - expected: " + result + " got: " + value); } value = VALUE2.flipBit(55); result = new BigInteger("36028798253531858"); if (!value.equals(result)) { fail("flipBit - expected: " + result + " got: " + value); } value = VALUE3.flipBit(55); result = new BigInteger("12345642872437548926155"); if (!value.equals(result)) { fail("flipBit - expected: " + result + " got: " + value); } } private void setBitTest() { BigInteger value = VALUE1.setBit(3); BigInteger result = new BigInteger("1242"); if (!value.equals(result)) { fail("setBit - expected: " + result + " got: " + value); } value = VALUE2.setBit(3); result = new BigInteger("1234567898"); if (!value.equals(result)) { fail("setBit - expected: " + result + " got: " + value); } value = VALUE3.setBit(3); result = new BigInteger("12345678901234567890123"); if (!value.equals(result)) { fail("setBit - expected: " + result + " got: " + value); } value = VALUE2.setBit(55); result = new BigInteger("36028798253531858"); if (!value.equals(result)) { fail("setBit - expected: " + result + " got: " + value); } value = VALUE3.setBit(55); result = new BigInteger("12345678901234567890123"); if (!value.equals(result)) { fail("setBit - expected: " + result + " got: " + value); } } private void testDivideAndRemainder() { SecureRandom random = new SecureRandom(); BigInteger n = new BigInteger(48, random); BigInteger[] qr = n.divideAndRemainder(n); if (!qr[0].equals(one) || !qr[1].equals(zero)) { fail("testDivideAndRemainder - expected: 1/0 got: " + qr[0] + "/" + qr[1]); } qr = n.divideAndRemainder(one); if (!qr[0].equals(n) || !qr[1].equals(zero)) { fail("testDivideAndRemainder - expected: " + n + "/0 got: " + qr[0] + "/" + qr[1]); } for (int rep = 0; rep < 10; ++rep) { BigInteger a = new BigInteger(100 - rep, 0, random); BigInteger b = new BigInteger(100 + rep, 0, random); BigInteger c = new BigInteger(10 + rep, 0, random); BigInteger d = a.multiply(b).add(c); BigInteger[] es = d.divideAndRemainder(a); if (!es[0].equals(b) || !es[1].equals(c)) { fail("testDivideAndRemainder - expected: " + b + "/" + c + " got: " + qr[0] + "/" + qr[1]); } } } private void testModInverse() { SecureRandom random = new SecureRandom(); for (int i = 0; i < 10; ++i) { BigInteger p = BigInteger.probablePrime(64, random); BigInteger q = new BigInteger(63, random).add(one); BigInteger inv = q.modInverse(p); BigInteger inv2 = inv.modInverse(p); if (!q.equals(inv2)) { fail("testModInverse failed symmetry test"); } BigInteger check = q.multiply(inv).mod(p); if (!one.equals(check)) { fail("testModInverse - expected: 1 got: " + check); } } // ModInverse for powers of 2 for (int i = 1; i <= 128; ++i) { BigInteger m = one.shiftLeft(i); BigInteger d = new BigInteger(i, random).setBit(0); BigInteger x = d.modInverse(m); BigInteger check = x.multiply(d).mod(m); if (!one.equals(check)) { fail("testModInverse - expected: 1 got: " + check); } } } private void testNegate() { if (!zero.equals(zero.negate())) { fail("zero - negate falied"); } if (!one.equals(one.negate().negate())) { fail("one - negate falied"); } if (!two.equals(two.negate().negate())) { fail("two - negate falied"); } } private void testNot() { for (int i = -10; i <= 10; ++i) { if(!BigInteger.valueOf(~i).equals( BigInteger.valueOf(i).not())) { fail("Problem: ~" + i + " should be " + ~i); } } } private void testOr() { for (int i = -10; i <= 10; ++i) { for (int j = -10; j <= 10; ++j) { if (!BigInteger.valueOf(i | j).equals( BigInteger.valueOf(i).or(BigInteger.valueOf(j)))) { fail("Problem: " + i + " OR " + j + " should be " + (i | j)); } } } } public void testPow() { if (!one.equals(zero.pow(0))) { fail("one pow equals failed"); } if (!zero.equals(zero.pow(123))) { fail("zero pow equals failed"); } if (!one.equals(one.pow(0))) { fail("one one equals failed"); } if (!one.equals(one.pow(123))) { fail("1 123 equals failed"); } if (!two.pow(147).equals(one.shiftLeft(147))) { fail("2 pow failed"); } if (!one.shiftLeft(7).pow(11).equals(one.shiftLeft(77))) { fail("pow 2 pow failed"); } BigInteger n = new BigInteger("1234567890987654321"); BigInteger result = one; for (int i = 0; i < 10; ++i) { try { BigInteger.valueOf(i).pow(-1); fail("expected ArithmeticException"); } catch (ArithmeticException e) {} if (!result.equals(n.pow(i))) { fail("mod pow equals failed"); } result = result.multiply(n); } } public void testToString() { SecureRandom random = new SecureRandom(); int trials = 256; BigInteger[] tests = new BigInteger[trials]; for (int i = 0; i < trials; ++i) { int len = random.nextInt(i + 1); tests[i] = new BigInteger(len, random); } for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; ++radix) { for (int i = 0; i < trials; ++i) { BigInteger n1 = tests[i]; String s = n1.toString(radix); BigInteger n2 = new BigInteger(s, radix); if (!n1.equals(n2)) { fail("testToStringRadix - radix:" + radix + ", n1:" + n1.toString(16) + ", n2:" + n2.toString(16)); } } } } private void xorTest() { BigInteger value = VALUE1.xor(VALUE2); BigInteger result = new BigInteger("1234568704"); if (!value.equals(result)) { fail("xor - expected: " + result + " got: " + value); } value = VALUE1.xor(VALUE3); result = new BigInteger("12345678901234567888921"); if (!value.equals(result)) { fail("xor - expected: " + result + " got: " + value); } value = VALUE3.xor(VALUE1); result = new BigInteger("12345678901234567888921"); if (!value.equals(result)) { fail("xor - expected: " + result + " got: " + value); } value = VALUE2.xor(new BigInteger("-1")); result = new BigInteger("-1234567891"); if (!value.equals(result)) { fail("xor - expected: " + result + " got: " + value); } value = VALUE3.xor(VALUE3); result = new BigInteger("0"); if (!value.equals(result)) { fail("xor - expected: " + result + " got: " + value); } } public void performTest() { clearBitTest(); flipBitTest(); setBitTest(); testDivideAndRemainder(); testModInverse(); testNegate(); testNot(); testOr(); testPow(); testToString(); xorTest(); BigInteger n1, n2, r1; // test division where the difference in bit length of the dividend and divisor is 32 bits n1 = new BigInteger("54975581388"); n2 = new BigInteger("10"); r1 = n1.divide(n2); if (!r1.toString(10).equals("5497558138")) { fail("BigInteger: failed Divide Test"); } // two's complement test byte[] zeroBytes = BigInteger.ZERO.toByteArray(); byte[] oneBytes = BigInteger.ONE.toByteArray(); byte[] minusOneBytes = BigInteger.ONE.negate().toByteArray(); BigInteger zero = new BigInteger(zeroBytes); if (!zero.equals(BigInteger.ZERO)) { fail("Failed constructing zero"); } BigInteger one = new BigInteger(oneBytes); if (!one.equals(BigInteger.ONE)) { fail("Failed constructing one"); } BigInteger minusOne = new BigInteger(minusOneBytes); if (!minusOne.equals(BigInteger.ONE.negate())) { fail("Failed constructing minus one"); } SecureRandom random = new SecureRandom(); byte[] randomBytes = new byte[100]; for (int i=0; i < 100; i++) { random.nextBytes(randomBytes); BigInteger bcInt = new BigInteger(randomBytes); BigInteger bcInt2 = new BigInteger(bcInt.toByteArray()); if (!bcInt.equals(bcInt2)) { fail("Failed constructing random value " + i); } // java.math.BigInteger jdkInt = new java.math.BigInteger(randomBytes); // byte[] bcBytes = bcInt.toByteArray(); // byte[] jdkBytes = jdkInt.toByteArray(); // if (!arrayEquals(bcBytes, jdkBytes)) // { // fail(""Failed constructing random value " + i); // } } } public static void main( String[] args) { runTest(new BigIntegerTest()); } }