/*-------------------------------------------------------------------- This source distribution is placed in the public domain by its author, Jason Papadopoulos. You may use it for any purpose, free of charge, without having to notify anyone. I disclaim any responsibility for any errors. Optionally, please be nice and tell me if you find this source to be useful. Again optionally, if you add to the functionality present here please consider making those additions public too, so that others may benefit from your work. --jasonp@boo.net 5/27/07 --------------------------------------------------------------------*/ #include #include msieve_obj *g_curr_factorization = NULL; /*--------------------------------------------------------------------*/ void handle_signal(int sig) { msieve_obj *obj = g_curr_factorization; printf("\nreceived signal %d; shutting down\n", sig); if (obj && (obj->flags & MSIEVE_FLAG_SIEVING_IN_PROGRESS)) obj->flags |= MSIEVE_FLAG_STOP_SIEVING; else _exit(0); } /*--------------------------------------------------------------------*/ void get_random_seeds(uint32 *seed1, uint32 *seed2) { uint32 tmp_seed1, tmp_seed2; /* In a multithreaded program, every msieve object should have two unique, non-correlated seeds chosen for it */ #ifndef WIN32 FILE *rand_device = fopen("/dev/urandom", "r"); if (rand_device != NULL) { /* Yay! Cryptographic-quality nondeterministic randomness! */ fread(&tmp_seed1, sizeof(uint32), (size_t)1, rand_device); fread(&tmp_seed2, sizeof(uint32), (size_t)1, rand_device); fclose(rand_device); } else #endif { /* For everyone else, sample the current time, the high-res timer (hopefully not correlated to the current time), and the process ID. Multithreaded applications should fold in the thread ID too */ uint64 high_res_time = read_clock(); tmp_seed1 = ((uint32)(high_res_time >> 32) ^ (uint32)time(NULL)) * (uint32)getpid(); tmp_seed2 = (uint32)high_res_time; } /* The final seeds are the result of a multiplicative hash of the initial seeds */ (*seed1) = tmp_seed1 * ((uint32)40499 * 65543); (*seed2) = tmp_seed2 * ((uint32)40499 * 65543); } /*--------------------------------------------------------------------*/ void print_usage(char *progname) { printf("\nMsieve v. %d.%02d\n", MSIEVE_MAJOR_VERSION, MSIEVE_MINOR_VERSION); printf("\nusage: %s [options] [one_number]\n", progname); printf("\nnumbers starting with '0' are treated as octal,\n" "numbers starting with '0x' are treated as hexadecimal\n"); printf("\noptions:\n" " -s save intermediate results to \n" " instead of the default %s\n" " -l append log information to \n" " instead of the default %s\n" " -i read one or more integers to factor from\n" " (default worktodo.ini) instead of\n" " from the command line\n" " -m manual mode: enter numbers via standard input\n" " -q quiet: do not generate any log information,\n" " only print any factors found\n" " -d deadline: if still sieving after \n" " minutes, shut down gracefully (default off)\n" " -r stop after finding relations\n" " -v verbose: write log information to screen\n" " as well as to logfile\n" " -t use at most threads\n\n" " quadratic sieve options:\n" " -c client: only perform sieving\n\n" " number field sieve options:\n" " -n use the number field sieve (97+ digits only;\n" " performs all NFS tasks in order)\n" " -nf read from / write to NFS factor base file\n" " instead of the default %s\n" " -np [X,Y] perform only NFS polynomial selection; if\n" " specified, cover the range from X to Y\n" " percent of the total polynomial search\n" " space, inclusive (1<=Xflags & MSIEVE_FLAG_FACTORIZATION_DONE)) { printf("\ncurrent factorization was interrupted\n"); exit(0); } /* If no logging is specified, at least print out the factors that were found */ if (!(g_curr_factorization->flags & (MSIEVE_FLAG_USE_LOGFILE | MSIEVE_FLAG_LOG_TO_STDOUT))) { factor = g_curr_factorization->factors; printf("\n"); printf("%s\n", buf); while (factor != NULL) { char *factor_type; if (factor->factor_type == MSIEVE_PRIME) factor_type = "p"; else if (factor->factor_type == MSIEVE_COMPOSITE) factor_type = "c"; else factor_type = "prp"; printf("%s%d: %s\n", factor_type, (int32)strlen(factor->number), factor->number); factor = factor->next; } printf("\n"); } /* save the current value of the random seeds, so that the next factorization will pick up the pseudorandom sequence where this factorization left off */ *seed1 = g_curr_factorization->seed1; *seed2 = g_curr_factorization->seed2; /* free the current factorization struct. The following avoids a race condition in the signal handler */ obj = g_curr_factorization; g_curr_factorization = NULL; if (obj) msieve_obj_free(obj); } #ifdef WIN32 DWORD WINAPI countdown_thread(LPVOID pminutes) { DWORD minutes = *(DWORD *)pminutes; if (minutes > 0x7fffffff / 60000) minutes = 0; /* infinite */ Sleep(minutes * 60000); raise(SIGINT); return 0; } #else void *countdown_thread(void *pminutes) { uint32 minutes = *(uint32 *)pminutes; if (minutes > 0xffffffff / 60) minutes = 0xffffffff / 60; /* infinite */ sleep(minutes * 60); raise(SIGINT); return NULL; } #endif /*--------------------------------------------------------------------*/ int main(int argc, char **argv) { char buf[300]; uint32 seed1, seed2; char *savefile_name = NULL; char *logfile_name = NULL; char *infile_name = "worktodo.ini"; char *nfs_fbfile_name = NULL; uint32 flags; char manual_mode = 0; int i; int32 deadline = 0; uint32 max_relations = 0; uint32 nfs_lower = 0; uint32 nfs_upper = 0; enum cpu_type cpu; uint32 cache_size1; uint32 cache_size2; uint32 num_threads = 0; get_cache_sizes(&cache_size1, &cache_size2); cpu = get_cpu_type(); if (signal(SIGINT, handle_signal) == SIG_ERR) { printf("could not install handler on SIGINT\n"); return -1; } if (signal(SIGTERM, handle_signal) == SIG_ERR) { printf("could not install handler on SIGTERM\n"); return -1; } flags = MSIEVE_FLAG_USE_LOGFILE; i = 1; buf[0] = 0; while (i < argc) { if (argv[i][0] == (char)('-')) { switch(tolower(argv[i][1])) { case 'h': case '?': print_usage(argv[0]); return 0; case 'i': case 's': case 'l': if (i + 1 < argc && argv[i+1][0] != '-') { if (tolower(argv[i][1]) == 'i') infile_name = argv[i+1]; else if (tolower(argv[i][1]) == 's') savefile_name = argv[i+1]; else logfile_name = argv[i+1]; i += 2; } else { print_usage(argv[0]); return -1; } break; case 'm': manual_mode = 1; i++; break; case 'n': if (argv[i][2] == 'p') { flags |= MSIEVE_FLAG_NFS_POLY; } else if (argv[i][2] == 's') { flags |= MSIEVE_FLAG_NFS_SIEVE; } else if (argv[i][2] == 'c') { if (argv[i][3] == '1') flags |= MSIEVE_FLAG_NFS_FILTER; else if (argv[i][3] == '2') flags |= MSIEVE_FLAG_NFS_LA; else if (argv[i][3] == '3') flags |= MSIEVE_FLAG_NFS_SQRT; else if (argv[i][3] == 0) flags |= MSIEVE_FLAG_NFS_FILTER | MSIEVE_FLAG_NFS_LA | MSIEVE_FLAG_NFS_SQRT; } else if (argv[i][2] == 0) { flags |= MSIEVE_FLAG_NFS_POLY | MSIEVE_FLAG_NFS_SIEVE | MSIEVE_FLAG_NFS_FILTER | MSIEVE_FLAG_NFS_LA | MSIEVE_FLAG_NFS_SQRT; } if (i + 1 < argc && argv[i+1][0] != '-') { if (argv[i][2] == 'f') { nfs_fbfile_name = argv[i+1]; i++; } else if ((argv[i][2] == 's' || argv[i][2] == 'c' || argv[i][2] == 'p') && strchr(argv[i+1], ',') != NULL ) { char *tmp; nfs_lower = strtoul(argv[i+1], &tmp, 10); tmp++; nfs_upper = strtoul(tmp, NULL, 10); i++; } } i++; break; case 'q': flags &= ~(MSIEVE_FLAG_USE_LOGFILE | MSIEVE_FLAG_LOG_TO_STDOUT); i++; break; case 'd': if (i + 1 < argc && isdigit(argv[i+1][0])) { deadline = atol(argv[i+1]); i += 2; } else { print_usage(argv[0]); return -1; } break; case 'r': if (i + 1 < argc && isdigit(argv[i+1][0])) { max_relations = atol(argv[i+1]); i += 2; } else { print_usage(argv[0]); return -1; } break; case 't': if (i + 1 < argc && isdigit(argv[i+1][0])) { num_threads = atol(argv[i+1]); i += 2; } else { print_usage(argv[0]); return -1; } break; case 'c': flags |= MSIEVE_FLAG_SKIP_QS_CYCLES; i++; break; case 'v': flags |= MSIEVE_FLAG_LOG_TO_STDOUT; i++; break; default: print_usage(argv[0]); return -1; } } else { if (isdigit(argv[i][0]) || argv[i][0] == '(' ) strncpy(buf, argv[i], sizeof(buf)); i++; } } get_random_seeds(&seed1, &seed2); if (deadline) { #ifdef WIN32 DWORD thread_id; CreateThread(NULL, 0, countdown_thread, &deadline, 0, &thread_id); #else pthread_t thread_id; pthread_create(&thread_id, NULL, countdown_thread, &deadline); #endif } if (isdigit(buf[0]) || buf[0] == '(' ) { factor_integer(buf, flags, savefile_name, logfile_name, nfs_fbfile_name, &seed1, &seed2, max_relations, nfs_lower, nfs_upper, cpu, cache_size1, cache_size2, num_threads); } else if (manual_mode) { while (1) { printf("\n\nnext number: "); fflush(stdout); buf[0] = 0; fgets(buf, (int)sizeof(buf), stdin); factor_integer(buf, flags, savefile_name, logfile_name, nfs_fbfile_name, &seed1, &seed2, max_relations, nfs_lower, nfs_upper, cpu, cache_size1, cache_size2, num_threads); if (feof(stdin)) break; } } else { FILE *infile = fopen(infile_name, "r"); if (infile == NULL) { printf("cannot open input file '%s'\n", infile_name); return 0; } while (1) { buf[0] = 0; fgets(buf, (int)sizeof(buf), infile); factor_integer(buf, flags, savefile_name, logfile_name, nfs_fbfile_name, &seed1, &seed2, max_relations, nfs_lower, nfs_upper, cpu, cache_size1, cache_size2, num_threads); if (feof(infile)) break; } fclose(infile); } return 0; }