/*
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;
}