using System; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math { /** * Utility methods for generating primes and testing for primality. */ public abstract class Primes { public static readonly int SmallFactorLimit = 211; private static readonly BigInteger One = BigInteger.One; private static readonly BigInteger Two = BigInteger.Two; private static readonly BigInteger Three = BigInteger.Three; /** * Used to return the output from the * {@linkplain Primes#enhancedMRProbablePrimeTest(BigInteger, SecureRandom, int) Enhanced * Miller-Rabin Probabilistic Primality Test} */ public class MROutput { internal static MROutput ProbablyPrime() { return new MROutput(false, null); } internal static MROutput ProvablyCompositeWithFactor(BigInteger factor) { return new MROutput(true, factor); } internal static MROutput ProvablyCompositeNotPrimePower() { return new MROutput(true, null); } private readonly bool mProvablyComposite; private readonly BigInteger mFactor; private MROutput(bool provablyComposite, BigInteger factor) { this.mProvablyComposite = provablyComposite; this.mFactor = factor; } public BigInteger Factor { get { return mFactor; } } public bool IsProvablyComposite { get { return mProvablyComposite; } } public bool IsNotPrimePower { get { return mProvablyComposite && mFactor == null; } } } /** * Used to return the output from the {@linkplain Primes#generateSTRandomPrime(Digest, int, byte[]) Shawe-Taylor Random_Prime Routine} */ public class STOutput { private readonly BigInteger mPrime; private readonly byte[] mPrimeSeed; private readonly int mPrimeGenCounter; internal STOutput(BigInteger prime, byte[] primeSeed, int primeGenCounter) { this.mPrime = prime; this.mPrimeSeed = primeSeed; this.mPrimeGenCounter = primeGenCounter; } public BigInteger Prime { get { return mPrime; } } public byte[] PrimeSeed { get { return mPrimeSeed; } } public int PrimeGenCounter { get { return mPrimeGenCounter; } } } /** * FIPS 186-4 C.6 Shawe-Taylor Random_Prime Routine * * Construct a provable prime number using a hash function. * * @param hash * the {@link Digest} instance to use (as "Hash()"). Cannot be null. * @param length * the length (in bits) of the prime to be generated. Must be at least 2. * @param inputSeed * the seed to be used for the generation of the requested prime. Cannot be null or * empty. * @return an {@link STOutput} instance containing the requested prime. */ public static STOutput GenerateSTRandomPrime(IDigest hash, int length, byte[] inputSeed) { if (hash == null) throw new ArgumentNullException("hash"); if (length < 2) throw new ArgumentException("must be >= 2", "length"); if (inputSeed == null) throw new ArgumentNullException("inputSeed"); if (inputSeed.Length == 0) throw new ArgumentException("cannot be empty", "inputSeed"); return ImplSTRandomPrime(hash, length, Arrays.Clone(inputSeed)); } /** * FIPS 186-4 C.3.2 Enhanced Miller-Rabin Probabilistic Primality Test * * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases. This is an * alternative to {@link #isMRProbablePrime(BigInteger, SecureRandom, int)} that provides more * information about a composite candidate, which may be useful when generating or validating * RSA moduli. * * @param candidate * the {@link BigInteger} instance to test for primality. * @param random * the source of randomness to use to choose bases. * @param iterations * the number of randomly-chosen bases to perform the test for. * @return an {@link MROutput} instance that can be further queried for details. */ public static MROutput EnhancedMRProbablePrimeTest(BigInteger candidate, SecureRandom random, int iterations) { CheckCandidate(candidate, "candidate"); if (random == null) throw new ArgumentNullException("random"); if (iterations < 1) throw new ArgumentException("must be > 0", "iterations"); if (candidate.BitLength == 2) return MROutput.ProbablyPrime(); if (!candidate.TestBit(0)) return MROutput.ProvablyCompositeWithFactor(Two); BigInteger w = candidate; BigInteger wSubOne = candidate.Subtract(One); BigInteger wSubTwo = candidate.Subtract(Two); int a = wSubOne.GetLowestSetBit(); BigInteger m = wSubOne.ShiftRight(a); for (int i = 0; i < iterations; ++i) { BigInteger b = BigIntegers.CreateRandomInRange(Two, wSubTwo, random); BigInteger g = b.Gcd(w); if (g.CompareTo(One) > 0) return MROutput.ProvablyCompositeWithFactor(g); BigInteger z = b.ModPow(m, w); if (z.Equals(One) || z.Equals(wSubOne)) continue; bool primeToBase = false; BigInteger x = z; for (int j = 1; j < a; ++j) { z = z.ModPow(Two, w); if (z.Equals(wSubOne)) { primeToBase = true; break; } if (z.Equals(One)) break; x = z; } if (!primeToBase) { if (!z.Equals(One)) { x = z; z = z.ModPow(Two, w); if (!z.Equals(One)) { x = z; } } g = x.Subtract(One).Gcd(w); if (g.CompareTo(One) > 0) return MROutput.ProvablyCompositeWithFactor(g); return MROutput.ProvablyCompositeNotPrimePower(); } } return MROutput.ProbablyPrime(); } /** * A fast check for small divisors, up to some implementation-specific limit. * * @param candidate * the {@link BigInteger} instance to test for division by small factors. * * @return true if the candidate is found to have any small factors, * false otherwise. */ public static bool HasAnySmallFactors(BigInteger candidate) { CheckCandidate(candidate, "candidate"); return ImplHasAnySmallFactors(candidate); } /** * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test * * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases. * * @param candidate * the {@link BigInteger} instance to test for primality. * @param random * the source of randomness to use to choose bases. * @param iterations * the number of randomly-chosen bases to perform the test for. * @return false if any witness to compositeness is found amongst the chosen bases * (so candidate is definitely NOT prime), or else true * (indicating primality with some probability dependent on the number of iterations * that were performed). */ public static bool IsMRProbablePrime(BigInteger candidate, SecureRandom random, int iterations) { CheckCandidate(candidate, "candidate"); if (random == null) throw new ArgumentException("cannot be null", "random"); if (iterations < 1) throw new ArgumentException("must be > 0", "iterations"); if (candidate.BitLength == 2) return true; if (!candidate.TestBit(0)) return false; BigInteger w = candidate; BigInteger wSubOne = candidate.Subtract(One); BigInteger wSubTwo = candidate.Subtract(Two); int a = wSubOne.GetLowestSetBit(); BigInteger m = wSubOne.ShiftRight(a); for (int i = 0; i < iterations; ++i) { BigInteger b = BigIntegers.CreateRandomInRange(Two, wSubTwo, random); if (!ImplMRProbablePrimeToBase(w, wSubOne, m, a, b)) return false; } return true; } /** * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test (to a fixed base). * * Run a single iteration of the Miller-Rabin algorithm against the specified base. * * @param candidate * the {@link BigInteger} instance to test for primality. * @param baseValue * the base value to use for this iteration. * @return false if the specified base is a witness to compositeness (so * candidate is definitely NOT prime), or else true. */ public static bool IsMRProbablePrimeToBase(BigInteger candidate, BigInteger baseValue) { CheckCandidate(candidate, "candidate"); CheckCandidate(baseValue, "baseValue"); if (baseValue.CompareTo(candidate.Subtract(One)) >= 0) throw new ArgumentException("must be < ('candidate' - 1)", "baseValue"); if (candidate.BitLength == 2) return true; BigInteger w = candidate; BigInteger wSubOne = candidate.Subtract(One); int a = wSubOne.GetLowestSetBit(); BigInteger m = wSubOne.ShiftRight(a); return ImplMRProbablePrimeToBase(w, wSubOne, m, a, baseValue); } private static void CheckCandidate(BigInteger n, string name) { if (n == null || n.SignValue < 1 || n.BitLength < 2) throw new ArgumentException("must be non-null and >= 2", name); } private static bool ImplHasAnySmallFactors(BigInteger x) { /* * Bundle trial divisors into ~32-bit moduli then use fast tests on the ~32-bit remainders. */ int m = 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23; int r = x.Mod(BigInteger.ValueOf(m)).IntValue; if ((r % 2) == 0 || (r % 3) == 0 || (r % 5) == 0 || (r % 7) == 0 || (r % 11) == 0 || (r % 13) == 0 || (r % 17) == 0 || (r % 19) == 0 || (r % 23) == 0) { return true; } m = 29 * 31 * 37 * 41 * 43; r = x.Mod(BigInteger.ValueOf(m)).IntValue; if ((r % 29) == 0 || (r % 31) == 0 || (r % 37) == 0 || (r % 41) == 0 || (r % 43) == 0) { return true; } m = 47 * 53 * 59 * 61 * 67; r = x.Mod(BigInteger.ValueOf(m)).IntValue; if ((r % 47) == 0 || (r % 53) == 0 || (r % 59) == 0 || (r % 61) == 0 || (r % 67) == 0) { return true; } m = 71 * 73 * 79 * 83; r = x.Mod(BigInteger.ValueOf(m)).IntValue; if ((r % 71) == 0 || (r % 73) == 0 || (r % 79) == 0 || (r % 83) == 0) { return true; } m = 89 * 97 * 101 * 103; r = x.Mod(BigInteger.ValueOf(m)).IntValue; if ((r % 89) == 0 || (r % 97) == 0 || (r % 101) == 0 || (r % 103) == 0) { return true; } m = 107 * 109 * 113 * 127; r = x.Mod(BigInteger.ValueOf(m)).IntValue; if ((r % 107) == 0 || (r % 109) == 0 || (r % 113) == 0 || (r % 127) == 0) { return true; } m = 131 * 137 * 139 * 149; r = x.Mod(BigInteger.ValueOf(m)).IntValue; if ((r % 131) == 0 || (r % 137) == 0 || (r % 139) == 0 || (r % 149) == 0) { return true; } m = 151 * 157 * 163 * 167; r = x.Mod(BigInteger.ValueOf(m)).IntValue; if ((r % 151) == 0 || (r % 157) == 0 || (r % 163) == 0 || (r % 167) == 0) { return true; } m = 173 * 179 * 181 * 191; r = x.Mod(BigInteger.ValueOf(m)).IntValue; if ((r % 173) == 0 || (r % 179) == 0 || (r % 181) == 0 || (r % 191) == 0) { return true; } m = 193 * 197 * 199 * 211; r = x.Mod(BigInteger.ValueOf(m)).IntValue; if ((r % 193) == 0 || (r % 197) == 0 || (r % 199) == 0 || (r % 211) == 0) { return true; } /* * NOTE: Unit tests depend on SMALL_FACTOR_LIMIT matching the * highest small factor tested here. */ return false; } private static bool ImplMRProbablePrimeToBase(BigInteger w, BigInteger wSubOne, BigInteger m, int a, BigInteger b) { BigInteger z = b.ModPow(m, w); if (z.Equals(One) || z.Equals(wSubOne)) return true; bool result = false; for (int j = 1; j < a; ++j) { z = z.ModPow(Two, w); if (z.Equals(wSubOne)) { result = true; break; } if (z.Equals(One)) return false; } return result; } private static STOutput ImplSTRandomPrime(IDigest d, int length, byte[] primeSeed) { int dLen = d.GetDigestSize(); if (length < 33) { int primeGenCounter = 0; byte[] c0 = new byte[dLen]; byte[] c1 = new byte[dLen]; for (;;) { Hash(d, primeSeed, c0, 0); Inc(primeSeed, 1); Hash(d, primeSeed, c1, 0); Inc(primeSeed, 1); uint c = Extract32(c0) ^ Extract32(c1); c &= (uint.MaxValue >> (32 - length)); c |= (1U << (length - 1)) | 1U; ++primeGenCounter; if (IsPrime32(c)) { return new STOutput(BigInteger.ValueOf((long)c), primeSeed, primeGenCounter); } if (primeGenCounter > (4 * length)) { throw new InvalidOperationException("Too many iterations in Shawe-Taylor Random_Prime Routine"); } } } STOutput rec = ImplSTRandomPrime(d, (length + 3)/2, primeSeed); { BigInteger c0 = rec.Prime; primeSeed = rec.PrimeSeed; int primeGenCounter = rec.PrimeGenCounter; int outlen = 8 * dLen; int iterations = (length - 1)/outlen; int oldCounter = primeGenCounter; BigInteger x = HashGen(d, primeSeed, iterations + 1); x = x.Mod(One.ShiftLeft(length - 1)).SetBit(length - 1); BigInteger c0x2 = c0.ShiftLeft(1); BigInteger tx2 = x.Subtract(One).Divide(c0x2).Add(One).ShiftLeft(1); int dt = 0; BigInteger c = tx2.Multiply(c0).Add(One); /* * TODO Since the candidate primes are generated by constant steps ('c0x2'), * sieving could be used here in place of the 'HasAnySmallFactors' approach. */ for (;;) { if (c.BitLength > length) { tx2 = One.ShiftLeft(length - 1).Subtract(One).Divide(c0x2).Add(One).ShiftLeft(1); c = tx2.Multiply(c0).Add(One); } ++primeGenCounter; /* * This is an optimization of the original algorithm, using trial division to screen out * many non-primes quickly. * * NOTE: 'primeSeed' is still incremented as if we performed the full check! */ if (!ImplHasAnySmallFactors(c)) { BigInteger a = HashGen(d, primeSeed, iterations + 1); a = a.Mod(c.Subtract(Three)).Add(Two); tx2 = tx2.Add(BigInteger.ValueOf(dt)); dt = 0; BigInteger z = a.ModPow(tx2, c); if (c.Gcd(z.Subtract(One)).Equals(One) && z.ModPow(c0, c).Equals(One)) { return new STOutput(c, primeSeed, primeGenCounter); } } else { Inc(primeSeed, iterations + 1); } if (primeGenCounter >= ((4 * length) + oldCounter)) { throw new InvalidOperationException("Too many iterations in Shawe-Taylor Random_Prime Routine"); } dt += 2; c = c.Add(c0x2); } } } private static uint Extract32(byte[] bs) { uint result = 0; int count = System.Math.Min(4, bs.Length); for (int i = 0; i < count; ++i) { uint b = bs[bs.Length - (i + 1)]; result |= (b << (8 * i)); } return result; } private static void Hash(IDigest d, byte[] input, byte[] output, int outPos) { d.BlockUpdate(input, 0, input.Length); d.DoFinal(output, outPos); } private static BigInteger HashGen(IDigest d, byte[] seed, int count) { int dLen = d.GetDigestSize(); int pos = count * dLen; byte[] buf = new byte[pos]; for (int i = 0; i < count; ++i) { pos -= dLen; Hash(d, seed, buf, pos); Inc(seed, 1); } return new BigInteger(1, buf); } private static void Inc(byte[] seed, int c) { int pos = seed.Length; while (c > 0 && --pos >= 0) { c += seed[pos]; seed[pos] = (byte)c; c >>= 8; } } private static bool IsPrime32(uint x) { /* * Use wheel factorization with 2, 3, 5 to select trial divisors. */ if (x <= 5) { return x == 2 || x == 3 || x == 5; } if ((x & 1) == 0 || (x % 3) == 0 || (x % 5) == 0) { return false; } uint[] ds = new uint[]{ 1, 7, 11, 13, 17, 19, 23, 29 }; uint b = 0; for (int pos = 1; ; pos = 0) { /* * Trial division by wheel-selected divisors */ while (pos < ds.Length) { uint d = b + ds[pos]; if (x % d == 0) { return x < 30; } ++pos; } b += 30; if ((b >> 16 != 0) || (b * b >= x)) { return true; } } } } }