Primes.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Security;
  7. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  8. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Math
  9. {
  10. /// <summary>Utility methods for generating primes and testing for primality.</summary>
  11. public static class Primes
  12. {
  13. public static readonly int SmallFactorLimit = 211;
  14. private static readonly BigInteger One = BigInteger.One;
  15. private static readonly BigInteger Two = BigInteger.Two;
  16. private static readonly BigInteger Three = BigInteger.Three;
  17. /// <summary>Used to return the output from the
  18. /// <see cref="EnhancedMRProbablePrimeTest(BigInteger, SecureRandom, int)">
  19. /// Enhanced Miller-Rabin Probabilistic Primality Test</see></summary>
  20. public sealed class MROutput
  21. {
  22. internal static MROutput ProbablyPrime()
  23. {
  24. return new MROutput(false, null);
  25. }
  26. internal static MROutput ProvablyCompositeWithFactor(BigInteger factor)
  27. {
  28. return new MROutput(true, factor);
  29. }
  30. internal static MROutput ProvablyCompositeNotPrimePower()
  31. {
  32. return new MROutput(true, null);
  33. }
  34. private readonly bool m_provablyComposite;
  35. private readonly BigInteger m_factor;
  36. private MROutput(bool provablyComposite, BigInteger factor)
  37. {
  38. m_provablyComposite = provablyComposite;
  39. m_factor = factor;
  40. }
  41. public BigInteger Factor => m_factor;
  42. public bool IsProvablyComposite => m_provablyComposite;
  43. public bool IsNotPrimePower => m_provablyComposite && m_factor == null;
  44. }
  45. /// <summary>Used to return the output from the <see cref="GenerateSTRandomPrime(IDigest, int, byte[])">
  46. /// Shawe-Taylor Random_Prime Routine</see></summary>
  47. public sealed class STOutput
  48. {
  49. private readonly BigInteger m_prime;
  50. private readonly byte[] m_primeSeed;
  51. private readonly int m_primeGenCounter;
  52. internal STOutput(BigInteger prime, byte[] primeSeed, int primeGenCounter)
  53. {
  54. m_prime = prime;
  55. m_primeSeed = primeSeed;
  56. m_primeGenCounter = primeGenCounter;
  57. }
  58. public BigInteger Prime => m_prime;
  59. public byte[] PrimeSeed => m_primeSeed;
  60. public int PrimeGenCounter => m_primeGenCounter;
  61. }
  62. /// <summary>FIPS 186-4 C.6 Shawe-Taylor Random_Prime Routine.</summary>
  63. /// <remarks>Construct a provable prime number using a hash function.</remarks>
  64. /// <param name="hash">The <see cref="IDigest"/> instance to use (as "Hash()"). Cannot be null.</param>
  65. /// <param name="length">The length (in bits) of the prime to be generated. Must be at least 2.</param>
  66. /// <param name="inputSeed">The seed to be used for the generation of the requested prime. Cannot be null or
  67. /// empty.</param>
  68. /// <returns>An <see cref="STOutput"/> instance containing the requested prime.</returns>
  69. public static STOutput GenerateSTRandomPrime(IDigest hash, int length, byte[] inputSeed)
  70. {
  71. if (hash == null)
  72. throw new ArgumentNullException(nameof(hash));
  73. if (length < 2)
  74. throw new ArgumentException("must be >= 2", nameof(length));
  75. if (inputSeed == null)
  76. throw new ArgumentNullException(nameof(inputSeed));
  77. if (inputSeed.Length == 0)
  78. throw new ArgumentException("cannot be empty", nameof(inputSeed));
  79. return ImplSTRandomPrime(hash, length, Arrays.Clone(inputSeed));
  80. }
  81. /// <summary>FIPS 186-4 C.3.2 Enhanced Miller-Rabin Probabilistic Primality Test.</summary>
  82. /// <remarks>
  83. /// Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases. This is an alternative to
  84. /// <see cref="IsMRProbablePrime(BigInteger, SecureRandom, int)"/> that provides more information about a
  85. /// composite candidate, which may be useful when generating or validating RSA moduli.
  86. /// </remarks>
  87. /// <param name="candidate">The <see cref="BigInteger"/> instance to test for primality.</param>
  88. /// <param name="random">The source of randomness to use to choose bases.</param>
  89. /// <param name="iterations">The number of randomly-chosen bases to perform the test for.</param>
  90. /// <returns>An <see cref="MROutput"/> instance that can be further queried for details.</returns>
  91. public static MROutput EnhancedMRProbablePrimeTest(BigInteger candidate, SecureRandom random, int iterations)
  92. {
  93. CheckCandidate(candidate, nameof(candidate));
  94. if (random == null)
  95. throw new ArgumentNullException(nameof(random));
  96. if (iterations < 1)
  97. throw new ArgumentException("must be > 0", nameof(iterations));
  98. if (candidate.BitLength == 2)
  99. return MROutput.ProbablyPrime();
  100. if (!candidate.TestBit(0))
  101. return MROutput.ProvablyCompositeWithFactor(Two);
  102. BigInteger w = candidate;
  103. BigInteger wSubOne = candidate.Subtract(One);
  104. BigInteger wSubTwo = candidate.Subtract(Two);
  105. int a = wSubOne.GetLowestSetBit();
  106. BigInteger m = wSubOne.ShiftRight(a);
  107. for (int i = 0; i < iterations; ++i)
  108. {
  109. BigInteger b = BigIntegers.CreateRandomInRange(Two, wSubTwo, random);
  110. BigInteger g = b.Gcd(w);
  111. if (g.CompareTo(One) > 0)
  112. return MROutput.ProvablyCompositeWithFactor(g);
  113. BigInteger z = b.ModPow(m, w);
  114. if (z.Equals(One) || z.Equals(wSubOne))
  115. continue;
  116. bool primeToBase = false;
  117. BigInteger x = z;
  118. for (int j = 1; j < a; ++j)
  119. {
  120. z = z.Square().Mod(w);
  121. if (z.Equals(wSubOne))
  122. {
  123. primeToBase = true;
  124. break;
  125. }
  126. if (z.Equals(One))
  127. break;
  128. x = z;
  129. }
  130. if (!primeToBase)
  131. {
  132. if (!z.Equals(One))
  133. {
  134. x = z;
  135. z = z.Square().Mod(w);
  136. if (!z.Equals(One))
  137. {
  138. x = z;
  139. }
  140. }
  141. g = x.Subtract(One).Gcd(w);
  142. if (g.CompareTo(One) > 0)
  143. return MROutput.ProvablyCompositeWithFactor(g);
  144. return MROutput.ProvablyCompositeNotPrimePower();
  145. }
  146. }
  147. return MROutput.ProbablyPrime();
  148. }
  149. /// <summary>A fast check for small divisors, up to some implementation-specific limit.</summary>
  150. /// <param name="candidate">The <see cref="BigInteger"/> instance to test for division by small factors.</param>
  151. /// <returns><c>true</c> if the candidate is found to have any small factors, <c>false</c> otherwise.</returns>
  152. public static bool HasAnySmallFactors(BigInteger candidate)
  153. {
  154. CheckCandidate(candidate, nameof(candidate));
  155. return ImplHasAnySmallFactors(candidate);
  156. }
  157. /// <summary>FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test.</summary>
  158. /// <remarks>Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases.</remarks>
  159. /// <param name="candidate">The <see cref="BigInteger"/> instance to test for primality.</param>
  160. /// <param name="random">The source of randomness to use to choose bases.</param>
  161. /// <param name="iterations">The number of randomly-chosen bases to perform the test for.</param>
  162. /// <returns>
  163. /// <c>false</c> if any witness to compositeness is found amongst the chosen bases (so
  164. /// <paramref name="candidate"/> is definitely NOT prime), or else <c>true</c> (indicating primality with some
  165. /// probability dependent on the number of iterations that were performed).
  166. /// </returns>
  167. public static bool IsMRProbablePrime(BigInteger candidate, SecureRandom random, int iterations)
  168. {
  169. CheckCandidate(candidate, nameof(candidate));
  170. if (random == null)
  171. throw new ArgumentException("cannot be null", nameof(random));
  172. if (iterations < 1)
  173. throw new ArgumentException("must be > 0", nameof(iterations));
  174. if (candidate.BitLength == 2)
  175. return true;
  176. if (!candidate.TestBit(0))
  177. return false;
  178. BigInteger w = candidate;
  179. BigInteger wSubOne = candidate.Subtract(One);
  180. BigInteger wSubTwo = candidate.Subtract(Two);
  181. int a = wSubOne.GetLowestSetBit();
  182. BigInteger m = wSubOne.ShiftRight(a);
  183. for (int i = 0; i < iterations; ++i)
  184. {
  185. BigInteger b = BigIntegers.CreateRandomInRange(Two, wSubTwo, random);
  186. if (!ImplMRProbablePrimeToBase(w, wSubOne, m, a, b))
  187. return false;
  188. }
  189. return true;
  190. }
  191. /// <summary>FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test (to a fixed base).</summary>
  192. /// <remarks>Run a single iteration of the Miller-Rabin algorithm against the specified base.</remarks>
  193. /// <param name="candidate">The <see cref="BigInteger"/> instance to test for primality.</param>
  194. /// <param name="baseValue">The base value to use for this iteration.</param>
  195. /// <returns><c>false</c> if <paramref name="baseValue"/> is a witness to compositeness (so
  196. /// <paramref name="candidate"/> is definitely NOT prime), or else <c>true</c>.</returns>
  197. public static bool IsMRProbablePrimeToBase(BigInteger candidate, BigInteger baseValue)
  198. {
  199. CheckCandidate(candidate, nameof(candidate));
  200. CheckCandidate(baseValue, nameof(baseValue));
  201. if (baseValue.CompareTo(candidate.Subtract(One)) >= 0)
  202. throw new ArgumentException("must be < ('candidate' - 1)", nameof(baseValue));
  203. if (candidate.BitLength == 2)
  204. return true;
  205. BigInteger w = candidate;
  206. BigInteger wSubOne = candidate.Subtract(One);
  207. int a = wSubOne.GetLowestSetBit();
  208. BigInteger m = wSubOne.ShiftRight(a);
  209. return ImplMRProbablePrimeToBase(w, wSubOne, m, a, baseValue);
  210. }
  211. private static void CheckCandidate(BigInteger n, string name)
  212. {
  213. if (n == null || n.SignValue < 1 || n.BitLength < 2)
  214. throw new ArgumentException("must be non-null and >= 2", name);
  215. }
  216. private static bool ImplHasAnySmallFactors(BigInteger x)
  217. {
  218. /*
  219. * Bundle trial divisors into ~32-bit moduli then use fast tests on the ~32-bit remainders.
  220. */
  221. int m = 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23;
  222. int r = x.Mod(BigInteger.ValueOf(m)).IntValue;
  223. if ((r % 2) == 0 || (r % 3) == 0 || (r % 5) == 0 || (r % 7) == 0 || (r % 11) == 0 || (r % 13) == 0
  224. || (r % 17) == 0 || (r % 19) == 0 || (r % 23) == 0)
  225. {
  226. return true;
  227. }
  228. m = 29 * 31 * 37 * 41 * 43;
  229. r = x.Mod(BigInteger.ValueOf(m)).IntValue;
  230. if ((r % 29) == 0 || (r % 31) == 0 || (r % 37) == 0 || (r % 41) == 0 || (r % 43) == 0)
  231. {
  232. return true;
  233. }
  234. m = 47 * 53 * 59 * 61 * 67;
  235. r = x.Mod(BigInteger.ValueOf(m)).IntValue;
  236. if ((r % 47) == 0 || (r % 53) == 0 || (r % 59) == 0 || (r % 61) == 0 || (r % 67) == 0)
  237. {
  238. return true;
  239. }
  240. m = 71 * 73 * 79 * 83;
  241. r = x.Mod(BigInteger.ValueOf(m)).IntValue;
  242. if ((r % 71) == 0 || (r % 73) == 0 || (r % 79) == 0 || (r % 83) == 0)
  243. {
  244. return true;
  245. }
  246. m = 89 * 97 * 101 * 103;
  247. r = x.Mod(BigInteger.ValueOf(m)).IntValue;
  248. if ((r % 89) == 0 || (r % 97) == 0 || (r % 101) == 0 || (r % 103) == 0)
  249. {
  250. return true;
  251. }
  252. m = 107 * 109 * 113 * 127;
  253. r = x.Mod(BigInteger.ValueOf(m)).IntValue;
  254. if ((r % 107) == 0 || (r % 109) == 0 || (r % 113) == 0 || (r % 127) == 0)
  255. {
  256. return true;
  257. }
  258. m = 131 * 137 * 139 * 149;
  259. r = x.Mod(BigInteger.ValueOf(m)).IntValue;
  260. if ((r % 131) == 0 || (r % 137) == 0 || (r % 139) == 0 || (r % 149) == 0)
  261. {
  262. return true;
  263. }
  264. m = 151 * 157 * 163 * 167;
  265. r = x.Mod(BigInteger.ValueOf(m)).IntValue;
  266. if ((r % 151) == 0 || (r % 157) == 0 || (r % 163) == 0 || (r % 167) == 0)
  267. {
  268. return true;
  269. }
  270. m = 173 * 179 * 181 * 191;
  271. r = x.Mod(BigInteger.ValueOf(m)).IntValue;
  272. if ((r % 173) == 0 || (r % 179) == 0 || (r % 181) == 0 || (r % 191) == 0)
  273. {
  274. return true;
  275. }
  276. m = 193 * 197 * 199 * 211;
  277. r = x.Mod(BigInteger.ValueOf(m)).IntValue;
  278. if ((r % 193) == 0 || (r % 197) == 0 || (r % 199) == 0 || (r % 211) == 0)
  279. {
  280. return true;
  281. }
  282. /*
  283. * NOTE: Unit tests depend on SMALL_FACTOR_LIMIT matching the
  284. * highest small factor tested here.
  285. */
  286. return false;
  287. }
  288. private static bool ImplMRProbablePrimeToBase(BigInteger w, BigInteger wSubOne, BigInteger m, int a, BigInteger b)
  289. {
  290. BigInteger z = b.ModPow(m, w);
  291. if (z.Equals(One) || z.Equals(wSubOne))
  292. return true;
  293. for (int j = 1; j < a; ++j)
  294. {
  295. z = z.Square().Mod(w);
  296. if (z.Equals(wSubOne))
  297. return true;
  298. if (z.Equals(One))
  299. return false;
  300. }
  301. return false;
  302. }
  303. private static STOutput ImplSTRandomPrime(IDigest d, int length, byte[] primeSeed)
  304. {
  305. int dLen = d.GetDigestSize();
  306. int cLen = System.Math.Max(4, dLen);
  307. if (length < 33)
  308. {
  309. int primeGenCounter = 0;
  310. byte[] c0 = new byte[cLen];
  311. byte[] c1 = new byte[cLen];
  312. for (;;)
  313. {
  314. Hash(d, primeSeed, c0, cLen - dLen);
  315. Inc(primeSeed, 1);
  316. Hash(d, primeSeed, c1, cLen - dLen);
  317. Inc(primeSeed, 1);
  318. uint c = Pack.BE_To_UInt32(c0, cLen - 4)
  319. ^ Pack.BE_To_UInt32(c1, cLen - 4);
  320. c &= uint.MaxValue >> (32 - length);
  321. c |= (1U << (length - 1)) | 1U;
  322. ++primeGenCounter;
  323. if (IsPrime32(c))
  324. return new STOutput(BigInteger.ValueOf(c), primeSeed, primeGenCounter);
  325. if (primeGenCounter > (4 * length))
  326. throw new InvalidOperationException("Too many iterations in Shawe-Taylor Random_Prime Routine");
  327. }
  328. }
  329. STOutput rec = ImplSTRandomPrime(d, (length + 3)/2, primeSeed);
  330. {
  331. BigInteger c0 = rec.Prime;
  332. primeSeed = rec.PrimeSeed;
  333. int primeGenCounter = rec.PrimeGenCounter;
  334. int outlen = 8 * dLen;
  335. int iterations = (length - 1)/outlen;
  336. int oldCounter = primeGenCounter;
  337. BigInteger x = HashGen(d, primeSeed, iterations + 1);
  338. x = x.Mod(One.ShiftLeft(length - 1)).SetBit(length - 1);
  339. BigInteger c0x2 = c0.ShiftLeft(1);
  340. BigInteger tx2 = x.Subtract(One).Divide(c0x2).Add(One).ShiftLeft(1);
  341. int dt = 0;
  342. BigInteger c = tx2.Multiply(c0).Add(One);
  343. /*
  344. * TODO Since the candidate primes are generated by constant steps ('c0x2'),
  345. * sieving could be used here in place of the 'HasAnySmallFactors' approach.
  346. */
  347. for (;;)
  348. {
  349. if (c.BitLength > length)
  350. {
  351. tx2 = One.ShiftLeft(length - 1).Subtract(One).Divide(c0x2).Add(One).ShiftLeft(1);
  352. c = tx2.Multiply(c0).Add(One);
  353. }
  354. ++primeGenCounter;
  355. /*
  356. * This is an optimization of the original algorithm, using trial division to screen out
  357. * many non-primes quickly.
  358. *
  359. * NOTE: 'primeSeed' is still incremented as if we performed the full check!
  360. */
  361. if (ImplHasAnySmallFactors(c))
  362. {
  363. Inc(primeSeed, iterations + 1);
  364. }
  365. else
  366. {
  367. BigInteger a = HashGen(d, primeSeed, iterations + 1);
  368. a = a.Mod(c.Subtract(Three)).Add(Two);
  369. tx2 = tx2.Add(BigInteger.ValueOf(dt));
  370. dt = 0;
  371. BigInteger z = a.ModPow(tx2, c);
  372. if (c.Gcd(z.Subtract(One)).Equals(One) && z.ModPow(c0, c).Equals(One))
  373. return new STOutput(c, primeSeed, primeGenCounter);
  374. }
  375. if (primeGenCounter >= ((4 * length) + oldCounter))
  376. throw new InvalidOperationException("Too many iterations in Shawe-Taylor Random_Prime Routine");
  377. dt += 2;
  378. c = c.Add(c0x2);
  379. }
  380. }
  381. }
  382. private static void Hash(IDigest d, byte[] input, byte[] output, int outPos)
  383. {
  384. d.BlockUpdate(input, 0, input.Length);
  385. d.DoFinal(output, outPos);
  386. }
  387. private static BigInteger HashGen(IDigest d, byte[] seed, int count)
  388. {
  389. int dLen = d.GetDigestSize();
  390. int pos = count * dLen;
  391. byte[] buf = new byte[pos];
  392. for (int i = 0; i < count; ++i)
  393. {
  394. pos -= dLen;
  395. Hash(d, seed, buf, pos);
  396. Inc(seed, 1);
  397. }
  398. return new BigInteger(1, buf);
  399. }
  400. private static void Inc(byte[] seed, int c)
  401. {
  402. int pos = seed.Length;
  403. while (c > 0 && --pos >= 0)
  404. {
  405. c += seed[pos];
  406. seed[pos] = (byte)c;
  407. c >>= 8;
  408. }
  409. }
  410. private static bool IsPrime32(uint x)
  411. {
  412. /*
  413. * Use wheel factorization with 2, 3, 5 to select trial divisors.
  414. */
  415. if (x < 32)
  416. return ((1 << (int)x) & 0b0010_0000_1000_1010_0010_1000_1010_1100) != 0;
  417. if (((1 << (int)(x % 30U)) & 0b1010_0000_1000_1010_0010_1000_1000_0010U) == 0)
  418. return false;
  419. uint[] ds = new uint[]{ 1, 7, 11, 13, 17, 19, 23, 29 };
  420. uint b = 0;
  421. for (int pos = 1;; pos = 0)
  422. {
  423. /*
  424. * Trial division by wheel-selected divisors
  425. */
  426. while (pos < ds.Length)
  427. {
  428. uint d = b + ds[pos];
  429. if (x % d == 0)
  430. return false;
  431. ++pos;
  432. }
  433. b += 30;
  434. if ((b >> 16 != 0) || (b * b >= x))
  435. return true;
  436. }
  437. }
  438. }
  439. }
  440. #pragma warning restore
  441. #endif