lucas-pratt_primality_proving.sf 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 08 January 2020
  4. # https://github.com/trizen
  5. # Prove the primality of a number, using the Lucas `U` sequence, recursively factoring N+1.
  6. # Choose P and Q such that D = P^2 - 4*Q is not a square modulo N.
  7. # Let N+1 = F*R with F > R, where R is odd and the prime factorization of F is known.
  8. # If there exists a Lucas sequence of discriminant D with U(N+1) == 0 (mod N) and gcd(U((N+1)/q), N) = 1 for each prime q dividing F, then N is prime;
  9. # If no such sequence exists for a given P and Q, a new P' and Q' with the same D can be computed as P' = P + 2 and Q' = P + Q + 1 (the same D must be used for all the factors q).
  10. # See also:
  11. # https://en.wikipedia.org/wiki/Primality_certificate
  12. # https://math.stackexchange.com/questions/663341/n1-primality-proving-is-slow
  13. func lucas_primality_proving(n, lim=2**64) is cached {
  14. if ((n <= lim) || (n <= 2)) {
  15. return n.is_prime
  16. }
  17. n.is_prob_prime || return false
  18. var d = n+1
  19. var f = d.trial_factor(1e6)
  20. var B = f.pop
  21. if (__FUNC__(B)) {
  22. f << B
  23. B = 1
  24. }
  25. func find_PQD() {
  26. var l = min(1e9, n-1)
  27. loop {
  28. var P = (irand(1,l))
  29. var Q = (irand(1,l) * [1,-1].rand)
  30. var D = (P*P - 4*Q)
  31. next if is_square(D % n)
  32. next if (P >= n)
  33. next if (Q >= n)
  34. next if (kronecker(D,n) != -1)
  35. return (P, Q, D)
  36. }
  37. }
  38. func prove_primality() {
  39. var (P, Q, D) = find_PQD()
  40. n.is_strong_pseudoprime(P+1) || return false
  41. lucasUmod(P, Q, n+1, n) == 0 || return false
  42. return f.uniq.all {|p|
  43. 1..Inf -> any {
  44. assert_eq(D, P*P - 4*Q)
  45. if (P>=n || Q>=n) {
  46. return __FUNC__()
  47. }
  48. if (is_coprime(lucasUmod(P, Q, d/p, n), n)) {
  49. say [P, Q, p]
  50. true
  51. }
  52. else {
  53. (P, Q) = (P+2, P+Q+1)
  54. n.is_strong_pseudoprime(P) || return false
  55. false
  56. }
  57. }
  58. }
  59. }
  60. loop {
  61. var A = f.prod
  62. if (A>B && is_coprime(A, B)) {
  63. say "\n:: Proving primality of: #{n}"
  64. return prove_primality()
  65. }
  66. var e = B.ecm_factor.grep(__FUNC__)
  67. f += e
  68. B /= e.prod
  69. }
  70. }
  71. say lucas_primality_proving(115792089237316195423570985008687907853269984665640564039457584007913129603823)
  72. __END__
  73. :: Proving primality of: 160667761273563902473
  74. [525548388, -399472563, 2]
  75. [525548388, -399472563, 23]
  76. [525548388, -399472563, 137]
  77. [525548388, -399472563, 2591]
  78. [525548388, -399472563, 77261]
  79. [525548388, -399472563, 127356937]
  80. :: Proving primality of: 84919921767502888050045396989
  81. [662860964, 2738161172, 2]
  82. [662860966, 3401022137, 3]
  83. [662860966, 3401022137, 5]
  84. [662860966, 3401022137, 257]
  85. [662860966, 3401022137, 2539]
  86. [662860966, 3401022137, 160667761273563902473]
  87. :: Proving primality of: 767990784468614637092681680819989903265059687929
  88. [162174617, -732365655, 2]
  89. [162174619, -570191037, 3]
  90. [162174619, -570191037, 5]
  91. [162174619, -570191037, 7]
  92. [162174619, -570191037, 56737]
  93. [162174619, -570191037, 190097]
  94. [162174619, -570191037, 3992873]
  95. [162174619, -570191037, 84919921767502888050045396989]
  96. :: Proving primality of: 1893865274499603695070553024902095101451637190432913
  97. [146526490, 989692981, 2]
  98. [146526490, 989692981, 3]
  99. [146526490, 989692981, 137]
  100. [146526490, 989692981, 767990784468614637092681680819989903265059687929]
  101. :: Proving primality of: 115792089237316195423570985008687907853269984665640564039457584007913129603823
  102. [171404524, -518797671, 2]
  103. [171404524, -518797671, 3]
  104. [171404524, -518797671, 1669]
  105. [171404524, -518797671, 14083]
  106. [171404524, -518797671, 1857767]
  107. [171404524, -518797671, 29170630189]
  108. [171404524, -518797671, 1893865274499603695070553024902095101451637190432913]
  109. true