mkp224o/main.c

813 lines
19 KiB
C
Raw Normal View History

2017-10-06 03:21:00 +02:00
#define _POSIX_C_SOURCE 200112L
2017-09-24 21:13:16 +02:00
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
2017-09-24 21:13:16 +02:00
#include <stdint.h>
#include <stdbool.h>
2017-09-24 21:13:16 +02:00
#include <string.h>
2018-07-20 19:10:06 +02:00
#include <time.h>
2017-09-24 21:13:16 +02:00
#include <pthread.h>
2017-09-25 19:49:47 +02:00
#include <signal.h>
2018-08-24 20:31:57 +02:00
#include <sodium/core.h>
2017-09-27 20:38:15 +02:00
#include <sodium/randombytes.h>
#ifdef PASSPHRASE
#include <sodium/crypto_pwhash.h>
#endif
2018-05-31 16:01:33 +02:00
#include <sodium/utils.h>
2017-09-24 21:13:16 +02:00
#include "types.h"
#include "vec.h"
2019-03-17 01:23:10 +01:00
#include "base32.h"
2017-10-06 02:14:33 +02:00
#include "cpucount.h"
2017-09-24 21:13:16 +02:00
#include "keccak.h"
#include "ioutil.h"
2018-07-09 18:38:41 +02:00
#include "common.h"
#include "yaml.h"
2017-09-24 21:13:16 +02:00
2019-03-16 20:57:29 +01:00
#include "filters.h"
#include "worker.h"
2021-12-08 21:14:20 +01:00
#include "likely.h"
2018-02-22 01:46:06 +01:00
#ifndef _WIN32
#define FSZ "%zu"
#else
#define FSZ "%Iu"
#endif
// Argon2 hashed passphrase stretching settings
// NOTE: changing these will break compatibility
#define PWHASH_OPSLIMIT 48
#define PWHASH_MEMLIMIT 64 * 1024 * 1024
#define PWHASH_ALG crypto_pwhash_ALG_ARGON2ID13
2017-09-24 21:13:16 +02:00
static int quietflag = 0;
static int verboseflag = 0;
#ifndef PCRE2FILTER
static int wantdedup = 0;
#endif
2017-09-24 21:13:16 +02:00
2018-07-09 18:38:41 +02:00
// 0, direndpos, onionendpos
// printstartpos = either 0 or direndpos
// printlen = either onionendpos + 1 or ONION_LEN + 1 (additional 1 is for newline)
size_t onionendpos; // end of .onion within string
size_t direndpos; // end of dir before .onion within string
size_t printstartpos; // where to start printing from
size_t printlen; // precalculated, related to printstartpos
2017-09-24 21:13:16 +02:00
2018-07-09 18:38:41 +02:00
pthread_mutex_t fout_mutex;
FILE *fout;
#ifdef PASSPHRASE
u8 orig_determseed[SEED_LEN];
const char *checkpointfile = 0;
#endif
2017-09-25 19:49:47 +02:00
static void termhandler(int sig)
{
switch (sig) {
case SIGTERM:
case SIGINT:
endwork = 1;
break;
}
}
2017-09-24 21:13:16 +02:00
2017-10-22 02:40:23 +02:00
#ifdef STATISTICS
2017-09-30 05:40:12 +02:00
struct tstatstruct {
u64 numcalc;
u64 numsuccess;
u64 numrestart;
2017-09-30 05:40:12 +02:00
u32 oldnumcalc;
u32 oldnumsuccess;
u32 oldnumrestart;
2017-09-30 05:40:12 +02:00
} ;
VEC_STRUCT(tstatsvec,struct tstatstruct);
#endif
static void printhelp(FILE *out,const char *progname)
2017-09-24 21:13:16 +02:00
{
2022-05-05 17:36:36 +02:00
// 0 1 2 3 4 5 6 7
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
fprintf(out,
2022-05-05 17:36:36 +02:00
"Usage: %s FILTER [FILTER...] [OPTION]\n"
" %s -f FILTERFILE [OPTION]\n"
2017-09-24 21:13:16 +02:00
"Options:\n"
2022-05-05 17:36:36 +02:00
" -f FILTERFILE specify filter file which contains filters separated\n"
" by newlines\n"
" -D deduplicate filters\n"
" -q do not print diagnostic output to stderr\n"
" -x do not print onion names\n"
" -v print more diagnostic data\n"
" -o FILENAME output onion names to specified file (append)\n"
" -O FILENAME output onion names to specified file (overwrite)\n"
" -F include directory names in onion names output\n"
" -d DIRNAME output directory\n"
" -t NUMTHREADS specify number of threads to utilise\n"
" (default - try detecting CPU core count)\n"
" -j NUMTHREADS same as -t\n"
" -n NUMKEYS specify number of keys (default - 0 - unlimited)\n"
" -N NUMWORDS specify number of words per key (default - 1)\n"
2023-06-09 16:16:46 +02:00
" -Z deprecated, does nothing\n"
" -z deprecated, does nothing\n"
" -B use batching key generation method (current default)\n"
2022-05-05 17:36:36 +02:00
" -s print statistics each 10 seconds\n"
" -S SECONDS print statistics every specified amount of seconds\n"
" -T do not reset statistics counters when printing\n"
" -y output generated keys in YAML format instead of\n"
" dumping them to filesystem\n"
" -Y [FILENAME [host.onion]]\n"
" parse YAML encoded input and extract key(s) to\n"
" filesystem\n"
#ifdef PASSPHRASE
2022-05-05 17:36:36 +02:00
" -p PASSPHRASE use passphrase to initialize the random seed with\n"
" -P same as -p, but takes passphrase from PASSPHRASE\n"
" environment variable\n"
" --checkpoint filename\n"
" load/save checkpoint of progress to specified file\n"
" (requires passphrase)\n"
#endif
2022-05-05 17:36:36 +02:00
" --rawyaml raw (unprefixed) public/secret keys for -y/-Y\n"
" (may be useful for tor controller API)\n"
" -h, --help, --usage print help to stdout and quit\n"
" -V, --version print version information to stdout and exit\n"
2017-09-24 21:13:16 +02:00
,progname,progname);
fflush(out);
2017-09-24 21:13:16 +02:00
}
2022-05-05 17:36:36 +02:00
static void printversion(void)
{
fprintf(stdout,"mkp224o " VERSION "\n");
fflush(stdout);
}
static void e_additional(void)
2018-05-31 16:01:33 +02:00
{
fprintf(stderr,"additional argument required\n");
exit(1);
2018-05-31 16:01:33 +02:00
}
#ifndef STATISTICS
static void e_nostatistics(void)
2018-05-31 16:01:33 +02:00
{
fprintf(stderr,"statistics support not compiled in\n");
exit(1);
2018-05-31 16:01:33 +02:00
}
#endif
static void setworkdir(const char *wd)
2017-09-24 21:13:16 +02:00
{
free(workdir);
size_t l = strlen(wd);
if (!l) {
workdir = 0;
workdirlen = 0;
if (!quietflag)
2018-05-31 16:01:33 +02:00
fprintf(stderr,"unset workdir\n");
2017-09-24 21:13:16 +02:00
return;
}
2018-02-23 01:03:17 +01:00
unsigned needslash = 0;
2017-09-24 21:13:16 +02:00
if (wd[l-1] != '/')
needslash = 1;
2018-06-16 15:22:52 +02:00
char *s = (char *) malloc(l + needslash + 1);
2017-10-10 03:02:43 +02:00
if (!s)
abort();
2018-05-31 16:01:33 +02:00
memcpy(s,wd,l);
2017-09-24 21:13:16 +02:00
if (needslash)
s[l++] = '/';
s[l] = 0;
2017-09-24 21:13:16 +02:00
workdir = s;
workdirlen = l;
if (!quietflag)
2017-09-30 05:40:12 +02:00
fprintf(stderr,"set workdir: %s\n",workdir);
2017-09-24 21:13:16 +02:00
}
2019-02-16 17:50:26 +01:00
#ifdef PASSPHRASE
static void setpassphrase(const char *pass)
{
static u8 salt[crypto_pwhash_SALTBYTES] = {0};
fprintf(stderr,"expanding passphrase (may take a while)...");
if (crypto_pwhash(determseed,sizeof(determseed),
pass,strlen(pass),salt,
PWHASH_OPSLIMIT,PWHASH_MEMLIMIT,PWHASH_ALG) != 0)
{
fprintf(stderr," out of memory!\n");
exit(1);
}
fprintf(stderr," done.\n");
}
static void savecheckpoint(void)
{
2021-12-08 21:14:20 +01:00
u8 checkpoint[SEED_LEN];
bool carry = 0;
pthread_mutex_lock(&determseed_mutex);
for (int i = 0; i < SEED_LEN; i++) {
checkpoint[i] = determseed[i] - orig_determseed[i] - carry;
carry = checkpoint[i] > determseed[i];
}
pthread_mutex_unlock(&determseed_mutex);
2021-12-08 21:14:20 +01:00
if (syncwrite(checkpointfile,1,checkpoint,SEED_LEN) < 0) {
pthread_mutex_lock(&fout_mutex);
2022-12-19 17:30:24 +01:00
fprintf(stderr,"ERROR: could not save checkpoint to \"%s\"\n",checkpointfile);
2021-12-08 21:14:20 +01:00
pthread_mutex_unlock(&fout_mutex);
}
}
2021-12-08 21:14:20 +01:00
static volatile int checkpointer_endwork = 0;
static void *checkpointworker(void *arg)
{
(void) arg;
struct timespec ts;
memset(&ts,0,sizeof(ts));
ts.tv_nsec = 100000000;
struct timespec nowtime;
u64 ilasttime,inowtime;
clock_gettime(CLOCK_MONOTONIC,&nowtime);
ilasttime = (1000000 * (u64)nowtime.tv_sec) + ((u64)nowtime.tv_nsec / 1000);
while (!unlikely(checkpointer_endwork)) {
clock_gettime(CLOCK_MONOTONIC,&nowtime);
inowtime = (1000000 * (u64)nowtime.tv_sec) + ((u64)nowtime.tv_nsec / 1000);
2021-12-08 21:22:24 +01:00
if ((i64)(inowtime - ilasttime) >= 300 * 1000000 /* 5 minutes */) {
2021-12-08 21:14:20 +01:00
savecheckpoint();
ilasttime = inowtime;
}
}
2021-12-08 21:14:20 +01:00
savecheckpoint();
return 0;
}
2019-02-16 17:50:26 +01:00
#endif
2021-12-08 21:14:20 +01:00
VEC_STRUCT(threadvec,pthread_t);
2017-09-24 21:13:16 +02:00
#include "filters_inc.inc.h"
2019-03-16 20:57:29 +01:00
#include "filters_main.inc.h"
enum worker_type {
WT_BATCH,
};
2017-09-30 05:40:12 +02:00
int main(int argc,char **argv)
2017-09-24 21:13:16 +02:00
{
2018-05-31 18:14:35 +02:00
const char *outfile = 0;
2018-07-09 18:38:41 +02:00
const char *infile = 0;
2020-01-17 15:15:56 +01:00
const char *onehostname = 0;
2017-09-24 21:13:16 +02:00
const char *arg;
int ignoreargs = 0;
int dirnameflag = 0;
int numthreads = 0;
enum worker_type wt = WT_BATCH;
2018-07-09 18:38:41 +02:00
int yamlinput = 0;
#ifdef PASSPHRASE
int deterministic = 0;
#endif
2018-07-09 18:38:41 +02:00
int outfileoverwrite = 0;
2017-09-24 21:13:16 +02:00
struct threadvec threads;
2017-09-30 05:40:12 +02:00
#ifdef STATISTICS
struct statsvec stats;
struct tstatsvec tstats;
u64 reportdelay = 0;
2017-09-30 14:43:32 +02:00
int realtimestats = 1;
2017-09-30 05:46:17 +02:00
#endif
2017-09-24 21:13:16 +02:00
int tret;
2018-08-24 20:31:57 +02:00
if (sodium_init() < 0) {
fprintf(stderr,"sodium_init() failed\n");
return 1;
}
2019-03-16 20:57:29 +01:00
worker_init();
2017-09-24 21:13:16 +02:00
filters_init();
setvbuf(stderr,0,_IONBF,0);
2017-09-24 21:13:16 +02:00
fout = stdout;
const char *progname = argv[0];
2018-05-31 16:01:33 +02:00
if (argc <= 1) {
printhelp(stderr,progname);
2018-05-31 16:01:33 +02:00
exit(1);
}
argc--; argv++;
2017-09-24 21:13:16 +02:00
while (argc--) {
arg = *argv++;
if (!ignoreargs && *arg == '-') {
int numargit = 0;
nextarg:
++arg;
++numargit;
if (*arg == '-') {
if (numargit > 1) {
2018-05-31 16:01:33 +02:00
fprintf(stderr,"unrecognised argument: -\n");
exit(1);
2017-09-24 21:13:16 +02:00
}
++arg;
if (!*arg)
ignoreargs = 1;
2018-05-31 16:01:33 +02:00
else if (!strcmp(arg,"help") || !strcmp(arg,"usage")) {
printhelp(stdout,progname);
2018-05-31 16:01:33 +02:00
exit(0);
}
2022-05-05 17:36:36 +02:00
else if (!strcmp(arg,"version")) {
printversion();
exit(0);
}
2020-01-17 15:15:56 +01:00
else if (!strcmp(arg,"rawyaml"))
yamlraw = 1;
2021-11-06 00:27:14 +01:00
#ifdef PASSPHRASE
else if (!strcmp(arg,"checkpoint")) {
if (argc--)
checkpointfile = *argv++;
else
e_additional();
}
#endif // PASSPHRASE
2017-09-24 21:13:16 +02:00
else {
2018-05-31 16:01:33 +02:00
fprintf(stderr,"unrecognised argument: --%s\n",arg);
exit(1);
2017-09-24 21:13:16 +02:00
}
numargit = 0;
}
else if (*arg == 0) {
if (numargit == 1)
ignoreargs = 1;
continue;
}
2018-05-31 16:01:33 +02:00
else if (*arg == 'h') {
printhelp(stdout,progname);
2018-05-31 16:01:33 +02:00
exit(0);
}
2022-05-05 17:36:36 +02:00
else if (*arg == 'V') {
printversion();
exit(0);
}
2017-09-24 21:13:16 +02:00
else if (*arg == 'f') {
if (argc--) {
if (!loadfilterfile(*argv++))
exit(1);
}
2018-05-31 16:01:33 +02:00
else
e_additional();
2017-09-24 21:13:16 +02:00
}
else if (*arg == 'D') {
#ifndef PCRE2FILTER
wantdedup = 1;
#else
fprintf(stderr,"WARNING: deduplication isn't supported with regex filters\n");
#endif
}
2017-09-24 21:13:16 +02:00
else if (*arg == 'q')
++quietflag;
else if (*arg == 'x')
fout = 0;
else if (*arg == 'v')
verboseflag = 1;
2017-09-24 21:13:16 +02:00
else if (*arg == 'o') {
outfileoverwrite = 0;
2017-09-24 21:13:16 +02:00
if (argc--)
outfile = *argv++;
2018-05-31 16:01:33 +02:00
else
e_additional();
2017-09-24 21:13:16 +02:00
}
else if (*arg == 'O') {
outfileoverwrite = 1;
2017-09-24 21:13:16 +02:00
if (argc--)
outfile = *argv++;
2018-05-31 16:01:33 +02:00
else
e_additional();
2017-09-24 21:13:16 +02:00
}
else if (*arg == 'F')
dirnameflag = 1;
else if (*arg == 'd') {
2018-05-31 16:01:33 +02:00
if (argc--)
2017-09-24 21:13:16 +02:00
setworkdir(*argv++);
2018-05-31 16:01:33 +02:00
else
e_additional();
2017-09-24 21:13:16 +02:00
}
2017-09-30 05:40:12 +02:00
else if (*arg == 't' || *arg == 'j') {
2017-09-24 21:13:16 +02:00
if (argc--)
numthreads = atoi(*argv++);
2018-05-31 16:01:33 +02:00
else
e_additional();
2017-09-24 21:13:16 +02:00
}
2017-09-25 19:49:47 +02:00
else if (*arg == 'n') {
if (argc--)
numneedgenerate = (size_t)atoll(*argv++);
2018-05-31 16:01:33 +02:00
else
e_additional();
2017-09-25 19:49:47 +02:00
}
2017-10-22 07:07:45 +02:00
else if (*arg == 'N') {
if (argc--)
numwords = atoi(*argv++);
2018-05-31 16:01:33 +02:00
else
e_additional();
2017-10-22 07:07:45 +02:00
}
2017-09-30 14:43:32 +02:00
else if (*arg == 'Z')
2023-06-09 16:16:46 +02:00
/* ignored */ ;
2017-09-24 21:13:16 +02:00
else if (*arg == 'z')
2023-06-09 16:16:46 +02:00
/* ignored */ ;
2019-01-19 17:44:35 +01:00
else if (*arg == 'B')
wt = WT_BATCH;
2017-09-30 05:40:12 +02:00
else if (*arg == 's') {
#ifdef STATISTICS
reportdelay = 10000000;
#else
2018-05-31 16:01:33 +02:00
e_nostatistics();
2017-09-30 05:40:12 +02:00
#endif
}
else if (*arg == 'S') {
#ifdef STATISTICS
if (argc--)
reportdelay = (u64)atoll(*argv++) * 1000000;
2018-05-31 16:01:33 +02:00
else
e_additional();
2017-09-30 05:40:12 +02:00
#else
2018-05-31 16:01:33 +02:00
e_nostatistics();
2017-09-30 05:40:12 +02:00
#endif
}
2017-09-30 14:43:32 +02:00
else if (*arg == 'T') {
2017-09-30 05:46:17 +02:00
#ifdef STATISTICS
2017-09-30 14:43:32 +02:00
realtimestats = 0;
2017-09-30 05:46:17 +02:00
#else
2018-05-31 16:01:33 +02:00
e_nostatistics();
2017-09-30 05:46:17 +02:00
#endif
}
else if (*arg == 'y')
yamloutput = 1;
else if (*arg == 'Y') {
2018-07-09 18:38:41 +02:00
yamlinput = 1;
if (argc) {
--argc;
infile = *argv++;
if (!*infile)
infile = 0;
if (argc) {
--argc;
2020-01-17 15:15:56 +01:00
onehostname = *argv++;
if (!*onehostname)
onehostname = 0;
if (onehostname && strlen(onehostname) != ONION_LEN) {
2018-07-09 18:38:41 +02:00
fprintf(stderr,"bad onion argument length\n");
exit(1);
2018-07-09 18:38:41 +02:00
}
}
}
2019-02-16 17:50:26 +01:00
}
#ifdef PASSPHRASE
2019-02-16 17:50:26 +01:00
else if (*arg == 'p') {
if (argc--) {
2019-02-16 17:50:26 +01:00
setpassphrase(*argv++);
2019-02-14 00:54:00 +01:00
deterministic = 1;
2019-02-16 17:50:26 +01:00
}
else
e_additional();
}
2019-02-16 17:50:26 +01:00
else if (*arg == 'P') {
const char *pass = getenv("PASSPHRASE");
if (!pass) {
fprintf(stderr,"store passphrase in PASSPHRASE environment variable\n");
exit(1);
}
setpassphrase(pass);
deterministic = 1;
}
#endif // PASSPHRASE
2017-09-24 21:13:16 +02:00
else {
2018-05-31 16:01:33 +02:00
fprintf(stderr,"unrecognised argument: -%c\n",*arg);
exit(1);
2017-09-24 21:13:16 +02:00
}
if (numargit)
goto nextarg;
}
2018-05-31 18:14:35 +02:00
else
filters_add(arg);
}
2020-01-17 15:15:56 +01:00
if (yamlinput && yamloutput) {
fprintf(stderr,"both -y and -Y does not make sense\n");
exit(1);
}
if (yamlraw && !yamlinput && !yamloutput) {
fprintf(stderr,"--rawyaml requires either -y or -Y to do anything\n");
exit(1);
}
2022-03-15 02:39:18 +01:00
#ifdef PASSPHRASE
2021-12-08 21:14:20 +01:00
if (checkpointfile && !deterministic) {
fprintf(stderr,"--checkpoint requires passphrase\n");
exit(1);
}
2022-03-15 02:39:18 +01:00
#endif
2021-12-08 21:14:20 +01:00
2018-05-31 18:14:35 +02:00
if (outfile) {
fout = fopen(outfile,!outfileoverwrite ? "a" : "w");
2018-05-31 18:14:35 +02:00
if (!fout) {
perror("failed to open output file");
exit(1);
2018-05-31 18:14:35 +02:00
}
2017-09-24 21:13:16 +02:00
}
2017-09-25 19:49:47 +02:00
2018-07-09 18:38:41 +02:00
if (!fout && yamloutput) {
fprintf(stderr,"nil output with yaml mode does not make sense\n");
exit(1);
2018-07-09 18:38:41 +02:00
}
2017-09-24 21:13:16 +02:00
if (workdir)
createdir(workdir,1);
2017-09-25 19:49:47 +02:00
2017-09-24 21:13:16 +02:00
direndpos = workdirlen;
onionendpos = workdirlen + ONION_LEN;
2017-09-25 19:49:47 +02:00
2017-09-24 21:13:16 +02:00
if (!dirnameflag) {
printstartpos = direndpos;
2018-07-09 18:38:41 +02:00
printlen = ONION_LEN + 1; // + '\n'
2017-09-24 21:13:16 +02:00
} else {
printstartpos = 0;
2018-07-09 18:38:41 +02:00
printlen = onionendpos + 1; // + '\n'
2017-09-24 21:13:16 +02:00
}
2017-09-25 19:49:47 +02:00
2018-07-09 18:38:41 +02:00
if (yamlinput) {
char *sname = makesname();
FILE *fin = stdin;
if (infile) {
fin = fopen(infile,"r");
if (!fin) {
fprintf(stderr,"failed to open input file\n");
return 1;
2018-07-09 18:38:41 +02:00
}
}
2020-01-17 15:15:56 +01:00
tret = yamlin_parseandcreate(fin,sname,onehostname,yamlraw);
2018-07-09 18:38:41 +02:00
if (infile) {
fclose(fin);
fin = 0;
}
free(sname);
if (tret)
return tret;
goto done;
}
filters_prepare();
filters_print();
2017-09-24 21:13:16 +02:00
#ifdef STATISTICS
if (!filters_count() && !reportdelay)
#else
2017-09-25 22:57:27 +02:00
if (!filters_count())
#endif
2017-09-25 22:57:27 +02:00
return 0;
2017-12-14 16:22:45 +01:00
#ifdef EXPANDMASK
if (numwords > 1 && flattened)
fprintf(stderr,"WARNING: -N switch will produce bogus results because we can't know filter width. reconfigure with --enable-besort and recompile.\n");
#endif
2018-07-09 18:38:41 +02:00
if (yamloutput)
yamlout_init();
2017-09-25 19:49:47 +02:00
2018-07-09 18:38:41 +02:00
pthread_mutex_init(&keysgenerated_mutex,0);
pthread_mutex_init(&fout_mutex,0);
#ifdef PASSPHRASE
pthread_mutex_init(&determseed_mutex,0);
#endif
2017-09-25 19:49:47 +02:00
2017-09-24 21:13:16 +02:00
if (numthreads <= 0) {
2017-10-06 02:14:33 +02:00
numthreads = cpucount();
if (numthreads <= 0)
numthreads = 1;
2017-09-24 21:13:16 +02:00
}
if (!quietflag)
fprintf(stderr,"using %d %s\n",
numthreads,numthreads == 1 ? "thread" : "threads");
2017-09-25 19:49:47 +02:00
2019-02-16 17:50:26 +01:00
#ifdef PASSPHRASE
if (deterministic) {
if (!quietflag && numneedgenerate != 1)
fprintf(stderr,"CAUTION: avoid using keys generated with same password for unrelated services, as single leaked key may help attacker to regenerate related keys.\n");
if (checkpointfile) {
2021-12-08 21:24:55 +01:00
memcpy(orig_determseed,determseed,sizeof(determseed));
// Read current checkpoint position if file exists
2021-12-08 21:14:20 +01:00
FILE *checkout = fopen(checkpointfile,"r");
if (checkout) {
u8 checkpoint[SEED_LEN];
2021-12-08 21:14:20 +01:00
if(fread(checkpoint,1,SEED_LEN,checkout) != SEED_LEN) {
fprintf(stderr,"failed to read checkpoint file\n");
exit(1);
}
fclose(checkout);
// Apply checkpoint to determseed
bool carry = 0;
for (int i = 0; i < SEED_LEN; i++) {
determseed[i] += checkpoint[i] + carry;
carry = determseed[i] < checkpoint[i];
}
}
}
}
2019-02-16 17:50:26 +01:00
#endif
2017-09-30 05:40:12 +02:00
signal(SIGTERM,termhandler);
signal(SIGINT,termhandler);
2017-09-25 19:49:47 +02:00
2017-09-24 21:13:16 +02:00
VEC_INIT(threads);
VEC_ADDN(threads,numthreads);
2017-09-30 05:40:12 +02:00
#ifdef STATISTICS
VEC_INIT(stats);
VEC_ADDN(stats,numthreads);
VEC_ZERO(stats);
2017-09-30 05:40:12 +02:00
VEC_INIT(tstats);
VEC_ADDN(tstats,numthreads);
VEC_ZERO(tstats);
2017-09-30 05:40:12 +02:00
#endif
2017-09-25 19:49:47 +02:00
2018-06-01 15:48:01 +02:00
pthread_attr_t tattr,*tattrp = &tattr;
tret = pthread_attr_init(tattrp);
if (tret) {
perror("pthread_attr_init");
tattrp = 0;
}
else {
2020-11-22 14:13:50 +01:00
// 256KiB plus whatever batch stuff uses if in batch mode
size_t ss = 256 << 10;
if (wt == WT_BATCH)
ss += worker_batch_memuse();
// align to 64KiB
ss = (ss + (64 << 10) - 1) & ~((64 << 10) - 1);
//printf("stack size: " FSZ "\n",ss);
tret = pthread_attr_setstacksize(tattrp,ss);
2018-06-01 15:48:01 +02:00
if (tret)
perror("pthread_attr_setstacksize");
}
2017-09-30 05:40:12 +02:00
for (size_t i = 0;i < VEC_LENGTH(threads);++i) {
void *tp = 0;
#ifdef STATISTICS
tp = &VEC_BUF(stats,i);
#endif
tret = pthread_create(
&VEC_BUF(threads,i),
tattrp,
#ifdef PASSPHRASE
deterministic
2023-06-09 16:16:46 +02:00
? CRYPTO_NAMESPACE(worker_batch_pass)
:
2019-01-19 17:44:35 +01:00
#endif
2023-06-09 16:16:46 +02:00
CRYPTO_NAMESPACE(worker_batch),
tp
);
2017-09-24 21:13:16 +02:00
if (tret) {
2018-06-01 15:48:01 +02:00
fprintf(stderr,"error while making " FSZ "th thread: %s\n",i,strerror(tret));
exit(1);
2017-09-24 21:13:16 +02:00
}
}
2017-09-25 19:49:47 +02:00
2018-06-01 15:48:01 +02:00
if (tattrp) {
tret = pthread_attr_destroy(tattrp);
if (tret)
perror("pthread_attr_destroy");
}
2022-03-15 02:39:18 +01:00
#ifdef PASSPHRASE
2021-12-08 21:14:20 +01:00
pthread_t checkpoint_thread;
if (checkpointfile) {
tret = pthread_create(&checkpoint_thread,NULL,checkpointworker,NULL);
if (tret) {
fprintf(stderr,"error while making checkpoint thread: %s\n",strerror(tret));
exit(1);
}
}
#endif
2017-09-30 05:40:12 +02:00
#ifdef STATISTICS
struct timespec nowtime;
u64 istarttime,inowtime,ireporttime = 0,elapsedoffset = 0;
if (clock_gettime(CLOCK_MONOTONIC,&nowtime) < 0) {
2018-05-31 16:01:33 +02:00
perror("failed to get time");
exit(1);
2017-09-30 05:40:12 +02:00
}
2018-02-23 01:03:17 +01:00
istarttime = (1000000 * (u64)nowtime.tv_sec) + ((u64)nowtime.tv_nsec / 1000);
2017-09-30 05:40:12 +02:00
#endif
2021-12-08 21:14:20 +01:00
2017-09-25 19:49:47 +02:00
struct timespec ts;
memset(&ts,0,sizeof(ts));
ts.tv_nsec = 100000000;
while (!endwork) {
if (numneedgenerate && keysgenerated >= numneedgenerate) {
endwork = 1;
break;
}
nanosleep(&ts,0);
2017-09-30 05:40:12 +02:00
#ifdef STATISTICS
clock_gettime(CLOCK_MONOTONIC,&nowtime);
2018-02-23 01:03:17 +01:00
inowtime = (1000000 * (u64)nowtime.tv_sec) + ((u64)nowtime.tv_nsec / 1000);
u64 sumcalc = 0,sumsuccess = 0,sumrestart = 0;
for (int i = 0;i < numthreads;++i) {
2017-09-30 05:40:12 +02:00
u32 newt,tdiff;
// numcalc
2017-10-06 02:25:51 +02:00
newt = VEC_BUF(stats,i).numcalc.v;
2017-09-30 05:40:12 +02:00
tdiff = newt - VEC_BUF(tstats,i).oldnumcalc;
VEC_BUF(tstats,i).oldnumcalc = newt;
VEC_BUF(tstats,i).numcalc += (u64)tdiff;
sumcalc += VEC_BUF(tstats,i).numcalc;
// numsuccess
2017-10-06 02:25:51 +02:00
newt = VEC_BUF(stats,i).numsuccess.v;
2017-09-30 05:40:12 +02:00
tdiff = newt - VEC_BUF(tstats,i).oldnumsuccess;
VEC_BUF(tstats,i).oldnumsuccess = newt;
VEC_BUF(tstats,i).numsuccess += (u64)tdiff;
sumsuccess += VEC_BUF(tstats,i).numsuccess;
// numrestart
newt = VEC_BUF(stats,i).numrestart.v;
tdiff = newt - VEC_BUF(tstats,i).oldnumrestart;
VEC_BUF(tstats,i).oldnumrestart = newt;
VEC_BUF(tstats,i).numrestart += (u64)tdiff;
sumrestart += VEC_BUF(tstats,i).numrestart;
2017-09-30 05:40:12 +02:00
}
2021-12-08 21:22:24 +01:00
if (reportdelay && (!ireporttime || (i64)(inowtime - ireporttime) >= (i64)reportdelay)) {
2017-09-30 05:40:12 +02:00
if (ireporttime)
ireporttime += reportdelay;
else
ireporttime = inowtime;
if (!ireporttime)
ireporttime = 1;
double calcpersec = (1000000.0 * sumcalc) / (inowtime - istarttime);
double succpersec = (1000000.0 * sumsuccess) / (inowtime - istarttime);
double restpersec = (1000000.0 * sumrestart) / (inowtime - istarttime);
fprintf(stderr,">calc/sec:%8lf, succ/sec:%8lf, rest/sec:%8lf, elapsed:%5.6lfsec\n",
calcpersec,succpersec,restpersec,
(inowtime - istarttime + elapsedoffset) / 1000000.0);
2017-09-30 05:40:12 +02:00
if (realtimestats) {
for (int i = 0;i < numthreads;++i) {
2017-09-30 05:40:12 +02:00
VEC_BUF(tstats,i).numcalc = 0;
VEC_BUF(tstats,i).numsuccess = 0;
VEC_BUF(tstats,i).numrestart = 0;
2017-09-30 05:40:12 +02:00
}
elapsedoffset += inowtime - istarttime;
istarttime = inowtime;
}
}
if (sumcalc > U64_MAX / 2) {
for (int i = 0;i < numthreads;++i) {
2017-09-30 05:40:12 +02:00
VEC_BUF(tstats,i).numcalc /= 2;
VEC_BUF(tstats,i).numsuccess /= 2;
VEC_BUF(tstats,i).numrestart /= 2;
2017-09-30 05:40:12 +02:00
}
u64 timediff = (inowtime - istarttime + 1) / 2;
elapsedoffset += timediff;
istarttime += timediff;
}
#endif
2017-09-25 19:49:47 +02:00
}
2017-09-30 05:40:12 +02:00
if (!quietflag)
2018-05-31 16:01:33 +02:00
fprintf(stderr,"waiting for threads to finish...");
2021-12-08 21:14:20 +01:00
2017-09-30 05:40:12 +02:00
for (size_t i = 0;i < VEC_LENGTH(threads);++i)
pthread_join(VEC_BUF(threads,i),0);
2021-12-08 21:14:20 +01:00
#ifdef PASSPHRASE
if (checkpointfile) {
checkpointer_endwork = 1;
pthread_join(checkpoint_thread,0);
}
#endif
2017-09-30 05:40:12 +02:00
if (!quietflag)
2018-05-31 16:01:33 +02:00
fprintf(stderr," done.\n");
2017-09-24 21:13:16 +02:00
2018-07-09 18:38:41 +02:00
if (yamloutput)
yamlout_clean();
2019-01-18 20:07:54 +01:00
#ifdef PASSPHRASE
pthread_mutex_destroy(&determseed_mutex);
2019-01-18 20:07:54 +01:00
#endif
pthread_mutex_destroy(&fout_mutex);
pthread_mutex_destroy(&keysgenerated_mutex);
2018-07-09 18:38:41 +02:00
done:
2017-09-24 21:13:16 +02:00
filters_clean();
2017-09-25 19:49:47 +02:00
if (outfile)
fclose(fout);
2017-09-24 21:13:16 +02:00
return 0;
}