pocklington-pratt_primality_proving.pl 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 05 January 2020
  4. # https://github.com/trizen
  5. # Prove the primality of a number, using the Pocklington primality test recursively.
  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. use 5.020;
  11. use strict;
  12. use warnings;
  13. use experimental qw(signatures);
  14. use List::Util qw(uniq);
  15. use ntheory qw(is_prime is_prob_prime primes);
  16. use Math::AnyNum qw(:overload isqrt prod is_coprime irand powmod primorial gcd);
  17. use Math::Prime::Util::GMP qw(ecm_factor is_strong_pseudoprime);
  18. my $primorial = primorial(10**6);
  19. sub trial_factor ($n) {
  20. my @f;
  21. my $g = gcd($primorial, $n);
  22. if ($g > 1) {
  23. my @primes = ntheory::factor($g);
  24. foreach my $p (@primes) {
  25. while ($n % $p == 0) {
  26. push @f, $p;
  27. $n /= $p;
  28. }
  29. }
  30. }
  31. return ($n, @f);
  32. }
  33. sub pocklington_pratt_primality_proving ($n, $lim = 2**64) {
  34. if ($n <= $lim or $n <= 2) {
  35. return is_prime($n); # fast deterministic test for small n
  36. }
  37. is_prob_prime($n) || return 0;
  38. if (ref($n) ne 'Math::AnyNum') {
  39. $n = Math::AnyNum->new("$n");
  40. }
  41. my $d = $n - 1;
  42. my ($B, @f) = trial_factor($d);
  43. if ($B > 1 and __SUB__->($B, $lim)) {
  44. push @f, $B;
  45. $B = 1;
  46. }
  47. for (; ;) {
  48. my $A = prod(@f);
  49. if ($A > $B and is_coprime($A, $B)) {
  50. say "\n:: Proving primality of: $n";
  51. foreach my $p (uniq(@f)) {
  52. for (; ;) {
  53. my $a = irand(2, $d);
  54. is_strong_pseudoprime($n, $a) || return 0;
  55. if (is_coprime(powmod($a, $d / $p, $n) - 1, $n)) {
  56. say "a = $a ; p = $p";
  57. last;
  58. }
  59. }
  60. }
  61. return 1;
  62. }
  63. my @ecm_factors = map { Math::AnyNum->new($_) } ecm_factor($B);
  64. foreach my $p (@ecm_factors) {
  65. if (__SUB__->($p, $lim)) {
  66. while ($B % $p == 0) {
  67. $B /= $p;
  68. $A *= $p;
  69. push @f, $p;
  70. }
  71. }
  72. if ($A > $B) {
  73. say ":: Stopping early with A = $A and B = $B" if ($B > 1);
  74. last;
  75. }
  76. }
  77. }
  78. }
  79. say "Is prime: ",
  80. pocklington_pratt_primality_proving(115792089237316195423570985008687907853269984665640564039457584007913129603823);
  81. __END__
  82. :: Proving primality of: 1202684276868524221513588244947
  83. a = 346396580104425418965575454682 ; p = 2
  84. a = 395385292850838170128328828116 ; p = 3
  85. a = 560648981353249253078437405876 ; p = 192697
  86. a = 494703015287234994679974119746 ; p = 5829139
  87. a = 306457770974323789423503072510 ; p = 59483944987587859
  88. :: Proving primality of: 3201964079152361724098258636758155557
  89. a = 1356115518279653627564352210970159943 ; p = 2
  90. a = 2457916028227754146876991447098503864 ; p = 13
  91. a = 11728301593361244989156925656983410 ; p = 51199
  92. a = 2108054294077847671434547666614921115 ; p = 1202684276868524221513588244947
  93. :: Proving primality of: 2848630210554880446022254608450222949126931851754251657020267
  94. a = 1209988187472090611751147313669268320351528758910368461329491 ; p = 2
  95. a = 2300573356420091000839516595493416230415669494600279441813823 ; p = 7
  96. a = 2255070062675661569997567047423251088740948129004746039001652 ; p = 71
  97. a = 1700776819424249129400987278064417150296142232503378309546959 ; p = 397
  98. a = 1557663127914051170819266186415060024746272157947950396848254 ; p = 22483
  99. a = 1529304355972906129963007304614010762285079880618804024992958 ; p = 100274029791527
  100. a = 1359380483007119191612142919174796446436066905484471515166032 ; p = 3201964079152361724098258636758155557
  101. :: Proving primality of: 57896044618658097711785492504343953926634992332820282019728792003956564801911
  102. a = 57400691074692315475639863020768426880305244856451980889960538168345429022524 ; p = 2
  103. a = 25820275722126461008372188295587408543429765560766435733697174460356575227321 ; p = 5
  104. a = 27298126184613458024322898773516636407461062104891054863568660611145831927443 ; p = 19
  105. a = 7100354002561105328600593201175960102344714262592146066784856909856617007329 ; p = 106969315701167
  106. a = 18941027101040193108179225001169566407134428948824247293492332749705988365235 ; p = 2848630210554880446022254608450222949126931851754251657020267
  107. :: Proving primality of: 115792089237316195423570985008687907853269984665640564039457584007913129603823
  108. a = 113522921208063424748606312287587727138037143611024280238876731030118912160215 ; p = 2
  109. a = 2309014289093855479517407977261240733911340029895025970257499692025785552300 ; p = 57896044618658097711785492504343953926634992332820282019728792003956564801911
  110. Is prime: 1