static PyObject * GMPy_MPZ_Function_IsPower(PyObject *self, PyObject *other) { int res; MPZ_Object* tempx; if (MPZ_Check(other)) { res = mpz_perfect_power_p(MPZ(other)); } else { if (!(tempx = GMPy_MPZ_From_Integer(other, NULL))) { TYPE_ERROR("is_power() requires 'mpz' argument"); return NULL; } else { res = mpz_perfect_power_p(tempx->z); Py_DECREF((PyObject*)tempx); } } if (res) Py_RETURN_TRUE; else Py_RETURN_FALSE; }
static PyObject * GMPy_MPZ_Method_IsPower(PyObject *self, PyObject *other) { int res; res = mpz_perfect_power_p(MPZ(self)); if (res) Py_RETURN_TRUE; else Py_RETURN_FALSE; }
// Factorization int factor(const Ptr<RCP<const Integer>> &f, const Integer &n, double B1) { int ret_val = 0; mpz_class _n, _f; _n = n.as_mpz(); #ifdef HAVE_CSYMPY_ECM if (mpz_perfect_power_p(_n.get_mpz_t())) { unsigned long int i = 1; mpz_class m, rem; rem = 1; // Any non zero number m = 2; // set `m` to 2**i, i = 1 at the begining // calculate log2n, this can be improved for (; m < _n; i++) m = m * 2; // eventually `rem` = 0 zero as `n` is a perfect power. `f_t` will // be set to a factor of `n` when that happens while (i > 1 && rem != 0) { mpz_rootrem(_f.get_mpz_t(), rem.get_mpz_t(), _n.get_mpz_t(), i); i--; } ret_val = 1; } else { if (mpz_probab_prime_p(_n.get_mpz_t(), 25) > 0) { // most probably, n is a prime ret_val = 0; _f = _n; } else { for (int i = 0; i < 10 && !ret_val; i++) ret_val = ecm_factor(_f.get_mpz_t(), _n.get_mpz_t(), B1, NULL); if (!ret_val) throw std::runtime_error("ECM failed to factor the given number"); } } #else // B1 is discarded if gmp-ecm is not installed ret_val = _factor_trial_division_sieve(_f, _n); #endif // HAVE_CSYMPY_ECM *f = integer(_f); return ret_val; }
int aks_is_prime(mpz_t n) { // Peform simple checks before running the AKS algorithm if (mpz_cmp_ui(n, 2) == 0) { return PRIME; } if (mpz_cmp_ui(n, 1) <= 0 || mpz_divisible_ui_p(n, 2)) { return COMPOSITE; } // Step 1: Check if n is a perfect power, meaning n = a ^ b where a is a natural number and b > 1 if (mpz_perfect_power_p(n)) { return COMPOSITE; } // Step 2: Find the smallest r such that or(n) > log(n) ^ 2 mpz_t r; mpz_init(r); find_smallest_r(r, n); if (aks_debug) gmp_printf("r=%Zd\n", r); // Step 3: Check if there exists an a <= r such that 1 < (a,n) < n if (check_a_exists(n, r)) { mpz_clear(r); return COMPOSITE; } if (aks_debug) gmp_printf("a does not exist\n"); // Step 4: Check if n <= r if (mpz_cmp(n, r) <= 0) { mpz_clear(r); return PRIME; } if (aks_debug) gmp_printf("checking polynomial equation\n"); // Step 5 if (check_polys(r, n)) { mpz_clear(r); return COMPOSITE; } mpz_clear(r); // Step 6 return PRIME; }
void check_tests () { mpz_t x; int i; int got, want; mpz_init (x); for (i = 0; tests[i].num_as_str != NULL; i++) { mpz_set_str (x, tests[i].num_as_str, 0); got = mpz_perfect_power_p (x); want = tests[i].want; if (got != want) { fprintf (stderr, "mpz_perfect_power_p returns %d when %d was expected\n", got, want); fprintf (stderr, "fault operand: %s\n", tests[i].num_as_str); abort (); } } mpz_clear (x); }
void check_one (mpz_t root1, mpz_t x2, unsigned long nth, int i) { mpz_t temp, temp2; mpz_t root2, rem2; mpz_init (root2); mpz_init (rem2); mpz_init (temp); mpz_init (temp2); MPZ_CHECK_FORMAT (root1); mpz_rootrem (root2, rem2, x2, nth); MPZ_CHECK_FORMAT (root2); MPZ_CHECK_FORMAT (rem2); mpz_pow_ui (temp, root1, nth); MPZ_CHECK_FORMAT (temp); mpz_add (temp2, temp, rem2); /* Is power of result > argument? */ if (mpz_cmp (root1, root2) != 0 || mpz_cmp (x2, temp2) != 0 || mpz_cmpabs (temp, x2) > 0) { fprintf (stderr, "ERROR after test %d\n", i); debug_mp (x2, 10); debug_mp (root1, 10); debug_mp (root2, 10); fprintf (stderr, "nth: %lu\n", nth); abort (); } if (nth > 1 && mpz_cmp_ui (temp, 1L) > 0 && ! mpz_perfect_power_p (temp)) { fprintf (stderr, "ERROR in mpz_perfect_power_p after test %d\n", i); debug_mp (temp, 10); debug_mp (root1, 10); fprintf (stderr, "nth: %lu\n", nth); abort (); } if (nth <= 10000 && mpz_sgn(x2) > 0) /* skip too expensive test */ { mpz_add_ui (temp2, root1, 1L); mpz_pow_ui (temp2, temp2, nth); MPZ_CHECK_FORMAT (temp2); /* Is square of (result + 1) <= argument? */ if (mpz_cmp (temp2, x2) <= 0) { fprintf (stderr, "ERROR after test %d\n", i); debug_mp (x2, 10); debug_mp (root1, 10); fprintf (stderr, "nth: %lu\n", nth); abort (); } } mpz_clear (root2); mpz_clear (rem2); mpz_clear (temp); mpz_clear (temp2); }
//----------------------- NFS ENTRY POINT ------------------------------------// void nfs(fact_obj_t *fobj) { //expect the input in fobj->nfs_obj.gmp_n char *input; msieve_obj *obj = NULL; char *nfs_args = NULL; // unused as yet enum cpu_type cpu = yafu_get_cpu_type(); mp_t mpN; factor_list_t factor_list; uint32 flags = 0; nfs_job_t job; uint32 relations_needed = 1; uint32 last_specialq = 0; struct timeval stop; // stop time of this job struct timeval start; // start time of this job struct timeval bstop; // stop time of sieving batch struct timeval bstart; // start time of sieving batch TIME_DIFF * difference; double t_time; uint32 pre_batch_rels = 0; char tmpstr[GSTR_MAXSIZE]; int process_done; enum nfs_state_e nfs_state; // initialize some job parameters memset(&job, 0, sizeof(nfs_job_t)); obj_ptr = NULL; //below a certain amount, revert to SIQS if (gmp_base10(fobj->nfs_obj.gmp_n) < fobj->nfs_obj.min_digits) { mpz_set(fobj->qs_obj.gmp_n, fobj->nfs_obj.gmp_n); SIQS(fobj); mpz_set(fobj->nfs_obj.gmp_n, fobj->qs_obj.gmp_n); return; } if (mpz_probab_prime_p(fobj->nfs_obj.gmp_n, NUM_WITNESSES)) { add_to_factor_list(fobj, fobj->nfs_obj.gmp_n); if (VFLAG >= 0) gmp_printf("PRP%d = %Zd\n", gmp_base10(fobj->nfs_obj.gmp_n), fobj->nfs_obj.gmp_n); logprint_oc(fobj->flogname, "a", "PRP%d = %s\n", gmp_base10(fobj->nfs_obj.gmp_n), mpz_conv2str(&gstr1.s, 10, fobj->nfs_obj.gmp_n)); mpz_set_ui(fobj->nfs_obj.gmp_n, 1); return; } if (mpz_perfect_square_p(fobj->nfs_obj.gmp_n)) { mpz_sqrt(fobj->nfs_obj.gmp_n, fobj->nfs_obj.gmp_n); add_to_factor_list(fobj, fobj->nfs_obj.gmp_n); logprint_oc(fobj->flogname, "a", "prp%d = %s\n", gmp_base10(fobj->nfs_obj.gmp_n), mpz_conv2str(&gstr1.s, 10, fobj->nfs_obj.gmp_n)); add_to_factor_list(fobj, fobj->nfs_obj.gmp_n); logprint_oc(fobj->flogname, "a", "prp%d = %s\n", gmp_base10(fobj->nfs_obj.gmp_n), mpz_conv2str(&gstr1.s, 10, fobj->nfs_obj.gmp_n)); mpz_set_ui(fobj->nfs_obj.gmp_n, 1); return; } if (mpz_perfect_power_p(fobj->nfs_obj.gmp_n)) { FILE *flog; uint32 j; if (VFLAG > 0) printf("input is a perfect power\n"); factor_perfect_power(fobj, fobj->nfs_obj.gmp_n); flog = fopen(fobj->flogname, "a"); if (flog == NULL) { printf("fopen error: %s\n", strerror(errno)); printf("could not open %s for appending\n", fobj->flogname); exit(1); } logprint(flog,"input is a perfect power\n"); for (j=0; j<fobj->num_factors; j++) { uint32 k; for (k=0; k<fobj->fobj_factors[j].count; k++) { logprint(flog,"prp%d = %s\n",gmp_base10(fobj->fobj_factors[j].factor), mpz_conv2str(&gstr1.s, 10, fobj->fobj_factors[j].factor)); } } fclose(flog); return; } if (fobj->nfs_obj.filearg[0] != '\0') { if (VFLAG > 0) printf("test: starting trial sieving\n"); trial_sieve(fobj); return; } //initialize the flag to watch for interrupts, and set the //pointer to the function to call if we see a user interrupt NFS_ABORT = 0; signal(SIGINT,nfsexit); //start a counter for the whole job gettimeofday(&start, NULL); //nfs state machine: input = (char *)malloc(GSTR_MAXSIZE * sizeof(char)); nfs_state = NFS_STATE_INIT; process_done = 0; while (!process_done) { switch (nfs_state) { case NFS_STATE_INIT: // write the input bigint as a string input = mpz_conv2str(&input, 10, fobj->nfs_obj.gmp_n); // create an msieve_obj // this will initialize the savefile to the outputfile name provided obj = msieve_obj_new(input, flags, fobj->nfs_obj.outputfile, fobj->nfs_obj.logfile, fobj->nfs_obj.fbfile, g_rand.low, g_rand.hi, (uint32)0, cpu, (uint32)L1CACHE, (uint32)L2CACHE, (uint32)THREADS, (uint32)0, nfs_args); fobj->nfs_obj.mobj = obj; // initialize these before checking existing files. If poly // select is resumed they will be changed by check_existing_files. job.last_leading_coeff = 0; job.poly_time = 0; job.use_max_rels = 0; job.snfs = NULL; // determine what to do next based on the state of various files. // this will set job.current_rels if it finds any nfs_state = check_existing_files(fobj, &last_specialq, &job); // before we get started, check to make sure we can find ggnfs sievers // if we are going to be doing sieving if (check_for_sievers(fobj, 1) == 1) nfs_state = NFS_STATE_DONE; if (VFLAG >= 0 && nfs_state != NFS_STATE_DONE) gmp_printf("nfs: commencing nfs on c%d: %Zd\n", gmp_base10(fobj->nfs_obj.gmp_n), fobj->nfs_obj.gmp_n); if (nfs_state != NFS_STATE_DONE) logprint_oc(fobj->flogname, "a", "nfs: commencing nfs on c%d: %s\n", gmp_base10(fobj->nfs_obj.gmp_n), mpz_conv2str(&gstr1.s, 10, fobj->nfs_obj.gmp_n)); // convert input to msieve bigint notation and initialize a list of factors gmp2mp_t(fobj->nfs_obj.gmp_n,&mpN); factor_list_init(&factor_list); if (fobj->nfs_obj.rangeq > 0) job.qrange = ceil((double)fobj->nfs_obj.rangeq / (double)THREADS); break; case NFS_STATE_POLY: if ((fobj->nfs_obj.nfs_phases == NFS_DEFAULT_PHASES) || (fobj->nfs_obj.nfs_phases & NFS_PHASE_POLY)) { // always check snfs forms (it is fast) snfs_choose_poly(fobj, &job); if( job.snfs == NULL ) { // either we never were doing snfs, or snfs form detect failed. // if the latter then bail with an error because the user // explicitly wants to run snfs... if (fobj->nfs_obj.snfs) { printf("nfs: failed to find snfs polynomial!\n"); exit(-1); } // init job.poly for gnfs job.poly = (mpz_polys_t*)malloc(sizeof(mpz_polys_t)); if (job.poly == NULL) { printf("nfs: couldn't allocate memory!\n"); exit(-1); } mpz_polys_init(job.poly); job.poly->rat.degree = 1; // maybe way off in the future this isn't true // assume gnfs for now job.poly->side = ALGEBRAIC_SPQ; do_msieve_polyselect(fobj, obj, &job, &mpN, &factor_list); } else { fobj->nfs_obj.snfs = 1; mpz_set(fobj->nfs_obj.gmp_n, job.snfs->n); } } nfs_state = NFS_STATE_SIEVE; break; case NFS_STATE_SIEVE: pre_batch_rels = job.current_rels; gettimeofday(&bstart, NULL); // sieve if the user has requested to (or by default). else, // set the done sieving flag. this will prevent some infinite loops, // for instance if we only want to post-process, but filtering // doesn't produce a matrix. if we don't want to sieve in that case, // then we're done. if (((fobj->nfs_obj.nfs_phases == NFS_DEFAULT_PHASES) || (fobj->nfs_obj.nfs_phases & NFS_PHASE_SIEVE)) && !(fobj->nfs_obj.nfs_phases & NFS_DONE_SIEVING)) do_sieving(fobj, &job); else fobj->nfs_obj.nfs_phases |= NFS_DONE_SIEVING; // if this has been previously marked, then go ahead and exit. if (fobj->nfs_obj.nfs_phases & NFS_DONE_SIEVING) process_done = 1; // if user specified -ns with a fixed start and range, // then mark that we're done sieving. if (fobj->nfs_obj.rangeq > 0) { // we're done sieving the requested range, but there may be // more phases to check, so don't exit yet fobj->nfs_obj.nfs_phases |= NFS_DONE_SIEVING; } // then move on to the next phase nfs_state = NFS_STATE_FILTCHECK; break; case NFS_STATE_FILTER: // if we've flagged not to do filtering, then assume we have // enough relations and move on to linear algebra if ((fobj->nfs_obj.nfs_phases == NFS_DEFAULT_PHASES) || (fobj->nfs_obj.nfs_phases & NFS_PHASE_FILTER)) relations_needed = do_msieve_filtering(fobj, obj, &job); else relations_needed = 0; if (relations_needed == 0) nfs_state = NFS_STATE_LINALG; else { // if we filtered, but didn't produce a matrix, raise the target // min rels by a few percent. this will prevent too frequent // filtering attempts while allowing the q_batch size to remain small. if (job.current_rels > job.min_rels) job.min_rels = job.current_rels * fobj->nfs_obj.filter_min_rels_nudge; else job.min_rels *= fobj->nfs_obj.filter_min_rels_nudge; if (VFLAG > 0) printf("nfs: raising min_rels by %1.2f percent to %u\n", 100*(fobj->nfs_obj.filter_min_rels_nudge-1), job.min_rels); nfs_state = NFS_STATE_SIEVE; } break; case NFS_STATE_LINALG: if ((fobj->nfs_obj.nfs_phases == NFS_DEFAULT_PHASES) || (fobj->nfs_obj.nfs_phases & NFS_PHASE_LA) || (fobj->nfs_obj.nfs_phases & NFS_PHASE_LA_RESUME)) { // msieve: build matrix flags = 0; flags = flags | MSIEVE_FLAG_USE_LOGFILE; if (VFLAG > 0) flags = flags | MSIEVE_FLAG_LOG_TO_STDOUT; flags = flags | MSIEVE_FLAG_NFS_LA; // add restart flag if requested if (fobj->nfs_obj.nfs_phases & NFS_PHASE_LA_RESUME) flags |= MSIEVE_FLAG_NFS_LA_RESTART; obj->flags = flags; if (VFLAG >= 0) printf("nfs: commencing msieve linear algebra\n"); logprint_oc(fobj->flogname, "a", "nfs: commencing msieve linear algebra\n"); // use a different number of threads for the LA, if requested if (LATHREADS > 0) { msieve_obj_free(obj); obj = msieve_obj_new(input, flags, fobj->nfs_obj.outputfile, fobj->nfs_obj.logfile, fobj->nfs_obj.fbfile, g_rand.low, g_rand.hi, (uint32)0, cpu, (uint32)L1CACHE, (uint32)L2CACHE, (uint32)LATHREADS, (uint32)0, nfs_args); } // try this hack - store a pointer to the msieve obj so that // we can change a flag on abort in order to interrupt the LA. obj_ptr = obj; nfs_solve_linear_system(obj, fobj->nfs_obj.gmp_n); if (obj_ptr->flags & MSIEVE_FLAG_STOP_SIEVING) nfs_state = NFS_STATE_DONE; else { // check for a .dat.deps file. if we don't have one, assume // its because the job was way oversieved and only trivial // dependencies were found. try again from filtering with // 20% less relations. FILE *t; sprintf(tmpstr, "%s.dep", fobj->nfs_obj.outputfile); if ((t = fopen(tmpstr, "r")) == NULL) { if (job.use_max_rels > 0) { // we've already tried again with an attempted fix to the trivial // dependencies problem, so either that wasn't the problem or // it didn't work. either way, give up. printf("nfs: no dependency file retry failed\n"); fobj->flags |= FACTOR_INTERRUPT; nfs_state = NFS_STATE_DONE; } else { // this should be sufficient to produce a matrix, but not too much // to trigger the assumed failure mode. if (job.min_rels == 0) { // if min_rels is not set, then we need to parse the .job file to compute it. parse_job_file(fobj, &job); nfs_set_min_rels(&job); } job.use_max_rels = job.min_rels * 1.5; printf("nfs: no dependency file found - trying again with %u relations\n", job.use_max_rels); nfs_state = NFS_STATE_FILTER; } } else { fclose(t); nfs_state = NFS_STATE_SQRT; } } // set the msieve threads back to where it was if we used // a different amount for linalg if (LATHREADS > 0) { msieve_obj_free(obj); obj = msieve_obj_new(input, flags, fobj->nfs_obj.outputfile, fobj->nfs_obj.logfile, fobj->nfs_obj.fbfile, g_rand.low, g_rand.hi, (uint32)0, cpu, (uint32)L1CACHE, (uint32)L2CACHE, (uint32)THREADS, (uint32)0, nfs_args); } obj_ptr = NULL; } else // not doing linalg nfs_state = NFS_STATE_SQRT; break; case NFS_STATE_SQRT: if ((fobj->nfs_obj.nfs_phases == NFS_DEFAULT_PHASES) || (fobj->nfs_obj.nfs_phases & NFS_PHASE_SQRT)) { uint32 retcode; // msieve: find factors flags = 0; flags = flags | MSIEVE_FLAG_USE_LOGFILE; if (VFLAG > 0) flags = flags | MSIEVE_FLAG_LOG_TO_STDOUT; flags = flags | MSIEVE_FLAG_NFS_SQRT; obj->flags = flags; if (VFLAG >= 0) printf("nfs: commencing msieve sqrt\n"); logprint_oc(fobj->flogname, "a", "nfs: commencing msieve sqrt\n"); // try this hack - store a pointer to the msieve obj so that // we can change a flag on abort in order to interrupt the sqrt. obj_ptr = obj; retcode = nfs_find_factors(obj, fobj->nfs_obj.gmp_n, &factor_list); obj_ptr = NULL; if (retcode) { extract_factors(&factor_list,fobj); if (mpz_cmp_ui(fobj->nfs_obj.gmp_n, 1) == 0) nfs_state = NFS_STATE_CLEANUP; //completely factored, clean up everything else nfs_state = NFS_STATE_DONE; //not factored completely, keep files and stop } else { if (VFLAG >= 0) { printf("nfs: failed to find factors... possibly no dependencies found\n"); printf("nfs: continuing with sieving\n"); } logprint_oc(fobj->flogname, "a", "nfs: failed to find factors... " "possibly no dependencies found\n" "nfs: continuing with sieving\n"); nfs_state = NFS_STATE_SIEVE; } } else nfs_state = NFS_STATE_DONE; //not factored completely, keep files and stop break; case NFS_STATE_CLEANUP: remove(fobj->nfs_obj.outputfile); remove(fobj->nfs_obj.fbfile); sprintf(tmpstr, "%s.p",fobj->nfs_obj.outputfile); remove(tmpstr); sprintf(tmpstr, "%s.br",fobj->nfs_obj.outputfile); remove(tmpstr); sprintf(tmpstr, "%s.cyc",fobj->nfs_obj.outputfile); remove(tmpstr); sprintf(tmpstr, "%s.dep",fobj->nfs_obj.outputfile); remove(tmpstr); sprintf(tmpstr, "%s.hc",fobj->nfs_obj.outputfile); remove(tmpstr); sprintf(tmpstr, "%s.mat",fobj->nfs_obj.outputfile); remove(tmpstr); sprintf(tmpstr, "%s.lp",fobj->nfs_obj.outputfile); remove(tmpstr); sprintf(tmpstr, "%s.d",fobj->nfs_obj.outputfile); remove(tmpstr); sprintf(tmpstr, "%s.mat.chk",fobj->nfs_obj.outputfile); remove(tmpstr); gettimeofday(&stop, NULL); difference = my_difftime (&start, &stop); t_time = ((double)difference->secs + (double)difference->usecs / 1000000); free(difference); if (VFLAG >= 0) printf("NFS elapsed time = %6.4f seconds.\n",t_time); logprint_oc(fobj->flogname, "a", "NFS elapsed time = %6.4f seconds.\n",t_time); logprint_oc(fobj->flogname, "a", "\n"); logprint_oc(fobj->flogname, "a", "\n"); // free stuff nfs_state = NFS_STATE_DONE; break; case NFS_STATE_DONE: process_done = 1; break; case NFS_STATE_FILTCHECK: if (job.current_rels >= job.min_rels) { if (VFLAG > 0) printf("nfs: found %u relations, need at least %u, proceeding with filtering ...\n", job.current_rels, job.min_rels); nfs_state = NFS_STATE_FILTER; } else { // compute eta by dividing how many rels we have left to find // by the average time per relation. we have average time // per relation because we've saved the time it took to do // the last batch of sieving and we know how many relations we // found in that batch. uint32 est_time; gettimeofday(&bstop, NULL); difference = my_difftime (&bstart, &bstop); t_time = ((double)difference->secs + (double)difference->usecs / 1000000); free(difference); est_time = (uint32)((job.min_rels - job.current_rels) * (t_time / (job.current_rels - pre_batch_rels))); // if the user doesn't want to sieve, then we can't make progress. if ((fobj->nfs_obj.nfs_phases == NFS_DEFAULT_PHASES) || (fobj->nfs_obj.nfs_phases & NFS_PHASE_SIEVE)) { if (VFLAG > 0) printf("nfs: found %u relations, need at least %u " "(filtering ETA: %uh %um), continuing with sieving ...\n", // uh... um... hmm... idk *shrug* job.current_rels, job.min_rels, est_time / 3600, (est_time % 3600) / 60); nfs_state = NFS_STATE_SIEVE; } else { if (VFLAG > 0) printf("nfs: found %u relations, need at least %u " "(filtering ETA: %uh %um), sieving not selected, finishing ...\n", job.current_rels, job.min_rels, est_time / 3600, (est_time % 3600) / 60); nfs_state = NFS_STATE_DONE; } } break; case NFS_STATE_STARTNEW: nfs_state = NFS_STATE_POLY; // create a new directory for this job //#ifdef _WIN32 // sprintf(tmpstr, "%s\%s", fobj->nfs_obj.ggnfs_dir, // mpz_conv2str(&gstr1.s, 10, fobj->nfs_obj.gmp_n)); // mkdir(tmpstr); //#else // sprintf(tmpstr, "%s/%s", fobj->nfs_obj.ggnfs_dir, // mpz_conv2str(&gstr1.s, 10, fobj->nfs_obj.gmp_n)); // mkdir(tmpstr, S_IRWXU); //#endif // point msieve and ggnfs to the new directory //#ifdef _WIN32 // sprintf(fobj->nfs_obj.outputfile, "%s\%s", // tmpstr, fobj->nfs_obj.outputfile); // sprintf(fobj->nfs_obj.logfile, "%s\%s", // tmpstr, fobj->nfs_obj.logfile); // sprintf(fobj->nfs_obj.fbfile, "%s\%s", // tmpstr, fobj->nfs_obj.fbfile); //#else // sprintf(fobj->nfs_obj.outputfile, "%s%s", // tmpstr, fobj->nfs_obj.outputfile); // sprintf(fobj->nfs_obj.logfile, "%s%s", // tmpstr, fobj->nfs_obj.logfile); // sprintf(fobj->nfs_obj.fbfile, "%s%s", // tmpstr, fobj->nfs_obj.fbfile); // //#endif // // msieve_obj_free(fobj->nfs_obj.mobj); // obj = msieve_obj_new(input, flags, fobj->nfs_obj.outputfile, fobj->nfs_obj.logfile, // fobj->nfs_obj.fbfile, g_rand.low, g_rand.hi, (uint32)0, nfs_lower, nfs_upper, cpu, // (uint32)L1CACHE, (uint32)L2CACHE, (uint32)THREADS, (uint32)0, (uint32)0, 0.0); // fobj->nfs_obj.mobj = obj; // // printf("output: %s\n", fobj->nfs_obj.mobj->savefile.name); // printf("log: %s\n", fobj->nfs_obj.mobj->logfile_name); // printf("fb: %s\n", fobj->nfs_obj.mobj->nfs_fbfile_name); break; // should really be "resume_job", since we do more than just resume sieving... case NFS_STATE_RESUMESIEVE: // last_specialq == 0 if: // 1) user specifies -R and -ns with params // 2) user specifies post processing steps only // 3) user wants to resume sieving (either with a solo -ns or no arguements) // but no data file or special-q was found // 4) -R was not specified (but then we won't be in this state, we'll be in DONE) // last_specialq > 1 if: // 5) user wants to resume sieving (either with a solo -ns or no arguements) // and a data file and special-q was found // 6) it contains poly->time info (in which case we'll be in NFS_STATE_RESUMEPOLY) strcpy(tmpstr, ""); if ((last_specialq == 0) && ((fobj->nfs_obj.nfs_phases == NFS_DEFAULT_PHASES) || (fobj->nfs_obj.nfs_phases & NFS_PHASE_SIEVE))) { // this if-block catches cases 1 and 3 from above uint32 missing_params = parse_job_file(fobj, &job); // set min_rels. get_ggnfs_params(fobj, &job); fill_job_file(fobj, &job, missing_params); // if any ggnfs params are missing, fill them // this means the user can provide an SNFS poly or external GNFS poly, // but let YAFU choose the other params // this won't override any params in the file. if (fobj->nfs_obj.startq > 0) { job.startq = fobj->nfs_obj.startq; sprintf(tmpstr, "nfs: resuming with sieving at user specified special-q %u\n", job.startq); } else { // this is a guess, may be completely wrong job.startq = (job.poly->side == RATIONAL_SPQ ? job.rlim : job.alim) / 2; sprintf(tmpstr, "nfs: continuing with sieving - could not determine " "last special q; using default startq\n"); } // next step is sieving nfs_state = NFS_STATE_SIEVE; } else if ((last_specialq == 0) && ((fobj->nfs_obj.nfs_phases & NFS_PHASE_FILTER) || (fobj->nfs_obj.nfs_phases & NFS_PHASE_LA) || (fobj->nfs_obj.nfs_phases & NFS_PHASE_LA_RESUME) || (fobj->nfs_obj.nfs_phases & NFS_PHASE_SQRT))) { // this if-block catches case 2 from above // with these options we don't check for the last special-q, so this isn't // really a new factorization if ((fobj->nfs_obj.nfs_phases & NFS_PHASE_FILTER)) { nfs_state = NFS_STATE_FILTCHECK; sprintf(tmpstr, "nfs: resuming with filtering\n"); } else if ((fobj->nfs_obj.nfs_phases & NFS_PHASE_LA) || (fobj->nfs_obj.nfs_phases & NFS_PHASE_LA_RESUME)) { nfs_state = NFS_STATE_LINALG; sprintf(tmpstr, "nfs: resuming with linear algebra\n"); } else if (fobj->nfs_obj.nfs_phases & NFS_PHASE_SQRT) { nfs_state = NFS_STATE_SQRT; sprintf(tmpstr, "nfs: resuming with sqrt\n"); } } else // data file already exists { // this if-block catches case 5 from above (void) parse_job_file(fobj, &job); // set min_rels. get_ggnfs_params(fobj, &job); if (fobj->nfs_obj.startq > 0) { // user wants to resume sieving. // i don't believe this case is ever executed... // because if startq is > 0, then last_specialq will be 0... job.startq = fobj->nfs_obj.startq; nfs_state = NFS_STATE_SIEVE; } else { job.startq = last_specialq; // we found some relations - find the appropriate state // given user input if ((fobj->nfs_obj.nfs_phases == NFS_DEFAULT_PHASES) || (fobj->nfs_obj.nfs_phases & NFS_PHASE_FILTER)) { nfs_state = NFS_STATE_FILTCHECK; sprintf(tmpstr, "nfs: resuming with filtering\n"); } else if (fobj->nfs_obj.nfs_phases & NFS_PHASE_SIEVE) { nfs_state = NFS_STATE_SIEVE; sprintf(tmpstr, "nfs: resuming with sieving at special-q = %u\n", last_specialq); } else if ((fobj->nfs_obj.nfs_phases & NFS_PHASE_LA) || (fobj->nfs_obj.nfs_phases & NFS_PHASE_LA_RESUME)) { nfs_state = NFS_STATE_LINALG; sprintf(tmpstr, "nfs: resuming with linear algebra\n"); } else if (fobj->nfs_obj.nfs_phases & NFS_PHASE_SQRT) { nfs_state = NFS_STATE_SQRT; sprintf(tmpstr, "nfs: resuming with sqrt\n"); } } } if (VFLAG >= 0) printf("%s", tmpstr); logprint_oc(fobj->flogname, "a", "%s", tmpstr); // if there is a job file and the user has specified -np, print // this warning. if (fobj->nfs_obj.nfs_phases & NFS_PHASE_POLY) { printf("WARNING: .job file exists! If you really want to redo poly selection," " delete the .job file.\n"); // non ideal solution to infinite loop in factor() if we return without factors // (should return error code instead) NFS_ABORT = 1; process_done = 1; } break; case NFS_STATE_RESUMEPOLY: if (VFLAG > 1) printf("nfs: resuming poly select\n"); fobj->nfs_obj.polystart = job.last_leading_coeff; nfs_state = NFS_STATE_POLY; break; default: printf("unknown state, bailing\n"); // non ideal solution to infinite loop in factor() if we return without factors // (should return error code instead) NFS_ABORT = 1; break; } //after every state, check elasped time against a specified timeout value gettimeofday(&stop, NULL); difference = my_difftime (&start, &stop); t_time = ((double)difference->secs + (double)difference->usecs / 1000000); free(difference); if ((fobj->nfs_obj.timeout > 0) && (t_time > (double)fobj->nfs_obj.timeout)) { if (VFLAG >= 0) printf("NFS timeout after %6.4f seconds.\n",t_time); logprint_oc(fobj->flogname, "a", "NFS timeout after %6.4f seconds.\n",t_time); process_done = 1; } if (NFS_ABORT) { print_factors(fobj); exit(1); } } //reset signal handler to default (no handler). signal(SIGINT,NULL); if (obj != NULL) msieve_obj_free(obj); free(input); if( job.snfs ) { snfs_clear(job.snfs); free(job.snfs); } else if( job.poly ) { mpz_polys_free(job.poly); free(job.poly); } return; }
int perfect_power(const Integer &n) { return mpz_perfect_power_p(n.as_mpz().get_mpz_t()); }
int main() { srand(1337); // The primes we will perform trial division with on small integers. std::vector<uint32_t> primes; // Generate the trial division primes using a simple sieve. { uint32_t max = (uint32_t)ceil(sqrt(TRIAL_BOUND)) + 1; char *sieve = new char[max]; memset(sieve, 1, max); for(uint32_t p = 2; p < max; ++p) { if(!sieve[p]) continue; primes.push_back(p); for(uint32_t i = p; i < max; i += p) sieve[i] = 0; } delete[] sieve; } mpz_class N; // Read numbers to factor from stdin until EOF. while(std::cin >> N) { // This quadratic sieve implementation is designed to factor numbers no larger than 100 bits. if(mpz_sizeinbase(N.get_mpz_t(), 2) > 100) { std::cerr << N << " is too large\n" << std::endl; continue; } std::stack<mpz_class> factors; factors.push(N); while(!factors.empty()) { mpz_class factor = factors.top(); factors.pop(); // If the factor is prime, print it. if(mpz_probab_prime_p(factor.get_mpz_t(), 10)) { std::cout << factor << std::endl; continue; // Run trial division if factor is small. } else if(factor < TRIAL_BOUND) { uint32_t f = factor.get_ui(); for(uint32_t p = 0; p < primes.size(); ++p) { if(f % primes[p] == 0) { factors.push(primes[p]); factors.push(factor / primes[p]); break; } } } else { // Before we run quadratic sieve, check for small factors. bool found_factor = false; for(uint32_t p = 0; p < primes.size(); ++p) { if(mpz_divisible_ui_p(factor.get_mpz_t(), primes[p])) { factors.push(primes[p]); factors.push(factor / primes[p]); found_factor = true; break; } } if(found_factor) continue; // Quadratic sieve doesn't handle perferct powers very well, handle those separately. if(mpz_perfect_power_p(factor.get_mpz_t())) { mpz_class root, rem; // Check root remainders up half of the amount of bits in factor. uint32_t max = mpz_sizeinbase(factor.get_mpz_t(), 2) / 2; for(uint32_t n = 2; n < max; ++n) { mpz_rootrem(root.get_mpz_t(), rem.get_mpz_t(), factor.get_mpz_t(), n); if(rem == 0) { // Push the n root factors. for(uint32_t i = 0; i < n; ++i) factors.push(root); break; } } } else { mpz_class f = quadratic_sieve(factor); factors.push(f); factors.push(factor / f); } } } std::cout << std::endl; } return 0; }
int check_specialcase(FILE *sieve_log, fact_obj_t *fobj) { //check for some special cases of input number //sieve_log is passed in already open, and should return open if (mpz_even_p(fobj->qs_obj.gmp_n)) { printf("input must be odd\n"); return 1; } if (mpz_probab_prime_p(fobj->qs_obj.gmp_n, NUM_WITNESSES)) { add_to_factor_list(fobj, fobj->qs_obj.gmp_n); if (sieve_log != NULL) logprint(sieve_log,"prp%d = %s\n", gmp_base10(fobj->qs_obj.gmp_n), mpz_conv2str(&gstr1.s, 10, fobj->qs_obj.gmp_n)); mpz_set_ui(fobj->qs_obj.gmp_n,1); return 1; } if (mpz_perfect_square_p(fobj->qs_obj.gmp_n)) { mpz_sqrt(fobj->qs_obj.gmp_n,fobj->qs_obj.gmp_n); add_to_factor_list(fobj, fobj->qs_obj.gmp_n); if (sieve_log != NULL) logprint(sieve_log,"prp%d = %s\n",gmp_base10(fobj->qs_obj.gmp_n), mpz_conv2str(&gstr1.s, 10, fobj->qs_obj.gmp_n)); add_to_factor_list(fobj, fobj->qs_obj.gmp_n); if (sieve_log != NULL) logprint(sieve_log,"prp%d = %s\n",gmp_base10(fobj->qs_obj.gmp_n), mpz_conv2str(&gstr1.s, 10, fobj->qs_obj.gmp_n)); mpz_set_ui(fobj->qs_obj.gmp_n,1); return 1; } if (mpz_perfect_power_p(fobj->qs_obj.gmp_n)) { if (VFLAG > 0) printf("input is a perfect power\n"); factor_perfect_power(fobj, fobj->qs_obj.gmp_n); if (sieve_log != NULL) { uint32 j; logprint(sieve_log,"input is a perfect power\n"); for (j=0; j<fobj->num_factors; j++) { uint32 k; for (k=0; k<fobj->fobj_factors[j].count; k++) { logprint(sieve_log,"prp%d = %s\n",gmp_base10(fobj->fobj_factors[j].factor), mpz_conv2str(&gstr1.s, 10, fobj->fobj_factors[j].factor)); } } } return 1; } if (mpz_sizeinbase(fobj->qs_obj.gmp_n,2) < 115) { //run MPQS, as SIQS doesn't work for smaller inputs //MPQS will take over the log file, so close it now. int i; // we've verified that the input is not odd or prime. also // do some very quick trial division before calling smallmpqs, which // does none of these things. for (i=1; i<25; i++) { if (mpz_tdiv_ui(fobj->qs_obj.gmp_n, spSOEprimes[i]) == 0) mpz_tdiv_q_ui(fobj->qs_obj.gmp_n, fobj->qs_obj.gmp_n, spSOEprimes[i]); } smallmpqs(fobj); return 1; //tells SIQS to not try to close the logfile } if (gmp_base10(fobj->qs_obj.gmp_n) > 140) { printf("input too big for SIQS\n"); return 1; } return 0; }
int is_aks_prime(mpz_t n) { mpz_t *px, *py; int retval; UV i, s, r, a; UV starta = 1; int _verbose = get_verbose_level(); if (mpz_cmp_ui(n, 4) < 0) return (mpz_cmp_ui(n, 1) <= 0) ? 0 : 1; /* Just for performance: check small divisors: 2*3*5*7*11*13*17*19*23 */ if (mpz_gcd_ui(0, n, 223092870UL) != 1 && mpz_cmp_ui(n, 23) > 0) return 0; if (mpz_perfect_power_p(n)) return 0; #if AKS_VARIANT == AKS_VARIANT_V6 /* From the V6 AKS paper */ { mpz_t sqrtn, t; double log2n; UV limit, startr; PRIME_ITERATOR(iter); mpz_init(sqrtn); mpz_sqrt(sqrtn, n); log2n = mpz_log2(n); limit = (UV) floor( log2n * log2n ); if (_verbose>1) gmp_printf("# AKS checking order_r(%Zd) to %"UVuf"\n", n, (unsigned long) limit); /* Using a native r limits us to ~2000 digits in the worst case (r ~ log^5n) * but would typically work for 100,000+ digits (r ~ log^3n). This code is * far too slow to matter either way. Composite r is ok here, but it will * always end up prime, so save time and just check primes. */ retval = 0; /* Start order search at a good spot. Idea from Nemana and Venkaiah. */ startr = (mpz_sizeinbase(n,2)-1) * (mpz_sizeinbase(n,2)-1); startr = (startr < 1002) ? 2 : startr - 100; for (r = 2; /* */; r = prime_iterator_next(&iter)) { if (mpz_divisible_ui_p(n, r) ) /* r divides n. composite. */ { retval = 0; break; } if (mpz_cmp_ui(sqrtn, r) <= 0) /* no r <= sqrtn divides n. prime. */ { retval = 1; break; } if (r < startr) continue; if (mpz_order_ui(r, n, limit) > limit) { retval = 2; break; } } prime_iterator_destroy(&iter); mpz_clear(sqrtn); if (retval != 2) return retval; /* Since r is prime, phi(r) = r-1. */ s = (UV) floor( sqrt(r-1) * log2n ); } #elif AKS_VARIANT == AKS_VARIANT_BORNEMANN /* Bernstein + Voloch */ { UV slim; double c2, x; /* small t = few iters of big poly. big t = many iters of small poly */ double const t = (mpz_sizeinbase(n, 2) <= 64) ? 32 : 40; double const t1 = (1.0/((t+1)*log(t+1)-t*log(t))); double const dlogn = mpz_logn(n); mpz_t tmp; PRIME_ITERATOR(iter); mpz_init(tmp); prime_iterator_setprime(&iter, (UV) (t1*t1 * dlogn*dlogn) ); r = prime_iterator_next(&iter); while (!is_primitive_root_uiprime(n,r)) r = prime_iterator_next(&iter); prime_iterator_destroy(&iter); slim = (UV) (2*t*(r-1)); c2 = dlogn * floor(sqrt(r)); { /* Binary search for first s in [1,slim] where x >= 0 */ UV bi = 1; UV bj = slim; while (bi < bj) { s = bi + (bj-bi)/2; mpz_bin_uiui(tmp, r+s-1, s); x = mpz_logn(tmp) / c2 - 1.0; if (x < 0) bi = s+1; else bj = s; } s = bi-1; } s = (s+3) >> 1; /* Bornemann checks factors up to (s-1)^2, we check to max(r,s) */ /* slim = (s-1)*(s-1); */ slim = (r > s) ? r : s; if (_verbose > 1) printf("# aks trial to %"UVuf"\n", slim); if (_GMP_trial_factor(n, 2, slim) > 1) { mpz_clear(tmp); return 0; } mpz_sqrt(tmp, n); if (mpz_cmp_ui(tmp, slim) <= 0) { mpz_clear(tmp); return 1; } mpz_clear(tmp); } #elif AKS_VARIANT == AKS_VARIANT_BERN21 { /* Bernstein 2003, theorem 2.1 (simplified) */ UV q; double slim, scmp, x; mpz_t t, t2; PRIME_ITERATOR(iter); mpz_init(t); mpz_init(t2); r = s = 0; while (1) { /* todo: Check r|n and r >= sqrt(n) here instead of waiting */ if (mpz_cmp_ui(n, r) <= 0) break; r = prime_iterator_next(&iter); q = largest_factor(r-1); mpz_set_ui(t, r); mpz_powm_ui(t, n, (r-1)/q, t); if (mpz_cmp_ui(t, 1) <= 0) continue; scmp = 2 * floor(sqrt(r)) * mpz_log2(n); slim = 20 * (r-1); /* Check viability */ mpz_bin_uiui(t, q+slim-1, slim); if (mpz_log2(t) < scmp) continue; for (s = 2; s < slim; s++) { mpz_bin_uiui(t, q+s-1, s); if (mpz_log2(t) > scmp) break; } if (s < slim) break; } mpz_clear(t); mpz_clear(t2); prime_iterator_destroy(&iter); if (_GMP_trial_factor(n, 2, s) > 1) return 0; } #elif AKS_VARIANT == AKS_VARIANT_BERN22 { /* Bernstein 2003, theorem 2.2 (simplified) */ UV q; double slim, scmp, x; mpz_t t, t2; PRIME_ITERATOR(iter); mpz_init(t); mpz_init(t2); r = s = 0; while (1) { /* todo: Check r|n and r >= sqrt(n) here instead of waiting */ if (mpz_cmp_ui(n, r) <= 0) break; r = prime_iterator_next(&iter); if (!is_primitive_root_uiprime(n,r)) continue; q = r-1; /* Since r is prime, phi(r) = r-1 */ scmp = 2 * floor(sqrt(r-1)) * mpz_log2(n); slim = 20 * (r-1); /* Check viability */ mpz_bin_uiui(t, q+slim-1, slim); if (mpz_log2(t) < scmp) continue; for (s = 2; s < slim; s++) { mpz_bin_uiui(t, q+s-1, s); if (mpz_log2(t) > scmp) break; } if (s < slim) break; } mpz_clear(t); mpz_clear(t2); prime_iterator_destroy(&iter); if (_GMP_trial_factor(n, 2, s) > 1) return 0; } #elif AKS_VARIANT == AKS_VARIANT_BERN23 { /* Bernstein 2003, theorem 2.3 (simplified) */ UV q, d, limit; double slim, scmp, sbin, x, log2n; mpz_t t, t2; PRIME_ITERATOR(iter); mpz_init(t); mpz_init(t2); log2n = mpz_log2(n); limit = (UV) floor( log2n * log2n ); r = 2; s = 0; while (1) { /* todo: Check r|n and r >= sqrt(n) here instead of waiting */ if (mpz_cmp_ui(n, r) <= 0) break; r++; UV gcd = mpz_gcd_ui(NULL, n, r); if (gcd != 1) { mpz_clear(t); mpz_clear(t2); return 0; } UV v = mpz_order_ui(r, n, limit); if (v >= limit) continue; mpz_set_ui(t2, r); totient(t, t2); q = mpz_get_ui(t); UV phiv = q/v; /* printf("phi(%lu)/v = %lu/%lu = %lu\n", r, q, v, phiv); */ /* This is extremely inefficient. */ /* Choose an s value we'd be happy with */ slim = 20 * (r-1); /* Quick check to see if it could work with s=slim, d=1 */ mpz_bin_uiui(t, q+slim-1, slim); sbin = mpz_log2(t); if (sbin < 2*floor(sqrt(q))*log2n) continue; for (s = 2; s < slim; s++) { mpz_bin_uiui(t, q+s-1, s); sbin = mpz_log2(t); if (sbin < 2*floor(sqrt(q))*log2n) continue; /* d=1 */ /* Check each number dividing phi(r)/v */ for (d = 2; d < phiv; d++) { if ((phiv % d) != 0) continue; scmp = 2 * d * floor(sqrt(q/d)) * log2n; if (sbin < scmp) break; } /* if we did not exit early, this s worked for each d. This s wins. */ if (d >= phiv) break; } if (s < slim) break; } mpz_clear(t); mpz_clear(t2); prime_iterator_destroy(&iter); if (_GMP_trial_factor(n, 2, s) > 1) return 0; } #elif AKS_VARIANT == AKS_VARIANT_BERN41 { double const log2n = mpz_log2(n); /* Tuning: Initial 'r' selection */ double const r0 = 0.008 * log2n * log2n; /* Tuning: Try a larger 'r' if 's' looks very large */ UV const rmult = 8; UV slim; mpz_t tmp, tmp2; PRIME_ITERATOR(iter); mpz_init(tmp); mpz_init(tmp2); /* r has to be at least 3. */ prime_iterator_setprime(&iter, (r0 < 2) ? 2 : (UV) r0); r = prime_iterator_next(&iter); /* r must be a primitive root. For performance, skip if s looks too big. */ while ( !is_primitive_root_uiprime(n, r) || !bern41_acceptable(n, r, rmult*(r-1), tmp, tmp2) ) r = prime_iterator_next(&iter); prime_iterator_destroy(&iter); { /* Binary search for first s in [1,lim] where conditions met */ UV bi = 1; UV bj = rmult * (r-1); while (bi < bj) { s = bi + (bj-bi)/2; if (!bern41_acceptable(n,r,s,tmp,tmp2)) bi = s+1; else bj = s; } s = bj; /* Our S goes from 2 to s+1. */ starta = 2; s = s+1; } /* printf("chose r=%lu s=%lu d = %lu i = %lu j = %lu\n", r, s, d, i, j); */ /* Check divisibility to s(s-1) to cover both gcd conditions */ slim = s * (s-1); if (_verbose > 1) printf("# aks trial to %"UVuf"\n", slim); if (_GMP_trial_factor(n, 2, slim) > 1) { mpz_clear(tmp); mpz_clear(tmp2); return 0; } /* If we checked divisibility to sqrt(n), then it is prime. */ mpz_sqrt(tmp, n); if (mpz_cmp_ui(tmp, slim) <= 0) { mpz_clear(tmp); mpz_clear(tmp2); return 1; } /* Check b^(n-1) = 1 mod n for b in [2..s] */ if (_verbose > 1) printf("# aks checking fermat to %"UVuf"\n", s); mpz_sub_ui(tmp2, n, 1); for (i = 2; i <= s; i++) { mpz_set_ui(tmp, i); mpz_powm(tmp, tmp, tmp2, n); if (mpz_cmp_ui(tmp, 1) != 0) { mpz_clear(tmp); mpz_clear(tmp2); return 0; } } mpz_clear(tmp); mpz_clear(tmp2); } #endif if (_verbose) gmp_printf("# AKS %Zd. r = %"UVuf" s = %"UVuf"\n", n, (unsigned long) r, (unsigned long) s); /* Create the three polynomials we will use */ New(0, px, r, mpz_t); New(0, py, r, mpz_t); if ( !px || !py ) croak("allocation failure\n"); for (i = 0; i < r; i++) { mpz_init(px[i]); mpz_init(py[i]); } retval = 1; for (a = starta; a <= s; a++) { retval = test_anr(a, n, r, px, py); if (!retval) break; if (_verbose>1) { printf("."); fflush(stdout); } } if (_verbose>1) { printf("\n"); fflush(stdout); }; /* Free the polynomials */ for (i = 0; i < r; i++) { mpz_clear(px[i]); mpz_clear(py[i]); } Safefree(px); Safefree(py); return retval; }
int aks (mpz_t n) { mpz_t r; mpz_t a; mpz_t max_a; mpz_t gcd_rslt; mpz_t totient_r; mpf_t ftotient_r; mpf_t sqrt_rslt; mpf_t sqrt_rslt2; mpf_t temp; mpf_t temp2; sli_t logn; /* For the sake of maple kernel */ int argc = 0; char **argv; char err[2048]; mpz_init (r); mpz_init (a); mpz_init (max_a); mpz_init (gcd_rslt); mpz_init (totient_r); mpf_init (ftotient_r); mpf_init (sqrt_rslt); mpf_init (sqrt_rslt2); mpf_init (temp); mpf_init (temp2); /* 1. If (n = a^k for a in N and b > 1) output COMPOSITE */ if (mpz_perfect_power_p (n) != 0) { printf ("Step 1 detected composite\n"); return FALSE; } /* 2. Find the smallest r such that or(n) > 4(log n)^2 */ find_smallest_r (r, n); gmp_printf ("good r seems to be %Zd\n", r); /* 3. If 1 < gcd(a, n) < n for some a <= r, output COMPOSITE */ /* for (a = 1; a <= r; a++) { * gcd_rslt = gcd(a, n); * if (gcd_rslt > 1 && gcd_rslt < n) { * return FALSE; * } * } */ for (mpz_set_ui (a, 1); mpz_cmp (a, r) < 0 || mpz_cmp (a, r) == 0; mpz_add_ui (a, a, 1)) { mpz_gcd (gcd_rslt, a, n); if (mpz_cmp_ui (gcd_rslt, 1) > 0 && mpz_cmp (gcd_rslt, n) < 0) { printf ("Step 3 detected composite\n"); return FALSE; } } /* 4. If n <= r, output PRIME */ if (mpz_cmp (n, r) < 0 || mpz_cmp (n, r) == 0) { printf ("Step 4 detected prime\n"); return TRUE; } /* 5. For a = 1 to floor(2*sqrt(totient(r))*(log n) * if ( (X+a)^n != X^n + a (mod X^r-1, n) ), output COMPOSITE * * Choices of implementation to evaluate the polynomial equality: * (1) Implement powermodreduce on polynomial ourselves (tough manly way) * (2) Use MAPLE (not so manly, but less painful) */ /* Compute totient(r), since r is prime, this is simply r-1 */ mpz_sub_ui (totient_r, r, 1); /* Compute log n (ceilinged) */ mpz_logbase2cl (&logn, n); /* Compute sqrt(totient(r)) */ mpf_set_z (ftotient_r, totient_r); mpf_sqrt (sqrt_rslt, ftotient_r); /* Compute 2*sqrt(totient(r)) */ mpf_mul_ui (sqrt_rslt2, sqrt_rslt, 2); /* Compute 2*sqrt(totient(r))*(log n) */ mpf_set (temp, sqrt_rslt2); mpf_set_si (temp2, logn); mpf_mul (temp, temp, temp2); /* Finally, compute max_a, after lots of singing and dancing */ mpf_floor (temp, temp); mpz_set_f (max_a, temp); gmp_printf ("max_a = %Zd\n", max_a); /* Now evaluate the polynomial equality with the help of maple kernel */ /* Set up maple kernel incantations */ MKernelVector kv; MCallBackVectorDesc cb = { textCallBack, 0, /* errorCallBack not used */ 0, /* statusCallBack not used */ 0, /* readLineCallBack not used */ 0, /* redirectCallBack not used */ 0, /* streamCallBack not used */ 0, /* queryInterrupt not used */ 0 /* callBackCallBack not used */ }; /* Initialize Maple */ if ((kv = StartMaple (argc, argv, &cb, NULL, NULL, err)) == NULL) { printf ("Could not start Maple, %s\n", err); exit (666); } /* Here comes the complexity and bottleneck */ /* for (a = 1; a <= max_a; a++) { * if (!poly_eq_holds(kv, a, n, r)) { * return FALSE; * } * } */ /* Make max_a only up to 5 */ mpz_set_ui (max_a, 5); for (mpz_set_ui (a, 1); mpz_cmp (a, max_a) < 0 || mpz_cmp (a, max_a) == 0; mpz_add_ui (a, a, 1)) { if (!poly_eq_holds (kv, a, n, r)) { printf ("Step 5 detected composite\n"); return FALSE; } } /* 6. Output PRIME */ printf ("Step 6 detected prime\n"); return TRUE; }
void check_random (int reps) { mpz_t n, np, temp, primes[NRP]; int i, j, k, unique, destroy, res; unsigned long int nrprimes, primebits; mp_limb_t g, exp[NRP], e; gmp_randstate_ptr rands; rands = RANDS; mpz_init (n); mpz_init (np); mpz_init (temp); for (i = 0; i < NRP; i++) mpz_init (primes[i]); for (i = 0; i < reps; i++) { mpz_urandomb (np, rands, 32); nrprimes = mpz_get_ui (np) % NRP + 1; /* 1-NRP unique primes */ mpz_urandomb (np, rands, 32); g = mpz_get_ui (np) % 32 + 2; /* gcd 2-33 */ for (j = 0; j < nrprimes;) { mpz_urandomb (np, rands, 32); primebits = mpz_get_ui (np) % 100 + 3; /* 3-102 bit primes */ mpz_urandomb (primes[j], rands, primebits); mpz_nextprime (primes[j], primes[j]); unique = 1; for (k = 0; k < j; k++) { if (mpz_cmp (primes[j], primes[k]) == 0) { unique = 0; break; } } if (unique) { mpz_urandomb (np, rands, 32); e = 371 / (10 * primebits) + mpz_get_ui (np) % 11 + 1; /* Magic constants */ exp[j++] = g * e; } } if (nrprimes > 1) { /* Destroy d exponents, d in [1, nrprimes - 1] */ if (nrprimes == 2) { destroy = 1; } else { mpz_urandomb (np, rands, 32); destroy = mpz_get_ui (np) % (nrprimes - 2) + 1; } g = exp[destroy]; for (k = destroy + 1; k < nrprimes; k++) g = mpn_gcd_1 (&g, 1, exp[k]); for (j = 0; j < destroy; j++) { mpz_urandomb (np, rands, 32); e = mpz_get_ui (np) % 50 + 1; while (mpn_gcd_1 (&g, 1, e) > 1) e++; exp[j] = e; } } /* Compute n */ mpz_pow_ui (n, primes[0], exp[0]); for (j = 1; j < nrprimes; j++) { mpz_pow_ui (temp, primes[j], exp[j]); mpz_mul (n, n, temp); } res = mpz_perfect_power_p (n); if (nrprimes == 1) { if (res == 0 && exp[0] > 1) { printf("n is a perfect power, perfpow_p disagrees\n"); gmp_printf("n = %Zu\nprimes[0] = %Zu\nexp[0] = %lu\n", n, primes[0], exp[0]); abort (); } else if (res == 1 && exp[0] == 1) { gmp_printf("n = %Zu\n", n); printf("n is now a prime number, but perfpow_p still believes n is a perfect power\n"); abort (); } } else { if (res == 1) { gmp_printf("n = %Zu\nn was destroyed, but perfpow_p still believes n is a perfect power\n", n); abort (); } } } mpz_clear (n); mpz_clear (np); mpz_clear (temp); for (i = 0; i < NRP; i++) mpz_clear (primes[i]); }