[libmath-prime-util-perl] 01/72: Updates for random_nbit_prime and documentation

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


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

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

commit 829338fdbea4a056f775a62e4851160706941fc7
Author: Dana Jacobsen <dana at acm.org>
Date:   Fri Aug 9 18:38:03 2013 -0700

    Updates for random_nbit_prime and documentation
---
 lib/Math/Prime/Util.pm | 132 +++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 122 insertions(+), 10 deletions(-)

diff --git a/lib/Math/Prime/Util.pm b/lib/Math/Prime/Util.pm
index efce890..4b0a753 100644
--- a/lib/Math/Prime/Util.pm
+++ b/lib/Math/Prime/Util.pm
@@ -723,7 +723,7 @@ sub primes {
     if ($_big_gcd_use < 0) {
       $_big_gcd_use = 0;
       my $lib = Math::BigInt->config()->{lib};
-      $_big_gcd_use = 1 if $lib =~ /^Math::BigInt::(GMP|Pari)/;
+      $_big_gcd_use = 1 if !$_HAVE_GMP && $lib =~ /^Math::BigInt::(GMP|Pari)/;
       _make_big_gcds() if $_big_gcd_use;
     }
 
@@ -741,7 +741,12 @@ sub primes {
         next unless (0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1)[$prime];
         return $prime;
       }
-      # Perform quick trial division
+      # With GMP, the fastest thing to do is check primality.
+      if ($_HAVE_GMP) {
+        next unless Math::Prime::Util::GMP::is_prime($prime);
+        return $prime;
+      }
+      # No MPU:GMP, so primality checking is slow.  Skip some composites here.
       next unless Math::BigInt::bgcd($prime, 7436429) == 1;
       if ($_big_gcd_use && $prime > $_big_gcd_top) {
         next unless Math::BigInt::bgcd($prime, $_big_gcd[0]) == 1;
@@ -819,6 +824,39 @@ sub primes {
     my($bits) = @_;
     _validate_num($bits, 2) || _validate_positive_integer($bits, 2);
 
+    # Fouque and Tibouchi (2011) Algorithm 1 (basic)
+    if (1 && $bits > 64) {
+      if (!defined $Math::BigInt::VERSION) {
+        eval { require Math::BigInt; Math::BigInt->import(try=>'GMP,Pari'); 1; }
+        or do { croak "Cannot load Math::BigInt"; };
+      }
+      my $irandf = _get_rand_func();
+      my $l = ($_Config{'maxbits'} > 32 && $bits > 79)  ?  63  :  31;
+      my $arange = (1 << $l) - 1;  # 2^$l-1
+      my $brange = Math::BigInt->new(2)->bpow($bits-$l-2)->bsub(1);
+      my $b = 2 * $irandf->($brange) + 1;
+      # Precalculate some modulii (TODO: add more or use F&T Alg 2)
+      my $em3 = ($bits % 2)  ?  (0,1,2)[$b % 3]  :  (0,2,1)[$b % 3];
+      my $loop_limit = 1_000_000;
+      while ($loop_limit-- > 0) {
+        my $a = (1 << $l) +  $irandf->($arange);
+        next if $a % 3 == $em3;
+        my $p = Math::BigInt->new("$a")->blsft($bits-$l-1)->badd($b);
+        # p:  1aaaaaaaabbbbbbbbbbbbbbbbbbbb1
+        #die " $a $b $p" if $a % 3 == $em3 && $p % 3 != 0;
+        #die "!$a $b $p" if $a % 3 != $em3 && $p % 3 == 0;
+        if ($_HAVE_GMP) {
+          next unless Math::Prime::Util::GMP::is_prime($p);
+        } else {
+          next unless Math::BigInt::bgcd($p, 4127218095) == 1;
+          next unless Math::BigInt::bgcd($p, 3948078067) == 1;
+          next unless is_prob_prime($p);
+        }
+        return $p;
+      } 
+      croak "Random function broken?";
+    }
+
     if (!defined $_random_nbit_ranges[$bits]) {
       my $bigbits = $bits > $_Config{'maxbits'};
       croak "Large random primes not supported on old Perl" if $] < 5.008 && $_Config{'maxbits'} > 32 && !$bigbits && $bits > 49;
@@ -2457,6 +2495,14 @@ L</is_prime> return probable prime results using the extra-strong
 Baillie-PSW test, which has had no counterexample found since it was
 published in 1980.
 
+For cryptographic key generation, you may want even more testing for probable
+primes (NIST recommends some additional M-R tests).  This can be done using
+additional random bases with L</is_strong_pseudoprime>, or a different test
+such as L</is_frobenius_underwood_pseudoprime>.  Even better, make sure
+L<Math::Prime::Util::GMP> is installed and use L</is_provable_prime> which
+should be reasonably fast for sizes under 2048 bits.
+Another possibility is to use L<Math::Prime::Util/random_maurer_prime> which
+constructs a random provable prime.
 
 
 =head2 primes
@@ -3407,12 +3453,13 @@ between 2 and the maximum representable bits (32, 64, or 100000 for native
 set will be uniformly selected, with randomness supplied via calls to the
 C<irand> function as described above.
 
-Since this uses the random_prime function, all uniformity properties of that
-function apply to this.  The n-bit range is partitioned into nearly equal
-segments less than C<2^32>, a segment is randomly selected, then the trivial
-Monte Carlo algorithm is used to select a prime from within the segment.
-This gives a reasonably uniform distribution, doesn't use excessive random
-source, and can be very fast.
+For bit size of 64 and lower, we use L</random_prime>, which will result in
+uniform results.  For sizes larger than 64, Algorithm 1 of Fouque and Tibouchi
+(2011) is used, wherein we select a random odd number for the lower bits, then
+loop selecting random upper bits until the result is prime.  This gives a very
+uniform distribution while running quickly.  The C<irand> function is used
+for randomness, so all the discussion in L</random_prime> about that applies
+here.
 
 The result will be a BigInt if the number of bits is greater than the native
 bit size.  For better performance with large bit sizes, install
@@ -3470,6 +3517,14 @@ partial result, and constructs a primality certificate for the final
 result, which is verified.  These add additional checks that the resulting
 value has been properly constructed.
 
+An alternative to this function is to run L</is_provable_prime> on the
+result of L</random_nbit_prime>, which will provide more diversity and
+will be faster up to 512 or so bits.  Maurer's method should be much
+faster for large bit sizes (larger than 2048).  If you don't need absolutely
+proven results, then using L</random_nbit_prime> followed by additional
+tests (L</is_strong_pseudoprime> and/or L</is_frobenius_underwood_pseudoprime>)
+should be much faster.
+
 
 =head2 random_maurer_prime_with_cert
 
@@ -4164,6 +4219,8 @@ functions.  All with fairly minimal installation requirements.
 
 =head1 PERFORMANCE
 
+=head2 PRIME COUNTS
+
 Counting the primes to C<10^10> (10 billion), with time in seconds.
 Pi(10^10) = 455,052,511.
 The numbers below are for sieving.  Calculating C<Pi(10^10)> takes 0.064
@@ -4213,6 +4270,7 @@ and 25+ GB of RAM.  SymPy 0.7.1 C<primepi> takes 292.2s.  However there are
 very fast solutions written by Robert William Hanks (included in the xt/
 directory of this distribution): pure Python in 12.1s and NUMPY in 2.8s.
 
+=head2 PRIMALITY TESTING
 
 C<is_prime>: my impressions for various sized inputs:
 
@@ -4287,6 +4345,7 @@ it is still much, much slower than a BPSW probable prime test for large inputs.
 
 =back
 
+=head2 FACTORING
 
 Factoring performance depends on the input, and the algorithm choices used
 are still being tuned.  L<Math::Factor::XS> is very fast when given input with
@@ -4318,6 +4377,7 @@ and L<Pari|http://pari.math.u-bordeaux.fr/>.  The latest yafu should cover most
 uses, with GGNFS likely only providing a benefit for numbers large enough to
 warrant distributed processing.
 
+=head2 PRIMALITY PROVING
 
 The C<n-1> proving algorithm in L<Math::Prime::Util::GMP> compares well to
 the version including in Pari.  Both are pretty fast to about 60 digits, and
@@ -4329,8 +4389,60 @@ including creating a certificate.  Times below 200 digits are faster than
 Pari 2.3.5's APR-CL proof.  For larger inputs the bottleneck is a limited set
 of discriminants, and time becomes more variable.  There is a larger set of
 discriminants on github that help, with 300-digit primes taking ~5 seconds on
-average and typically under a minute for 500-digits.  For serious primality
-proving, I recommend L<Primo|http://www.ellipsa.eu/>.
+average and typically under a minute for 500-digits.  For primality proving
+with very large numbers, I recommend L<Primo|http://www.ellipsa.eu/>.
+
+=head2 RANDOM PRIME GENERATION
+
+Seconds per prime for random prime generation on a circa-2009 workstation,
+with L<Math::Prime::Util::GMP> installed.
+
+  bits    random   +testing  random(p)   Maurer   CPMaurer
+  -----  --------  --------  ---------  --------  --------
+     64    0.0003  +0.000003   0.0003     0.0003    0.022
+    128    0.0040  +0.00016    0.0099     0.081     0.057
+    256    0.0073  +0.0004     0.057      0.19      0.16
+    512    0.020   +0.0012     0.43       0.52      0.41
+   1024    0.089   +0.0060     6.3        1.3       2.19
+   2048    0.62    +0.039                 4.8      10.99
+   4096    6.24    +0.25                 31.9      79.71
+   8192   58.6     +1.61                234.0     947.3
+
+  random    = random_nbit_prime  (results pass BPSW)
+  random+   = additional time for 3 M-R and a frobenius test
+  random(p) = is_provable_prime(random_nbit_prime(bits))
+  maurer    = random_maurer_prime
+  CPMaurer  = Crypt::Primes::maurer
+
+L</random_nbit_prime> is reasonably fast, and for most purposes should be
+adequate.  For cryptographic purposes, one may want additional tests or a
+proven prime.  Additional tests are quite cheap, as shown by the time for
+three extra M-R and a Frobenius test.  At these bit sizes, the chances a
+composite number passes BPSW, three more M-R tests, and a Frobenius test
+is I<extraordinarily> small.
+
+For bit sizes under 600 or so (200 digits), using L</is_provable_prime> on
+the result of L</random_nbit_prime> is quite fast.  Typically this will
+actually be faster than generating a proven prime with Maurer's algorithm.
+However, as the bit sizes increase, proving primality becomes quite expensive
+so Maurer's method is typically best for proven random primes over 512 bits.
+
+L</random_maurer_prime> constructs a provable prime.  A primality test is
+run on each intermediate, and it also constructs a complete primality
+certificate which is verified at the end (and can be returned).  While the
+result is uniformly distributed, only about 10% of the primes in the range
+are selected for output.  This is a result of the FastPrime algorithm and
+is usually unimportant.
+
+L<Crypt::Primes/maurer> is included for comparison.  It is pretty fast for
+small sizes but gets slow as the size increases.  It does not perform any
+primality checks on the intermediate results or the final result (I highly
+recommended you run a primality test on the output).
+Additionally important for servers, L<Crypt::Primes/maurer> uses excessive
+system entropy and can grind to a halt if C</dev/random> is exhausted
+(it can take B<days> to return).  The times above are on a machine running
+L<HAVEGED|http://www.issihosts.com/haveged/>
+so never waits for entropy.
 
 
 =head1 AUTHORS

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