lucas-pocklington_primality_proving.sf 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 10 January 2020
  4. # https://github.com/trizen
  5. # Prove the primality of a number N, using the Lucas `U` sequence and the Pocklington primality test, recursively factoring N-1 and N+1 (whichever is easier to factorize first).
  6. # See also:
  7. # https://en.wikipedia.org/wiki/Pocklington_primality_test
  8. # https://en.wikipedia.org/wiki/Primality_certificate
  9. # https://mathworld.wolfram.com/PrattCertificate.html
  10. # https://math.stackexchange.com/questions/663341/n1-primality-proving-is-slow
  11. func lucas_pocklington_primality_proving(n, lim=2**64) is cached {
  12. if ((n <= lim) || (n <= 2)) {
  13. return n.is_prime
  14. }
  15. n.is_prob_prime || return false
  16. var nm1 = n-1
  17. var np1 = n+1
  18. const TRIAL_LIMIT = 1e6
  19. var f1 = nm1.trial_factor(TRIAL_LIMIT)
  20. var f2 = np1.trial_factor(TRIAL_LIMIT)
  21. var B1 = f1.pop
  22. var B2 = f2.pop
  23. if (B1 < TRIAL_LIMIT) {
  24. f1 << B1
  25. B1 = 1
  26. }
  27. if (B2 < TRIAL_LIMIT) {
  28. f2 << B2
  29. B2 = 1
  30. }
  31. if (f1.prod<B1 && f2.prod<B2) {
  32. if (B1 < B2) {
  33. if (__FUNC__(B1, lim)) {
  34. f1 << B1
  35. B1 = 1
  36. }
  37. elsif (__FUNC__(B2, lim)) {
  38. f2 << B2
  39. B2 = 1
  40. }
  41. }
  42. else {
  43. if (__FUNC__(B2, lim)) {
  44. f2 << B2
  45. B2 = 1
  46. }
  47. elsif (__FUNC__(B1, lim)) {
  48. f1 << B1
  49. B1 = 1
  50. }
  51. }
  52. }
  53. func pocklington_prove_primality() {
  54. f1.uniq.all {|p|
  55. 1..Inf -> any {
  56. var a = irand(2, nm1)
  57. n.is_strong_pseudoprime(a) || return false
  58. if (is_coprime(powmod(a, nm1/p, n) - 1, n)) {
  59. say [a, p]
  60. true
  61. }
  62. else {
  63. false
  64. }
  65. }
  66. }
  67. }
  68. func find_PQD() {
  69. var l = min(1e6, n-1)
  70. loop {
  71. var P = (irand(1,l))
  72. var Q = (irand(1,l) * [1,-1].rand)
  73. var D = (P*P - 4*Q)
  74. next if is_square(D % n)
  75. next if (P >= n)
  76. next if (Q >= n)
  77. next if (kronecker(D,n) != -1)
  78. return (P, Q, D)
  79. }
  80. }
  81. func lucas_prove_primality() {
  82. var (P, Q, D) = find_PQD()
  83. n.is_strong_pseudoprime(P+1) || return false
  84. lucasUmod(P, Q, np1, n) == 0 || return false
  85. return f2.uniq.all {|p|
  86. 1..Inf -> any {
  87. assert_eq(D, P*P - 4*Q)
  88. if (P>=n || Q>=n) {
  89. return __FUNC__()
  90. }
  91. if (is_coprime(lucasUmod(P, Q, np1/p, n), n)) {
  92. say [P, Q, p]
  93. true
  94. }
  95. else {
  96. (P, Q) = (P+2, P+Q+1)
  97. n.is_strong_pseudoprime(P) || return false
  98. false
  99. }
  100. }
  101. }
  102. }
  103. loop {
  104. var A1 = f1.prod
  105. var A2 = f2.prod
  106. if (A1>B1 && is_coprime(A1, B1)) {
  107. say "\n:: N-1 primality proving of: #{n}"
  108. return pocklington_prove_primality()
  109. }
  110. if (A2>B2 && is_coprime(A2, B2)) {
  111. say "\n:: N+1 primality proving of: #{n}"
  112. return lucas_prove_primality()
  113. }
  114. for p in ((B1*B2).ecm_factor) {
  115. if (B1%p == 0 && __FUNC__(p, lim)) {
  116. while (B1%p == 0) {
  117. f1 << p
  118. A1 *= p
  119. B1 /= p
  120. }
  121. if (__FUNC__(B1, lim)) {
  122. f1 << B1
  123. A1 *= B1
  124. B1 /= B1
  125. }
  126. break if (A1 > B1)
  127. }
  128. if (B2%p == 0 && __FUNC__(p, lim)) {
  129. while (B2%p == 0) {
  130. f2 << p
  131. A2 *= p
  132. B2 /= p
  133. }
  134. if (__FUNC__(B2, lim)) {
  135. f2 << B2
  136. A2 *= B2
  137. B2 /= B2
  138. }
  139. break if (A2 > B2)
  140. }
  141. }
  142. }
  143. }
  144. say lucas_pocklington_primality_proving(610347760013638302077109801592928591036750649061221421483459)
  145. __END__
  146. :: N-1 proving primality of: 10200837030535946432415781
  147. [8109413315100632090346069, 2]
  148. [6217691240797091025962993, 3]
  149. [1683759098694605074537760, 5]
  150. [6095863793857504156729879, 103]
  151. [7370888006164389927696208, 3167]
  152. [5752952585500377495777556, 57910426226274407]
  153. :: N+1 proving primality of: 9596539444846996965759470133559
  154. [707331559, 2780343822, 2]
  155. [707331559, 2780343822, 5]
  156. [707331559, 2780343822, 29]
  157. [707331559, 2780343822, 811]
  158. [707331559, 2780343822, 10200837030535946432415781]
  159. :: N+1 proving primality of: 72274331657576353317849179356870186439080146899611
  160. [463737873, 907446171, 2]
  161. [463737875, 1371184045, 7]
  162. [463737875, 1371184045, 271]
  163. [463737875, 1371184045, 1597]
  164. [463737875, 1371184045, 32843]
  165. [463737875, 1371184045, 2703313]
  166. [463737875, 1371184045, 9596539444846996965759470133559]
  167. :: N-1 proving primality of: 610347760013638302077109801592928591036750649061221421483459
  168. [458927913562990853766467404877977676633964854423861109730700, 2]
  169. [521567765542977579939751238756224795178906383030754017389367, 3]
  170. [174471562612093345937604728173142260370910552339274032675230, 6689]
  171. [406206980707027884885407295255687843286085618117473520920511, 70139]
  172. [114626012721946710404343117115811868015815903146304429630277, 72274331657576353317849179356870186439080146899611]
  173. true