|
|
|
/*
|
|
|
|
* Vanitygen, vanity bitcoin address generator
|
|
|
|
* Copyright (C) 2011 <samr7@cs.washington.edu>
|
|
|
|
*
|
|
|
|
* Vanitygen is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* Vanitygen 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 Affero General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with Vanitygen. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include <openssl/ec.h>
|
|
|
|
#include <openssl/bn.h>
|
|
|
|
#include <openssl/rand.h>
|
|
|
|
|
|
|
|
#include "oclengine.h"
|
|
|
|
#include "pattern.h"
|
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
|
|
|
|
const char *version = VANITYGEN_VERSION;
|
|
|
|
const int debug = 0;
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
usage(const char *name)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"oclVanitygen %s (" OPENSSL_VERSION_TEXT ")\n"
|
|
|
|
"Usage: %s [-vqrikNTS] [-d <device>] [-f <filename>|-] [<pattern>...]\n"
|
|
|
|
"Generates a bitcoin receiving address matching <pattern>, and outputs the\n"
|
|
|
|
"address and associated private key. The private key may be stored in a safe\n"
|
|
|
|
"location or imported into a bitcoin client to spend any balance received on\n"
|
|
|
|
"the address.\n"
|
|
|
|
"By default, <pattern> is interpreted as an exact prefix.\n"
|
|
|
|
"\n"
|
|
|
|
"Options:\n"
|
|
|
|
"-v Verbose output\n"
|
|
|
|
"-q Quiet output\n"
|
|
|
|
"-i Case-insensitive prefix search\n"
|
|
|
|
"-k Keep pattern and continue search after finding a match\n"
|
|
|
|
"-N Generate namecoin address\n"
|
|
|
|
"-T Generate bitcoin testnet address\n"
|
|
|
|
"-X <version> Generate address with the given version\n"
|
|
|
|
"-e Encrypt private keys, prompt for password\n"
|
|
|
|
"-E <password> Encrypt private keys with <password> (UNSAFE)\n"
|
|
|
|
"-p <platform> Select OpenCL platform\n"
|
|
|
|
"-d <device> Select OpenCL device\n"
|
|
|
|
"-S Safe mode, disable OpenCL loop unrolling optimizations\n"
|
|
|
|
"-w <worksize> Set work items per thread in a work unit\n"
|
|
|
|
"-t <threads> Set target thread count per multiprocessor\n"
|
|
|
|
"-g <x>x<y> Set grid size\n"
|
|
|
|
"-b <invsize> Set modular inverse ops per thread\n"
|
|
|
|
"-V Enable kernel/OpenCL/hardware verification (SLOW)\n"
|
|
|
|
"-f <file> File containing list of patterns, one per line\n"
|
|
|
|
" (Use \"-\" as the file name for stdin)\n"
|
|
|
|
"-o <file> Write pattern matches to <file>\n"
|
|
|
|
"-s <file> Seed random number generator from <file>\n",
|
|
|
|
version, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int addrtype = 0;
|
|
|
|
int privtype = 128;
|
|
|
|
int regex = 0;
|
|
|
|
int caseinsensitive = 0;
|
|
|
|
int opt;
|
|
|
|
char pwbuf[128];
|
|
|
|
int platformidx = -1, deviceidx = -1;
|
|
|
|
int prompt_password = 0;
|
|
|
|
char *seedfile = NULL;
|
|
|
|
FILE *fp = NULL;
|
|
|
|
char **patterns, *pend;
|
|
|
|
int verbose = 1;
|
|
|
|
int npatterns = 0;
|
|
|
|
int nthreads = 0;
|
|
|
|
int worksize = 0;
|
|
|
|
int nrows = 0, ncols = 0;
|
|
|
|
int invsize = 0;
|
|
|
|
int remove_on_match = 1;
|
|
|
|
int verify_mode = 0;
|
|
|
|
int safe_mode = 0;
|
|
|
|
vg_context_t *vcp = NULL;
|
|
|
|
vg_ocl_context_t *vocp = NULL;
|
|
|
|
EC_POINT *pubkey_base = NULL;
|
|
|
|
const char *result_file = NULL;
|
|
|
|
const char *key_password = NULL;
|
|
|
|
|
|
|
|
while ((opt = getopt(argc, argv,
|
|
|
|
"vqikNTX:eE:p:P:d:w:t:g:b:VSh?f:o:s:")) != -1) {
|
|
|
|
switch (opt) {
|
|
|
|
case 'v':
|
|
|
|
verbose = 2;
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
verbose = 0;
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
caseinsensitive = 1;
|
|
|
|
break;
|
|
|
|
case 'k':
|
|
|
|
remove_on_match = 0;
|
|
|
|
break;
|
|
|
|
case 'N':
|
|
|
|
addrtype = 52;
|
|
|
|
privtype = 180;
|
|
|
|
break;
|
|
|
|
case 'T':
|
|
|
|
addrtype = 111;
|
|
|
|
privtype = 239;
|
|
|
|
break;
|
|
|
|
case 'X':
|
|
|
|
addrtype = atoi(optarg);
|
|
|
|
privtype = 128 + addrtype;
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
prompt_password = 1;
|
|
|
|
break;
|
|
|
|
case 'E':
|
|
|
|
key_password = optarg;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
platformidx = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
deviceidx = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
worksize = atoi(optarg);
|
|
|
|
if (worksize == 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Invalid work size '%s'\n", optarg);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
nthreads = atoi(optarg);
|
|
|
|
if (nthreads == 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Invalid thread count '%s'\n", optarg);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'g':
|
|
|
|
nrows = 0;
|
|
|
|
ncols = strtol(optarg, &pend, 0);
|
|
|
|
if (pend && *pend == 'x') {
|
|
|
|
nrows = strtol(pend+1, NULL, 0);
|
|
|
|
}
|
|
|
|
if (!nrows || !ncols) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Invalid grid size '%s'\n", optarg);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
invsize = atoi(optarg);
|
|
|
|
if (!invsize) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Invalid modular inverse size '%s'\n",
|
|
|
|
optarg);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (invsize & (invsize - 1)) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Modular inverse size must be "
|
|
|
|
"a power of 2\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'V':
|
|
|
|
verify_mode = 1;
|
|
|
|
break;
|
|
|
|
case 'S':
|
|
|
|
safe_mode = 1;
|
|
|
|
break;
|
|
|
|
case 'P': {
|
|
|
|
if (pubkey_base != NULL) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Multiple base pubkeys specified\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
EC_KEY *pkey = vg_exec_context_new_key();
|
|
|
|
pubkey_base = EC_POINT_hex2point(
|
|
|
|
EC_KEY_get0_group(pkey),
|
|
|
|
optarg, NULL, NULL);
|
|
|
|
EC_KEY_free(pkey);
|
|
|
|
if (pubkey_base == NULL) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Invalid base pubkey\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'f':
|
|
|
|
if (fp) {
|
|
|
|
fprintf(stderr, "Multiple files specified\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (!strcmp(optarg, "-")) {
|
|
|
|
fp = stdin;
|
|
|
|
} else {
|
|
|
|
fp = fopen(optarg, "r");
|
|
|
|
if (!fp) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Could not open %s: %s\n",
|
|
|
|
optarg, strerror(errno));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
if (result_file) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Multiple output files specified\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
result_file = optarg;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
if (seedfile != NULL) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Multiple RNG seeds specified\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
seedfile = optarg;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage(argv[0]);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x10000000L
|
|
|
|
/* Complain about older versions of OpenSSL */
|
|
|
|
if (verbose > 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Built with " OPENSSL_VERSION_TEXT "\n"
|
|
|
|
"WARNING: Use OpenSSL 1.0.0d+ for best performance\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (caseinsensitive && regex)
|
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: case insensitive mode incompatible with "
|
|
|
|
"regular expressions\n");
|
|
|
|
|
|
|
|
if (seedfile) {
|
|
|
|
opt = -1;
|
|
|
|
#if !defined(_WIN32)
|
|
|
|
{ struct stat st;
|
|
|
|
if (!stat(seedfile, &st) &&
|
|
|
|
(st.st_mode & (S_IFBLK|S_IFCHR))) {
|
|
|
|
opt = 32;
|
|
|
|
} }
|
|
|
|
#endif
|
|
|
|
opt = RAND_load_file(seedfile, opt);
|
|
|
|
if (!opt) {
|
|
|
|
fprintf(stderr, "Could not load RNG seed %s\n", optarg);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (verbose > 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Read %d bytes from RNG seed file\n", opt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fp) {
|
|
|
|
if (!vg_read_file(fp, &patterns, &npatterns)) {
|
|
|
|
fprintf(stderr, "Failed to load pattern file\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (fp != stdin)
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (optind >= argc) {
|
|
|
|
usage(argv[0]);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
patterns = &argv[optind];
|
|
|
|
npatterns = argc - optind;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (regex) {
|
|
|
|
vcp = vg_regex_context_new(addrtype, privtype);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
vcp = vg_prefix_context_new(addrtype, privtype,
|
|
|
|
caseinsensitive);
|
|
|
|
}
|
|
|
|
|
|
|
|
vcp->vc_verbose = verbose;
|
|
|
|
vcp->vc_result_file = result_file;
|
|
|
|
vcp->vc_remove_on_match = remove_on_match;
|
|
|
|
vcp->vc_pubkey_base = pubkey_base;
|
|
|
|
|
|
|
|
vcp->vc_output_match = vg_output_match_console;
|
|
|
|
vcp->vc_output_timing = vg_output_timing_console;
|
|
|
|
|
|
|
|
if (!vg_context_add_patterns(vcp, (const char ** const)patterns,
|
|
|
|
npatterns))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (!vcp->vc_npatterns) {
|
|
|
|
fprintf(stderr, "No patterns to search\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prompt_password) {
|
|
|
|
if (!vg_read_password(pwbuf, sizeof(pwbuf)))
|
|
|
|
return 1;
|
|
|
|
key_password = pwbuf;
|
|
|
|
}
|
|
|
|
vcp->vc_key_protect_pass = key_password;
|
|
|
|
if (key_password) {
|
|
|
|
if (!vg_check_password_complexity(key_password, verbose))
|
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Protecting private keys with "
|
|
|
|
"weak password\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((verbose > 0) && regex && (vcp->vc_npatterns > 1))
|
|
|
|
fprintf(stderr,
|
|
|
|
"Regular expressions: %ld\n", vcp->vc_npatterns);
|
|
|
|
|
|
|
|
vocp = vg_ocl_context_new(vcp, platformidx, deviceidx,
|
|
|
|
safe_mode, verify_mode,
|
|
|
|
worksize, nthreads, nrows, ncols, invsize);
|
|
|
|
if (!vocp) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
vg_opencl_loop(vocp);
|
|
|
|
vg_ocl_context_free(vocp);
|
|
|
|
return 0;
|
|
|
|
}
|