Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
samr7
GitHub Repository: samr7/vanitygen
Path: blob/master/vanitygen.c
239 views
1
/*
2
* Vanitygen, vanity bitcoin address generator
3
* Copyright (C) 2011 <[email protected]>
4
*
5
* Vanitygen is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU Affero General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* any later version.
9
*
10
* Vanitygen is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU Affero General Public License for more details.
14
*
15
* You should have received a copy of the GNU Affero General Public License
16
* along with Vanitygen. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include <stdio.h>
20
#include <string.h>
21
#include <math.h>
22
#include <assert.h>
23
24
#include <pthread.h>
25
26
#include <openssl/sha.h>
27
#include <openssl/ripemd.h>
28
#include <openssl/ec.h>
29
#include <openssl/bn.h>
30
#include <openssl/rand.h>
31
32
#include "pattern.h"
33
#include "util.h"
34
35
const char *version = VANITYGEN_VERSION;
36
37
38
/*
39
* Address search thread main loop
40
*/
41
42
void *
43
vg_thread_loop(void *arg)
44
{
45
unsigned char hash_buf[128];
46
unsigned char *eckey_buf;
47
unsigned char hash1[32];
48
49
int i, c, len, output_interval;
50
int hash_len;
51
52
const BN_ULONG rekey_max = 10000000;
53
BN_ULONG npoints, rekey_at, nbatch;
54
55
vg_context_t *vcp = (vg_context_t *) arg;
56
EC_KEY *pkey = NULL;
57
const EC_GROUP *pgroup;
58
const EC_POINT *pgen;
59
const int ptarraysize = 256;
60
EC_POINT *ppnt[ptarraysize];
61
EC_POINT *pbatchinc;
62
63
vg_test_func_t test_func = vcp->vc_test;
64
vg_exec_context_t ctx;
65
vg_exec_context_t *vxcp;
66
67
struct timeval tvstart;
68
69
70
memset(&ctx, 0, sizeof(ctx));
71
vxcp = &ctx;
72
73
vg_exec_context_init(vcp, &ctx);
74
75
pkey = vxcp->vxc_key;
76
pgroup = EC_KEY_get0_group(pkey);
77
pgen = EC_GROUP_get0_generator(pgroup);
78
79
for (i = 0; i < ptarraysize; i++) {
80
ppnt[i] = EC_POINT_new(pgroup);
81
if (!ppnt[i]) {
82
fprintf(stderr, "ERROR: out of memory?\n");
83
exit(1);
84
}
85
}
86
pbatchinc = EC_POINT_new(pgroup);
87
if (!pbatchinc) {
88
fprintf(stderr, "ERROR: out of memory?\n");
89
exit(1);
90
}
91
92
BN_set_word(&vxcp->vxc_bntmp, ptarraysize);
93
EC_POINT_mul(pgroup, pbatchinc, &vxcp->vxc_bntmp, NULL, NULL,
94
vxcp->vxc_bnctx);
95
EC_POINT_make_affine(pgroup, pbatchinc, vxcp->vxc_bnctx);
96
97
npoints = 0;
98
rekey_at = 0;
99
nbatch = 0;
100
vxcp->vxc_key = pkey;
101
vxcp->vxc_binres[0] = vcp->vc_addrtype;
102
c = 0;
103
output_interval = 1000;
104
gettimeofday(&tvstart, NULL);
105
106
if (vcp->vc_format == VCF_SCRIPT) {
107
hash_buf[ 0] = 0x51; // OP_1
108
hash_buf[ 1] = 0x41; // pubkey length
109
// gap for pubkey
110
hash_buf[67] = 0x51; // OP_1
111
hash_buf[68] = 0xae; // OP_CHECKMULTISIG
112
eckey_buf = hash_buf + 2;
113
hash_len = 69;
114
115
} else {
116
eckey_buf = hash_buf;
117
hash_len = 65;
118
}
119
120
while (!vcp->vc_halt) {
121
if (++npoints >= rekey_at) {
122
vg_exec_context_upgrade_lock(vxcp);
123
/* Generate a new random private key */
124
EC_KEY_generate_key(pkey);
125
npoints = 0;
126
127
/* Determine rekey interval */
128
EC_GROUP_get_order(pgroup, &vxcp->vxc_bntmp,
129
vxcp->vxc_bnctx);
130
BN_sub(&vxcp->vxc_bntmp2,
131
&vxcp->vxc_bntmp,
132
EC_KEY_get0_private_key(pkey));
133
rekey_at = BN_get_word(&vxcp->vxc_bntmp2);
134
if ((rekey_at == BN_MASK2) || (rekey_at > rekey_max))
135
rekey_at = rekey_max;
136
assert(rekey_at > 0);
137
138
EC_POINT_copy(ppnt[0], EC_KEY_get0_public_key(pkey));
139
vg_exec_context_downgrade_lock(vxcp);
140
141
npoints++;
142
vxcp->vxc_delta = 0;
143
144
if (vcp->vc_pubkey_base)
145
EC_POINT_add(pgroup,
146
ppnt[0],
147
ppnt[0],
148
vcp->vc_pubkey_base,
149
vxcp->vxc_bnctx);
150
151
for (nbatch = 1;
152
(nbatch < ptarraysize) && (npoints < rekey_at);
153
nbatch++, npoints++) {
154
EC_POINT_add(pgroup,
155
ppnt[nbatch],
156
ppnt[nbatch-1],
157
pgen, vxcp->vxc_bnctx);
158
}
159
160
} else {
161
/*
162
* Common case
163
*
164
* EC_POINT_add() can skip a few multiplies if
165
* one or both inputs are affine (Z_is_one).
166
* This is the case for every point in ppnt, as
167
* well as pbatchinc.
168
*/
169
assert(nbatch == ptarraysize);
170
for (nbatch = 0;
171
(nbatch < ptarraysize) && (npoints < rekey_at);
172
nbatch++, npoints++) {
173
EC_POINT_add(pgroup,
174
ppnt[nbatch],
175
ppnt[nbatch],
176
pbatchinc,
177
vxcp->vxc_bnctx);
178
}
179
}
180
181
/*
182
* The single most expensive operation performed in this
183
* loop is modular inversion of ppnt->Z. There is an
184
* algorithm implemented in OpenSSL to do batched inversion
185
* that only does one actual BN_mod_inverse(), and saves
186
* a _lot_ of time.
187
*
188
* To take advantage of this, we batch up a few points,
189
* and feed them to EC_POINTs_make_affine() below.
190
*/
191
192
EC_POINTs_make_affine(pgroup, nbatch, ppnt, vxcp->vxc_bnctx);
193
194
for (i = 0; i < nbatch; i++, vxcp->vxc_delta++) {
195
/* Hash the public key */
196
len = EC_POINT_point2oct(pgroup, ppnt[i],
197
POINT_CONVERSION_UNCOMPRESSED,
198
eckey_buf,
199
65,
200
vxcp->vxc_bnctx);
201
assert(len == 65);
202
203
SHA256(hash_buf, hash_len, hash1);
204
RIPEMD160(hash1, sizeof(hash1), &vxcp->vxc_binres[1]);
205
206
switch (test_func(vxcp)) {
207
case 1:
208
npoints = 0;
209
rekey_at = 0;
210
i = nbatch;
211
break;
212
case 2:
213
goto out;
214
default:
215
break;
216
}
217
}
218
219
c += i;
220
if (c >= output_interval) {
221
output_interval = vg_output_timing(vcp, c, &tvstart);
222
if (output_interval > 250000)
223
output_interval = 250000;
224
c = 0;
225
}
226
227
vg_exec_context_yield(vxcp);
228
}
229
230
out:
231
vg_exec_context_del(&ctx);
232
vg_context_thread_exit(vcp);
233
234
for (i = 0; i < ptarraysize; i++)
235
if (ppnt[i])
236
EC_POINT_free(ppnt[i]);
237
if (pbatchinc)
238
EC_POINT_free(pbatchinc);
239
return NULL;
240
}
241
242
243
#if !defined(_WIN32)
244
int
245
count_processors(void)
246
{
247
FILE *fp;
248
char buf[512];
249
int count = 0;
250
251
fp = fopen("/proc/cpuinfo", "r");
252
if (!fp)
253
return -1;
254
255
while (fgets(buf, sizeof(buf), fp)) {
256
if (!strncmp(buf, "processor\t", 10))
257
count += 1;
258
}
259
fclose(fp);
260
return count;
261
}
262
#endif
263
264
int
265
start_threads(vg_context_t *vcp, int nthreads)
266
{
267
pthread_t thread;
268
269
if (nthreads <= 0) {
270
/* Determine the number of threads */
271
nthreads = count_processors();
272
if (nthreads <= 0) {
273
fprintf(stderr,
274
"ERROR: could not determine processor count\n");
275
nthreads = 1;
276
}
277
}
278
279
if (vcp->vc_verbose > 1) {
280
fprintf(stderr, "Using %d worker thread(s)\n", nthreads);
281
}
282
283
while (--nthreads) {
284
if (pthread_create(&thread, NULL, vg_thread_loop, vcp))
285
return 0;
286
}
287
288
vg_thread_loop(vcp);
289
return 1;
290
}
291
292
293
void
294
usage(const char *name)
295
{
296
fprintf(stderr,
297
"Vanitygen %s (" OPENSSL_VERSION_TEXT ")\n"
298
"Usage: %s [-vqnrik1NT] [-t <threads>] [-f <filename>|-] [<pattern>...]\n"
299
"Generates a bitcoin receiving address matching <pattern>, and outputs the\n"
300
"address and associated private key. The private key may be stored in a safe\n"
301
"location or imported into a bitcoin client to spend any balance received on\n"
302
"the address.\n"
303
"By default, <pattern> is interpreted as an exact prefix.\n"
304
"\n"
305
"Options:\n"
306
"-v Verbose output\n"
307
"-q Quiet output\n"
308
"-n Simulate\n"
309
"-r Use regular expression match instead of prefix\n"
310
" (Feasibility of expression is not checked)\n"
311
"-i Case-insensitive prefix search\n"
312
"-k Keep pattern and continue search after finding a match\n"
313
"-1 Stop after first match\n"
314
"-N Generate namecoin address\n"
315
"-T Generate bitcoin testnet address\n"
316
"-X <version> Generate address with the given version\n"
317
"-F <format> Generate address with the given format (pubkey or script)\n"
318
"-P <pubkey> Specify base public key for piecewise key generation\n"
319
"-e Encrypt private keys, prompt for password\n"
320
"-E <password> Encrypt private keys with <password> (UNSAFE)\n"
321
"-t <threads> Set number of worker threads (Default: number of CPUs)\n"
322
"-f <file> File containing list of patterns, one per line\n"
323
" (Use \"-\" as the file name for stdin)\n"
324
"-o <file> Write pattern matches to <file>\n"
325
"-s <file> Seed random number generator from <file>\n",
326
version, name);
327
}
328
329
#define MAX_FILE 4
330
331
int
332
main(int argc, char **argv)
333
{
334
int addrtype = 0;
335
int scriptaddrtype = 5;
336
int privtype = 128;
337
int pubkeytype;
338
enum vg_format format = VCF_PUBKEY;
339
int regex = 0;
340
int caseinsensitive = 0;
341
int verbose = 1;
342
int simulate = 0;
343
int remove_on_match = 1;
344
int only_one = 0;
345
int prompt_password = 0;
346
int opt;
347
char *seedfile = NULL;
348
char pwbuf[128];
349
const char *result_file = NULL;
350
const char *key_password = NULL;
351
char **patterns;
352
int npatterns = 0;
353
int nthreads = 0;
354
vg_context_t *vcp = NULL;
355
EC_POINT *pubkey_base = NULL;
356
357
FILE *pattfp[MAX_FILE], *fp;
358
int pattfpi[MAX_FILE];
359
int npattfp = 0;
360
int pattstdin = 0;
361
362
int i;
363
364
while ((opt = getopt(argc, argv, "vqnrik1eE:P:NTX:F:t:h?f:o:s:")) != -1) {
365
switch (opt) {
366
case 'v':
367
verbose = 2;
368
break;
369
case 'q':
370
verbose = 0;
371
break;
372
case 'n':
373
simulate = 1;
374
break;
375
case 'r':
376
regex = 1;
377
break;
378
case 'i':
379
caseinsensitive = 1;
380
break;
381
case 'k':
382
remove_on_match = 0;
383
break;
384
case '1':
385
only_one = 1;
386
break;
387
case 'N':
388
addrtype = 52;
389
privtype = 180;
390
scriptaddrtype = -1;
391
break;
392
case 'T':
393
addrtype = 111;
394
privtype = 239;
395
scriptaddrtype = 196;
396
break;
397
case 'X':
398
addrtype = atoi(optarg);
399
privtype = 128 + addrtype;
400
scriptaddrtype = addrtype;
401
break;
402
case 'F':
403
if (!strcmp(optarg, "script"))
404
format = VCF_SCRIPT;
405
else
406
if (strcmp(optarg, "pubkey")) {
407
fprintf(stderr,
408
"Invalid format '%s'\n", optarg);
409
return 1;
410
}
411
break;
412
case 'P': {
413
if (pubkey_base != NULL) {
414
fprintf(stderr,
415
"Multiple base pubkeys specified\n");
416
return 1;
417
}
418
EC_KEY *pkey = vg_exec_context_new_key();
419
pubkey_base = EC_POINT_hex2point(
420
EC_KEY_get0_group(pkey),
421
optarg, NULL, NULL);
422
EC_KEY_free(pkey);
423
if (pubkey_base == NULL) {
424
fprintf(stderr,
425
"Invalid base pubkey\n");
426
return 1;
427
}
428
break;
429
}
430
431
case 'e':
432
prompt_password = 1;
433
break;
434
case 'E':
435
key_password = optarg;
436
break;
437
case 't':
438
nthreads = atoi(optarg);
439
if (nthreads == 0) {
440
fprintf(stderr,
441
"Invalid thread count '%s'\n", optarg);
442
return 1;
443
}
444
break;
445
case 'f':
446
if (npattfp >= MAX_FILE) {
447
fprintf(stderr,
448
"Too many input files specified\n");
449
return 1;
450
}
451
if (!strcmp(optarg, "-")) {
452
if (pattstdin) {
453
fprintf(stderr, "ERROR: stdin "
454
"specified multiple times\n");
455
return 1;
456
}
457
fp = stdin;
458
} else {
459
fp = fopen(optarg, "r");
460
if (!fp) {
461
fprintf(stderr,
462
"Could not open %s: %s\n",
463
optarg, strerror(errno));
464
return 1;
465
}
466
}
467
pattfp[npattfp] = fp;
468
pattfpi[npattfp] = caseinsensitive;
469
npattfp++;
470
break;
471
case 'o':
472
if (result_file) {
473
fprintf(stderr,
474
"Multiple output files specified\n");
475
return 1;
476
}
477
result_file = optarg;
478
break;
479
case 's':
480
if (seedfile != NULL) {
481
fprintf(stderr,
482
"Multiple RNG seeds specified\n");
483
return 1;
484
}
485
seedfile = optarg;
486
break;
487
default:
488
usage(argv[0]);
489
return 1;
490
}
491
}
492
493
#if OPENSSL_VERSION_NUMBER < 0x10000000L
494
/* Complain about older versions of OpenSSL */
495
if (verbose > 0) {
496
fprintf(stderr,
497
"WARNING: Built with " OPENSSL_VERSION_TEXT "\n"
498
"WARNING: Use OpenSSL 1.0.0d+ for best performance\n");
499
}
500
#endif
501
502
if (caseinsensitive && regex)
503
fprintf(stderr,
504
"WARNING: case insensitive mode incompatible with "
505
"regular expressions\n");
506
507
pubkeytype = addrtype;
508
if (format == VCF_SCRIPT)
509
{
510
if (scriptaddrtype == -1)
511
{
512
fprintf(stderr,
513
"Address type incompatible with script format\n");
514
return 1;
515
}
516
addrtype = scriptaddrtype;
517
}
518
519
if (seedfile) {
520
opt = -1;
521
#if !defined(_WIN32)
522
{ struct stat st;
523
if (!stat(seedfile, &st) &&
524
(st.st_mode & (S_IFBLK|S_IFCHR))) {
525
opt = 32;
526
} }
527
#endif
528
opt = RAND_load_file(seedfile, opt);
529
if (!opt) {
530
fprintf(stderr, "Could not load RNG seed %s\n", optarg);
531
return 1;
532
}
533
if (verbose > 0) {
534
fprintf(stderr,
535
"Read %d bytes from RNG seed file\n", opt);
536
}
537
}
538
539
if (regex) {
540
vcp = vg_regex_context_new(addrtype, privtype);
541
542
} else {
543
vcp = vg_prefix_context_new(addrtype, privtype,
544
caseinsensitive);
545
}
546
547
vcp->vc_verbose = verbose;
548
vcp->vc_result_file = result_file;
549
vcp->vc_remove_on_match = remove_on_match;
550
vcp->vc_only_one = only_one;
551
vcp->vc_format = format;
552
vcp->vc_pubkeytype = pubkeytype;
553
vcp->vc_pubkey_base = pubkey_base;
554
555
vcp->vc_output_match = vg_output_match_console;
556
vcp->vc_output_timing = vg_output_timing_console;
557
558
if (!npattfp) {
559
if (optind >= argc) {
560
usage(argv[0]);
561
return 1;
562
}
563
patterns = &argv[optind];
564
npatterns = argc - optind;
565
566
if (!vg_context_add_patterns(vcp,
567
(const char ** const) patterns,
568
npatterns))
569
return 1;
570
}
571
572
for (i = 0; i < npattfp; i++) {
573
fp = pattfp[i];
574
if (!vg_read_file(fp, &patterns, &npatterns)) {
575
fprintf(stderr, "Failed to load pattern file\n");
576
return 1;
577
}
578
if (fp != stdin)
579
fclose(fp);
580
581
if (!regex)
582
vg_prefix_context_set_case_insensitive(vcp, pattfpi[i]);
583
584
if (!vg_context_add_patterns(vcp,
585
(const char ** const) patterns,
586
npatterns))
587
return 1;
588
}
589
590
if (!vcp->vc_npatterns) {
591
fprintf(stderr, "No patterns to search\n");
592
return 1;
593
}
594
595
if (prompt_password) {
596
if (!vg_read_password(pwbuf, sizeof(pwbuf)))
597
return 1;
598
key_password = pwbuf;
599
}
600
vcp->vc_key_protect_pass = key_password;
601
if (key_password) {
602
if (!vg_check_password_complexity(key_password, verbose))
603
fprintf(stderr,
604
"WARNING: Protecting private keys with "
605
"weak password\n");
606
}
607
608
if ((verbose > 0) && regex && (vcp->vc_npatterns > 1))
609
fprintf(stderr,
610
"Regular expressions: %ld\n", vcp->vc_npatterns);
611
612
if (simulate)
613
return 0;
614
615
if (!start_threads(vcp, nthreads))
616
return 1;
617
return 0;
618
}
619
620