make checkpoint stuff actually proper

This commit is contained in:
cathugger 2021-12-08 20:14:20 +00:00
parent f575bbe011
commit 5b4074a47e
No known key found for this signature in database
GPG key ID: 9BADDA2DAF6F01A8
3 changed files with 225 additions and 40 deletions

114
main.c
View file

@ -29,6 +29,8 @@
#include "worker.h"
#include "likely.h"
#ifndef _WIN32
#define FSZ "%zu"
#else
@ -182,35 +184,55 @@ static void setpassphrase(const char *pass)
static void savecheckpoint(void)
{
if (checkpointfile) {
// Open checkpoint file
FILE *checkout = fopen(checkpointfile, "w");
if (!checkout) {
fprintf(stderr,"cannot open checkpoint file for writing\n");
exit(1);
}
// Calculate checkpoint as the difference between original seed and the current seed
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);
// Write checkpoint file
if(fwrite(checkpoint, 1, SEED_LEN, checkout) != SEED_LEN) {
fprintf(stderr,"cannot write to checkpoint file\n");
exit(1);
}
fclose(checkout);
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);
if (syncwrite(checkpointfile,1,checkpoint,SEED_LEN) < 0) {
pthread_mutex_lock(&fout_mutex);
fprintf(stderr,"ERROR: could not save checkpoint\n");
pthread_mutex_unlock(&fout_mutex);
}
}
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);
if (inowtime - ilasttime >= 300 * 1000000 /* 5 minutes */) {
savecheckpoint();
ilasttime = inowtime;
}
}
savecheckpoint();
return 0;
}
#endif
VEC_STRUCT(threadvec, pthread_t);
VEC_STRUCT(threadvec,pthread_t);
#include "filters_inc.inc.h"
#include "filters_main.inc.h"
@ -458,6 +480,11 @@ int main(int argc,char **argv)
exit(1);
}
if (checkpointfile && !deterministic) {
fprintf(stderr,"--checkpoint requires passphrase\n");
exit(1);
}
if (outfile) {
fout = fopen(outfile,!outfileoverwrite ? "a" : "w");
if (!fout) {
@ -543,16 +570,16 @@ int main(int argc,char **argv)
numthreads,numthreads == 1 ? "thread" : "threads");
#ifdef PASSPHRASE
memcpy(orig_determseed, determseed, sizeof(determseed));
if (deterministic) {
memcpy(orig_determseed,determseed,sizeof(determseed));
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) {
// Read current checkpoint position if file exists
FILE *checkout = fopen(checkpointfile, "r");
FILE *checkout = fopen(checkpointfile,"r");
if (checkout) {
u8 checkpoint[SEED_LEN];
if(fread(checkpoint, 1, SEED_LEN, checkout) != SEED_LEN) {
if(fread(checkpoint,1,SEED_LEN,checkout) != SEED_LEN) {
fprintf(stderr,"failed to read checkpoint file\n");
exit(1);
}
@ -634,6 +661,18 @@ int main(int argc,char **argv)
perror("pthread_attr_destroy");
}
#if PASSPHRASE
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
#ifdef STATISTICS
struct timespec nowtime;
u64 istarttime,inowtime,ireporttime = 0,elapsedoffset = 0;
@ -643,20 +682,15 @@ int main(int argc,char **argv)
}
istarttime = (1000000 * (u64)nowtime.tv_sec) + ((u64)nowtime.tv_nsec / 1000);
#endif
struct timespec ts;
memset(&ts,0,sizeof(ts));
ts.tv_nsec = 100000000;
u16 loopcounter = 0;
while (!endwork) {
if (numneedgenerate && keysgenerated >= numneedgenerate) {
endwork = 1;
break;
}
loopcounter++;
if (loopcounter >= 3000) { // Save checkpoint every 5 minutes
savecheckpoint();
loopcounter = 0;
}
nanosleep(&ts,0);
#ifdef STATISTICS
@ -722,14 +756,18 @@ int main(int argc,char **argv)
#endif
}
#ifdef PASSPHRASE
savecheckpoint();
#endif
if (!quietflag)
fprintf(stderr,"waiting for threads to finish...");
for (size_t i = 0;i < VEC_LENGTH(threads);++i)
pthread_join(VEC_BUF(threads,i),0);
#ifdef PASSPHRASE
if (checkpointfile) {
checkpointer_endwork = 1;
pthread_join(checkpoint_thread,0);
}
#endif
if (!quietflag)
fprintf(stderr," done.\n");