/// <summary>
        /// Generate a prime number using with a given approximate length and byte length margin
        /// </summary>
        /// <param name="threads">How many threads to use to generate primes</param>
        /// <param name="approximateByteCount">The byte array length around which the prime generator will select lengths</param>
        /// <param name="byteMargin">Allowed deviation of byte length from approximateByteCount</param>
        /// <param name="certainty">How many iterations of the fermat test should be run to test primailty for each generated number</param>
        /// <param name="provider">Random provider that will be used to generate random primes</param>
        /// <returns>A prime number that is aproximately approximateByteCount long</returns>
        public static BigInteger GeneratePrime(int threads, int approximateByteCount, int byteMargin, int certainty, RandomProvider provider)
        {
            var        found  = false;
            BigInteger result = BigInteger.Zero;

            for (int i = 0; i < threads; ++i)
            {
                Task.Factory.StartNew(() =>
                {
                    char left    = '\0';
                    byte rand    = 0;
                    BigInteger b = BigInteger.Zero;
                    while (!found)
                    {
                        if (left == 0)
                        {
                            rand = provider.GetBytes(1)[0];
                            left = (char)8;
                        }

                        byte[] b1          = provider.GetBytes(approximateByteCount + (provider.GetBytes(1)[0] % byteMargin) * (rand % 2 == 1 ? 1 : -1));
                        b1[0]             |= 1;   // Always odd
                        b1[b1.Length - 1] &= 127; // Always positive
                        b      = new BigInteger(b1);
                        rand >>= 1;
                        --left;
                        if (IsProbablePrime(b, provider, certainty))
                        {
                            found  = true;
                            result = b;
                        }
                    }
                });
            }
            while (!found)
            {
                System.Threading.Thread.Sleep(125);
            }
            return(result);
        }