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);
}
}