package org.bouncycastle.math.test; import java.math.BigInteger; import java.security.SecureRandom; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.math.Primes; import org.bouncycastle.math.Primes.MROutput; import org.bouncycastle.math.Primes.STOutput; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.BigIntegers; public class PrimesTest extends TestCase { private static final int ITERATIONS = 10; private static final int PRIME_BITS = 256; private static final int PRIME_CERTAINTY = 100; private static final BigInteger TWO = BigInteger.valueOf(2); private static final SecureRandom R = new SecureRandom(); public void testHasAnySmallFactors() { for (int iterations = 0; iterations < ITERATIONS; ++iterations) { BigInteger prime = randomPrime(); assertFalse(Primes.hasAnySmallFactors(prime)); // NOTE: Loop through ALL small values to be sure no small primes are missing for (int smallFactor = 2; smallFactor <= Primes.SMALL_FACTOR_LIMIT; ++smallFactor) { BigInteger nonPrimeWithSmallFactor = BigInteger.valueOf(smallFactor).multiply(prime); assertTrue(Primes.hasAnySmallFactors(nonPrimeWithSmallFactor)); } } } public void testEnhancedMRProbablePrime() { int mrIterations = (PRIME_CERTAINTY + 1) / 2; for (int iterations = 0; iterations < ITERATIONS; ++iterations) { BigInteger prime = randomPrime(); MROutput mr = Primes.enhancedMRProbablePrimeTest(prime, R, mrIterations); assertFalse(mr.isProvablyComposite()); assertFalse(mr.isNotPrimePower()); assertNull(mr.getFactor()); BigInteger primePower = prime; for (int i = 0; i <= (iterations % 8); ++i) { primePower = primePower.multiply(prime); } MROutput mr2 = Primes.enhancedMRProbablePrimeTest(primePower, R, mrIterations); assertTrue(mr2.isProvablyComposite()); assertFalse(mr2.isNotPrimePower()); assertEquals(mr2.getFactor(), prime); BigInteger nonPrimePower = randomPrime().multiply(prime); MROutput mr3 = Primes.enhancedMRProbablePrimeTest(nonPrimePower, R, mrIterations); assertTrue(mr3.isProvablyComposite()); assertTrue(mr3.isNotPrimePower()); assertNull(mr.getFactor()); } } public void testMRProbablePrime() { int mrIterations = (PRIME_CERTAINTY + 1) / 2; for (int iterations = 0; iterations < ITERATIONS; ++iterations) { BigInteger prime = randomPrime(); assertTrue(Primes.isMRProbablePrime(prime, R, mrIterations)); BigInteger nonPrime = randomPrime().multiply(prime); assertFalse(Primes.isMRProbablePrime(nonPrime, R, mrIterations)); } } public void testMRProbablePrimeToBase() { int mrIterations = (PRIME_CERTAINTY + 1) / 2; for (int iterations = 0; iterations < ITERATIONS; ++iterations) { BigInteger prime = randomPrime(); assertTrue(referenceIsMRProbablePrime(prime, mrIterations)); BigInteger nonPrime = randomPrime().multiply(prime); assertFalse(referenceIsMRProbablePrime(nonPrime, mrIterations)); } } public void testSTRandomPrime() { Digest[] digests = new Digest[]{ new SHA1Digest(), new SHA256Digest() }; for (int digestIndex = 0; digestIndex < digests.length; ++digestIndex) { int coincidenceCount = 0; Digest digest = digests[digestIndex]; for (int iterations = 0; iterations < ITERATIONS; ++iterations) { try { byte[] inputSeed = new byte[16]; R.nextBytes(inputSeed); STOutput st = Primes.generateSTRandomPrime(digest, PRIME_BITS, inputSeed); assertTrue(isPrime(st.getPrime())); STOutput st2 = Primes.generateSTRandomPrime(digest, PRIME_BITS, inputSeed); assertEquals(st.getPrime(), st2.getPrime()); assertEquals(st.getPrimeGenCounter(), st2.getPrimeGenCounter()); assertTrue(Arrays.areEqual(st.getPrimeSeed(), st2.getPrimeSeed())); for (int i = 0; i < inputSeed.length; ++i) { inputSeed[i] ^= 0xFF; } STOutput st3 = Primes.generateSTRandomPrime(digest, PRIME_BITS, inputSeed); assertTrue(!st.getPrime().equals(st3.getPrime())); assertFalse(Arrays.areEqual(st.getPrimeSeed(), st3.getPrimeSeed())); if (st.getPrimeGenCounter() == st3.getPrimeGenCounter()) { ++coincidenceCount; } } catch (IllegalStateException e) { if (e.getMessage().startsWith("Too many iterations")) { --iterations; continue; } throw e; } } assertTrue(coincidenceCount * coincidenceCount < ITERATIONS); } } public static Test suite() { return new TestSuite(PrimesTest.class); } private static boolean referenceIsMRProbablePrime(BigInteger x, int numBases) { BigInteger xSubTwo = x.subtract(TWO); for (int i = 0; i < numBases; ++i) { BigInteger b = BigIntegers.createRandomInRange(TWO, xSubTwo, R); if (!Primes.isMRProbablePrimeToBase(x, b)) { return false; } } return true; } private static boolean isPrime(BigInteger x) { return x.isProbablePrime(PRIME_CERTAINTY); } private static BigInteger randomPrime() { return new BigInteger(PRIME_BITS, PRIME_CERTAINTY, R); } }