The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

245 lines
6.4KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. namespace PrimesHelpers
  21. {
  22. static void createSmallSieve (const int numBits, BigInteger& result)
  23. {
  24. result.setBit (numBits);
  25. result.clearBit (numBits); // to enlarge the array
  26. result.setBit (0);
  27. int n = 2;
  28. do
  29. {
  30. for (int i = n + n; i < numBits; i += n)
  31. result.setBit (i);
  32. n = result.findNextClearBit (n + 1);
  33. }
  34. while (n <= (numBits >> 1));
  35. }
  36. static void bigSieve (const BigInteger& base, const int numBits, BigInteger& result,
  37. const BigInteger& smallSieve, const int smallSieveSize)
  38. {
  39. jassert (! base[0]); // must be even!
  40. result.setBit (numBits);
  41. result.clearBit (numBits); // to enlarge the array
  42. int index = smallSieve.findNextClearBit (0);
  43. do
  44. {
  45. const unsigned int prime = ((unsigned int) index << 1) + 1;
  46. BigInteger r (base), remainder;
  47. r.divideBy (prime, remainder);
  48. unsigned int i = prime - remainder.getBitRangeAsInt (0, 32);
  49. if (r.isZero())
  50. i += prime;
  51. if ((i & 1) == 0)
  52. i += prime;
  53. i = (i - 1) >> 1;
  54. while (i < (unsigned int) numBits)
  55. {
  56. result.setBit ((int) i);
  57. i += prime;
  58. }
  59. index = smallSieve.findNextClearBit (index + 1);
  60. }
  61. while (index < smallSieveSize);
  62. }
  63. static bool findCandidate (const BigInteger& base, const BigInteger& sieve,
  64. const int numBits, BigInteger& result, const int certainty)
  65. {
  66. for (int i = 0; i < numBits; ++i)
  67. {
  68. if (! sieve[i])
  69. {
  70. result = base + (unsigned int) ((i << 1) + 1);
  71. if (Primes::isProbablyPrime (result, certainty))
  72. return true;
  73. }
  74. }
  75. return false;
  76. }
  77. static bool passesMillerRabin (const BigInteger& n, int iterations)
  78. {
  79. const BigInteger one (1), two (2);
  80. const BigInteger nMinusOne (n - one);
  81. BigInteger d (nMinusOne);
  82. const int s = d.findNextSetBit (0);
  83. d >>= s;
  84. BigInteger smallPrimes;
  85. int numBitsInSmallPrimes = 0;
  86. for (;;)
  87. {
  88. numBitsInSmallPrimes += 256;
  89. createSmallSieve (numBitsInSmallPrimes, smallPrimes);
  90. const int numPrimesFound = numBitsInSmallPrimes - smallPrimes.countNumberOfSetBits();
  91. if (numPrimesFound > iterations + 1)
  92. break;
  93. }
  94. int smallPrime = 2;
  95. while (--iterations >= 0)
  96. {
  97. smallPrime = smallPrimes.findNextClearBit (smallPrime + 1);
  98. BigInteger r (smallPrime);
  99. r.exponentModulo (d, n);
  100. if (r != one && r != nMinusOne)
  101. {
  102. for (int j = 0; j < s; ++j)
  103. {
  104. r.exponentModulo (two, n);
  105. if (r == nMinusOne)
  106. break;
  107. }
  108. if (r != nMinusOne)
  109. return false;
  110. }
  111. }
  112. return true;
  113. }
  114. }
  115. //==============================================================================
  116. BigInteger Primes::createProbablePrime (const int bitLength,
  117. const int certainty,
  118. const int* randomSeeds,
  119. int numRandomSeeds)
  120. {
  121. using namespace PrimesHelpers;
  122. int defaultSeeds [16];
  123. if (numRandomSeeds <= 0)
  124. {
  125. randomSeeds = defaultSeeds;
  126. numRandomSeeds = numElementsInArray (defaultSeeds);
  127. Random r1, r2;
  128. for (int j = 10; --j >= 0;)
  129. {
  130. r1.setSeedRandomly();
  131. for (int i = numRandomSeeds; --i >= 0;)
  132. defaultSeeds[i] ^= r1.nextInt() ^ r2.nextInt();
  133. }
  134. }
  135. BigInteger smallSieve;
  136. const int smallSieveSize = 15000;
  137. createSmallSieve (smallSieveSize, smallSieve);
  138. BigInteger p;
  139. for (int i = numRandomSeeds; --i >= 0;)
  140. {
  141. BigInteger p2;
  142. Random r (randomSeeds[i]);
  143. r.fillBitsRandomly (p2, 0, bitLength);
  144. p ^= p2;
  145. }
  146. p.setBit (bitLength - 1);
  147. p.clearBit (0);
  148. const int searchLen = jmax (1024, (bitLength / 20) * 64);
  149. while (p.getHighestBit() < bitLength)
  150. {
  151. p += 2 * searchLen;
  152. BigInteger sieve;
  153. bigSieve (p, searchLen, sieve,
  154. smallSieve, smallSieveSize);
  155. BigInteger candidate;
  156. if (findCandidate (p, sieve, searchLen, candidate, certainty))
  157. return candidate;
  158. }
  159. jassertfalse;
  160. return BigInteger();
  161. }
  162. bool Primes::isProbablyPrime (const BigInteger& number, const int certainty)
  163. {
  164. using namespace PrimesHelpers;
  165. if (! number[0])
  166. return false;
  167. if (number.getHighestBit() <= 10)
  168. {
  169. const unsigned int num = number.getBitRangeAsInt (0, 10);
  170. for (unsigned int i = num / 2; --i > 1;)
  171. if (num % i == 0)
  172. return false;
  173. return true;
  174. }
  175. else
  176. {
  177. if (number.findGreatestCommonDivisor (2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23) != 1)
  178. return false;
  179. return passesMillerRabin (number, certainty);
  180. }
  181. }
  182. } // namespace juce