Example #1
0
        public static string GetCertificateOfPrimality(BigInteger probable, BigInteger accuracy)
        {
            BigInteger witness = CryptoRandomSingleton.RandomRange(Two, probable - Two);
            BigInteger modPow  = BigInteger.ModPow(witness, probable - 1, probable);

            string result = null;

            if (modPow == 1)             // a^n-1 mod n == 1
            {
                modPow = BigInteger.ModPow(witness, 2 * accuracy, probable);
                BigInteger gcd = BigInteger.GreatestCommonDivisor(modPow - 1, probable);

                if (gcd == 1)
                {
                    result  = Environment.NewLine;
                    result += string.Format("Certificate of primality({0})", probable) + Environment.NewLine;
                    result += "{" + Environment.NewLine;
                    result += "   " + string.Format("{0} ^ {1}-1 mod {1} == 1{2}", witness, probable, Environment.NewLine);
                    result += "   " + string.Format("GCD({0}, {1}) == 1{2}", (modPow - 1), probable, Environment.NewLine);
                    result += "}" + Environment.NewLine;
                }
            }

            return(result);
        }
Example #2
0
        public static bool IsProbablyPrime(BigInteger primeHopeful, int testCount)
        {
            bool result = false;

            using (outsideExecutionTime.StartTimer())
            {
                Log.MethodEnter("MillerRabinPrimalityTest", nameof(primeHopeful), $"{primeHopeful}, {nameof(testCount)}: {testCount}");

                if (primeHopeful == 2 || primeHopeful == 3 || primeHopeful == 5 || primeHopeful == 7)
                {
                    FoundFactor(primeHopeful, BigInteger.GreatestCommonDivisor(primeHopeful, 210));
                    result = true;
                    goto exit;
                }

                BigInteger remainder = primeHopeful & 1;                 // % Two;
                if (remainder == 0)
                {
                    FoundFactor(primeHopeful, 2);
                    result = false;
                    goto exit;
                }

                BigInteger hopefulLess1 = primeHopeful - 1;
                BigInteger quotientD    = hopefulLess1;

                remainder = quotientD & 1;                 // % Two;

                long divisionCountR = 0;
                while (remainder == 0)
                {
                    quotientD = quotientD >> 1;                    // / Two;
                    remainder = quotientD & 1;                     // % Two;
                    divisionCountR++;
                }

                BigInteger hopefulLess2 = primeHopeful - Two;
                BigInteger residueX;
                BigInteger priorResidueX;
                BigInteger randomA = 0;

                // Tracks previous random values, prevents testing with the same value twice,
                // which would dramatically reduce our confidence in the primality of a probable prime.
                // Seems unlikely to happen, but its not a hit to performance to check.
                List <BigInteger> previousRandomValues = new List <BigInteger>();

                int counter  = 1;
                int modCount = 1;
                for (counter = 1; counter <= testCount; counter++)
                {
                    do
                    {
                        randomA = CryptoRandomSingleton.RandomRange(Two, hopefulLess2);
                    }while (previousRandomValues.Contains(randomA));
                    previousRandomValues.Add(randomA);

                    Log.Message($"MillerRabin check prime hopeful (P) against random n: {randomA}");

                    using (insideExecutionTime.StartTimer())
                    {
                        residueX = BigInteger.ModPow(randomA, quotientD, primeHopeful);
                        Log.Message($"MillerRabin check a^d ≡ r (mod primeHopeful): {randomA}^{quotientD} ≡ {residueX} (mod {primeHopeful})");
                    }
                    if (residueX == 1 || residueX == hopefulLess1)
                    {
                        BigInteger gcd = BigInteger.GreatestCommonDivisor(residueX - 1, primeHopeful);                         // Chance to factor: GCD((a^d mod n) − 1, n)
                        Log.Message($"A) Chance to factor:  GCD((a^d mod n) − 1, primeHopeful)");
                        if (gcd != 1 && gcd != primeHopeful)
                        {
                            FoundFactor(primeHopeful, gcd);
                            result = false;
                            goto exit;
                        }
                        continue;
                    }

                    modCount = 1;
                    while (modCount <= divisionCountR)
                    {
                        priorResidueX = residueX;
                        residueX      = BigInteger.ModPow(residueX, 2, primeHopeful);
                        Log.Message($"MillerRabin check a^2 ≡ r (mod primeHopeful): {priorResidueX}^2 ≡ {residueX} (mod {primeHopeful})");

                        if (residueX == 1)
                        {
                            // Chance to factor: a^(d*2^r)-1
                            BigInteger twoR  = BigInteger.Pow(2, (int)divisionCountR);
                            BigInteger dTwoR = BigInteger.Multiply(quotientD, twoR);

                            if (dTwoR < int.MaxValue)
                            {
                                int        pow             = (int)dTwoR;
                                BigInteger potentialFactor = BigInteger.Pow(randomA, pow) - 1;
                                BigInteger gcd             = BigInteger.GreatestCommonDivisor(potentialFactor, primeHopeful);
                                Log.Message($"B) Chance to factor: GCD(a^(d*(2^r))-1, primeHopeful): GCD({randomA}^({quotientD}*2^{divisionCountR})-1 == {potentialFactor - 1}, primeHopeful) == {gcd}");
                                if (gcd != 1 && gcd != primeHopeful)
                                {
                                    FoundFactor(primeHopeful, gcd);
                                    result = false;
                                    goto exit;
                                }
                            }

                            Log.MethodLeave();
                            return(false);
                        }

                        if (residueX == hopefulLess1)
                        {
                            // Chance to factor: GCD((a^(d*2^r) mod n) − 1, n)
                            BigInteger twoR            = BigInteger.Pow(2, (int)divisionCountR);
                            BigInteger dTwoR           = BigInteger.Multiply(quotientD, twoR);
                            BigInteger potentialFactor = BigInteger.ModPow(randomA, dTwoR, primeHopeful);
                            BigInteger gcd             = BigInteger.GreatestCommonDivisor(potentialFactor - 1, primeHopeful);
                            Log.Message($"C) Chance to factor: GCD( a^(d*(2^r)) ≡ m−1 (mod primeHopeful) , primeHopeful): GCD( {randomA}^({quotientD}*(2^{divisionCountR})) ≡ {potentialFactor}-1 (mod primeHopeful) == {potentialFactor - 1}, primeHopeful) == {gcd}");
                            if (gcd != 1 && gcd != primeHopeful)
                            {
                                FoundFactor(primeHopeful, gcd);
                                result = false;
                                goto exit;
                            }

                            break;
                        }

                        modCount++;
                    }

                    if (residueX != hopefulLess1)
                    {
                        // ??? Chance to factor ???

                        BigInteger twoR             = BigInteger.Pow(2, (int)divisionCountR);
                        BigInteger dTwoR            = BigInteger.Multiply(quotientD, twoR);
                        BigInteger potentialFactor1 = BigInteger.ModPow(randomA, dTwoR, primeHopeful);
                        BigInteger gcd1             = BigInteger.GreatestCommonDivisor(potentialFactor1 - 1, primeHopeful);
                        Log.Message($"D) Chance to factor: GCD( a^(d*(2^r)) ≡ m−1 (mod primeHopeful) , primeHopeful): GCD( {randomA}^({quotientD}*(2^{divisionCountR})) ≡ {potentialFactor1}-1 (mod primeHopeful) == {potentialFactor1 - 1}, primeHopeful) == {gcd1}");
                        if (gcd1 != 1 && gcd1 != primeHopeful)
                        {
                            FoundFactor(primeHopeful, gcd1);
                            result = false;
                            goto exit;
                        }

                        result = false;
                        goto exit;
                    }
                }

                result = true;
                goto exit;
            }

exit:
            Log.MethodLeave();
            return(result);
        }
        /// <summary>
        /// Returns a probable prime of size bits and will search n rounds for a composite
        /// </summary>
        /// <param name="bitSize">Size of prime, in bits</param>
        /// <param name="testCount">Number of different bases to use when testing probable prime  for composites as evidence of primality</param>
        /// <returns></returns>
        public BigInteger GetProbablePrime(int bitSize, int testCount)
        {
            BigInteger result = 0;

            //Log.Message(".");
            Log.MethodEnter("ProvablePrime", nameof(bitSize), bitSize);

            if (cancelToken.IsCancellationRequested)
            {
                Log.Message("ProvablePrime.CancellationToken.IsCancellationRequested();");
                Log.MethodLeave();
                return(-1);
            }

            if (bitSize <= 20)
            {
                Log.Message("***MAXIMUM RECURSION DEPT REACHED");
                result = TrialDivision.FindSmallPrimes(bitSize);
                Log.Message("***Hopeful prime: {0}", result);
            }
            else
            {
                //double c = 0.1;
                int    m = 20;
                double r = 0.5;

                if (bitSize > 2 * m)
                {
                    double rnd  = 0;
                    bool   done = false;
                    while (!done)
                    {
                        rnd  = CryptoRandomSingleton.NextDouble();
                        r    = Math.Pow(2, rnd - 1);
                        done = (bitSize - r * bitSize) > m;
                    }
                }

                int newBits = (int)Math.Floor(r * bitSize) + 1;

                BigInteger smallPrime = GetProbablePrime(newBits, testCount);

                if (smallPrime == -1)
                {
                    Log.MethodLeave();
                    return(-1);
                }
                Log.Message("After Recursion: Length = {0}", smallPrime.ToString().Length);

                BigInteger pow = BigInteger.Pow(Two, bitSize - 1);
                BigInteger Q   = Two * smallPrime;
                BigInteger I   = pow / Q;

                bool success = false;
                while (!success)
                {
                    if (cancelToken.IsCancellationRequested)
                    {
                        Log.Message("ProvablePrime.CancellationToken.IsCancellationRequested();");
                        Log.MethodLeave();
                        return(-1);
                    }

                    //LogMethod("Loop[{0}]: TestComposite({1})", _loopCount, result);

                    BigInteger J     = I + 1;
                    BigInteger K     = 2 * I;
                    BigInteger rand1 = CryptoRandomSingleton.RandomRange(J, K);
                    result = 2 * rand1;
                    result = result * smallPrime;
                    result = result + 1;

                    bool isPrime = false;
                    if (Eratosthenes.IsTooLarge(result))
                    {
                        isPrime = true;
                    }
                    else
                    {
                        isPrime = Eratosthenes.IsPrime(result);
                    }

                    if (isPrime)
                    {
                        //LogMethod("ProvablePrime.RandomRange(J: {0}, K: {1}) = {2}", J, K, rand1);
                        if (MillerRabin.IsProbablyPrime(result, testCount))
                        {
                            success = true;
                            string cert = MillerRabin.GetCertificateOfPrimality(result, rand1);

                            if (cert != null)
                            {
                                Log.Message(cert);
                            }
                        }
                    }
                }
            }

            //Log.Message(".");
            Log.MethodLeave();
            return(result);
        }