/* Copyright (C) 2022 Stephen Hewitt, cambridgeclarion.org This file is part of a programme to research fast Fermat factorisation algorithms. This is free software: you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public Licence along with this programme. If not, see . A copy of the licence is also available at https://www.cambridgeclarion.org/download/GPLv3.txt It has the following cryptographic hash SHA256 3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986 */ /* This programme is for research on Fermat factorisation algorithms. This is a benchmark programme to measure and compare the performance of a filtering algorithm implemented in different ways. For more information see the articles on www.cambridgeclarion.org "Empirical explorations of faster Fermat factorisation" by Stephen Hewitt */ #include #include #include "gmp.h" #include "timings.h" extern "C" { #include "zf.h" } #define ARRAYSIZE(a) (sizeof a/sizeof a[0]) const char* lsd2series[] = { #include "lsd2series.gh" }; typedef struct { unsigned long category; unsigned long long input_range; } Optimum; Optimum optima[] = { #include "optima.gh" }; static int status_message(int status, const char* message) { fprintf(stderr, "benchmark: status %d %s\n", status, message); return status; } static void printbig(const mpz_t number, const char* message, int base) { printf("%s ", message); mpz_out_str(0, base, number); putchar('\n'); } // calculate the designator value which is a sort of pun in hex eg 0xABB3 int characterise(mpz_t pq, unsigned requested_primes_n, unsigned long* category) { unsigned long lsb3 = mpz_fdiv_ui(pq, 8); // first base 2 which is special case unsigned long designator; if (!lsb3 & 1) return status_message(89, "illegal binary ending: N is even"); else if ((lsb3 & 3) == 3) designator = 3; else designator = lsb3; unsigned long A_designator = 0xa; unsigned long B_designator = 0xb; for (unsigned prime_index = 1; prime_index < requested_primes_n; prime_index++) { unsigned long base = strlen(lsd2series[prime_index]); // the total number of possible lsd values, which is indeed the base unsigned lsd = mpz_fdiv_ui(pq, base); A_designator <<= 4; B_designator <<= 4; designator |= (lsd2series[prime_index][lsd] == 'A') ? A_designator: B_designator; } *category = designator; return 0; } void copy_to_result(Result& result, const Output& output) { result.tr = output.skip_n; result.max_skip = output.max_skip; result.search_secs = output.search_secs; result.setup_secs = output.setup_secs; } /* Factorises the pq number (ie N) represented by the hex string pq_string Checks that its own factorisation is correct by multiplying p and q and checking against original number but does not store p and q Factorises both with tuned M and untuned M and returns the time taken for each with some other information - info goes into *tuned and *untuned Output structs - note the other info is for confirmation/diagnostics only and could be calculated in advance for each category of pq Also writes the category of pq into *category, for convenience of caller Returns 0 if all is well. */ int get_timings(Comparison & comparison, unsigned long category, const char* pq_string) { int ret; mpz_t gmp_n; unsigned long designator; Output output; // original yafu value unsigned long M = 2 * 2 * 2 * 2 * 3 * 3 * 5 * 5 * 7 * 7; if (mpz_init_set_str(gmp_n, pq_string, 16)) return 19; ret = zFermat1(&output, gmp_n); if (ret) goto free_and_return; copy_to_result(comparison.sparse, output); comparison.sparse.M = M; ret = zFermat2(&output, M, gmp_n); if (ret) goto free_and_return; copy_to_result(comparison.untuned, output); comparison.untuned.M = M; ret = 47; // return code = could not match category, default unless match in the following loop for (unsigned i = 0; i < ARRAYSIZE(optima); i++) { if (category == optima[i].category) { M = optima[i].input_range; ret = zFermat2(&output, M, gmp_n); copy_to_result(comparison.tuned, output); comparison.tuned.M = M; break; } } free_and_return: mpz_clear(gmp_n); return ret; }