This is an automated email from the git hooks/post-receive script. ppm-guest pushed a commit to annotated tag v0.36 in repository libmath-prime-util-perl.
commit 4d3882cb7ef54ef73370fdc6c40af3338cf9a773 Author: Dana Jacobsen <d...@acm.org> Date: Fri Jan 10 14:11:08 2014 -0800 Add simple (and likely buggy) Pollard Rho DLP --- TODO | 9 ++++++++ factor.c | 53 ++++++++++++++++++++++++++++++++++++++++++++ factor.h | 3 +++ t/19-moebius.t | 1 + util.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++--------- util.h | 3 +++ 6 files changed, 128 insertions(+), 10 deletions(-) diff --git a/TODO b/TODO index 6c8682a..2150c53 100644 --- a/TODO +++ b/TODO @@ -61,3 +61,12 @@ - look at sieve.c style prime walking - Add Inverse Li and Legendre Phi to API? + +- Iterators speedup: + 1) config option for sieved next_prime. Very general, would make + next_prime run fast when called many times sequentially. Nasty + mixing with threads. + 2) iterator, PrimeIterator, or PrimeArray in XS using segment sieve. + +- Perhaps have main segment know the filled in range. That would allow + a sieved next_prime, and might speed up some counts and the like. diff --git a/factor.c b/factor.c index bbb8931..636aebc 100644 --- a/factor.c +++ b/factor.c @@ -920,3 +920,56 @@ int squfof_factor(UV n, UV *factors, UV rounds) factors[0] = n; return 1; } + +UV dlp_trial(UV a, UV g, UV p, UV maxrounds) { + UV t, n = 1; + if (maxrounds > p) maxrounds = p; + for (n = 1; n < maxrounds; n++) { + t = powmod(g, n, p); + if (t == a) + return n; + } + return 0; +} + +#define pollard_rho_cycle(u,v,w,p,n,a,g) \ + switch (u % 3) { \ + case 0: u = mulmod(u,u,p); v = mulmod(v,2,n); w = mulmod(w,2,n); break;\ + case 1: u = mulmod(u,a,p); v = addmod(v,1,n); break;\ + case 2: u = mulmod(u,g,p); w = addmod(w,1,n); break;\ + } + +UV dlp_prho(UV a, UV g, UV p, UV maxrounds) { + UV i; + UV n = znorder(g, p); + UV u=1, v=0, w=0; + UV U=u, V=v, W=w; + int const verbose = _XS_get_verbose(); + + if (verbose > 1 && n != p-1) printf("for g=%lu p=%lu, order is %lu\n", g, p, n); + if (maxrounds > n) maxrounds = n; + for (i = 1; i < maxrounds; i++) { + pollard_rho_cycle(u,v,w,p,n,a,g); /* xi, ai, bi */ + pollard_rho_cycle(U,V,W,p,n,a,g); + pollard_rho_cycle(U,V,W,p,n,a,g); /* x2i, a2i, b2i */ + if (verbose > 3) printf( "%3lu %4lu %3lu %3lu %4lu %3lu %3lu\n", i, u, v, w, U, V, W ); + if (u == U) { + UV r1, r2, k; + r1 = submod(v, V, n); + if (r1 == 0) { + if (verbose) printf("DLP Rho failure, r=0\n"); + return 0; + } + r2 = submod(W, w, n); + k = divmod(r2, r1, n); + if (powmod(g,k,p) != a) { + if (verbose > 2) printf("r1 = %lu r2 = %lu k = %lu\n", r1, r2, k); + if (verbose) printf("Incorrect DLP Rho solution: %lu\n", k); + return 0; + } + if (verbose) printf("DLP Rho solution found after %lu steps\n", i); + return k; + } + } + return 0; +} diff --git a/factor.h b/factor.h index 7c4682c..03d324c 100644 --- a/factor.h +++ b/factor.h @@ -21,4 +21,7 @@ extern int squfof_factor(UV n, UV *factors, UV rounds); extern UV* _divisor_list(UV n, UV *num_divisors); +extern UV dlp_trial(UV a, UV g, UV p, UV maxrounds); +extern UV dlp_prho(UV a, UV g, UV p, UV maxrounds); + #endif diff --git a/t/19-moebius.t b/t/19-moebius.t index dd56fe6..9ee1c56 100644 --- a/t/19-moebius.t +++ b/t/19-moebius.t @@ -332,6 +332,7 @@ my @znlogs = ( [ [3,3,8], 1], [ [10,2,101], 25], [ [2,55,101], 73], # 2 = 55^73 mod 101 + [ [228,2,383], 110], [ [3061666278, 499998, 3332205179], 22], ); if ($usexs) { diff --git a/util.c b/util.c index 611fb94..9a3515c 100644 --- a/util.c +++ b/util.c @@ -1062,17 +1062,66 @@ UV znprimroot(UV n) { return 0; } -/* Find smallest n where a = g^n mod p */ -/* This implementation is just a stupid placeholder. */ +/* Calculate 1/a mod p. From William Hart. */ +UV modinverse(UV a, UV p) { + IV u1 = 1, u3 = a; + IV v1 = 0, v3 = p; + IV t1 = 0, t3 = 0; + IV quot; + while (v3) { + quot = u3 - v3; + if (u3 < (v3<<2)) { + if (quot < v3) { + if (quot < 0) { + t1 = u1; u1 = v1; v1 = t1; + t3 = u3; u3 = v3; v3 = t3; + } else { + t1 = u1 - v1; u1 = v1; v1 = t1; + t3 = u3 - v3; u3 = v3; v3 = t3; + } + } else if (quot < (v3<<1)) { + t1 = u1 - (v1<<1); u1 = v1; v1 = t1; + t3 = u3 - (v3<<1); u3 = v3; v3 = t3; + } else { + t1 = u1 - v1*3; u1 = v1; v1 = t1; + t3 = u3 - v3*3; u3 = v3; v3 = t3; + } + } else { + quot = u3 / v3; + t1 = u1 - v1*quot; u1 = v1; v1 = t1; + t3 = u3 - v3*quot; u3 = v3; v3 = t3; + } + } + if (u1 < 0) u1 += p; + return u1; +} + +UV divmod(UV a, UV b, UV n) { /* a / b mod n */ + UV binv = modinverse(b, n); + if (binv == 0) return 0; + return mulmod(a, binv, n); +} + +/* Find smallest n where a = g^n mod p + * This implementation is just a stupid placeholder. + * When prho or bsgs gets working well, lower the trial limit + */ +#define DLP_TRIAL_NUM 1000000 UV znlog(UV a, UV g, UV p) { - UV t, n = 1; - if (a == 0 || g == 0 || p < 2) return 0; - for (n = 1; n < p; n++) { - t = powmod(g, n, p); - if (t == a) - return n; - } - return 0; + UV k; + const int verbose = _XS_get_verbose(); + if (a == 0 || g == 0 || p < 2) + return 0; + k = dlp_trial(a, g, p, DLP_TRIAL_NUM); + if (k != 0 || p <= DLP_TRIAL_NUM) + return k; + if (verbose) printf(" dlp trial failed. Trying prho\n"); + k = dlp_prho(a, g, p, 1000000); + if (k != 0) + return k; + if (verbose) printf(" dlp prho failed. Back to trial\n"); + k = dlp_trial(a, g, p, p); + return k; } long double _XS_chebyshev_theta(UV n) diff --git a/util.h b/util.h index 0afdff7..e214598 100644 --- a/util.h +++ b/util.h @@ -31,6 +31,9 @@ extern int kronecker_uu(UV a, UV b); extern int kronecker_su(IV a, UV b); extern int kronecker_ss(IV a, IV b); +extern UV modinverse(UV a, UV p); /* Returns 1/a mod p */ +extern UV divmod(UV a, UV b, UV n); /* Returns a/b mod n */ + extern UV totient(UV n); extern int moebius(UV n); extern UV exp_mangoldt(UV n); -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libmath-prime-util-perl.git _______________________________________________ Pkg-perl-cvs-commits mailing list Pkg-perl-cvs-commits@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-perl-cvs-commits