static void select_point(mpz_t x, mpz_t y, mpz_t a, mpz_t b, mpz_t N, mpz_t t, mpz_t t2) { mpz_t Q, t3, t4; gmp_randstate_t* p_randstate = get_randstate(); mpz_init(Q); mpz_init(t3); mpz_init(t4); mpz_set_ui(y, 0); while (mpz_sgn(y) == 0) { /* select a Q s.t. (Q,N) != -1 */ do { do { /* mpz_urandomm(x, *p_randstate, N); */ mpz_urandomb(x, *p_randstate, 32); /* May as well make x small */ mpz_mod(x, x, N); } while (mpz_sgn(x) == 0); mpz_mul(t, x, x); mpz_add(t, t, a); mpz_mul(t, t, x); mpz_add(t, t, b); mpz_mod(Q, t, N); } while (mpz_jacobi(Q, N) == -1); /* Select Y */ sqrtmod(y, Q, N, t, t2, t3, t4); /* TODO: if y^2 mod Ni != t, return composite */ if (mpz_sgn(y) == 0) croak("y == 0 in point selection\n"); } mpz_clear(Q); mpz_clear(t3); mpz_clear(t4); }
static PyObject * GMPy_MPZ_Function_Jacobi(PyObject *self, PyObject *args) { MPZ_Object *tempx = NULL, *tempy = NULL; long res; if (PyTuple_GET_SIZE(args) != 2) { TYPE_ERROR("jacobi() requires 'mpz','mpz' arguments"); return NULL; } if (!(tempx = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL)) || !(tempy = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL))) { Py_XDECREF((PyObject*)tempx); Py_XDECREF((PyObject*)tempy); return NULL; } if (mpz_sgn(tempy->z) <= 0 || mpz_even_p(tempy->z)) { VALUE_ERROR("y must be odd and >0"); Py_DECREF((PyObject*)tempx); Py_DECREF((PyObject*)tempy); return NULL; } res = (long)(mpz_jacobi(tempx->z, tempy->z)); Py_DECREF((PyObject*)tempx); Py_DECREF((PyObject*)tempy); return PyIntOrLong_FromLong(res); }
/* See Cohen 1.5.3 */ int modified_cornacchia(mpz_t x, mpz_t y, mpz_t D, mpz_t p) { int result = 0; mpz_t a, b, c, d; if (mpz_cmp_ui(p, 2) == 0) { mpz_add_ui(x, D, 8); if (mpz_perfect_square_p(x)) { mpz_sqrt(x, x); mpz_set_ui(y, 1); result = 1; } return result; } if (mpz_jacobi(D, p) == -1) /* No solution */ return 0; mpz_init(a); mpz_init(b); mpz_init(c); mpz_init(d); sqrtmod(x, D, p, a, b, c, d); if ( (mpz_even_p(D) && mpz_odd_p(x)) || (mpz_odd_p(D) && mpz_even_p(x)) ) mpz_sub(x, p, x); mpz_mul_ui(a, p, 2); mpz_set(b, x); mpz_sqrt(c, p); mpz_mul_ui(c, c, 2); /* Euclidean algorithm */ while (mpz_cmp(b, c) > 0) { mpz_set(d, a); mpz_set(a, b); mpz_mod(b, d, b); } mpz_mul_ui(c, p, 4); mpz_mul(a, b, b); mpz_sub(a, c, a); /* a = 4p - b^2 */ mpz_abs(d, D); /* d = |D| */ if (mpz_divisible_p(a, d)) { mpz_divexact(c, a, d); if (mpz_perfect_square_p(c)) { mpz_set(x, b); mpz_sqrt(y, c); result = 1; } } mpz_clear(a); mpz_clear(b); mpz_clear(c); mpz_clear(d); return result; }
/* ************************************************************************* * mpz_euler_prp: (also called a Solovay-Strassen pseudoprime) * An "Euler pseudoprime" to the base a is an odd composite number n with, * (a,n)=1 such that a^((n-1)/2)=(a/n) mod n [(a/n) is the Jacobi symbol] * *************************************************************************/ int mpz_euler_prp(mpz_t n, mpz_t a) { mpz_t res; mpz_t exp; int ret = 0; if (mpz_cmp_ui(a, 2) < 0) return PRP_ERROR; if (mpz_cmp_ui(n, 2) < 0) return PRP_COMPOSITE; if (mpz_divisible_ui_p(n, 2)) { if (mpz_cmp_ui(n, 2) == 0) return PRP_PRIME; else return PRP_COMPOSITE; } mpz_init_set_ui(res, 0); mpz_gcd(res, n, a); if (mpz_cmp_ui(res, 1) > 0) { mpz_clear(res); return PRP_COMPOSITE; } mpz_init_set(exp, n); mpz_sub_ui(exp, exp, 1); /* exp = n-1 */ mpz_divexact_ui(exp, exp, 2); /* exp = (n-1)/2 */ mpz_powm(res, a, exp, n); /* reuse exp to calculate jacobi(a,n) mod n */ ret = mpz_jacobi(a,n); mpz_set(exp, n); if (ret == -1) mpz_sub_ui(exp, exp, 1); else if (ret == 1) mpz_add_ui(exp, exp, 1); mpz_mod(exp, exp, n); if (mpz_cmp(res, exp) == 0) { mpz_clear(res); mpz_clear(exp); return PRP_PRP; } else { mpz_clear(res); mpz_clear(exp); return PRP_COMPOSITE; } }/* method mpz_euler_prp */
/* find square root of a modulo p (p prime) */ int sqrtmod(int a,int p) { int p8,alpha,i; int x,c,s,n,b,J,r2a,r,ret; mpz_t za,zp; if(p==2) return a&1; mpz_init_set_si(za,a); mpz_init_set_si(zp,p); if(mpz_jacobi(za,zp)!=1) { /* no square root */ ret=0; goto end; } p8=p&7; if(p8==3 || p8==5 || p8==7) { if((p8&3)==3) { ret=powmod(a,(p+1)/4,p); goto end; } x=powmod(a,(p+3)/8,p); c=(ll)x*x%p; ret=c==a?x:(ll)x*powmod(2,(p-1)/4,p)%p; goto end; } alpha=0; s=p-1; while(!(s&1)) s>>=1,alpha++; r=powmod(a,(s+1)/2,p); r2a=(ll)r*powmod(a,(s+1)/2-1,p)%p; do { n=rand31()%(p-2)+2; mpz_set_si(za,n); } while(mpz_jacobi(za,zp)!=-1); b=powmod(n,s,p); J=0; for(i=0;i<alpha-1;i++) { c=powmod(b,2*J,p); c=(ll)r2a*c%p; c=powmod(c,1<<(alpha-i-2),p); if(c==p-1) J+=1<<i; } ret=(ll)r*powmod(b,J,p)%p; end: mpz_clear(zp); mpz_clear(za); return ret; }
/* checks if the factor p was found by P+1 or P-1 (when prime). a is the initial seed. */ static void pp1_check_factor (mpz_t a, mpz_t p) { if (mpz_probab_prime_p (p, PROBAB_PRIME_TESTS)) { mpz_mul (a, a, a); mpz_sub_ui (a, a, 4); if (mpz_jacobi (a, p) == 1) outputf (OUTPUT_NORMAL, "[factor found by P-1]\n"); } }
/* See Cohen 1.5.2 */ int cornacchia(mpz_t x, mpz_t y, mpz_t D, mpz_t p) { int result = 0; mpz_t a, b, c, d; if (mpz_jacobi(D, p) < 0) /* No solution */ return 0; mpz_init(a); mpz_init(b); mpz_init(c); mpz_init(d); sqrtmod(x, D, p, a, b, c, d); mpz_set(a, p); mpz_set(b, x); mpz_sqrt(c, p); while (mpz_cmp(b,c) > 0) { mpz_set(d, a); mpz_set(a, b); mpz_mod(b, d, b); } mpz_mul(a, b, b); mpz_sub(a, p, a); /* a = p - b^2 */ mpz_abs(d, D); /* d = |D| */ if (mpz_divisible_p(a, d)) { mpz_divexact(c, a, d); if (mpz_perfect_square_p(c)) { mpz_set(x, b); mpz_sqrt(y, c); result = 1; } } mpz_clear(a); mpz_clear(b); mpz_clear(c); mpz_clear(d); return result; }
static int E1 (MP_INT *out, const MP_INT *in, const MP_INT *n) { mpz_mul_2exp (out, in, 1); mpz_add_ui (out, out, 1); switch (mpz_jacobi (out, n)) { case 1: mpz_mul_2exp (out, out, 2); break; case -1: mpz_mul_2exp (out, out, 1); break; case 0: return -1; /* key factored! */ } if (mpz_cmp (out, n) >= 0) return -1; /* input was too large */ return 0; }
static void select_curve_params(mpz_t a, mpz_t b, mpz_t g, long D, mpz_t *roots, long i, mpz_t N, mpz_t t) { int N_is_not_1_congruent_3; mpz_set_ui(a, 0); mpz_set_ui(b, 0); if (D == -3) { mpz_set_si(b, -1); } else if (D == -4) { mpz_set_si(a, -1); } else { mpz_sub_ui(t, roots[i], 1728); mpz_mod(t, t, N); /* c = (j * inverse(j-1728)) mod n */ if (mpz_divmod(b, roots[i], t, N, b)) { mpz_mul_si(a, b, -3); /* r = -3c */ mpz_mul_si(b, b, 2); /* s = 2c */ } } mpz_mod(a, a, N); mpz_mod(b, b, N); /* g: 1 < g < Ni && (g/Ni) != -1 && (g%3!=1 || cubic non-residue) */ N_is_not_1_congruent_3 = ! mpz_congruent_ui_p(N, 1, 3); for ( mpz_set_ui(g, 2); mpz_cmp(g, N) < 0; mpz_add_ui(g, g, 1) ) { if (mpz_jacobi(g, N) != -1) continue; if (N_is_not_1_congruent_3) break; mpz_sub_ui(t, N, 1); mpz_tdiv_q_ui(t, t, 3); mpz_powm(t, g, t, N); /* t = g^((Ni-1)/3) mod Ni */ if (mpz_cmp_ui(t, 1) == 0) continue; if (D == -3) { mpz_powm_ui(t, t, 3, N); if (mpz_cmp_ui(t, 1) != 0) /* Additional check when D == -3 */ continue; } break; } if (mpz_cmp(g, N) >= 0) /* No g can be found: N is composite */ mpz_set_ui(g, 0); }
static Variant HHVM_FUNCTION(gmp_jacobi, const Variant& dataA, const Variant& dataB) { mpz_t gmpDataA, gmpDataB; if (!variantToGMPData(cs_GMP_FUNC_NAME_GMP_JACOBI, gmpDataA, dataA)) { return false; } if (!variantToGMPData(cs_GMP_FUNC_NAME_GMP_JACOBI, gmpDataB, dataB)) { mpz_clear(gmpDataA); return false; } int64_t result = mpz_jacobi(gmpDataA, gmpDataB); mpz_clear(gmpDataA); mpz_clear(gmpDataB); return result; }
static int VNRW_GMP_E1( const VNAsymCryptCtx_t * ctx, mpz_t zm ) { int ret = 0, jacobi = 0; VNRW_GMP_Ctx_t * gmpCtx = VN_CONTAINER_OF( ctx, VNRW_GMP_Ctx_t, mCtx ); assert( VN_TYPE_VNRWSign_GMP == ctx->mType || VN_TYPE_VNRWEnc_GMP == ctx->mType ); mpz_mul_ui( zm, zm, 2 ); mpz_add_ui( zm, zm, 1 ); jacobi = mpz_jacobi( zm, gmpCtx->mN ); if( 1 == jacobi ) { mpz_mul_ui( zm, zm, 4 ); } else if( -1 == jacobi ) { mpz_mul_ui( zm, zm, 2 ); } else { ret = 0; } return ret; }
/* Recursive routine to prove via ECPP */ static int ecpp_down(int i, mpz_t Ni, int facstage, int *pmaxH, int* dilist, mpz_t* sfacs, int* nsfacs, char** prooftextptr) { mpz_t a, b, u, v, m, q, minfactor, sqrtn, mD, t, t2; mpz_t mlist[6]; mpz_t qlist[6]; UV nm1a; IV np1lp, np1lq; struct ec_affine_point P; int k, dindex, pindex, nidigits, facresult, curveresult, downresult, stage, D; int verbose = get_verbose_level(); nidigits = mpz_sizeinbase(Ni, 10); downresult = _GMP_is_prob_prime(Ni); if (downresult == 0) return 0; if (downresult == 2) { if (mpz_sizeinbase(Ni,2) <= 64) { /* No need to put anything in the proof */ if (verbose) printf("%*sN[%d] (%d dig) PRIME\n", i, "", i, nidigits); return 2; } downresult = 1; } if (i == 0 && facstage == 2 && miller_rabin_random(Ni, 2, 0) == 0) { gmp_printf("\n\n**** BPSW counter-example found? ****\n**** N = %Zd ****\n\n", Ni); return 0; } VERBOSE_PRINT_N(i, nidigits, *pmaxH, facstage); mpz_init(a); mpz_init(b); mpz_init(u); mpz_init(v); mpz_init(m); mpz_init(q); mpz_init(mD); mpz_init(minfactor); mpz_init(sqrtn); mpz_init(t); mpz_init(t2); mpz_init(P.x);mpz_init(P.y); for (k = 0; k < 6; k++) { mpz_init(mlist[k]); mpz_init(qlist[k]); } /* Any factors q found must be strictly > minfactor. * See Atkin and Morain, 1992, section 6.4 */ mpz_root(minfactor, Ni, 4); mpz_add_ui(minfactor, minfactor, 1); mpz_mul(minfactor, minfactor, minfactor); mpz_sqrt(sqrtn, Ni); stage = 0; if (nidigits > 700) stage = 1; /* Too rare to find them */ if (i == 0 && facstage > 1) stage = facstage; for ( ; stage <= facstage; stage++) { int next_stage = (stage > 1) ? stage : 1; for (dindex = -1; dindex < 0 || dilist[dindex] != 0; dindex++) { int poly_type; /* just for debugging/verbose */ int poly_degree; int allq = (nidigits < 400); /* Do all q values together, or not */ if (dindex == -1) { /* n-1 and n+1 tests */ int nm1_success = 0; int np1_success = 0; const char* ptype = ""; mpz_sub_ui(m, Ni, 1); mpz_sub_ui(t2, sqrtn, 1); mpz_tdiv_q_2exp(t2, t2, 1); /* t2 = minfactor */ nm1_success = check_for_factor(u, m, t2, t, stage, sfacs, nsfacs, 0); mpz_add_ui(m, Ni, 1); mpz_add_ui(t2, sqrtn, 1); mpz_tdiv_q_2exp(t2, t2, 1); /* t2 = minfactor */ np1_success = check_for_factor(v, m, t2, t, stage, sfacs, nsfacs, 0); /* If both successful, pick smallest */ if (nm1_success > 0 && np1_success > 0) { if (mpz_cmp(u, v) <= 0) np1_success = 0; else nm1_success = 0; } if (nm1_success > 0) { ptype = "n-1"; mpz_set(q, u); D = 1; } else if (np1_success > 0) { ptype = "n+1"; mpz_set(q, v); D = -1; } else continue; if (verbose) { printf(" %s\n", ptype); fflush(stdout); } downresult = ecpp_down(i+1, q, next_stage, pmaxH, dilist, sfacs, nsfacs, prooftextptr); if (downresult == 0) goto end_down; /* composite */ if (downresult == 1) { /* nothing found at this stage */ VERBOSE_PRINT_N(i, nidigits, *pmaxH, facstage); continue; } if (verbose) { printf("%*sN[%d] (%d dig) %s", i, "", i, nidigits, ptype); fflush(stdout); } curveresult = (nm1_success > 0) ? _GMP_primality_bls_3(Ni, q, &nm1a) : _GMP_primality_bls_15(Ni, q, &np1lp, &np1lq); if (verbose) { printf(" %d\n", curveresult); fflush(stdout); } if ( ! curveresult ) { /* This ought not happen */ if (verbose) gmp_printf("\n Could not prove %s with N = %Zd\n", ptype, Ni); downresult = 1; continue; } goto end_down; } pindex = dilist[dindex]; if (pindex < 0) continue; /* We marked this for skip */ /* Get the values for D, degree, and poly type */ poly_degree = poly_class_poly_num(pindex, &D, NULL, &poly_type); if (poly_degree == 0) croak("Unknown value in dilist[%d]: %d\n", dindex, pindex); if ( (-D % 4) != 3 && (-D % 16) != 4 && (-D % 16) != 8 ) croak("Invalid discriminant '%d' in list\n", D); /* D must also be squarefree in odd divisors, but assume it. */ /* Make sure we can get a class polynomial for this D. */ if (poly_degree > 16 && stage == 0) { if (verbose) printf(" [1]"); break; } /* Make the continue-search vs. backtrack decision */ if (*pmaxH > 0 && poly_degree > *pmaxH) break; mpz_set_si(mD, D); /* (D/N) must be 1, and we have to have a u,v solution */ if (mpz_jacobi(mD, Ni) != 1) continue; if ( ! modified_cornacchia(u, v, mD, Ni) ) continue; if (verbose > 1) { printf(" %d", D); fflush(stdout); } /* We're going to factor all the values for this discriminant then pick * the smallest. This adds a little time, but it means we go down * faster. This makes smaller proofs, and might even save time. */ choose_m(mlist, D, u, v, Ni, t, t2); if (allq) { int x, y; /* We have 0 to 6 m values. Try to factor them, put in qlist. */ for (k = 0; k < 6; k++) { mpz_set_ui(qlist[k], 0); if (mpz_sgn(mlist[k])) { facresult = check_for_factor(qlist[k], mlist[k], minfactor, t, stage, sfacs, nsfacs, poly_degree); /* -1 = couldn't find, 0 = no big factors, 1 = found */ if (facresult <= 0) mpz_set_ui(qlist[k], 0); } } /* Sort any q values by size, so we work on the smallest first */ for (x = 0; x < 5; x++) if (mpz_sgn(qlist[x])) for (y = x+1; y < 6; y++) if (mpz_sgn(qlist[y]) && mpz_cmp(qlist[x],qlist[y]) > 0) { mpz_swap( qlist[x], qlist[y] ); mpz_swap( mlist[x], mlist[y] ); } } /* Try to make a proof with the first (smallest) q value. * Repeat for others if we have to. */ for (k = 0; k < 6; k++) { int maxH = *pmaxH; int minH = (nidigits <= 240) ? 7 : (nidigits+39)/40; if (allq) { if (mpz_sgn(qlist[k]) == 0) continue; mpz_set(m, mlist[k]); mpz_set(q, qlist[k]); } else { if (mpz_sgn(mlist[k]) == 0) continue; mpz_set(m, mlist[k]); facresult = check_for_factor(q, m, minfactor, t, stage, sfacs, nsfacs, poly_degree); if (facresult <= 0) continue; } if (verbose) { printf(" %d (%s %d)\n", D, poly_class_type_name(poly_type), poly_degree); fflush(stdout); } if (maxH == 0) { maxH = minH-1 + poly_degree; if (facstage > 1) /* We worked hard to get here, */ maxH = 2*maxH + 10; /* try hard to make use of it. */ } else if (maxH > minH && maxH > (poly_degree+2)) { maxH--; } /* Great, now go down. */ downresult = ecpp_down(i+1, q, next_stage, &maxH, dilist, sfacs, nsfacs, prooftextptr); /* Nothing found, look at more polys in the future */ if (downresult == 1 && *pmaxH > 0) *pmaxH = maxH; if (downresult == 0) goto end_down; /* composite */ if (downresult == 1) { /* nothing found at this stage */ VERBOSE_PRINT_N(i, nidigits, *pmaxH, facstage); continue; } /* Awesome, we found the q chain and are in STAGE 2 */ if (verbose) { printf("%*sN[%d] (%d dig) %d (%s %d)", i, "", i, nidigits, D, poly_class_type_name(poly_type), poly_degree); fflush(stdout); } /* Try with only one or two roots, then 8 if that didn't work. */ /* TODO: This should be done using a root iterator in find_curve() */ curveresult = find_curve(a, b, P.x, P.y, D, pindex, m, q, Ni, 1); if (curveresult == 1) { if (verbose) { printf(" [redo roots]"); fflush(stdout); } curveresult = find_curve(a, b, P.x, P.y, D, pindex, m, q, Ni, 8); } if (verbose) { printf(" %d\n", curveresult); fflush(stdout); } if (curveresult == 1) { /* Something is wrong. Very likely the class poly coefficients are incorrect. We've wasted lots of time, and need to try again. */ dilist[dindex] = -2; /* skip this D value from now on */ if (verbose) gmp_printf("\n Invalidated D = %d with N = %Zd\n", D, Ni); downresult = 1; continue; } /* We found it was composite or proved it */ goto end_down; } /* k loop for D */ } /* D */ } /* fac stage */ /* Nothing at this level */ if (downresult != 1) croak("ECPP internal error: downresult is %d at end\n", downresult); if (verbose) { if (*pmaxH > 0) printf(" (max %d)", *pmaxH); printf(" ---\n"); fflush(stdout); } if (*pmaxH > 0) *pmaxH = *pmaxH + 2; end_down: if (downresult == 2) { if (0 && verbose > 1) { gmp_printf("\n"); if (D == 1) { gmp_printf("Type BLS3\nN %Zd\nQ %Zd\nA %"UVuf"\n", Ni, q, nm1a); } else if (D == -1) { gmp_printf("Type BLS15\nN %Zd\nQ %Zd\nLP %"IVdf"\nLQ %"IVdf"\n", Ni, q, np1lp, np1lq); } else { gmp_printf("Type ECPP\nN %Zd\nA %Zd\nB %Zd\nM %Zd\nQ %Zd\nX %Zd\nY %Zd\n", Ni, a, b, m, q, P.x, P.y); } gmp_printf("\n"); fflush(stdout); } /* Prepend our proof to anything that exists. */ if (prooftextptr != 0) { char *proofstr, *proofptr; int curprooflen = (*prooftextptr == 0) ? 0 : strlen(*prooftextptr); if (D == 1) { int myprooflen = 20 + 2*(4 + mpz_sizeinbase(Ni, 10)) + 1*21; New(0, proofstr, myprooflen + curprooflen + 1, char); proofptr = proofstr; proofptr += gmp_sprintf(proofptr, "Type BLS3\nN %Zd\nQ %Zd\n", Ni,q); proofptr += sprintf(proofptr, "A %"UVuf"\n", nm1a); } else if (D == -1) {
// TODO: Custom implementation? inline int JacobiSymbol( const BigInt& m, const BigInt& n ) { return mpz_jacobi( m.LockedPointer(), n.LockedPointer() ); }
static PyObject * GMPY_mpz_is_extrastronglucas_prp(PyObject *self, PyObject *args) { MPZ_Object *n, *p; PyObject *result = 0; mpz_t zD, s, nmj, nm2, res; /* these are needed for the LucasU and LucasV part of this function */ mpz_t uh, vl, vh, ql, qh, tmp; mp_bitcnt_t r = 0, j = 0; int ret = 0; if (PyTuple_Size(args) != 2) { TYPE_ERROR("is_extra_strong_lucas_prp() requires 2 integer arguments"); return NULL; } mpz_init(zD); mpz_init(s); mpz_init(nmj); mpz_init(nm2); mpz_init(res); mpz_init(uh); mpz_init(vl); mpz_init(vh); mpz_init(ql); mpz_init(qh); mpz_init(tmp); n = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL); p = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL); if (!n || !p) { TYPE_ERROR("is_extra_strong_lucas_prp() requires 2 integer arguments"); goto cleanup; } /* Check if p*p - 4 == 0. */ mpz_mul(zD, p->z, p->z); mpz_sub_ui(zD, zD, 4); if (mpz_sgn(zD) == 0) { VALUE_ERROR("invalid value for p in is_extra_strong_lucas_prp()"); goto cleanup; } /* Require n > 0. */ if (mpz_sgn(n->z) <= 0) { VALUE_ERROR("is_extra_strong_lucas_prp() requires 'n' be greater than 0"); goto cleanup; } /* Check for n == 1 */ if (mpz_cmp_ui(n->z, 1) == 0) { result = Py_False; goto cleanup; } /* Handle n even. */ if (mpz_divisible_ui_p(n->z, 2)) { if (mpz_cmp_ui(n->z, 2) == 0) result = Py_True; else result = Py_False; goto cleanup; } /* Check GCD */ mpz_mul_ui(res, zD, 2); mpz_gcd(res, res, n->z); if ((mpz_cmp(res, n->z) != 0) && (mpz_cmp_ui(res, 1) > 0)) { VALUE_ERROR("is_extra_strong_lucas_prp() requires gcd(n,2*D) == 1"); goto cleanup; } /* nmj = n - (D/n), where (D/n) is the Jacobi symbol */ mpz_set(nmj, n->z); ret = mpz_jacobi(zD, n->z); if (ret == -1) mpz_add_ui(nmj, nmj, 1); else if (ret == 1) mpz_sub_ui(nmj, nmj, 1); r = mpz_scan1(nmj, 0); mpz_fdiv_q_2exp(s, nmj, r); mpz_set(nm2, n->z); mpz_sub_ui(nm2, nm2, 2); /* make sure that either U_s == 0 mod n or V_s == +/-2 mod n, or */ /* V_((2^t)*s) == 0 mod n for some t with 0 <= t < r-1 */ mpz_set_si(uh, 1); mpz_set_si(vl, 2); mpz_set(vh, p->z); mpz_set_si(ql, 1); mpz_set_si(qh, 1); mpz_set_si(tmp,0); for (j = mpz_sizeinbase(s,2)-1; j >= 1; j--) { /* ql = ql*qh (mod n) */ mpz_mul(ql, ql, qh); mpz_mod(ql, ql, n->z); if (mpz_tstbit(s,j) == 1) { /* qh = ql*q */ mpz_set(qh, ql); /* uh = uh*vh (mod n) */ mpz_mul(uh, uh, vh); mpz_mod(uh, uh, n->z); /* vl = vh*vl - p*ql (mod n) */ mpz_mul(vl, vh, vl); mpz_mul(tmp, ql, p->z); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n->z); /* vh = vh*vh - 2*qh (mod n) */ mpz_mul(vh, vh, vh); mpz_mul_si(tmp, qh, 2); mpz_sub(vh, vh, tmp); mpz_mod(vh, vh, n->z); } else { /* qh = ql */ mpz_set(qh, ql); /* uh = uh*vl - ql (mod n) */ mpz_mul(uh, uh, vl); mpz_sub(uh, uh, ql); mpz_mod(uh, uh, n->z); /* vh = vh*vl - p*ql (mod n) */ mpz_mul(vh, vh, vl); mpz_mul(tmp, ql, p->z); mpz_sub(vh, vh, tmp); mpz_mod(vh, vh, n->z); /* vl = vl*vl - 2*ql (mod n) */ mpz_mul(vl, vl, vl); mpz_mul_si(tmp, ql, 2); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n->z); } } /* ql = ql*qh */ mpz_mul(ql, ql, qh); /* qh = ql*q */ mpz_set(qh, ql); /* uh = uh*vl - ql */ mpz_mul(uh, uh, vl); mpz_sub(uh, uh, ql); /* vl = vh*vl - p*ql */ mpz_mul(vl, vh, vl); mpz_mul(tmp, ql, p->z); mpz_sub(vl, vl, tmp); /* ql = ql*qh */ mpz_mul(ql, ql, qh); mpz_mod(uh, uh, n->z); mpz_mod(vl, vl, n->z); /* uh contains LucasU_s and vl contains LucasV_s */ if ((mpz_cmp_ui(uh, 0) == 0) || (mpz_cmp_ui(vl, 0) == 0) || (mpz_cmp(vl, nm2) == 0) || (mpz_cmp_si(vl, 2) == 0)) { result = Py_True; goto cleanup; } for (j = 1; j < r-1; j++) { /* vl = vl*vl - 2*ql (mod n) */ mpz_mul(vl, vl, vl); mpz_mul_si(tmp, ql, 2); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n->z); /* ql = ql*ql (mod n) */ mpz_mul(ql, ql, ql); mpz_mod(ql, ql, n->z); if (mpz_cmp_ui(vl, 0) == 0) { result = Py_True; goto cleanup; } } result = Py_False; cleanup: Py_XINCREF(result); mpz_clear(zD); mpz_clear(s); mpz_clear(nmj); mpz_clear(nm2); mpz_clear(res); mpz_clear(uh); mpz_clear(vl); mpz_clear(vh); mpz_clear(ql); mpz_clear(qh); mpz_clear(tmp); Py_XDECREF((PyObject*)p); Py_XDECREF((PyObject*)n); return result; }
static PyObject * GMPY_mpz_is_lucas_prp(PyObject *self, PyObject *args) { MPZ_Object *n, *p, *q; PyObject *result = 0; mpz_t zD, res, index; /* used for calculating the Lucas U sequence */ mpz_t uh, vl, vh, ql, qh, tmp; mp_bitcnt_t s = 0, j = 0; int ret; if (PyTuple_Size(args) != 3) { TYPE_ERROR("is_lucas_prp() requires 3 integer arguments"); return NULL; } mpz_init(zD); mpz_init(res); mpz_init(index); mpz_init(uh); mpz_init(vl); mpz_init(vh); mpz_init(ql); mpz_init(qh); mpz_init(tmp); n = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL); p = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL); q = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 2), NULL); if (!n || !p || !q) { TYPE_ERROR("is_lucas_prp() requires 3 integer arguments"); goto cleanup; } /* Check if p*p - 4*q == 0. */ mpz_mul(zD, p->z, p->z); mpz_mul_ui(tmp, q->z, 4); mpz_sub(zD, zD, tmp); if (mpz_sgn(zD) == 0) { VALUE_ERROR("invalid values for p,q in is_lucas_prp()"); goto cleanup; } /* Require n > 0. */ if (mpz_sgn(n->z) <= 0) { VALUE_ERROR("is_lucas_prp() requires 'n' be greater than 0"); goto cleanup; } /* Check for n == 1 */ if (mpz_cmp_ui(n->z, 1) == 0) { result = Py_False; goto cleanup; } /* Handle n even. */ if (mpz_divisible_ui_p(n->z, 2)) { if (mpz_cmp_ui(n->z, 2) == 0) result = Py_True; else result = Py_False; goto cleanup; } /* Check GCD */ mpz_mul(res, zD, q->z); mpz_mul_ui(res, res, 2); mpz_gcd(res, res, n->z); if ((mpz_cmp(res, n->z) != 0) && (mpz_cmp_ui(res, 1) > 0)) { VALUE_ERROR("is_lucas_prp() requires gcd(n,2*q*D) == 1"); goto cleanup; } /* index = n-(D/n), where (D/n) is the Jacobi symbol */ mpz_set(index, n->z); ret = mpz_jacobi(zD, n->z); if (ret == -1) mpz_add_ui(index, index, 1); else if (ret == 1) mpz_sub_ui(index, index, 1); /* mpz_lucasumod(res, p, q, index, n); */ mpz_set_si(uh, 1); mpz_set_si(vl, 2); mpz_set(vh, p->z); mpz_set_si(ql, 1); mpz_set_si(qh, 1); mpz_set_si(tmp,0); s = mpz_scan1(index, 0); for (j = mpz_sizeinbase(index,2)-1; j >= s+1; j--) { /* ql = ql*qh (mod n) */ mpz_mul(ql, ql, qh); mpz_mod(ql, ql, n->z); if (mpz_tstbit(index,j) == 1) { /* qh = ql*q */ mpz_mul(qh, ql, q->z); /* uh = uh*vh (mod n) */ mpz_mul(uh, uh, vh); mpz_mod(uh, uh, n->z); /* vl = vh*vl - p*ql (mod n) */ mpz_mul(vl, vh, vl); mpz_mul(tmp, ql, p->z); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n->z); /* vh = vh*vh - 2*qh (mod n) */ mpz_mul(vh, vh, vh); mpz_mul_si(tmp, qh, 2); mpz_sub(vh, vh, tmp); mpz_mod(vh, vh, n->z); } else { /* qh = ql */ mpz_set(qh, ql); /* uh = uh*vl - ql (mod n) */ mpz_mul(uh, uh, vl); mpz_sub(uh, uh, ql); mpz_mod(uh, uh, n->z); /* vh = vh*vl - p*ql (mod n) */ mpz_mul(vh, vh, vl); mpz_mul(tmp, ql, p->z); mpz_sub(vh, vh, tmp); mpz_mod(vh, vh, n->z); /* vl = vl*vl - 2*ql (mod n) */ mpz_mul(vl, vl, vl); mpz_mul_si(tmp, ql, 2); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n->z); } } /* ql = ql*qh */ mpz_mul(ql, ql, qh); /* qh = ql*q */ mpz_mul(qh, ql, q->z); /* uh = uh*vl - ql */ mpz_mul(uh, uh, vl); mpz_sub(uh, uh, ql); /* vl = vh*vl - p*ql */ mpz_mul(vl, vh, vl); mpz_mul(tmp, ql, p->z); mpz_sub(vl, vl, tmp); /* ql = ql*qh */ mpz_mul(ql, ql, qh); for (j = 1; j <= s; j++) { /* uh = uh*vl (mod n) */ mpz_mul(uh, uh, vl); mpz_mod(uh, uh, n->z); /* vl = vl*vl - 2*ql (mod n) */ mpz_mul(vl, vl, vl); mpz_mul_si(tmp, ql, 2); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n->z); /* ql = ql*ql (mod n) */ mpz_mul(ql, ql, ql); mpz_mod(ql, ql, n->z); } /* uh contains our return value */ mpz_mod(res, uh, n->z); if (mpz_cmp_ui(res, 0) == 0) result = Py_True; else result = Py_False; cleanup: Py_XINCREF(result); mpz_clear(zD); mpz_clear(res); mpz_clear(index); mpz_clear(uh); mpz_clear(vl); mpz_clear(vh); mpz_clear(ql); mpz_clear(qh); mpz_clear(tmp); Py_XDECREF((PyObject*)p); Py_XDECREF((PyObject*)q); Py_XDECREF((PyObject*)n); return result; }
static PyObject * GMPY_mpz_is_euler_prp(PyObject *self, PyObject *args) { MPZ_Object *a, *n; PyObject *result = 0; mpz_t res, exp; int ret; if (PyTuple_Size(args) != 2) { TYPE_ERROR("is_euler_prp() requires 2 integer arguments"); return NULL; } n = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL); a = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL); if (!a || !n) { TYPE_ERROR("is_euler_prp() requires 2 integer arguments"); goto cleanup; } mpz_init(res); mpz_init(exp); /* Require a >= 2. */ if (mpz_cmp_ui(a->z, 2) < 0) { VALUE_ERROR("is_euler_prp() requires 'a' greater than or equal to 2"); goto cleanup; } /* Require n > 0. */ if (mpz_sgn(n->z) <= 0) { VALUE_ERROR("is_euler_prp() requires 'n' be greater than 0"); goto cleanup; } /* Check for n == 1 */ if (mpz_cmp_ui(n->z, 1) == 0) { result = Py_False; goto cleanup; } /* Handle n even. */ if (mpz_divisible_ui_p(n->z, 2)) { if (mpz_cmp_ui(n->z, 2) == 0) result = Py_True; else result = Py_False; goto cleanup; } /* Check gcd(a,b) */ mpz_gcd(res, n->z, a->z); if (mpz_cmp_ui(res, 1) > 0) { VALUE_ERROR("is_euler_prp() requires gcd(n,a) == 1"); goto cleanup; } mpz_set(exp, n->z); mpz_sub_ui(exp, exp, 1); mpz_divexact_ui(exp, exp, 2); mpz_powm(res, a->z, exp, n->z); /* reuse exp to calculate jacobi(a,n) mod n */ ret = mpz_jacobi(a->z,n->z); mpz_set(exp, n->z); if (ret == -1) mpz_sub_ui(exp, exp, 1); else if (ret == 1) mpz_add_ui(exp, exp, 1); mpz_mod(exp, exp, n->z); if (mpz_cmp(res, exp) == 0) result = Py_True; else result = Py_False; cleanup: Py_XINCREF(result); mpz_clear(res); mpz_clear(exp); Py_XDECREF((PyObject*)a); Py_XDECREF((PyObject*)n); return result; }
static PyObject * GMPY_mpz_is_strongselfridge_prp(PyObject *self, PyObject *args) { MPZ_Object *n; PyObject *result = 0, *temp = 0; long d = 5, p = 1, q = 0, max_d = 1000000; int jacobi = 0; mpz_t zD; if (PyTuple_Size(args) != 1) { TYPE_ERROR("is_strong_selfridge_prp() requires 1 integer argument"); return NULL; } mpz_init(zD); n = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL); if (!n) { TYPE_ERROR("is_strong_selfridge_prp() requires 1 integer argument"); goto cleanup; } /* Require n > 0. */ if (mpz_sgn(n->z) <= 0) { VALUE_ERROR("is_strong_selfridge_prp() requires 'n' be greater than 0"); goto cleanup; } /* Check for n == 1 */ if (mpz_cmp_ui(n->z, 1) == 0) { result = Py_False; goto cleanup; } /* Handle n even. */ if (mpz_divisible_ui_p(n->z, 2)) { if (mpz_cmp_ui(n->z, 2) == 0) result = Py_True; else result = Py_False; goto cleanup; } mpz_set_ui(zD, d); while (1) { jacobi = mpz_jacobi(zD, n->z); /* if jacobi == 0, d is a factor of n, therefore n is composite... */ /* if d == n, then either n is either prime or 9... */ if (jacobi == 0) { if ((mpz_cmpabs(zD, n->z) == 0) && (mpz_cmp_ui(zD, 9) != 0)) { result = Py_True; goto cleanup; } else { result = Py_False; goto cleanup; } } if (jacobi == -1) break; /* if we get to the 5th d, make sure we aren't dealing with a square... */ if (d == 13) { if (mpz_perfect_square_p(n->z)) { result = Py_False; goto cleanup; } } if (d < 0) { d *= -1; d += 2; } else { d += 2; d *= -1; } /* make sure we don't search forever */ if (d >= max_d) { VALUE_ERROR("appropriate value for D cannot be found in is_strong_selfridge_prp()"); goto cleanup; } mpz_set_si(zD, d); } q = (1-d)/4; /* Since "O" is used, the refcount for n is incremented so deleting * temp will not delete n. */ temp = Py_BuildValue("Oll", n, p, q); if (!temp) goto cleanup; result = GMPY_mpz_is_stronglucas_prp(NULL, temp); Py_DECREF(temp); goto return_result; cleanup: Py_XINCREF(result); return_result: mpz_clear(zD); Py_DECREF((PyObject*)n); return result; }
/* mpz_legendre was a separate function in gmp 3.1.1 and earlier, but as of 4.0 it's a #define alias for mpz_jacobi. */ int __gmpz_legendre (mpz_srcptr a, mpz_srcptr b) { return mpz_jacobi (a, b); }
/* ******************************************************************************************* * mpz_extrastronglucas_prp: * Let U_n = LucasU(p,1), V_n = LucasV(p,1), and D=p^2-4. * An "extra strong Lucas pseudoprime" to the base p is a composite n = (2^r)*s+(D/n), where * s is odd and (n,2D)=1, such that either U_s == 0 mod n and V_s == +/-2 mod n, or * V_((2^t)*s) == 0 mod n for some t with 0 <= t < r-1 [(D/n) is the Jacobi symbol] * *******************************************************************************************/ int mpz_extrastronglucas_prp(mpz_t n, long int p) { mpz_t zD; mpz_t s; mpz_t nmj; /* n minus jacobi(D/n) */ mpz_t res; mpz_t uh, vl, vh, ql, qh, tmp; /* these are needed for the LucasU and LucasV part of this function */ long int d = p*p - 4; long int q = 1; unsigned long int r = 0; int ret = 0; int j = 0; if (d == 0) /* Does not produce a proper Lucas sequence */ return PRP_ERROR; if (mpz_cmp_ui(n, 2) < 0) return PRP_COMPOSITE; if (mpz_divisible_ui_p(n, 2)) { if (mpz_cmp_ui(n, 2) == 0) return PRP_PRIME; else return PRP_COMPOSITE; } mpz_init_set_si(zD, d); mpz_init(res); mpz_mul_ui(res, zD, 2); mpz_gcd(res, res, n); if ((mpz_cmp(res, n) != 0) && (mpz_cmp_ui(res, 1) > 0)) { mpz_clear(zD); mpz_clear(res); return PRP_COMPOSITE; } mpz_init(s); mpz_init(nmj); /* nmj = n - (D/n), where (D/n) is the Jacobi symbol */ mpz_set(nmj, n); ret = mpz_jacobi(zD, n); if (ret == -1) mpz_add_ui(nmj, nmj, 1); else if (ret == 1) mpz_sub_ui(nmj, nmj, 1); r = mpz_scan1(nmj, 0); mpz_fdiv_q_2exp(s, nmj, r); /* make sure that either (U_s == 0 mod n and V_s == +/-2 mod n), or */ /* V_((2^t)*s) == 0 mod n for some t with 0 <= t < r-1 */ mpz_init_set_si(uh, 1); mpz_init_set_si(vl, 2); mpz_init_set_si(vh, p); mpz_init_set_si(ql, 1); mpz_init_set_si(qh, 1); mpz_init_set_si(tmp,0); for (j = mpz_sizeinbase(s,2)-1; j >= 1; j--) { /* ql = ql*qh (mod n) */ mpz_mul(ql, ql, qh); mpz_mod(ql, ql, n); if (mpz_tstbit(s,j) == 1) { /* qh = ql*q */ mpz_mul_si(qh, ql, q); /* uh = uh*vh (mod n) */ mpz_mul(uh, uh, vh); mpz_mod(uh, uh, n); /* vl = vh*vl - p*ql (mod n) */ mpz_mul(vl, vh, vl); mpz_mul_si(tmp, ql, p); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n); /* vh = vh*vh - 2*qh (mod n) */ mpz_mul(vh, vh, vh); mpz_mul_si(tmp, qh, 2); mpz_sub(vh, vh, tmp); mpz_mod(vh, vh, n); } else { /* qh = ql */ mpz_set(qh, ql); /* uh = uh*vl - ql (mod n) */ mpz_mul(uh, uh, vl); mpz_sub(uh, uh, ql); mpz_mod(uh, uh, n); /* vh = vh*vl - p*ql (mod n) */ mpz_mul(vh, vh, vl); mpz_mul_si(tmp, ql, p); mpz_sub(vh, vh, tmp); mpz_mod(vh, vh, n); /* vl = vl*vl - 2*ql (mod n) */ mpz_mul(vl, vl, vl); mpz_mul_si(tmp, ql, 2); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n); } } /* ql = ql*qh */ mpz_mul(ql, ql, qh); /* qh = ql*q */ mpz_mul_si(qh, ql, q); /* uh = uh*vl - ql */ mpz_mul(uh, uh, vl); mpz_sub(uh, uh, ql); /* vl = vh*vl - p*ql */ mpz_mul(vl, vh, vl); mpz_mul_si(tmp, ql, p); mpz_sub(vl, vl, tmp); /* ql = ql*qh */ mpz_mul(ql, ql, qh); mpz_mod(uh, uh, n); mpz_mod(vl, vl, n); /* tmp = n-2, for the following comparison */ mpz_sub_ui(tmp, n, 2); /* uh contains LucasU_s and vl contains LucasV_s */ if (((mpz_cmp_ui(uh, 0) == 0) && ((mpz_cmp(vl, tmp) == 0) || (mpz_cmp_si(vl, 2) == 0))) || (mpz_cmp_ui(vl, 0) == 0)) { mpz_clear(zD); mpz_clear(s); mpz_clear(nmj); mpz_clear(res); mpz_clear(uh); mpz_clear(vl); mpz_clear(vh); mpz_clear(ql); mpz_clear(qh); mpz_clear(tmp); return PRP_PRP; } for (j = 1; j < r-1; j++) { /* vl = vl*vl - 2*ql (mod n) */ mpz_mul(vl, vl, vl); mpz_mul_si(tmp, ql, 2); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n); /* ql = ql*ql (mod n) */ mpz_mul(ql, ql, ql); mpz_mod(ql, ql, n); if (mpz_cmp_ui(vl, 0) == 0) { mpz_clear(zD); mpz_clear(s); mpz_clear(nmj); mpz_clear(res); mpz_clear(uh); mpz_clear(vl); mpz_clear(vh); mpz_clear(ql); mpz_clear(qh); mpz_clear(tmp); return PRP_PRP; } } mpz_clear(zD); mpz_clear(s); mpz_clear(nmj); mpz_clear(res); mpz_clear(uh); mpz_clear(vl); mpz_clear(vh); mpz_clear(ql); mpz_clear(qh); mpz_clear(tmp); return PRP_COMPOSITE; }/* method mpz_extrastronglucas_prp */
int mpz_qrmn_p (mpz_srcptr a, mpz_srcptr p, mpz_srcptr q, mpz_srcptr n) { return ((mpz_jacobi(a, p) == 1) && (mpz_jacobi(a, q) == 1)); }
void mpz_sqrtmp_r (mpz_ptr root, mpz_srcptr a, mpz_srcptr p) { /* ? a \neq 0 */ if (mpz_get_ui(a) != 0) { /* ? p = 3 (mod 4) */ if (mpz_congruent_ui_p(p, 3L, 4L)) { mpz_t foo; mpz_init_set(foo, p); mpz_add_ui(foo, foo, 1L); mpz_fdiv_q_2exp(foo, foo, 2L); mpz_powm(root, a, foo, p); mpz_clear(foo); return; } /* ! p = 1 (mod 4) */ else { /* ! s = (p-1)/4 */ mpz_t s; mpz_init_set(s, p); mpz_sub_ui(s, s, 1L); mpz_fdiv_q_2exp(s, s, 2L); /* ? p = 5 (mod 8) */ if (mpz_congruent_ui_p(p, 5L, 8L)) { mpz_t foo, b; mpz_init(foo); mpz_powm(foo, a, s, p); mpz_init_set(b, p); mpz_add_ui(b, b, 3L); mpz_fdiv_q_2exp(b, b, 3L); mpz_powm(root, a, b, p); /* ? a^{(p-1)/4} = 1 (mod p) */ if (mpz_cmp_ui(foo, 1L) == 0) { mpz_clear(foo), mpz_clear(s), mpz_clear(b); return; } /* ! a^{(p-1)/4} = -1 (mod p) */ else { do mpz_wrandomm(b, p); while (mpz_jacobi(b, p) != -1); mpz_powm(b, b, s, p); mpz_mul(root, root, b); mpz_mod(root, root, p); mpz_clear(foo), mpz_clear(s), mpz_clear(b); return; } } /* ! p = 1 (mod 8) */ else { mpz_t foo, bar, b, t; mpz_init(foo), mpz_init(bar); mpz_powm(foo, a, s, p); /* while a^s = 1 (mod p) */ while (mpz_cmp_ui(foo, 1L) == 0) { /* ? s odd */ if (mpz_odd_p(s)) { mpz_add_ui(s, s, 1L); mpz_fdiv_q_2exp(s, s, 1L); mpz_powm(root, a, s, p); mpz_clear(foo), mpz_clear(s); return; } /* ! s even */ else { mpz_fdiv_q_2exp(s, s, 1L); } mpz_powm(foo, a, s, p); } /* ! a^s = -1 (mod p) */ mpz_init(b); do mpz_wrandomm(b, p); while (mpz_jacobi(b, p) != -1); mpz_init_set(t, p); mpz_sub_ui(t, t, 1L); mpz_fdiv_q_2exp(t, t, 1L); /* while s even */ while (mpz_even_p(s)) { mpz_fdiv_q_2exp(s, s, 1L); mpz_fdiv_q_2exp(t, t, 1L); mpz_powm(foo, a, s, p); mpz_powm(bar, b, t, p); mpz_mul(foo, foo, bar); mpz_mod(foo, foo, p); mpz_set_si(bar, -1L); /* ? a^s * b^t = -1 (mod p) */ if (mpz_congruent_p(foo, bar, p)) { mpz_set(bar, p); mpz_sub_ui(bar, bar, 1L); mpz_fdiv_q_2exp(bar, bar, 1L); mpz_add(t, t, bar); } } mpz_add_ui(s, s, 1L); mpz_fdiv_q_2exp(s, s, 1L); mpz_fdiv_q_2exp(t, t, 1L); mpz_powm(foo, a, s, p); mpz_powm(bar, b, t, p); mpz_mul(root, foo, bar); mpz_mod(root, root, p); mpz_clear(foo), mpz_clear(bar); mpz_clear(s), mpz_clear(b), mpz_clear(t); return; } } } /* error, return zero root */ mpz_set_ui(root, 0L); }
/* ******************************************************************************* * mpz_lucas_prp: * A "Lucas pseudoprime" with parameters (P,Q) is a composite n with D=P^2-4Q, * (n,2QD)=1 such that U_(n-(D/n)) == 0 mod n [(D/n) is the Jacobi symbol] * *******************************************************************************/ int mpz_lucas_prp(mpz_t n, long int p, long int q) { mpz_t zD; mpz_t res; mpz_t index; mpz_t uh, vl, vh, ql, qh, tmp; /* used for calculating the Lucas U sequence */ int s = 0, j = 0; int ret = 0; long int d = p*p - 4*q; if (d == 0) /* Does not produce a proper Lucas sequence */ return PRP_ERROR; if (mpz_cmp_ui(n, 2) < 0) return PRP_COMPOSITE; if (mpz_divisible_ui_p(n, 2)) { if (mpz_cmp_ui(n, 2) == 0) return PRP_PRIME; else return PRP_COMPOSITE; } mpz_init(index); mpz_init_set_si(zD, d); mpz_init(res); mpz_mul_si(res, zD, q); mpz_mul_ui(res, res, 2); mpz_gcd(res, res, n); if ((mpz_cmp(res, n) != 0) && (mpz_cmp_ui(res, 1) > 0)) { mpz_clear(zD); mpz_clear(res); mpz_clear(index); return PRP_COMPOSITE; } /* index = n-(D/n), where (D/n) is the Jacobi symbol */ mpz_set(index, n); ret = mpz_jacobi(zD, n); if (ret == -1) mpz_add_ui(index, index, 1); else if (ret == 1) mpz_sub_ui(index, index, 1); /* mpz_lucasumod(res, p, q, index, n); */ mpz_init_set_si(uh, 1); mpz_init_set_si(vl, 2); mpz_init_set_si(vh, p); mpz_init_set_si(ql, 1); mpz_init_set_si(qh, 1); mpz_init_set_si(tmp,0); s = mpz_scan1(index, 0); for (j = mpz_sizeinbase(index,2)-1; j >= s+1; j--) { /* ql = ql*qh (mod n) */ mpz_mul(ql, ql, qh); mpz_mod(ql, ql, n); if (mpz_tstbit(index,j) == 1) { /* qh = ql*q */ mpz_mul_si(qh, ql, q); /* uh = uh*vh (mod n) */ mpz_mul(uh, uh, vh); mpz_mod(uh, uh, n); /* vl = vh*vl - p*ql (mod n) */ mpz_mul(vl, vh, vl); mpz_mul_si(tmp, ql, p); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n); /* vh = vh*vh - 2*qh (mod n) */ mpz_mul(vh, vh, vh); mpz_mul_si(tmp, qh, 2); mpz_sub(vh, vh, tmp); mpz_mod(vh, vh, n); } else { /* qh = ql */ mpz_set(qh, ql); /* uh = uh*vl - ql (mod n) */ mpz_mul(uh, uh, vl); mpz_sub(uh, uh, ql); mpz_mod(uh, uh, n); /* vh = vh*vl - p*ql (mod n) */ mpz_mul(vh, vh, vl); mpz_mul_si(tmp, ql, p); mpz_sub(vh, vh, tmp); mpz_mod(vh, vh, n); /* vl = vl*vl - 2*ql (mod n) */ mpz_mul(vl, vl, vl); mpz_mul_si(tmp, ql, 2); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n); } } /* ql = ql*qh */ mpz_mul(ql, ql, qh); /* qh = ql*q */ mpz_mul_si(qh, ql, q); /* uh = uh*vl - ql */ mpz_mul(uh, uh, vl); mpz_sub(uh, uh, ql); /* vl = vh*vl - p*ql */ mpz_mul(vl, vh, vl); mpz_mul_si(tmp, ql, p); mpz_sub(vl, vl, tmp); /* ql = ql*qh */ mpz_mul(ql, ql, qh); for (j = 1; j <= s; j++) { /* uh = uh*vl (mod n) */ mpz_mul(uh, uh, vl); mpz_mod(uh, uh, n); /* vl = vl*vl - 2*ql (mod n) */ mpz_mul(vl, vl, vl); mpz_mul_si(tmp, ql, 2); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n); /* ql = ql*ql (mod n) */ mpz_mul(ql, ql, ql); mpz_mod(ql, ql, n); } mpz_mod(res, uh, n); /* uh contains our return value */ mpz_clear(zD); mpz_clear(index); mpz_clear(uh); mpz_clear(vl); mpz_clear(vh); mpz_clear(ql); mpz_clear(qh); mpz_clear(tmp); if (mpz_cmp_ui(res, 0) == 0) { mpz_clear(res); return PRP_PRP; } else { mpz_clear(res); return PRP_COMPOSITE; } }/* method mpz_lucas_prp */
/* Recursive routine to prove via ECPP */ static int ecpp_down(int i, mpz_t Ni, int facstage, IV* dlist, mpz_t* sfacs, int* nsfacs, char** prooftextptr) { mpz_t a, b, u, v, m, q, minfactor, sqrtn, mD, t, t2; mpz_t mlist[6]; UV nm1a; IV np1lp, np1lq; struct ec_affine_point P; int k, dnum, nidigits, facresult, curveresult, downresult, stage, D; int verbose = get_verbose_level(); nidigits = mpz_sizeinbase(Ni, 10); k = _GMP_is_prob_prime(Ni); if (k == 0) return 0; if (k == 2) { /* No need to put anything in the proof */ if (verbose) printf("%*sN[%d] (%d dig) PRIME\n", i, "", i, nidigits); return 2; } downresult = 0; if (verbose) { printf("%*sN[%d] (%d dig)", i, "", i, nidigits); if (facstage > 1) printf(" FS %d", facstage); fflush(stdout); } mpz_init(a); mpz_init(b); mpz_init(u); mpz_init(v); mpz_init(m); mpz_init(q); mpz_init(mD); mpz_init(minfactor); mpz_init(sqrtn); mpz_init(t); mpz_init(t2); mpz_init(P.x);mpz_init(P.y); for (k = 0; k < 6; k++) mpz_init(mlist[k]); /* Any factors q found must be strictly > minfactor. * See Atkin and Morain, 1992, section 6.4 */ mpz_root(minfactor, Ni, 4); mpz_add_ui(minfactor, minfactor, 1); mpz_mul(minfactor, minfactor, minfactor); mpz_sqrt(sqrtn, Ni); for (stage = (i == 0) ? facstage : 1; stage <= facstage; stage++) { int next_stage = (stage > 1) ? stage : 1; for (dnum = 0; dlist[dnum] != 0; dnum++) { int poly_type; /* just for debugging/verbose */ int poly_degree; D = -dlist[dnum]; if (D > 1) continue; /* Marked for skip */ if (D == 1) { /* n-1 test */ mpz_sub_ui(m, Ni, 1); /* m = N-1 */ mpz_sub_ui(t2, sqrtn, 1); mpz_tdiv_q_2exp(t2, t2, 1); /* t2 = minfactor */ facresult = check_for_factor2(q, m, t2, t, stage, sfacs, nsfacs, 0); if (facresult <= 0) continue; if (verbose) { printf(" n-1\n"); fflush(stdout); } downresult = ecpp_down(i+1, q, next_stage, dlist, sfacs, nsfacs, prooftextptr); if (downresult == 0) /* composite */ goto end_down; if (downresult == 1) { /* nothing found at this stage */ if (verbose) { printf("%*sN[%d] (%d dig)", i, "", i, nidigits); if (facstage > 1) printf(" FS %d", facstage); fflush(stdout); } continue; } if (verbose) { printf("%*sN[%d] (%d dig) n-1", i, "", i, nidigits); fflush(stdout); } curveresult = _GMP_primality_bls_3(Ni, q, &nm1a); if (verbose) { printf(" %d\n", curveresult); fflush(stdout); } if ( ! curveresult ) { /* This ought not happen */ dlist[dnum] = -2; /* skip this D value from now on */ if (verbose) gmp_printf("\n Could not prove n-1 with N = %Zd\n", D, Ni); downresult = 0; continue; } goto end_down; } if (D == -1) { /* n+1 test */ mpz_add_ui(m, Ni, 1); /* m = N+1 */ mpz_add_ui(t2, sqrtn, 1); mpz_tdiv_q_2exp(t2, t2, 1); /* t2 = minfactor */ facresult = check_for_factor2(q, m, t2, t, stage, sfacs, nsfacs, 0); if (facresult <= 0) continue; if (verbose) { printf(" n+1\n"); fflush(stdout); } downresult = ecpp_down(i+1, q, next_stage, dlist, sfacs, nsfacs, prooftextptr); if (downresult == 0) /* composite */ goto end_down; if (downresult == 1) { /* nothing found at this stage */ if (verbose) { printf("%*sN[%d] (%d dig)", i, "", i, nidigits); if (facstage > 1) printf(" FS %d", facstage); fflush(stdout); } continue; } if (verbose) { printf("%*sN[%d] (%d dig) n-1", i, "", i, nidigits); fflush(stdout); } curveresult = _GMP_primality_bls_15(Ni, q, &np1lp, &np1lq); if (verbose) { printf(" %d\n", curveresult); fflush(stdout); } if ( ! curveresult ) { /* This ought not happen */ dlist[dnum] = -2; /* skip this D value from now on */ if (verbose) gmp_printf("\n Could not prove n-1 with N = %Zd\n", D, Ni); downresult = 0; continue; } goto end_down; } if ( (-D % 4) != 3 && (-D % 16) != 4 && (-D % 16) != 8 ) croak("Invalid discriminant '%d' in list\n", D); /* D must also be squarefree in odd divisors, but assume it. */ /* Make sure we can get a class polynomial for this D. */ poly_degree = poly_class_poly(D, NULL, &poly_type); if (poly_degree == 0) continue; /* We'll save time in the long run by not looking at big polys once * we've found a good path from the start. TODO: Needs more tuning. */ if (stage == 0 && i >= 0 && poly_degree > 2) break; if (facstage == 1) { if (i > 2 && nidigits < 1100 && poly_degree > 24) break; if (i > 3 && nidigits < 950 && poly_degree > 15) break; if (i > 4 && nidigits < 800 && poly_degree > 11) break; if (i > 8 && nidigits < 700 && poly_degree > 9) break; if (i > 16 && nidigits < 600 && poly_degree > 8) break; } mpz_set_si(mD, D); /* (D/N) must be 1, and we have to have a u,v solution */ if (mpz_jacobi(mD, Ni) != 1) continue; if ( ! modified_cornacchia(u, v, mD, Ni) ) continue; if (verbose > 1) { printf(" %d", D); fflush(stdout); } choose_m(mlist, D, u, v, Ni, t, t2); for (k = 0; k < 6; k++) { facresult = check_for_factor2(q, mlist[k], minfactor, t, stage, sfacs, nsfacs, poly_degree); /* -1 = couldn't find, 0 = no big factors, 1 = found */ if (facresult <= 0) continue; mpz_set(m, mlist[k]); if (verbose) { printf(" %d (%s %d)\n", D, (poly_type == 1) ? "Hilbert" : "Weber", poly_degree); fflush(stdout); } /* Great, now go down. */ downresult = ecpp_down(i+1, q, next_stage, dlist, sfacs, nsfacs, prooftextptr); if (downresult == 0) /* composite */ goto end_down; if (downresult == 1) { /* nothing found at this stage */ if (verbose) { printf("%*sN[%d] (%d dig)", i, "", i, nidigits); if (facstage > 1) printf(" FS %d", facstage); fflush(stdout); } continue; } /* Awesome, we found the q chain and are in STAGE 2 */ if (verbose) { printf("%*sN[%d] (%d dig) %d (%s %d)", i, "", i, nidigits, D, (poly_type == 1) ? "Hilbert" : "Weber", poly_degree); fflush(stdout); } curveresult = find_curve(a, b, P.x, P.y, D, m, q, Ni); if (verbose) { printf(" %d\n", curveresult); fflush(stdout); } if (curveresult == 1) { /* Oh no! We can't find a point on the curve. Something is right * messed up, and we've wasted a lot of time. Sigh. */ dlist[dnum] = -2; /* skip this D value from now on */ if (verbose) gmp_printf("\n Invalidated D = %d with N = %Zd\n", D, Ni); downresult = 0; continue; } /* We found it was composite or proved it */ goto end_down; } /* k loop for D */ } /* D */ } /* fac stage */ /* Nothing at this level */ downresult = 1; if (verbose) { printf(" ---\n"); fflush(stdout); } end_down: if (downresult == 2) { if (0 && verbose > 1) { if (D == 1) { gmp_printf("\n"); gmp_printf("Type BLS3\n"); gmp_printf("N %Zd\n", Ni); gmp_printf("Q %Zd\n", q); gmp_printf("A %lu\n", (unsigned long) nm1a); gmp_printf("\n"); fflush(stdout); } else if (D == -1) { gmp_printf("\n"); gmp_printf("Type BLS15\n"); gmp_printf("N %Zd\n", Ni); gmp_printf("Q %Zd\n", q); gmp_printf("LP %ld\n", (signed long) np1lp); gmp_printf("LQ %ld\n", (signed long) np1lq); gmp_printf("\n"); fflush(stdout); } else { gmp_printf("\n"); gmp_printf("Type ECPP\n"); gmp_printf("N %Zd\n", Ni); gmp_printf("A %Zd\n", a); gmp_printf("B %Zd\n", b); gmp_printf("M %Zd\n", m); gmp_printf("Q %Zd\n", q); gmp_printf("X %Zd\n", P.x); gmp_printf("Y %Zd\n", P.y); gmp_printf("\n"); fflush(stdout); } } /* Prepend our proof to anything that exists. */ if (prooftextptr != 0) { char *proofstr, *proofptr; int curprooflen = (*prooftextptr == 0) ? 0 : strlen(*prooftextptr); if (D == 1) { int myprooflen = 20 + 2*(4 + mpz_sizeinbase(Ni, 10)) + 1*21; New(0, proofstr, myprooflen + curprooflen + 1, char); proofptr = proofstr; proofptr += gmp_sprintf(proofptr, "Type BLS3\nN %Zd\nQ %Zd\nA %"UVuf"\n", Ni, q, nm1a); } else if (D == -1) {
/* *********************************************************************************************** * mpz_selfridge_prp: * A "Lucas-Selfridge pseudoprime" n is a "Lucas pseudoprime" using Selfridge parameters of: * Find the first element D in the sequence {5, -7, 9, -11, 13, ...} such that Jacobi(D,n) = -1 * Then use P=1 and Q=(1-D)/4 in the Lucas pseudoprime test. * Make sure n is not a perfect square, otherwise the search for D will only stop when D=n. * ***********************************************************************************************/ int mpz_selfridge_prp(mpz_t n) { long int d = 5, p = 1, q = 0; int max_d = 1000000; int jacobi = 0; mpz_t zD; if (mpz_cmp_ui(n, 2) < 0) return PRP_COMPOSITE; if (mpz_divisible_ui_p(n, 2)) { if (mpz_cmp_ui(n, 2) == 0) return PRP_PRIME; else return PRP_COMPOSITE; } mpz_init_set_ui(zD, d); while (1) { jacobi = mpz_jacobi(zD, n); /* if jacobi == 0, d is a factor of n, therefore n is composite... */ /* if d == n, then either n is either prime or 9... */ if (jacobi == 0) { if ((mpz_cmpabs(zD, n) == 0) && (mpz_cmp_ui(zD, 9) != 0)) { mpz_clear(zD); return PRP_PRIME; } else { mpz_clear(zD); return PRP_COMPOSITE; } } if (jacobi == -1) break; /* if we get to the 5th d, make sure we aren't dealing with a square... */ if (d == 13) { if (mpz_perfect_square_p(n)) { mpz_clear(zD); return PRP_COMPOSITE; } } if (d < 0) { d *= -1; d += 2; } else { d += 2; d *= -1; } /* make sure we don't search forever */ if (d >= max_d) { mpz_clear(zD); return PRP_ERROR; } mpz_set_si(zD, d); } mpz_clear(zD); q = (1-d)/4; return mpz_lucas_prp(n, p, q); }/* method mpz_selfridge_prp */
/* * Run the randomized quadratic frobenius test to check whether [n] is a a * prime. The Parameter [k] determines how many times the test will be run at * most. If the test returns "composite", it will not be run again. */ int main(int argc, char *argv[]) { Primality result; #define VARS n, b, c, bb4c mpz_t VARS; uint64_t n_, b_ = 0, c_; uint64_t false_positives = 0; uint64_t lower_bound = 5, upper_bound = 1000000; mpz_inits(VARS, NULL); if (argc > 2) lower_bound = strtoul(argv[1], NULL, 10); if (argc > 1) upper_bound = strtoul(argv[argc > 2 ? 2 : 1], NULL, 10); printf("%lu to %lu\n", lower_bound, upper_bound); for (n_ = lower_bound | 1; n_ <= upper_bound; n_+=2) { mpz_set_ui(n, n_); if (mpz_perfect_square_p(n) || mpz_probab_prime_p(n, 100)) continue; #ifdef SMALL_C for (c_ = 2; c_ < n_; c_++) { if (jacobi(n_ - c_, n_) != 1) continue; #else c_ = n_ - 4; mpz_sub_ui(c, n, 4); #endif for (b_ = 1; b_ < n_; b_++) { mpz_mul(bb4c, b, b); mpz_addmul_ui(bb4c, c, 4); mpz_mod(bb4c, bb4c, n); if (mpz_jacobi(bb4c, n) == -1) break; if (b_ % 1000 == 999) { fprintf(stderr, "Could not find a valid parameter pair (b, c)\n"); goto next_n; } } #ifdef SMALL_C break; } #endif result = steps_3_4_5(n, b, c); if (result != composite) { false_positives++; fflush(stdout); printf("Found a false positive: n = %lu, b = %lu, c = %lu\n", n_, b_, c_); } if (n_ % 10000000 == 1) { fprintf(stderr, "."); fflush(stderr); } next_n: ; } printf("\nA total number of %lu false positives were found among the numbers %lu,...,%lu\n", false_positives, lower_bound, upper_bound); mpz_clears(VARS, NULL); return 0; }