Browse Source

Add "-s" option for external RNG seed.

Use a read-mostly optimized lock to synchronize access to patterns.
Bump version to 0.11
master
samr7 14 years ago
parent
commit
dddc627798
  1. 7
      CHANGELOG
  2. 258
      vanitygen.c

7
CHANGELOG

@ -41,3 +41,10 @@ Version 0.9, released July 10 2011:
- Add flag to retain patterns after being matched - Add flag to retain patterns after being matched
- Add output/result file option - Add output/result file option
- Add quiet option and clean up status bar display - Add quiet option and clean up status bar display
Version 0.10, released July 12 2011:
- Improve performance using modular inverse optimization
Version 0.11, released July 12 2011:
- Add new thread synchronization lock
- Add seed file option for RNG

258
vanitygen.c

@ -28,6 +28,7 @@
#include <openssl/ec.h> #include <openssl/ec.h>
#include <openssl/obj_mac.h> #include <openssl/obj_mac.h>
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/rand.h>
#include <pcre.h> #include <pcre.h>
@ -36,11 +37,12 @@
#include <sys/time.h> #include <sys/time.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h>
#else #else
#include "winglue.c" #include "winglue.c"
#endif #endif
const char *version = "0.10"; const char *version = "0.11";
const int debug = 0; const int debug = 0;
int verbose = 1; int verbose = 1;
int remove_on_match = 1; int remove_on_match = 1;
@ -169,11 +171,16 @@ typedef struct _vg_thread_context_s {
EC_KEY *vct_key; EC_KEY *vct_key;
EC_POINT *vct_point; EC_POINT *vct_point;
int vct_delta; int vct_delta;
int vct_flags;
unsigned char vct_binres[25]; unsigned char vct_binres[25];
BIGNUM vct_bntarg; BIGNUM vct_bntarg;
BIGNUM vct_bnbase; BIGNUM vct_bnbase;
BIGNUM vct_bntmp; BIGNUM vct_bntmp;
BIGNUM vct_bntmp2; BIGNUM vct_bntmp2;
struct _vg_thread_context_s *vct_next;
int vct_mode;
int vct_stop;
} vg_thread_context_t; } vg_thread_context_t;
@ -395,6 +402,157 @@ output_match(EC_KEY *pkey, const char *pattern, vg_context_t *vcp)
} }
/*
* To synchronize pattern lists, we use a special shared-exclusive lock
* geared toward being held in shared mode 99.9% of the time.
*/
static pthread_mutex_t vg_thread_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t vg_thread_rdcond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t vg_thread_wrcond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t vg_thread_upcond = PTHREAD_COND_INITIALIZER;
static vg_thread_context_t *vg_threads = NULL;
static int vg_thread_excl = 0;
void
__vg_thread_yield(vg_thread_context_t *vctp)
{
vctp->vct_mode = 0;
while (vg_thread_excl) {
if (vctp->vct_stop) {
assert(vg_thread_excl);
vctp->vct_stop = 0;
pthread_cond_signal(&vg_thread_upcond);
}
pthread_cond_wait(&vg_thread_rdcond, &vg_thread_lock);
}
assert(!vctp->vct_stop);
assert(!vctp->vct_mode);
vctp->vct_mode = 1;
}
void
vg_thread_downgrade_lock(vg_thread_context_t *vctp)
{
pthread_mutex_lock(&vg_thread_lock);
assert(vctp->vct_mode == 2);
assert(!vctp->vct_stop);
if (!--vg_thread_excl) {
vctp->vct_mode = 1;
pthread_cond_broadcast(&vg_thread_rdcond);
pthread_mutex_unlock(&vg_thread_lock);
return;
}
pthread_cond_signal(&vg_thread_wrcond);
__vg_thread_yield(vctp);
pthread_mutex_unlock(&vg_thread_lock);
}
void
vg_thread_init_lock(vg_thread_context_t *vctp)
{
vctp->vct_mode = 0;
vctp->vct_stop = 0;
pthread_mutex_lock(&vg_thread_lock);
vctp->vct_next = vg_threads;
vg_threads = vctp;
__vg_thread_yield(vctp);
pthread_mutex_unlock(&vg_thread_lock);
}
void
vg_thread_del_lock(vg_thread_context_t *vctp)
{
vg_thread_context_t *tp, **pprev;
if (vctp->vct_mode == 2)
vg_thread_downgrade_lock(vctp);
pthread_mutex_lock(&vg_thread_lock);
assert(vctp->vct_mode == 1);
vctp->vct_mode = 0;
for (pprev = &vg_threads, tp = *pprev;
(tp != vctp) && (tp != NULL);
pprev = &tp->vct_next, tp = *pprev);
assert(tp == vctp);
*pprev = tp->vct_next;
if (tp->vct_stop)
pthread_cond_signal(&vg_thread_upcond);
pthread_mutex_unlock(&vg_thread_lock);
}
int
vg_thread_upgrade_lock(vg_thread_context_t *vctp)
{
vg_thread_context_t *tp;
if (vctp->vct_mode == 2)
return 0;
pthread_mutex_lock(&vg_thread_lock);
assert(vctp->vct_mode == 1);
vctp->vct_mode = 0;
if (vg_thread_excl++) {
assert(vctp->vct_stop);
vctp->vct_stop = 0;
pthread_cond_signal(&vg_thread_upcond);
pthread_cond_wait(&vg_thread_wrcond, &vg_thread_lock);
for (tp = vg_threads; tp != NULL; tp = tp->vct_next) {
assert(!tp->vct_mode);
assert(!tp->vct_stop);
}
} else {
for (tp = vg_threads; tp != NULL; tp = tp->vct_next) {
if (tp->vct_mode) {
assert(tp->vct_mode != 2);
tp->vct_stop = 1;
}
}
do {
for (tp = vg_threads; tp != NULL; tp = tp->vct_next) {
if (tp->vct_mode) {
assert(tp->vct_mode != 2);
pthread_cond_wait(&vg_thread_upcond,
&vg_thread_lock);
break;
}
}
} while (tp);
}
vctp->vct_mode = 2;
pthread_mutex_unlock(&vg_thread_lock);
return 1;
}
void
vg_thread_yield(vg_thread_context_t *vctp)
{
if (vctp->vct_mode == 2)
vg_thread_downgrade_lock(vctp);
else if (vctp->vct_stop) {
assert(vctp->vct_mode == 1);
pthread_mutex_lock(&vg_thread_lock);
__vg_thread_yield(vctp);
pthread_mutex_unlock(&vg_thread_lock);
}
assert(vctp->vct_mode == 1);
}
/* /*
* Address search thread main loop * Address search thread main loop
*/ */
@ -407,6 +565,7 @@ vg_thread_loop(vg_context_t *vcp)
int i, c, len; int i, c, len;
const BN_ULONG rekey_max = 10000000;
BN_ULONG npoints, rekey_at, nbatch; BN_ULONG npoints, rekey_at, nbatch;
EC_KEY *pkey = NULL; EC_KEY *pkey = NULL;
@ -415,12 +574,11 @@ vg_thread_loop(vg_context_t *vcp)
const int ptarraysize = 256; const int ptarraysize = 256;
EC_POINT *ppnt[ptarraysize]; EC_POINT *ppnt[ptarraysize];
vg_thread_context_t ctx;
vg_test_func_t test_func = vcp->vc_test; vg_test_func_t test_func = vcp->vc_test;
vg_thread_context_t ctx;
struct timeval tvstart; struct timeval tvstart;
static pthread_mutex_t crypto_mutex = PTHREAD_MUTEX_INITIALIZER;
memset(ctx.vct_binres, 0, sizeof(ctx.vct_binres)); memset(ctx.vct_binres, 0, sizeof(ctx.vct_binres));
@ -432,7 +590,7 @@ vg_thread_loop(vg_context_t *vcp)
BN_set_word(&ctx.vct_bnbase, 58); BN_set_word(&ctx.vct_bnbase, 58);
pthread_mutex_lock(&crypto_mutex); pthread_mutex_lock(&vg_thread_lock);
pkey = EC_KEY_new_by_curve_name(NID_secp256k1); pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
assert(pkey); assert(pkey);
pgroup = EC_KEY_get0_group(pkey); pgroup = EC_KEY_get0_group(pkey);
@ -441,7 +599,8 @@ vg_thread_loop(vg_context_t *vcp)
assert(pgen); assert(pgen);
EC_KEY_precompute_mult(pkey, ctx.vct_bnctx); EC_KEY_precompute_mult(pkey, ctx.vct_bnctx);
pthread_mutex_unlock(&crypto_mutex);
pthread_mutex_unlock(&vg_thread_lock);
for (i = 0; i < ptarraysize; i++) { for (i = 0; i < ptarraysize; i++) {
ppnt[i] = EC_POINT_new(pgroup); ppnt[i] = EC_POINT_new(pgroup);
@ -451,16 +610,20 @@ vg_thread_loop(vg_context_t *vcp)
} }
} }
vg_thread_init_lock(&ctx);
npoints = 0; npoints = 0;
rekey_at = 0; rekey_at = 0;
nbatch = 0; nbatch = 0;
ctx.vct_flags = 0;
ctx.vct_key = pkey; ctx.vct_key = pkey;
ctx.vct_binres[0] = vcp->vc_addrtype; ctx.vct_binres[0] = vcp->vc_addrtype;
c = 0; c = 0;
gettimeofday(&tvstart, NULL); gettimeofday(&tvstart, NULL);
while (1) { while (1) {
if (npoints >= rekey_at) { if (++npoints >= rekey_at) {
pthread_mutex_lock(&crypto_mutex); pthread_mutex_lock(&vg_thread_lock);
/* Generate a new random private key */ /* Generate a new random private key */
EC_KEY_generate_key(pkey); EC_KEY_generate_key(pkey);
npoints = 0; npoints = 0;
@ -472,12 +635,12 @@ vg_thread_loop(vg_context_t *vcp)
&ctx.vct_bntmp, &ctx.vct_bntmp,
EC_KEY_get0_private_key(pkey)); EC_KEY_get0_private_key(pkey));
rekey_at = BN_get_word(&ctx.vct_bntmp2); rekey_at = BN_get_word(&ctx.vct_bntmp2);
if ((rekey_at == BN_MASK2) || (rekey_at > 1000000)) if ((rekey_at == BN_MASK2) || (rekey_at > rekey_max))
rekey_at = 1000000; rekey_at = rekey_max;
assert(rekey_at > 0); assert(rekey_at > 0);
EC_POINT_copy(ppnt[0], EC_KEY_get0_public_key(pkey)); EC_POINT_copy(ppnt[0], EC_KEY_get0_public_key(pkey));
pthread_mutex_unlock(&crypto_mutex); pthread_mutex_unlock(&vg_thread_lock);
npoints++; npoints++;
ctx.vct_delta = 0; ctx.vct_delta = 0;
@ -488,7 +651,6 @@ vg_thread_loop(vg_context_t *vcp)
ppnt[0], ppnt[0],
ppnt[nbatch-1], ppnt[nbatch-1],
pgen, ctx.vct_bnctx); pgen, ctx.vct_bnctx);
npoints++;
} }
/* /*
@ -541,9 +703,13 @@ vg_thread_loop(vg_context_t *vcp)
output_timing(c, &tvstart, vcp); output_timing(c, &tvstart, vcp);
c = 0; c = 0;
} }
vg_thread_yield(&ctx);
} }
out: out:
vg_thread_del_lock(&ctx);
BN_clear_free(&ctx.vct_bntarg); BN_clear_free(&ctx.vct_bntarg);
BN_clear_free(&ctx.vct_bnbase); BN_clear_free(&ctx.vct_bnbase);
BN_clear_free(&ctx.vct_bntmp); BN_clear_free(&ctx.vct_bntmp);
@ -1468,7 +1634,6 @@ typedef struct _vg_prefix_context_s {
vg_context_t base; vg_context_t base;
avl_root_t vcp_avlroot; avl_root_t vcp_avlroot;
BIGNUM vcp_difficulty; BIGNUM vcp_difficulty;
pthread_mutex_t vcp_lock;
} vg_prefix_context_t; } vg_prefix_context_t;
void void
@ -1486,7 +1651,6 @@ vg_prefix_context_free(vg_prefix_context_t *vcpp)
assert(npfx_left == vcpp->base.vc_npatterns); assert(npfx_left == vcpp->base.vc_npatterns);
BN_clear_free(&vcpp->vcp_difficulty); BN_clear_free(&vcpp->vcp_difficulty);
pthread_mutex_destroy(&vcpp->vcp_lock);
free(vcpp); free(vcpp);
} }
@ -1649,9 +1813,12 @@ vg_prefix_test(vg_context_t *vcp, vg_thread_context_t *vctp)
BN_bin2bn(vctp->vct_binres, sizeof(vctp->vct_binres), BN_bin2bn(vctp->vct_binres, sizeof(vctp->vct_binres),
&vctp->vct_bntarg); &vctp->vct_bntarg);
pthread_mutex_lock(&vcpp->vcp_lock); retry:
vp = vg_prefix_avl_search(&vcpp->vcp_avlroot, &vctp->vct_bntarg); vp = vg_prefix_avl_search(&vcpp->vcp_avlroot, &vctp->vct_bntarg);
if (vp) { if (vp) {
if (vg_thread_upgrade_lock(vctp))
goto retry;
BN_clear(&vctp->vct_bntmp); BN_clear(&vctp->vct_bntmp);
BN_set_word(&vctp->vct_bntmp, vctp->vct_delta); BN_set_word(&vctp->vct_bntmp, vctp->vct_delta);
BN_add(&vctp->vct_bntmp2, BN_add(&vctp->vct_bntmp2,
@ -1689,10 +1856,8 @@ vg_prefix_test(vg_context_t *vcp, vg_thread_context_t *vctp)
res = 1; res = 1;
} }
if (avl_root_empty(&vcpp->vcp_avlroot)) { if (avl_root_empty(&vcpp->vcp_avlroot)) {
pthread_mutex_unlock(&vcpp->vcp_lock);
return 2; return 2;
} }
pthread_mutex_unlock(&vcpp->vcp_lock);
return res; return res;
} }
@ -1712,7 +1877,6 @@ vg_prefix_context_new(int addrtype, int privtype)
vcpp->base.vc_test = vg_prefix_test; vcpp->base.vc_test = vg_prefix_test;
avl_root_init(&vcpp->vcp_avlroot); avl_root_init(&vcpp->vcp_avlroot);
BN_init(&vcpp->vcp_difficulty); BN_init(&vcpp->vcp_difficulty);
pthread_mutex_init(&vcpp->vcp_lock, NULL);
} }
return vcpp; return vcpp;
} }
@ -1726,7 +1890,6 @@ typedef struct _vg_regex_context_s {
pcre_extra **vcr_regex_extra; pcre_extra **vcr_regex_extra;
const char **vcr_regex_pat; const char **vcr_regex_pat;
unsigned long vcr_nalloc; unsigned long vcr_nalloc;
pthread_rwlock_t vcr_lock;
} vg_regex_context_t; } vg_regex_context_t;
int int
@ -1814,7 +1977,6 @@ vg_regex_context_free(vg_regex_context_t *vcrp)
} }
if (vcrp->vcr_nalloc) if (vcrp->vcr_nalloc)
free(vcrp->vcr_regex); free(vcrp->vcr_regex);
pthread_rwlock_destroy(&vcrp->vcr_lock);
free(vcrp); free(vcrp);
} }
@ -1864,7 +2026,7 @@ vg_regex_test(vg_context_t *vcp, vg_thread_context_t *vctp)
* Run the regular expressions on it * Run the regular expressions on it
* SLOW, runs in linear time with the number of REs * SLOW, runs in linear time with the number of REs
*/ */
pthread_rwlock_rdlock(&vcrp->vcr_lock); restart_loop:
nres = vcrp->base.vc_npatterns; nres = vcrp->base.vc_npatterns;
if (!nres) { if (!nres) {
res = 2; res = 2;
@ -1887,21 +2049,11 @@ vg_regex_test(vg_context_t *vcp, vg_thread_context_t *vctp)
} }
re = vcrp->vcr_regex[i]; re = vcrp->vcr_regex[i];
pthread_rwlock_unlock(&vcrp->vcr_lock);
pthread_rwlock_wrlock(&vcrp->vcr_lock); if (vg_thread_upgrade_lock(vctp) &&
nres = vcrp->base.vc_npatterns; ((i >= vcrp->base.vc_npatterns) ||
if ((i >= nres) || (vcrp->vcr_regex[i] != re)) { (vcrp->vcr_regex[i] != re)))
/* Redo the search */ goto restart_loop;
i = -1;
pthread_rwlock_unlock(&vcrp->vcr_lock);
pthread_rwlock_rdlock(&vcrp->vcr_lock);
nres = vcrp->base.vc_npatterns;
if (!nres) {
res = 2;
goto out;
}
continue;
}
BN_clear(&vctp->vct_bntmp); BN_clear(&vctp->vct_bntmp);
BN_set_word(&vctp->vct_bntmp, vctp->vct_delta); BN_set_word(&vctp->vct_bntmp, vctp->vct_delta);
@ -1937,12 +2089,10 @@ vg_regex_test(vg_context_t *vcp, vg_thread_context_t *vctp)
res = 1; res = 1;
} }
out: out:
pthread_rwlock_unlock(&vcrp->vcr_lock);
BN_clear_free(&bnrem); BN_clear_free(&bnrem);
return res; return res;
} }
vg_regex_context_t * vg_regex_context_t *
vg_regex_context_new(int addrtype, int privtype) vg_regex_context_new(int addrtype, int privtype)
{ {
@ -1959,7 +2109,6 @@ vg_regex_context_new(int addrtype, int privtype)
vcrp->base.vc_test = vg_regex_test; vcrp->base.vc_test = vg_regex_test;
vcrp->vcr_regex = NULL; vcrp->vcr_regex = NULL;
vcrp->vcr_nalloc = 0; vcrp->vcr_nalloc = 0;
pthread_rwlock_init(&vcrp->vcr_lock, NULL);
} }
return vcrp; return vcrp;
} }
@ -2106,7 +2255,8 @@ usage(const char *name)
"-t <threads> Set number of worker threads (Default: number of CPUs)\n" "-t <threads> Set number of worker threads (Default: number of CPUs)\n"
"-f <file> File containing list of patterns, one per line\n" "-f <file> File containing list of patterns, one per line\n"
" (Use \"-\" as the file name for stdin)\n" " (Use \"-\" as the file name for stdin)\n"
"-o <file> Write pattern matches to <file>\n", "-o <file> Write pattern matches to <file>\n"
"-s <file> Seed random number generator from <file>\n",
version, name); version, name);
} }
@ -2118,13 +2268,14 @@ main(int argc, char **argv)
int regex = 0; int regex = 0;
int caseinsensitive = 0; int caseinsensitive = 0;
int opt; int opt;
char *seedfile = NULL;
FILE *fp = NULL; FILE *fp = NULL;
char **patterns; char **patterns;
int npatterns = 0; int npatterns = 0;
int nthreads = 0; int nthreads = 0;
void *thread_arg = NULL; void *thread_arg = NULL;
while ((opt = getopt(argc, argv, "vqrikNTt:h?f:o:")) != -1) { while ((opt = getopt(argc, argv, "vqrikNTt:h?f:o:s:")) != -1) {
switch (opt) { switch (opt) {
case 'v': case 'v':
verbose = 2; verbose = 2;
@ -2163,7 +2314,7 @@ main(int argc, char **argv)
if (!strcmp(optarg, "-")) { if (!strcmp(optarg, "-")) {
fp = stdin; fp = stdin;
} else { } else {
fp = fopen(optarg, "r+"); fp = fopen(optarg, "r");
if (!fp) { if (!fp) {
printf("Could not open %s: %s\n", printf("Could not open %s: %s\n",
optarg, strerror(errno)); optarg, strerror(errno));
@ -2178,6 +2329,12 @@ main(int argc, char **argv)
} }
result_file = optarg; result_file = optarg;
break; break;
case 's':
if (seedfile != NULL) {
printf("Multiple RNG seeds specified\n");
return 1;
}
seedfile = optarg;
default: default:
usage(argv[0]); usage(argv[0]);
return 1; return 1;
@ -2188,6 +2345,25 @@ main(int argc, char **argv)
printf("WARNING: case insensitive mode incompatible with " printf("WARNING: case insensitive mode incompatible with "
"regular expressions\n"); "regular expressions\n");
if (seedfile) {
opt = -1;
#if !defined(_WIN32)
{ struct stat st;
if (!stat(optarg, &st) &&
(st.st_mode & (S_IFBLK|S_IFCHR))) {
opt = 32;
} }
#endif
opt = RAND_load_file(seedfile, opt);
if (!opt) {
printf("Could not load RNG seed %s\n", optarg);
return 1;
}
if (verbose > 0) {
printf("Read %d bytes from RNG seed file\n", opt);
}
}
if (fp) { if (fp) {
if (!read_file(fp, &patterns, &npatterns)) { if (!read_file(fp, &patterns, &npatterns)) {
printf("Failed to load pattern file\n"); printf("Failed to load pattern file\n");

Loading…
Cancel
Save