[libmath-prime-util-perl] 03/11: Make random_*_prime do bignums when passed Math::BigInt objects

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


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

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

commit 7943a7b4920b21a09b5c6c093a3f3f28b5cbb980
Author: Dana Jacobsen <dana at acm.org>
Date:   Wed Dec 5 09:03:09 2012 -0800

    Make random_*_prime do bignums when passed Math::BigInt objects
---
 lib/Math/Prime/Util.pm | 61 ++++++++++++++++++++++++++++++--------------------
 1 file changed, 37 insertions(+), 24 deletions(-)

diff --git a/lib/Math/Prime/Util.pm b/lib/Math/Prime/Util.pm
index b044abe..e098b1f 100644
--- a/lib/Math/Prime/Util.pm
+++ b/lib/Math/Prime/Util.pm
@@ -192,8 +192,9 @@ sub _validate_positive_integer {
   croak "Parameter '$n' must be a positive integer" if $n =~ tr/0123456789//c;
   croak "Parameter '$n' must be >= $min" if defined $min && $n < $min;
   croak "Parameter '$n' must be <= $max" if defined $max && $n > $max;
-  # this used instead of '<=' to fix strings like ~0+delta
-  if ($n < $_Config{'maxparam'} || int($n) eq $_Config{'maxparam'}) {
+  # The second term is used instead of '<=' to fix strings like ~0+delta.
+  # The third works around a rare BigInt bug (e.g. 23 > 18446744073709551615 !!)
+  if ($n < $_Config{'maxparam'} || int($n) eq $_Config{'maxparam'} || "$n" < $_Config{'maxparam'}) {
     $_[0] = $_[0]->as_number() if ref($_[0]) eq 'Math::BigFloat';
     $_[0] = int($_[0]->bstr) if ref($_[0]) eq 'Math::BigInt';
   } elsif (ref($n) ne 'Math::BigInt') {
@@ -540,11 +541,12 @@ sub primes {
 
   sub random_ndigit_prime {
     my($digits) = @_;
-    _validate_positive_integer($digits, 1,
-             (defined $bigint::VERSION) ? 10000 : $_Config{'maxdigits'});
+    my $usebigint = (   defined $bigint::VERSION
+                     || (defined $digits && ref($digits) =~ /^Math::Big/));
+    _validate_positive_integer($digits, 1, $usebigint ? undef : $_Config{'maxbits'});
 
     if (!defined $_random_ndigit_ranges[$digits]) {
-      if ( defined $bigint::VERSION  &&  $digits >= $_Config{'maxdigits'} ) {
+      if ( $usebigint  &&  $digits >= $_Config{'maxdigits'} ) {
         my $low  = Math::BigInt->new('10')->bpow($digits-1);
         my $high = Math::BigInt->new('10')->bpow($digits);
         $_random_ndigit_ranges[$digits] = [next_prime($low), prev_prime($high)];
@@ -564,11 +566,12 @@ sub primes {
 
   sub random_nbit_prime {
     my($bits) = @_;
-    _validate_positive_integer($bits, 2,
-             (defined $bigint::VERSION) ? 100000 : $_Config{'maxbits'});
+    my $usebigint = (   defined $bigint::VERSION
+                     || (defined $bits && ref($bits) =~ /^Math::Big/));
+    _validate_positive_integer($bits, 2, $usebigint ? undef : $_Config{'maxbits'});
 
     if (!defined $_random_nbit_ranges[$bits]) {
-      if ( defined $bigint::VERSION  &&  $bits >= $_Config{'maxbits'} ) {
+      if ( $usebigint  &&  $bits >= $_Config{'maxbits'} ) {
         my $low  = Math::BigInt->new('2')->bpow($bits-1);
         my $high = Math::BigInt->new('2')->bpow($bits);
         # Don't pull the range in to primes, just odds
@@ -586,20 +589,22 @@ sub primes {
 
   sub random_maurer_prime {
     my($k) = @_;
-    _validate_positive_integer($k, 2,
-             (defined $bigint::VERSION) ? 100000 : $_Config{'maxbits'});
+    my $usebigint = (   defined $bigint::VERSION
+                     || (defined $k && ref($k) =~ /^Math::Big/));
+    _validate_positive_integer($k, 2, $usebigint ? undef : $_Config{'maxbits'});
 
     my $p0 = 32;    # Use uniform random method for this many or less
 
     return random_nbit_prime($k) if $k <= $p0;
 
-    eval {
-      require Math::BigInt;   Math::BigInt->import( try=>'GMP,Pari' );
-      require Math::BigFloat; Math::BigFloat->import();
-      1;
-    } or do {
-      croak "Cannot load Math::BigInt and Math::BigFloat";
-    };
+    if (!defined $Math::BigInt::VERSION) {
+      eval { require Math::BigInt;   Math::BigInt->import(try=>'GMP,Pari'); 1; }
+      or do { croak "Cannot load Math::BigInt"; };
+    }
+    if (!defined $Math::BigFloat::VERSION) {
+      eval { require Math::BigFloat;   Math::BigFloat->import(); 1; }
+      or do { croak "Cannot load Math::BigFloat"; };
+    }
 
     my $c = Math::BigFloat->new("0.09");  # higher = more trial divisions
     my $r = Math::BigFloat->new("0.5");
@@ -641,16 +646,22 @@ sub primes {
       }
       #warn "$n passes trial division\n";
 
+      # Now we do Lemma 1 -- a special case of the Pocklington test.
+      # Let F = q where q is prime, and n = 2RF+1.
+      # If F > sqrt(n) or F odd and F > R, and a^((n-1)/F)-1 mod n = 1, n prime.
+
       # a is a random number between 2 and $n-2
       my $a = 2 + $get_rand_range->( $n - 4 );
       my $b = $a->copy->bmodpow($n-1, $n);
       next unless $b == 1;
       #warn "$n passes a^n-1 == 1\n";
 
-      # We now get to choose between Maurer's original proposal:
-      #   check gcd(a^((n-1)/q)-1,n)==1 for each factor q of n-1
-      # thusly:
+      # This is Lemma 1 from Maurer's paper.  Also see Menezes 4.59.
+      # First let's double check our conditions.  They better be true -- we
+      # went to some effort to ensure they were when we arrived here!
+      next if $q <= $R || ($q % 2) == 0;
 
+      # Given the above, we have only one GCD to check and we're done!
       $b = $a->copy->bmodpow(2*$R, $n);
       next unless Math::BigInt::bgcd($b-1, $n) == 1;
       #warn "$n passes final gcd\n";
@@ -659,18 +670,20 @@ sub primes {
       # some tests on x & y from 2R = xq+y (see Lemma 2 from Maurer's paper).
       # Crypt::Primes does the q test but doesn't seem to do the x/y and
       # perfect square portions.
-      #   next if ($q <= $n->copy->bpow(1/3));
+      #   next if $q <= $n->copy->broot(3);
       #   my $x = (2*$R)->bdiv($q)->bfloor;
       #   my $y = 2*$R - $x*$q;
       #   my $z = $y*$y - 4*$x;
       #   next if $z == 0;
-      #   next if $z is a perfect square
-      # Menezes seems to imply only the q test needs to be done.
+      #   next if $z->bsqrt->bfloor->bpow(2) == $z;  # perfect square
+      # Menezes seems to imply only the q test needs to be done, but that
+      # doesn't follow from Lemma 2.  Here's my problem: with q > R we'll
+      # end up with x=0 most of the time, hence z will be a perfect square.
 
       # We perhaps could verify with a BPSW test on the result.  This could:
       #  1) save us from accidently outputing a non-prime due to some mistake
       #  2) make history by finding the first known BPSW pseudo-prime
-      # croak "Maurer prime $n failed BPSW" unless is_prob_prime($n);
+      croak "Maurer prime $n=2*$R*$q+1 failed BPSW" unless is_prob_prime($n);
       #warn "     and passed BPSW.\n";
 
       return $n;

-- 
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