[libmath-prime-util-perl] 09/29: Allow BLS75 theorem 7 n-1 proofs
Partha P. Mukherjee
ppm-guest at moszumanska.debian.org
Thu May 21 18:48:16 UTC 2015
This is an automated email from the git hooks/post-receive script.
ppm-guest pushed a commit to annotated tag v0.27
in repository libmath-prime-util-perl.
commit 17559c6acaf9d010e87060b45374aa7a527eda95
Author: Dana Jacobsen <dana at acm.org>
Date: Fri May 10 16:35:25 2013 -0700
Allow BLS75 theorem 7 n-1 proofs
---
examples/verify-gmp-ecpp-cert.pl | 5 ++-
lib/Math/Prime/Util.pm | 65 ++++++++++++++++++++++-----
lib/Math/Prime/Util/PP.pm | 94 +++++++++++++++++++++++++---------------
xt/primality-proofs.pl | 11 +++--
4 files changed, 123 insertions(+), 52 deletions(-)
diff --git a/examples/verify-gmp-ecpp-cert.pl b/examples/verify-gmp-ecpp-cert.pl
index de3e616..7c629ce 100755
--- a/examples/verify-gmp-ecpp-cert.pl
+++ b/examples/verify-gmp-ecpp-cert.pl
@@ -4,6 +4,9 @@ use strict;
use Math::BigInt try=>"GMP,Pari";
use Math::Prime::Util qw/:all/;
use Data::Dump qw/dump/;
+my $bifilter = sub { my($ctx, $n) = @_;
+ return {dump=>"$n"} if ref($n) eq "Math::BigInt";
+ undef; };
# Takes the output of GMP-ECPP, creates a certificate in the format used
# by MPU, and runs it through the verifier.
@@ -57,5 +60,5 @@ while (<>) {
}
}
-print dump(\@cert), "\n";
+print dump_filtered(\@cert, $bifilter), "\n";
print verify_prime(@cert) ? "SUCCESS\n" : "FAILURE\n";
diff --git a/lib/Math/Prime/Util.pm b/lib/Math/Prime/Util.pm
index 0a7f465..bd59e50 100644
--- a/lib/Math/Prime/Util.pm
+++ b/lib/Math/Prime/Util.pm
@@ -234,9 +234,8 @@ sub _validate_positive_integer {
if (ref($_[0])) {
$_[0] = Math::BigInt->new("$_[0]") unless ref($_[0]) eq 'Math::BigInt';
- $_bigint_small = Math::BigInt->new("$_Config{'maxparam'}")
- unless defined $_bigint_small;
- if ($_[0]->bacmp($_bigint_small) <= 0) {
+ # Stupid workaround for Math::BigInt::GMP RT # 71548
+ if ($_[0]->bacmp(''.~0) <= 0) {
$_[0] = int($_[0]->bstr);
} else {
$_[0]->upgrade(undef) if $_[0]->upgrade(); # Stop BigFloat upgrade
@@ -251,8 +250,8 @@ sub _validate_positive_integer {
}
}
# One of these will be true:
- # 1) $n <= max and $n is not a bigint
- # 2) $n > max and $n is a bigint
+ # 1) $n <= ~0 and $n is not a bigint
+ # 2) $n > ~0 and $n is a bigint
1;
}
@@ -1802,6 +1801,13 @@ sub verify_prime {
if ($method eq 'n-1') {
# BLS75 or generalized Pocklington
# http://www.ams.org/journals/mcom/1975-29-130/S0025-5718-1975-0384673-1/S0025-5718-1975-0384673-1.pdf
+ # Pull of optional theorem 7 data
+ my ($theorem, $t7_B1, $t7_B, $t7_a) = (5, undef, undef, undef);
+ if (scalar @pdata == 3 && ref($pdata[0]) eq 'ARRAY' && $pdata[0]->[0] =~ /^(B|T7|Theorem\s*7)$/i) {
+ $theorem = 7;
+ (undef, $t7_B1, $t7_B, $t7_a) = @{shift @pdata};
+ $t7_B = Math::BigInt->new("$t7_B");
+ }
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;
@@ -1858,10 +1864,42 @@ sub verify_prime {
print "primality fail: A and B not coprime\n" if $verbose;
return 0;
}
- # Theorem 5, m = 1, page 624
- {
+ if ($theorem == 7) {
+ if ($B != $t7_B) {
+ print "primality fail: T7 unfactored != unfactored\n" if $verbose;
+ return 0;
+ }
+ if ($t7_B1 < 1) {
+ print "primality fail: T7 B value < 1\n" if $verbose;
+ return 0;
+ }
+ # 1. Check $B has no factors smaller than $t7_B1
+ my $no_small_factors = 0;
+ if ($_HAVE_GMP) {
+ my @trial = Math::Prime::Util::GMP::trial_factor($B, $t7_B1);
+ $no_small_factors = (scalar @trial == 1);
+ } elsif ($B <= ''.~0) {
+ my @trial = Math::Prime::Util::PP::trial_factor($B, $t7_B1);
+ $no_small_factors = (scalar @trial == 1);
+ } else {
+ # This is slow when B1 > 1M, but with a bigint B it's faster than
+ # doing trial divisions (but much slower with native B).
+ $no_small_factors =
+ (Math::BigInt::bgcd($B, primorial(Math::BigInt->new($t7_B1))) == 1);
+ }
+ if (!$no_small_factors) {
+ print "primality fail: T7 B has a factor smaller than B1\n" if $verbose;
+ return 0;
+ }
+ # 2. Add $B and $t7_a to lists so they get checked as part of (I).
+ push @prime_factors, $B;
+ push @pfas, $t7_a;
+ }
+ { # Theorem 5, m = 1, page 624; Theorem 7, page 626
my ($s,$r) = $B->copy->bdiv($A->copy->bmul(2));
- my $fpart = ($A+1) * (2*$A*$A + ($r-1) * $A + 1);
+ my $fpart = ($theorem == 7)
+ ? ($A*$t7_B1+1) * (2*$A*$A + ($r-$t7_B1) * $A + 1)
+ : ($A+1) * (2*$A*$A + ($r-1) * $A + 1);
if ($n >= $fpart) {
print "primality fail: not enough factors\n" if $verbose;
return 0;
@@ -1883,7 +1921,7 @@ sub verify_prime {
return 0;
}
}
- print "primality success: $n by BLS75 theorem 5\n" if $verbose > 1;
+ print "primality success: $n by BLS75 theorem $theorem\n" if $verbose > 1;
return 1;
}
@@ -2873,9 +2911,9 @@ A certificate is an array holding an C<n-cert>. An C<n-cert> is one of:
4 a^(n-1) = 1 mod n
5 a^((n-1)/f) != 1 mod n for each factor
- n,"n-1",[n-cert, ...],[a,...]
+ n,"n-1",[optional B-block],[n-cert, ...],[a,...]
An n-1 certificate suitable for the generalized Pocklington or the
- BLS75 (Brillhart-Lehmer-Selfridge 1975, theorem 5) test. The
+ BLS75 (Brillhart-Lehmer-Selfridge 1975, theorem 5) n-1 test. The
proof is performed using BLS75 theorem 5 which requires n-1 to be
factored up to (n/2)^1/3. If n-1 is factored to more than
sqrt(n), then the conditions are identical to the generalized
@@ -2892,6 +2930,11 @@ A certificate is an array holding an C<n-cert>. An C<n-cert> is one of:
5 for each pair (f,a) representing a factor n-cert and its 'a':
- a^(n-1) = 1 mod n
- gcd( a^((n-1)/f)-1, n ) = 1
+ If the optional B block is present, then theorem 7 will be used.
+ The B-block consists of 4 items: "B" as an identifier, the
+ factoring limit B indicating that the unfactored portion has no
+ factors smaller than B, the unfactored amount F, and an 'a' value
+ to be tested with F as in step 5.
n,"AGKM",[ec-block],[ec-block],...
An Elliptic Curve certificate. We are given n, the method "AGKM"
diff --git a/lib/Math/Prime/Util/PP.pm b/lib/Math/Prime/Util/PP.pm
index de34252..5ed8e7b 100644
--- a/lib/Math/Prime/Util/PP.pm
+++ b/lib/Math/Prime/Util/PP.pm
@@ -69,19 +69,25 @@ sub _validate_positive_integer {
if ref($n) ne 'Math::BigInt' && $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;
- if ($n <= ~0) {
- $_[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') {
- croak "Parameter '$n' outside of integer range" if !defined $bigint::VERSION;
- $_[0] = Math::BigInt->new("$n"); # Make $n a proper bigint object
- $_[0]->upgrade(undef) if $_[0]->upgrade(); # Stop BigFloat upgrade
+ if (ref($_[0])) {
+ $_[0] = Math::BigInt->new("$_[0]") unless ref($_[0]) eq 'Math::BigInt';
+ # Stupid workaround for Math::BigInt::GMP RT # 71548
+ if ($_[0]->bacmp(''.~0) <= 0) {
+ $_[0] = int($_[0]->bstr);
+ croak "Didn't convert!" if ref($_[0]);
+ } else {
+ $_[0]->upgrade(undef) if $_[0]->upgrade(); # Stop BigFloat upgrade
+ }
} else {
- $_[0]->upgrade(undef) if $_[0]->upgrade(); # Stop BigFloat upgrade
+ if ($n > ~0) {
+ croak "Parameter '$n' outside of integer range" if !defined $bigint::VERSION;
+ $_[0] = Math::BigInt->new("$n"); # Make $n a proper bigint object
+ $_[0]->upgrade(undef) if $_[0]->upgrade(); # Stop BigFloat upgrade
+ }
}
# One of these will be true:
- # 1) $n <= max and $n is not a bigint
- # 2) $n > max and $n is a bigint
+ # 1) $n <= ~0 and $n is not a bigint
+ # 2) $n > ~0 and $n is a bigint
1;
}
@@ -1115,21 +1121,32 @@ sub _basic_factor {
}
sub trial_factor {
- my($n) = @_;
+ my($n, $maxlim) = @_;
_validate_positive_integer($n);
+ $maxlim = $n unless defined $maxlim && _validate_positive_integer($maxlim);
- my @factors = _basic_factor($n);
+ # Don't use _basic factor here -- they want a trial forced.
+ #my @factors = _basic_factor($n);
+ return ($n) if $n < 4;
+ my @factors;
+ while ( !($n % 2) ) { push @factors, 2; $n = int($n / 2); }
+ while ( !($n % 3) ) { push @factors, 3; $n = int($n / 3); }
+ while ( !($n % 5) ) { push @factors, 5; $n = int($n / 5); }
+ $n = int($n->bstr) if ref($n) eq 'Math::BigInt' && $n <= ''.~0;
return @factors if $n < 4;
my $limit = int( sqrt($n) + 0.001);
+ $limit = $maxlim if $limit > $maxlim;
my $f = 7;
SEARCH: while ($f <= $limit) {
foreach my $finc (4, 2, 4, 2, 4, 6, 2, 6) {
if ( (($n % $f) == 0) && ($f <= $limit) ) {
do { push @factors, $f; $n = int($n/$f); } while (($n % $f) == 0);
- $n = int($n->bstr) if ref($n) eq 'Math::BigInt' && $n <= ~0;
- last SEARCH if $n == 1 || Math::Prime::Util::is_prob_prime($n);
+ $n = int($n->bstr) if ref($n) eq 'Math::BigInt' && $n <= ''.~0;
+ #last SEARCH if $n == 1 || Math::Prime::Util::is_prob_prime($n);
+ last SEARCH if $n == 1;
$limit = int( sqrt($n) + 0.001);
+ $limit = $maxlim if $limit > $maxlim;
}
$f += $finc;
}
@@ -1875,22 +1892,15 @@ sub primality_proof_bls75 {
my $B = $nm1->copy; # unfactored part
my @factors = (2);
croak "BLS75 error: n-1 not even" unless $nm1->is_even();
+ my $trial_B = 20000;
{
while ($B->is_even) { $B /= 2; $A *= 2; }
- my $tlim = $_primes_small[-1];
- if ($B > $tlim*$tlim) {
- my @small_primes = @_primes_small[2 .. $#_primes_small];
- foreach my $f (@small_primes) {
- if (($B % $f) == 0) {
- push @factors, $f;
- do { $B /= $f; $A *= $f; } while (($B % $f) == 0);
- last if $B <= $tlim*$tlim;
- }
- }
- }
- if ($B <= $tlim*$tlim) {
- push @factors, factor($B);
- $A *= $B; $B /= $B;
+ my @tf = trial_factor($B, $trial_B);
+ pop @tf if $tf[-1] > $trial_B;
+ foreach my $f (@tf) {
+ next if $f == $factors[-1];
+ push @factors, $f;
+ do { $B /= $f; $A *= $f; } while (($B % $f) == 0);
}
}
my @nstack;
@@ -1903,15 +1913,14 @@ sub primality_proof_bls75 {
} else {
push @nstack, $B;
}
- my $using_theorem_7 = 0;
+ my $theorem = 5;
while (@nstack) {
my ($s,$r) = $B->copy->bdiv($A->copy->bmul(2));
my $fpart = ($A+1) * (2*$A*$A + ($r-1) * $A + 1);
last if $n < $fpart;
# Theorem 7....
- # my $tlim = $_primes_small[-1];
- # $fpart = ($A*$tlim+1) * (2*$A*$A + ($r-$tlim) * $A + 1);
- # if ($n < $fpart) { $using_theorem_7 = 1; last; }
+ $fpart = ($A*$trial_B+1) * (2*$A*$A + ($r-$trial_B) * $A + 1);
+ if ($n < $fpart) { $theorem = 7; last; }
my $m = pop @nstack;
# Don't use bignum if it has gotten small enough.
@@ -1948,7 +1957,9 @@ sub primality_proof_bls75 {
}
# Did we factor enough?
my ($s,$r) = $B->copy->bdiv($A->copy->bmul(2));
- my $fpart = ($A+1) * (2*$A*$A + ($r-1) * $A + 1);
+ my $fpart = ($theorem == 5)
+ ? ($A+1) * (2*$A*$A + ($r-1) * $A + 1)
+ : ($A*$trial_B+1) * (2*$A*$A + ($r-$trial_B) * $A + 1);
return (1,[]) if $n >= $fpart;
# Check we didn't mess up
croak "BLS75 error: $A * $B != $nm1" unless $A*$B == $nm1;
@@ -1964,7 +1975,7 @@ sub primality_proof_bls75 {
foreach my $f (@factors) {
my $success = 0;
foreach my $a (2 .. 10000) {
- my $ap = Math::BigInt->new("$a");
+ my $ap = Math::BigInt->new($a);
next unless $ap->copy->bmodpow($nm1, $n) == 1;
next unless Math::BigInt::bgcd($ap->copy->bmodpow($nm1/$f, $n)->bsub(1), $n) == 1;
push @as, $a;
@@ -1979,8 +1990,19 @@ sub primality_proof_bls75 {
}
push @fac_proofs, (scalar @$fproof == 1) ? $fproof->[0] : $fproof;
}
- my @proof = ($n, "n-1", [@fac_proofs], [@as]);
- return (2, [@proof]);
+ if ($theorem == 5) {
+ return (2, [$n, "n-1", [@fac_proofs], [@as]]);
+ } else {
+ my $t7a = 0;
+ my $f = $B;
+ foreach my $a (2 .. 10000) {
+ my $ap = Math::BigInt->new($a);
+ next unless $ap->copy->bmodpow($nm1, $n) == 1;
+ next unless Math::BigInt::bgcd($ap->copy->bmodpow($nm1/$f, $n)->bsub(1), $n) == 1;
+ return (2, [$n, "n-1", ["B", $trial_B, $B, $a], [@fac_proofs], [@as]]);
+ }
+ }
+ return @composite;
}
diff --git a/xt/primality-proofs.pl b/xt/primality-proofs.pl
index 580be8d..4c0cf7b 100644
--- a/xt/primality-proofs.pl
+++ b/xt/primality-proofs.pl
@@ -6,7 +6,10 @@ use Math::BigInt lib=>"GMP";
#use Crypt::Primes 'maurer';
use Math::Pari qw/isprime/;
use Crypt::Random 'makerandom';
-use Data::Dump 'dump';
+use Data::Dump::Filtered 'dump_filtered';
+my $bifilter = sub { my($ctx, $n) = @_;
+ return {dump=>"$n"} if ref($n) eq "Math::BigInt";
+ undef; };
$|++;
my $num = 71;
@@ -56,7 +59,7 @@ foreach my $certn (@certs) {
print proof_mark($certn->[1]);
next if $v;
print "\n\n$certn->[0] didn't verify!\n\n";
- print dump($certn->[1]);
+ print dump_filtered($certn->[1], $bifilter);
die;
}
print "\n";
@@ -64,8 +67,8 @@ print "\n";
sub proof_mark {
my $cert = shift;
my $type = (scalar @$cert == 1) ? "bpsw" : $cert->[1];
- if (!defined $type) { die "\nNo cert:\n\n", dump($cert); }
- if ($type =~ /n-1/i) { return '1'; }
+ if (!defined $type) { die "\nNo cert:\n\n", dump_filtered($cert, $bifilter); }
+ if ($type =~ /n-1/i) { return ($cert->[2]->[0] eq 'B') ? '7' : '5'; }
elsif ($type =~ /bpsw/i) { return '.'; }
elsif ($type =~ /ecpp|agkm/i) { return 'E'; }
return '?';
--
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