summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2022-11-08 23:18:07 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2022-11-08 23:18:07 +0700
commit283ab033ec1275a500b80a4c300edb6e4e43f7e5 (patch)
tree62d725fea9eed8a61662a7dec7389e0a2c4d54fb
parentBigInteger improvements (diff)
downloadBouncyCastle.NET-ed25519-283ab033ec1275a500b80a4c300edb6e4e43f7e5.tar.xz
Primes improvements
-rw-r--r--crypto/src/math/Primes.cs287
1 files changed, 101 insertions, 186 deletions
diff --git a/crypto/src/math/Primes.cs b/crypto/src/math/Primes.cs
index fb279f103..79bce32cd 100644
--- a/crypto/src/math/Primes.cs
+++ b/crypto/src/math/Primes.cs
@@ -1,15 +1,14 @@
 using System;
 
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Utilities;
 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
+    /// <summary>Utility methods for generating primes and testing for primality.</summary>
+    public static class Primes
     {
         public static readonly int SmallFactorLimit = 211;
 
@@ -17,12 +16,10 @@ namespace Org.BouncyCastle.Math
         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
+        /// <summary>Used to return the output from the
+        /// <see cref="EnhancedMRProbablePrimeTest(BigInteger, SecureRandom, int)">
+        /// Enhanced Miller-Rabin Probabilistic Primality Test</see></summary>
+        public sealed class MROutput
         {
             internal static MROutput ProbablyPrime()
             {
@@ -39,115 +36,83 @@ namespace Org.BouncyCastle.Math
                 return new MROutput(true, null);
             }
 
-            private readonly bool mProvablyComposite;
-            private readonly BigInteger mFactor;
+            private readonly bool m_provablyComposite;
+            private readonly BigInteger m_factor;
 
             private MROutput(bool provablyComposite, BigInteger factor)
             {
-                this.mProvablyComposite = provablyComposite;
-                this.mFactor = factor;
+                m_provablyComposite = provablyComposite;
+                m_factor = factor;
             }
 
-            public BigInteger Factor
-            {
-                get { return mFactor; }
-            }
+            public BigInteger Factor => m_factor;
 
-            public bool IsProvablyComposite
-            {
-                get { return mProvablyComposite; }
-            }
+            public bool IsProvablyComposite => m_provablyComposite;
 
-            public bool IsNotPrimePower
-            {
-                get { return mProvablyComposite && mFactor == null; }
-            }
+            public bool IsNotPrimePower => m_provablyComposite && m_factor == null;
         }
 
-        /**
-         * Used to return the output from the {@linkplain Primes#generateSTRandomPrime(Digest, int, byte[]) Shawe-Taylor Random_Prime Routine} 
-         */
-        public class STOutput
+        /// <summary>Used to return the output from the <see cref="GenerateSTRandomPrime(IDigest, int, byte[])">
+        /// Shawe-Taylor Random_Prime Routine</see></summary>
+        public sealed class STOutput
         {
-            private readonly BigInteger mPrime;
-            private readonly byte[] mPrimeSeed;
-            private readonly int mPrimeGenCounter;
+            private readonly BigInteger m_prime;
+            private readonly byte[] m_primeSeed;
+            private readonly int m_primeGenCounter;
 
             internal STOutput(BigInteger prime, byte[] primeSeed, int primeGenCounter)
             {
-                this.mPrime = prime;
-                this.mPrimeSeed = primeSeed;
-                this.mPrimeGenCounter = primeGenCounter;
+                m_prime = prime;
+                m_primeSeed = primeSeed;
+                m_primeGenCounter = primeGenCounter;
             }
 
-            public BigInteger Prime
-            {
-                get { return mPrime; }
-            }
+            public BigInteger Prime => m_prime;
 
-            public byte[] PrimeSeed
-            {
-                get { return mPrimeSeed; }
-            }
+            public byte[] PrimeSeed => m_primeSeed;
 
-            public int PrimeGenCounter
-            {
-                get { return mPrimeGenCounter; }
-            }
+            public int PrimeGenCounter => m_primeGenCounter;
         }
 
-        /**
-         * 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.
-         */
+        /// <summary>FIPS 186-4 C.6 Shawe-Taylor Random_Prime Routine.</summary>
+        /// <remarks>Construct a provable prime number using a hash function.</remarks>
+        /// <param name="hash">The <see cref="IDigest"/> instance to use (as "Hash()"). Cannot be null.</param>
+        /// <param name="length">The length (in bits) of the prime to be generated. Must be at least 2.</param>
+        /// <param name="inputSeed">The seed to be used for the generation of the requested prime. Cannot be null or
+        /// empty.</param>
+        /// <returns>An <see cref="STOutput"/> instance containing the requested prime.</returns>
         public static STOutput GenerateSTRandomPrime(IDigest hash, int length, byte[] inputSeed)
         {
             if (hash == null)
-                throw new ArgumentNullException("hash");
+                throw new ArgumentNullException(nameof(hash));
             if (length < 2)
-                throw new ArgumentException("must be >= 2", "length");
+                throw new ArgumentException("must be >= 2", nameof(length));
             if (inputSeed == null)
-                throw new ArgumentNullException("inputSeed");
+                throw new ArgumentNullException(nameof(inputSeed));
             if (inputSeed.Length == 0)
-                throw new ArgumentException("cannot be empty", "inputSeed");
+                throw new ArgumentException("cannot be empty", nameof(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.
-         */
+        /// <summary>FIPS 186-4 C.3.2 Enhanced Miller-Rabin Probabilistic Primality Test.</summary>
+        /// <remarks>
+        /// Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases. This is an alternative to
+        /// <see cref="IsMRProbablePrime(BigInteger, SecureRandom, int)"/> that provides more information about a
+        /// composite candidate, which may be useful when generating or validating RSA moduli.
+        /// </remarks>
+        /// <param name="candidate">The <see cref="BigInteger"/> instance to test for primality.</param>
+        /// <param name="random">The source of randomness to use to choose bases.</param>
+        /// <param name="iterations">The number of randomly-chosen bases to perform the test for.</param>
+        /// <returns>An <see cref="MROutput"/> instance that can be further queried for details.</returns>
         public static MROutput EnhancedMRProbablePrimeTest(BigInteger candidate, SecureRandom random, int iterations)
         {
-            CheckCandidate(candidate, "candidate");
+            CheckCandidate(candidate, nameof(candidate));
 
             if (random == null)
-                throw new ArgumentNullException("random");
+                throw new ArgumentNullException(nameof(random));
             if (iterations < 1)
-                throw new ArgumentException("must be > 0", "iterations");
+                throw new ArgumentException("must be > 0", nameof(iterations));
 
             if (candidate.BitLength == 2)
                 return MROutput.ProbablyPrime();
@@ -180,7 +145,7 @@ namespace Org.BouncyCastle.Math
                 BigInteger x = z;
                 for (int j = 1; j < a; ++j)
                 {
-                    z = z.ModPow(Two, w);
+                    z = z.Square().Mod(w);
 
                     if (z.Equals(wSubOne))
                     {
@@ -199,7 +164,7 @@ namespace Org.BouncyCastle.Math
                     if (!z.Equals(One))
                     {
                         x = z;
-                        z = z.ModPow(Two, w);
+                        z = z.Square().Mod(w);
 
                         if (!z.Equals(One))
                         {
@@ -219,46 +184,34 @@ namespace Org.BouncyCastle.Math
             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 <code>true</code> if the candidate is found to have any small factors,
-         *         <code>false</code> otherwise.
-         */
+        /// <summary>A fast check for small divisors, up to some implementation-specific limit.</summary>
+        /// <param name="candidate">The <see cref="BigInteger"/> instance to test for division by small factors.</param>
+        /// <returns><c>true</c> if the candidate is found to have any small factors, <c>false</c> otherwise.</returns>
         public static bool HasAnySmallFactors(BigInteger candidate)
         {
-            CheckCandidate(candidate, "candidate");
+            CheckCandidate(candidate, nameof(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 <code>false</code> if any witness to compositeness is found amongst the chosen bases
-         *         (so <code>candidate</code> is definitely NOT prime), or else <code>true</code>
-         *         (indicating primality with some probability dependent on the number of iterations
-         *         that were performed).
-         */
+        /// <summary>FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test.</summary>
+        /// <remarks>Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases.</remarks>
+        /// <param name="candidate">The <see cref="BigInteger"/> instance to test for primality.</param>
+        /// <param name="random">The source of randomness to use to choose bases.</param>
+        /// <param name="iterations">The number of randomly-chosen bases to perform the test for.</param>
+        /// <returns>
+        /// <c>false</c> if any witness to compositeness is found amongst the chosen bases (so
+        /// <paramref name="candidate"/> is definitely NOT prime), or else <c>true</c> (indicating primality with some
+        /// probability dependent on the number of iterations that were performed).
+        /// </returns>
         public static bool IsMRProbablePrime(BigInteger candidate, SecureRandom random, int iterations)
         {
-            CheckCandidate(candidate, "candidate");
+            CheckCandidate(candidate, nameof(candidate));
 
             if (random == null)
-                throw new ArgumentException("cannot be null", "random");
+                throw new ArgumentException("cannot be null", nameof(random));
             if (iterations < 1)
-                throw new ArgumentException("must be > 0", "iterations");
+                throw new ArgumentException("must be > 0", nameof(iterations));
 
             if (candidate.BitLength == 2)
                 return true;
@@ -283,25 +236,19 @@ namespace Org.BouncyCastle.Math
             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 <code>false</code> if the specified base is a witness to compositeness (so
-         *         <code>candidate</code> is definitely NOT prime), or else <code>true</code>.
-         */
+        /// <summary>FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test (to a fixed base).</summary>
+        /// <remarks>Run a single iteration of the Miller-Rabin algorithm against the specified base.</remarks>
+        /// <param name="candidate">The <see cref="BigInteger"/> instance to test for primality.</param>
+        /// <param name="baseValue">The base value to use for this iteration.</param>
+        /// <returns><c>false</c> if <paramref name="baseValue"/> is a witness to compositeness (so
+        /// <paramref name="candidate"/> is definitely NOT prime), or else <c>true</c>.</returns>
         public static bool IsMRProbablePrimeToBase(BigInteger candidate, BigInteger baseValue)
         {
-            CheckCandidate(candidate, "candidate");
-            CheckCandidate(baseValue, "baseValue");
+            CheckCandidate(candidate, nameof(candidate));
+            CheckCandidate(baseValue, nameof(baseValue));
 
             if (baseValue.CompareTo(candidate.Subtract(One)) >= 0)
-                throw new ArgumentException("must be < ('candidate' - 1)", "baseValue");
+                throw new ArgumentException("must be < ('candidate' - 1)", nameof(baseValue));
 
             if (candidate.BitLength == 2)
                 return true;
@@ -411,59 +358,52 @@ namespace Org.BouncyCastle.Math
             if (z.Equals(One) || z.Equals(wSubOne))
                 return true;
 
-            bool result = false;
-
             for (int j = 1; j < a; ++j)
             {
-                z = z.ModPow(Two, w);
+                z = z.Square().Mod(w);
 
                 if (z.Equals(wSubOne))
-                {
-                    result = true;
-                    break;
-                }
+                    return true;
 
                 if (z.Equals(One))
                     return false;
             }
 
-            return result;
+            return false;
         }
 
         private static STOutput ImplSTRandomPrime(IDigest d, int length, byte[] primeSeed)
         {
             int dLen = d.GetDigestSize();
+            int cLen = System.Math.Max(4, dLen);
 
             if (length < 33)
             {
                 int primeGenCounter = 0;
 
-                byte[] c0 = new byte[dLen];
-                byte[] c1 = new byte[dLen];
+                byte[] c0 = new byte[cLen];
+                byte[] c1 = new byte[cLen];
 
                 for (;;)
                 {
-                    Hash(d, primeSeed, c0, 0);
+                    Hash(d, primeSeed, c0, cLen - dLen);
                     Inc(primeSeed, 1);
 
-                    Hash(d, primeSeed, c1, 0);
+                    Hash(d, primeSeed, c1, cLen - dLen);
                     Inc(primeSeed, 1);
 
-                    uint c = Extract32(c0) ^ Extract32(c1);
-                    c &= (uint.MaxValue >> (32 - length));
+                    uint c = Pack.BE_To_UInt32(c0, cLen - 4)
+                           ^ Pack.BE_To_UInt32(c1, cLen - 4);
+                    c &= uint.MaxValue >> (32 - length);
                     c |= (1U << (length - 1)) | 1U;
 
                     ++primeGenCounter;
 
                     if (IsPrime32(c))
-                    {
-                        return new STOutput(BigInteger.ValueOf((long)c), primeSeed, primeGenCounter);
-                    }
+                        return new STOutput(BigInteger.ValueOf(c), primeSeed, primeGenCounter);
 
                     if (primeGenCounter > (4 * length))
-                    {
                         throw new InvalidOperationException("Too many iterations in Shawe-Taylor Random_Prime Routine");
-                    }
                 }
             }
 
@@ -508,7 +448,11 @@ namespace Org.BouncyCastle.Math
                      * 
                      * NOTE: 'primeSeed' is still incremented as if we performed the full check!
                      */
-                    if (!ImplHasAnySmallFactors(c))
+                    if (ImplHasAnySmallFactors(c))
+                    {
+                        Inc(primeSeed, iterations + 1);
+                    }
+                    else
                     {
                         BigInteger a = HashGen(d, primeSeed, iterations + 1);
                         a = a.Mod(c.Subtract(Three)).Add(Two);
@@ -519,19 +463,11 @@ namespace Org.BouncyCastle.Math
                         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);
@@ -539,20 +475,6 @@ namespace Org.BouncyCastle.Math
             }
         }
 
-        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);
@@ -590,19 +512,15 @@ namespace Org.BouncyCastle.Math
              * Use wheel factorization with 2, 3, 5 to select trial divisors.
              */
 
-            if (x <= 5)
-            {
-                return x == 2 || x == 3 || x == 5;
-            }
+            if (x < 32)
+                return ((1 << (int)x) & 0b0010_0000_1000_1010_0010_1000_1010_1100) != 0;
 
-            if ((x & 1) == 0 || (x % 3) == 0 || (x % 5) == 0)
-            {
+            if (((1 << (int)(x % 30U)) & 0b1010_0000_1000_1010_0010_1000_1000_0010U) == 0)
                 return false;
-            }
 
             uint[] ds = new uint[]{ 1, 7, 11, 13, 17, 19, 23, 29 };
             uint b = 0;
-            for (int pos = 1; ; pos = 0)
+            for (int pos = 1;; pos = 0)
             {
                 /*
                  * Trial division by wheel-selected divisors
@@ -611,18 +529,15 @@ namespace Org.BouncyCastle.Math
                 {
                     uint d = b + ds[pos];
                     if (x % d == 0)
-                    {
-                        return x < 30;
-                    }
+                        return false;
+
                     ++pos;
                 }
 
                 b += 30;
 
                 if ((b >> 16 != 0) || (b * b >= x))
-                {
                     return true;
-                }
             }
         }
     }