[libmath-prime-util-perl] 03/18: Primality verification (needs documentation)

Partha P. Mukherjee ppm-guest at moszumanska.debian.org
Thu May 21 18:48:02 UTC 2015


This is an automated email from the git hooks/post-receive script.

ppm-guest pushed a commit to annotated tag v0.26
in repository libmath-prime-util-perl.

commit 1bd6c492a8145dc0fa901f39daf9f1525fe566b9
Author: Dana Jacobsen <dana at acm.org>
Date:   Wed Apr 10 19:17:33 2013 -0700

    Primality verification (needs documentation)
---
 lib/Math/Prime/Util.pm | 132 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 131 insertions(+), 1 deletion(-)

diff --git a/lib/Math/Prime/Util.pm b/lib/Math/Prime/Util.pm
index 702c42a..09abf9b 100644
--- a/lib/Math/Prime/Util.pm
+++ b/lib/Math/Prime/Util.pm
@@ -12,10 +12,11 @@ BEGIN {
 # parent is cleaner, and in the Perl 5.10.1 / 5.12.0 core, but not earlier.
 # use parent qw( Exporter );
 use base qw( Exporter );
+use Data::Dump qw/dump/;
 our @EXPORT_OK =
   qw( prime_get_config prime_set_config
       prime_precalc prime_memfree
-      is_prime is_prob_prime is_provable_prime
+      is_prime is_prob_prime is_provable_prime verify_prime
       is_strong_pseudoprime is_strong_lucas_pseudoprime
       is_aks_prime
       miller_rabin
@@ -1646,6 +1647,135 @@ sub is_provable_prime {
   return 0;
 }
 
+sub verify_prime {
+  my @pdata = @_;
+  my $verbose = $_Config{'verbose'};
+
+  croak "Parameter must be defined" if scalar @pdata == 0;
+  my $n = shift @pdata;
+  if (length($n) == 1) {
+    return 1 if $n =~ /^[2357]$/;
+    print "primality fail: $n tiny and not prime\n" if $verbose;
+    return 0;
+  }
+
+  if (!defined $Math::BigInt::VERSION) {
+    eval { require Math::BigInt;   Math::BigInt->import(try=>'GMP,Pari'); 1; }
+    or do { croak "Cannot load Math::BigInt"; };
+  }
+  $n = Math::BigInt->new("$n");
+  if ($n->is_even) {
+    print "primality fail: $n even\n" if $verbose;
+    return 0;
+  }
+
+  my $method = (scalar @pdata > 0) ? shift @pdata : 'BPSW';
+
+  if ($method eq 'BPSW') {
+    if ($n > Math::BigInt->new("18446744073709551615")) {
+      print "primality fail: $n too large for BPSW proof\n" if $verbose;
+      return 0;
+    }
+    my $bpsw = 0;
+    if ($_HAVE_GMP) {
+      $bpsw = Math::Prime::Util::GMP::is_prob_prime($n);
+    } else {
+      $bpsw = Math::Prime::Util::PP::miller_rabin($n, 2)
+           && Math::Prime::Util::PP::is_strong_lucas_pseudoprime($n);
+    }
+    if (!$bpsw) {
+      print "primality fail: BPSW indicated $n is composite\n" if $verbose;
+      return 0;
+    }
+    print "primality success: $n by BPSW\n" if $verbose > 1;
+    return 1;
+  }
+  if ($method eq 'n-1') {
+    # BLS75
+    # http://www.ams.org/journals/mcom/1975-29-130/S0025-5718-1975-0384673-1/S0025-5718-1975-0384673-1.pdf
+    if (scalar @pdata != 2 || (ref($pdata[0]) ne 'ARRAY') || (ref($pdata[1]) ne 'ARRAY')) {
+      warn "verify_prime: incorrect n-1 format, must have factors and a values\n";
+      return 0;
+    }
+    my @factors = @{shift @pdata};
+    my @as = @{shift @pdata};
+    if ($#factors != $#as) {
+      warn "verify_prime: incorrect n-1 format, must have a value for each factor\n";
+      return 0;
+    }
+
+    my $nm1 = $n - 1;
+    my $A = $n-$n+1;  # Factored part    (F_1 in BLS paper)
+    my $B = $nm1;     # Unfactored part  (R_1 in BLS paper)
+
+    my @prime_factors;
+    my @pfas;
+    my %factors_seen;
+    foreach my $farray (@factors) {
+      my $f;
+      my $a = shift @as;
+      if (ref($farray) eq 'ARRAY') {
+        $f = Math::BigInt->new("$farray->[0]");
+        return 0 unless verify_prime(@$farray);
+      } else {
+        $f = $farray;
+        return 0 unless verify_prime($f);
+      }
+      next if defined $factors_seen{"$f"};   # repeated factors
+      if (($B % $f) != 0) {
+        print "primality fail: given factor $f does not divide $nm1\n" if $verbose;
+        return 0;
+      }
+      while (($B % $f) == 0) {
+        $B /= $f;
+        $A *= $f;
+      }
+      push @prime_factors, $f;
+      push @pfas, $a;
+      $factors_seen{"$f"} = 1;
+    }
+    croak "BLS75 error: $A * $B != $nm1" unless $A*$B == $nm1;
+    croak "BLS75 error: $A not even" unless $A->is_even();
+
+    # TODO: consider: if B=1 and a single a is given, then Lucas test.
+
+    if (Math::BigInt::bgcd($A, $B) != 1) {
+      print "primality fail: A and B not coprime\n" if $verbose;
+      return 0;
+    }
+    # Theorem 5, m = 1, page 624
+    {
+      my ($s,$r) = $B->copy->bdiv($A->copy->bmul(2));
+      my $fpart = ($A+1) * (2*$A*$A + ($r-1) * $A + 1);
+      if ($n >= $fpart) {
+        print "primality fail: not enough factors\n" if $verbose;
+        return 0;
+      }
+      my $rtest = $r*$r - 8*$s;
+      my $rtestroot = $rtest->copy->bsqrt;
+      if ($s != 0 && ($rtestroot*$rtestroot) == $rtest) {
+        print "primality fail: BLS75 theorem 5: s=$s, r=$r indicates composite\n" if $verbose;
+        return 0;
+      }
+    }
+    # Now verify (I), page 623
+    foreach my $i (0 .. $#prime_factors) {
+      my $f = $prime_factors[$i];
+      my $a = Math::BigInt->new("$pfas[$i]");
+      if ($a->copy->bmodpow($nm1, $n) != 1 ||
+          Math::BigInt::bgcd($a->copy->bmodpow($nm1/$f, $n)->bsub(1), $n) != 1) {
+        print "primality fail: BLS75 factor=$f, a=$a failed.\n" if $verbose;
+        return 0;
+      }
+    }
+    print "primality success: $n by BLS75 theorem 5\n" if $verbose > 1;
+    return 1;
+  }
+
+  warn "verify_prime: Unknown method: '$method'.\n";
+  return 0;
+}
+
 
 #############################################################################
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libmath-prime-util-perl.git



More information about the Pkg-perl-cvs-commits mailing list