コード例 #1
0
        /// <summary>
        /// Determines whether a number is probably prime using the Rabin-Miller's test
        /// </summary>
        /// <remarks>
        /// Before applying the test, the number is tested for divisibility by X first primes.
        /// Different amounts X were determined for different bit lengths and are used as a constant.
        /// </remarks>
        /// <param name="T">BigInteger to check for primality</param>
        /// <param name="confidence">Number of chosen bases</param>
        /// <param name="rng">RandomNumberGenerator object</param>
        /// <param name="bitLength">Bit length of T (if not provided, the method calculates it)</param>
        /// <returns>True if this is probably prime</returns>
        public static bool IsProbablePrime(this BigInteger T, int confidence, RandomNumberGenerator rng, int bitLength = -1)
        {
            var thisVal = BigInteger.Abs(T);

            if (thisVal.IsZero || thisVal.IsOne)
            {
                return(false);
            }

            if (bitLength == -1)
            {
                bitLength = thisVal.BitCount();
            }
            var take = PrimeFactorsToUse(bitLength);

            if (thisVal <= UInt64.MaxValue)
            {
                var uival = (UInt64)thisVal;

                foreach (var smallPrime in PrimesBelow1M.Take(take))
                {
                    if (smallPrime >= uival)
                    {
                        return(true);
                    }

                    if (uival % smallPrime == 0)
                    {
                        return(false);
                    }
                }
            }
            else
            {
                foreach (var smallPrime in PrimesBelow1M_BI.Take(take))
                {
                    if ((thisVal % smallPrime).IsZero)
                    {
                        return(false);
                    }
                }
            }

            return(thisVal.RabinMillerTest(confidence, rng));
        }
コード例 #2
0
        /// <summary>
        /// Generates a random probable safe prime positive BigInteger of exactly the specified bit length using the provided RNG.
        /// Safe prime is a prime P such that P=2*Q+1, where Q is prime. Such Q is called a Sophie Germain prime.
        /// This method uses the Combined Sieve approach to improve performance as compared to naive algorithm.
        /// See Michael Wiener ``Safe Prime Generation with a Combined Sieve'', 2003 (https://eprint.iacr.org/2003/186)
        /// </summary>
        /// <param name="T">This parameter is irrelevant, required due to lack of static extension methods in C#</param>
        /// <param name="bits">Bit length of prime to generate</param>
        /// <param name="confidence">Number of chosen bases</param>
        /// <param name="rng">RandomNumberGenerator object</param>
        /// <returns>A probably prime number</returns>
        /// <exception cref="ArgumentOutOfRangeException">`bits` must be >= 3</exception>
        public static BigInteger GenSafePseudoPrime(this BigInteger T, int bits, int confidence, RandomNumberGenerator rng)
        {
            if (bits < 3)
            {
                throw new ArgumentOutOfRangeException(nameof(bits), bits, "GenSafePseudoPrime can only generate prime numbers of 3 bits or more");
            }

            BigInteger result;

            var qbits = bits - 1;
            var take  = PrimeFactorsToUse(bits);

            do
            {
                BigInteger q;

                var done = false;

                while (!done)
                {
                    q  = BigInteger.Zero.GenRandomBits(qbits, rng);
                    q |= BigInteger.One; // make it odd

                    var fail = false;

                    if (q <= UInt64.MaxValue)
                    {
                        var uival = (UInt64)q;

                        foreach (var curSmallPrime in PrimesBelow1M.Take(take))
                        {
                            if (curSmallPrime >= uival)
                            {
                                fail = true; // not a fail but we skip Rabin-Miller test using this flag
                                done = true; // and exit the outer while loop
                                break;
                            }

                            var rem = uival % curSmallPrime;

                            // Sieve: if rem=0 then Q is composite;
                            //        if second condition is true, then P will be divisible by curSmallPrime
                            if (rem == 0 || rem == (curSmallPrime - 1) / 2)
                            {
                                fail = true;
                                break;
                            }
                        }
                    }
                    else
                    {
                        foreach (var curSmallPrime in PrimesBelow1M_BI.Take(take))
                        {
                            var rem = q % curSmallPrime;

                            // Sieve: if rem=0 then Q is composite;
                            //        if second condition is true, then P will be divisible by curSmallPrime
                            if (rem.IsZero || rem == (curSmallPrime - BigInteger.One) / Two)
                            {
                                fail = true;
                                break;
                            }
                        }
                    }

                    if (fail)
                    {
                        continue;                              // try another Q
                    }
                    done = q.RabinMillerTest(confidence, rng); // returns true if Q is prime
                }

                result = Two * q + BigInteger.One;
            } while (!result.RabinMillerTest(confidence, rng)); // no need to check divisibility by small primes, can go straight to Rabin-Miller

            return(result);
        }