pepin-proth_primality_test_generalized.sf 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 04 January 2020
  4. # https://github.com/trizen
  5. # Generalization of the Pépin-Proth test.
  6. # Let `n` be an odd positive integer that is not a perfect power:
  7. # 1) find an integer `a` such that: kronecker(a, n) = -1.
  8. # 2) if `n` is prime, then: a^((n-1)/2) == -1 (mod n)
  9. # There are a few composites that also satisfy this property for some values of `a`.
  10. # To overcome this, we try to find `a` in the sequence `k, k+1, k+2, ...`, where `k` is a random starting value <= floor(sqrt(n)). A random value of `k` is computed at each iteration.
  11. # For better accuracy, we repeat the test several times. If we find an `a` such that `kronecker(a, n) = -1` and `a^((n-1)/2) != -1 (mod n)`, then `n` is definitely composite.
  12. # See also:
  13. # https://en.wikipedia.org/wiki/P%C3%A9pin's_test
  14. # https://en.wikipedia.org/wiki/Proth%27s_theorem
  15. # https://en.wikipedia.org/wiki/Pocklington_primality_test
  16. func pepin_primality_test(n, reps=10) {
  17. return true if (n == 2)
  18. return false if (n.is_even)
  19. return false if (n <= 1)
  20. return false if (n.is_power)
  21. var s = n.isqrt
  22. reps.times {
  23. var a = (s.irand..n -> first {|k|
  24. kronecker(k, n) == -1
  25. })
  26. powmod(a, (n-1)/2, n) == n-1 || return false
  27. }
  28. return true
  29. }
  30. #
  31. ## Run a few tests
  32. #
  33. assert(pepin_primality_test(41! + 1))
  34. assert(pepin_primality_test(2**127 - 1))
  35. assert(!pepin_primality_test(43! + 1))
  36. assert(!pepin_primality_test(335603208601))
  37. assert(!pepin_primality_test(30459888232201))
  38. assert(!pepin_primality_test(30990302851201))
  39. assert(!pepin_primality_test(162021627721801))
  40. assert(!pepin_primality_test(2107679818823041))
  41. assert(!pepin_primality_test(15245346051376561))
  42. assert(!pepin_primality_test(15667976553657751))
  43. assert(!pepin_primality_test(1372144392322327801))
  44. say pepin_primality_test.first(25)
  45. assert_eq([341, 561, 645, 1105, 1387, 1729, 1905, 2047, 2465, 2701, 2821, 3277, 4033,
  46. 4369, 4371, 4681, 5461, 6601, 7957, 8321, 8481, 8911, 10261, 10585, 11305,
  47. 12801, 13741, 13747, 13981, 14491, 15709, 15841, 16705, 18705, 18721, 19951,
  48. 23001, 23377, 25761, 29341].grep(pepin_primality_test), [])
  49. assert_eq([561, 1105, 1729, 2465, 2821, 6601, 8911, 10585, 15841, 29341, 41041, 46657,
  50. 52633, 62745, 63973, 75361, 101101, 115921, 126217, 162401, 172081, 188461,
  51. 252601, 278545, 294409, 314821, 334153, 340561, 399001, 410041, 449065, 488881,
  52. 512461].grep(pepin_primality_test), [])