From 927c650808355e92c497f3a6405ec7183652715b Mon Sep 17 00:00:00 2001 From: samr7 Date: Thu, 7 Jul 2011 12:29:14 -0700 Subject: [PATCH] Vanitygen 0.1 as released on forum. --- CHANGELOG | 25 ++ Makefile | 9 + README | 53 ++++ vanitygen.c | 787 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 874 insertions(+) create mode 100644 CHANGELOG create mode 100644 Makefile create mode 100644 README create mode 100644 vanitygen.c diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..1cb4bcf --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,25 @@ +Version 0.1, released July 4 2011: + - Exact prefix searching + - Regular expression searching + +Version 0.2, released July 5 2011: + - Fix the regular expression problem reported by pyna and + molecular. + - Add support for multi-pattern searching. + +Version 0.3, released July 5 2011: + - Resolve the pcre_study() bug reported by an0therlr3 + - Add probability so far and time estimates suggested by davux + - Clean up the display, make it look more like phoenix miner + +Version 0.4, released July 6 2011: + - Fix assertion failure when using exact prefixes starting with + more than one 1, reported by SgtSpike + - Port to Windows, start distributing Win32 binaries + +Version 0.5, released July 7 2011: + - Now with worker threads and CPU count detection, suggested by + davux and others + - Exact prefixes can now be matched case-insensitively with + "-i", for SgtSpike + - Fixed an integer overflow problem with the status display diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..69cf68b --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +LIBS=-lpcre -lcrypto -lm -lpthread +CFLAGS=-ggdb -O3 -Wall +OBJS=vanitygen.o + +vanitygen: $(OBJS) + $(CC) $(OBJS) -o $@ $(CFLAGS) $(LIBS) + +clean: + rm -f $(OBJS) vanitygen diff --git a/README b/README new file mode 100644 index 0000000..b78b3ca --- /dev/null +++ b/README @@ -0,0 +1,53 @@ +I'd like to present a standalone command line vanity address generator +called vanitygen. + +There are plenty of quality tools to do this right now already. So why +use vanitygen? The main reason is that it is fast, more than an order +of magnitude faster than the official bitcoin client with the vanity +address patch applied. This is despite the fact that it runs on the +CPU and does not use OpenCL or CUDA. Vanitygen is also a bit more +user-friendly in that it provides feedback on its rate of progress and +how many keys it has checked. + +Vanitygen is written in C, and is provided in source code form and +pre-built Win32 binaries. At present, vanitygen can be built on Linux, +and requires the openssl and pcre libraries. + +Vanitygen can generate regular bitcoin addresses, namecoin addresses, +and testnet addresses. + +Vanitygen can search for exact prefixes or regular expression matches. +When searching for exact prefixes, vanitygen will ensure that the +prefix is possible, will provide a difficulty estimate, and will run +about 30% faster. Exact prefixes are case-sensitive by default, but +may be searched case-insensitively using the "-i" option. Regular +expression patterns follow the Perl-compatible regular expression +language. + +Vanitygen can accept a list of patterns to search for, either on the +command line, or from a file or stdin using the "-f" option. File +sources should have one pattern per line. When searching for N exact +prefixes, performance of O(logN) can be expected, and extremely long +lists of prefixes will have little effect on search rate. Searching +for N regular expressions will have varied performance depending on the +complexity of the expressions, but O(N) performance can be expected. + +By defaut, vanitygen will spawn one worker thread for each CPU in your +system. If you wish to limit the number of worker threads created by +vanitygen, use the "-t" option. + +The example below completed quicker than average, and took about 45 sec +to finish, using both cores of my aging Core 2 Duo E6600: + +$ ./vanitygen 1Love +Difficulty: 4476342 +[48165 K/s][total 2080000][Prob 37.2%][50% in 21.2s] +Pattern: 1Love +Address: 1LoveRg5t2NCDLUZh6Q8ixv74M5YGVxXaN +Privkey: 5JLUmjZiirgziDmWmNprPsNx8DYwfecUNk1FQXmDPaoKB36fX1o + +Currently, it is difficult to import the private key into bitcoin. +Sipa's showwallet branch has a new command called "importprivkey" that +accepts the base-58 encoded private key. Vanitygen has been tested to +work with that version of bitcoin. + diff --git a/vanitygen.c b/vanitygen.c new file mode 100644 index 0000000..db065cc --- /dev/null +++ b/vanitygen.c @@ -0,0 +1,787 @@ +/* + * Vanitygen, vanity bitcoin address generator + * Copyright (C) 2011 + * + * 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 . + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +const int debug = 0; + +static const char *b58_alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + +void +encode_b58_check(void *buf, size_t len, char *result) +{ + unsigned char hash1[32]; + unsigned char hash2[32]; + + int d, p; + + BN_CTX *bnctx; + BIGNUM *bn, *bndiv, *bntmp; + BIGNUM bna, bnb, bnbase, bnrem; + unsigned char *binres; + int brlen, zpfx; + + bnctx = BN_CTX_new(); + BN_init(&bna); + BN_init(&bnb); + BN_init(&bnbase); + BN_init(&bnrem); + BN_set_word(&bnbase, 58); + + bn = &bna; + bndiv = &bnb; + + brlen = (2 * len) + 4; + binres = malloc(brlen); + memcpy(binres, buf, len); + + SHA256(binres, len, hash1); + SHA256(hash1, sizeof(hash1), hash2); + memcpy(&binres[len], hash2, 4); + + BN_bin2bn(binres, len + 4, bn); + + for (zpfx = 0; zpfx < (len + 4) && binres[zpfx] == 0; zpfx++); + + p = brlen; + while (!BN_is_zero(bn)) { + BN_div(bndiv, &bnrem, bn, &bnbase, bnctx); + bntmp = bn; + bn = bndiv; + bndiv = bntmp; + d = BN_get_word(&bnrem); + binres[--p] = b58_alphabet[d]; + } + + while (zpfx--) { + binres[--p] = b58_alphabet[0]; + } + + memcpy(result, &binres[p], brlen - p); + result[brlen - p] = '\0'; + + free(binres); + BN_clear_free(&bna); + BN_clear_free(&bnb); + BN_clear_free(&bnbase); + BN_clear_free(&bnrem); + BN_CTX_free(bnctx); +} + +void +encode_address(EC_KEY *pkey, int addrtype, char *result) +{ + unsigned char eckey_buf[128], *pend; + unsigned char binres[21] = {0,}; + unsigned char hash1[32]; + + pend = eckey_buf; + + i2o_ECPublicKey(pkey, &pend); + + binres[0] = addrtype; + SHA256(eckey_buf, pend - eckey_buf, hash1); + RIPEMD160(hash1, sizeof(hash1), &binres[1]); + + encode_b58_check(binres, sizeof(binres), result); +} + +void +encode_privkey(EC_KEY *pkey, int addrtype, char *result) +{ + unsigned char eckey_buf[128]; + const BIGNUM *bn; + int nbytes; + + bn = EC_KEY_get0_private_key(pkey); + + eckey_buf[0] = addrtype; + nbytes = BN_bn2bin(bn, &eckey_buf[1]); + + encode_b58_check(eckey_buf, nbytes + 1, result); +} + + +void +dumphex(const unsigned char *src, size_t len) +{ + size_t i; + for (i = 0; i < len; i++) { + printf("%02x", src[i]); + } + printf("\n"); +} + +void +dumpbn(const BIGNUM *bn) +{ + char *buf; + buf = BN_bn2hex(bn); + printf("%s\n", buf); + OPENSSL_free(buf); +} + +void +output_match(EC_KEY *pkey, int addrtype, int privtype) +{ + unsigned char key_buf[512], *pend; + char print_buf[512]; + int len; + + assert(EC_KEY_check_key(pkey)); + + /* Hexadecimal OpenSSL notation */ + pend = key_buf; + len = i2o_ECPublicKey(pkey, &pend); + printf("Pubkey (hex): "); + dumphex(key_buf, len); + pend = key_buf; + len = i2d_ECPrivateKey(pkey, &pend); + printf("Privkey (hex): "); + dumphex(key_buf, len); + + /* Base-58 bitcoin notation public key hash */ + encode_address(pkey, addrtype, print_buf); + printf("Address: %s\n", print_buf); + + /* Base-58 bitcoin notation private key */ + encode_privkey(pkey, privtype, print_buf); + printf("Privkey: %s\n", print_buf); +} + + +/* + * Search for a key for which the encoded address has a specific prefix. + * Uses bignum arithmetic to predetermine value ranges. + * Faster than regular expression searching. + */ +void +generate_address_prefix(int addrtype, int privtype, const char *pfx) +{ + unsigned char eckey_buf[128]; + unsigned char hash1[32]; + unsigned char binres[25] = {0,}; + char *dbuf; + + int i, p, c, t; + int b58pow, b58ceil, b58top = 0; + + BN_ULONG npoints, rekey_at; + + int zero_prefix = 0; + int check_upper = 0; + + BN_CTX *bnctx; + BIGNUM *bnap, *bnbp, *bntp; + BIGNUM bntarg, bnceil, bnfloor; + BIGNUM bnbase; + BIGNUM bnhigh, bnlow, bnhigh2, bnlow2; + BIGNUM bntmp, bntmp2; + + EC_KEY *pkey; + const EC_GROUP *pgroup; + const EC_POINT *pgen; + EC_POINT *ppnt = NULL; + + struct timeval tvstart, tvnow, tv; + + bnctx = BN_CTX_new(); + + BN_init(&bntarg); + BN_init(&bnceil); + BN_init(&bnfloor); + BN_init(&bnbase); + BN_init(&bnhigh); + BN_init(&bnlow); + BN_init(&bnhigh2); + BN_init(&bnlow2); + BN_init(&bntmp); + BN_init(&bntmp2); + + BN_set_word(&bnbase, 58); + + /* + * Step 1: compute the integer boundaries for accepted addresses + * Results are stored in bnlow, bnhigh, bnlow2, bnhigh2. + */ + + p = strlen(pfx); + + for (i = 0; i < p; i++) { + for (c = 0; c < 58; c++) { + if (pfx[i] == b58_alphabet[c]) + break; + } + if (c >= 58) { + printf("Invalid character '%c' in address\n", pfx[i]); + return; + } + if (i == zero_prefix) { + if (c == 0) { + /* Add another zero prefix */ + zero_prefix++; + if (zero_prefix > 19) { + printf("Prefix is too long\n"); + return; + } + continue; + } + + /* First non-zero character */ + b58top = c; + BN_set_word(&bntarg, c); + + } else { + BN_set_word(&bntmp2, c); + BN_mul(&bntmp, &bntarg, &bnbase, bnctx); + BN_add(&bntarg, &bntmp, &bntmp2); + } + } + + /* Power-of-two ceiling and floor values based on leading 1s */ + BN_clear(&bntmp); + BN_set_bit(&bntmp, 200 - (zero_prefix * 8)); + BN_set_word(&bntmp2, 1); + BN_sub(&bnceil, &bntmp, &bntmp2); + BN_set_bit(&bnfloor, 192 - (zero_prefix * 8)); + + if (b58top) { + /* + * If a non-zero was given in the prefix, find the + * numeric boundaries of the prefix. + */ + BN_copy(&bntmp, &bnceil); + bnap = &bntmp; + bnbp = &bntmp2; + b58pow = 0; + while (BN_cmp(bnap, &bnbase) > 0) { + b58pow++; + BN_div(bnbp, NULL, bnap, &bnbase, bnctx); + bntp = bnap; + bnap = bnbp; + bnbp = bntp; + } + b58ceil = BN_get_word(bnap); + + if ((b58pow - (p - zero_prefix)) < 6) { + /* + * Do not allow the prefix to constrain the + * check value, this is ridiculous. + */ + printf("Prefix is too long\n"); + return; + } + + BN_set_word(&bntmp2, b58pow - (p - zero_prefix)); + BN_exp(&bntmp, &bnbase, &bntmp2, bnctx); + BN_mul(&bnlow, &bntmp, &bntarg, bnctx); + BN_set_word(&bnhigh, 1); + BN_sub(&bntmp2, &bntmp, &bnhigh); + BN_add(&bnhigh, &bnlow, &bntmp2); + + if (b58top <= b58ceil) { + /* Fill out the upper range too */ + check_upper = 1; + BN_mul(&bnlow2, &bnlow, &bnbase, bnctx); + BN_mul(&bntmp2, &bnhigh, &bnbase, bnctx); + BN_set_word(&bntmp, 57); + BN_add(&bnhigh2, &bntmp2, &bntmp); + + /* + * Addresses above the ceiling will have one + * fewer "1" prefix in front than we require. + */ + if (BN_cmp(&bnceil, &bnlow2) < 0) + /* High prefix is above the ceiling */ + check_upper = 0; + else if (BN_cmp(&bnceil, &bnhigh2) < 0) + /* High prefix is partly above the ceiling */ + BN_copy(&bnhigh2, &bnceil); + + /* + * Addresses below the floor will have another + * "1" prefix in front instead of our target. + */ + if (BN_cmp(&bnfloor, &bnhigh) >= 0) { + /* Low prefix is completely below the floor */ + check_upper = 0; + BN_copy(&bnhigh, &bnhigh2); + BN_copy(&bnlow, &bnlow2); + } + else if (BN_cmp(&bnfloor, &bnlow) > 0) { + /* Low prefix is partly below the floor */ + BN_copy(&bnlow, &bnfloor); + } + } + + } else { + BN_copy(&bnhigh, &bnceil); + BN_set_word(&bnlow, 0); + } + + /* Limit the prefix to the address type */ + BN_clear(&bntmp); + BN_set_word(&bntmp, addrtype); + BN_lshift(&bntmp2, &bntmp, 192); + + if (check_upper) { + if (BN_cmp(&bntmp2, &bnhigh2) > 0) + check_upper = 0; + else if (BN_cmp(&bntmp2, &bnlow2) > 0) + BN_copy(&bnlow2, &bntmp2); + } + + if (BN_cmp(&bntmp2, &bnhigh) > 0) { + if (!check_upper) { + printf("Address prefix not possible\n"); + return; + } + check_upper = 0; + BN_copy(&bnhigh, &bnhigh2); + BN_copy(&bnlow, &bnlow2); + } + else if (BN_cmp(&bntmp2, &bnlow) > 0) { + BN_copy(&bnlow, &bntmp2); + } + + BN_set_word(&bntmp, addrtype + 1); + BN_lshift(&bntmp2, &bntmp, 192); + + if (check_upper) { + if (BN_cmp(&bntmp2, &bnlow2) < 0) + check_upper = 0; + else if (BN_cmp(&bntmp2, &bnhigh2) < 0) + BN_copy(&bnlow2, &bntmp2); + } + + if (BN_cmp(&bntmp2, &bnlow) < 0) { + if (!check_upper) { + printf("Address prefix not possible\n"); + return; + } + check_upper = 0; + BN_copy(&bnhigh, &bnhigh2); + BN_copy(&bnlow, &bnlow2); + } + else if (BN_cmp(&bntmp2, &bnhigh) < 0) { + BN_copy(&bnhigh, &bntmp2); + } + + /* Address ranges are complete */ + + if (debug) { + if (check_upper) { + printf("Upper Min: "); + dumpbn(&bnlow2); + printf("Upper Max: "); + dumpbn(&bnhigh2); + } + printf("Min: "); + dumpbn(&bnlow); + printf("Max: "); + dumpbn(&bnhigh); + } + + /* Determine the probability of finding a match */ + BN_sub(&bntarg, &bnhigh, &bnlow); + if (check_upper) { + BN_sub(&bntmp, &bnhigh2, &bnlow2); + BN_add(&bntmp2, &bntarg, &bntmp); + BN_copy(&bntarg, &bntmp2); + } + BN_set_word(&bntmp, 0); + BN_set_bit(&bntmp, 192); + BN_div(&bntmp2, NULL, &bntmp, &bntarg, bnctx); + dbuf = BN_bn2dec(&bntmp2); + printf("Difficulty: %s\n", dbuf); + OPENSSL_free(dbuf); + + /* + * Step 2: Search for matching private keys + * Generate a base private key, and start searching increments. + */ + + pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + pgroup = EC_KEY_get0_group(pkey); + pgen = EC_GROUP_get0_generator(pgroup); + + EC_KEY_precompute_mult(pkey, bnctx); + + npoints = 0; + rekey_at = 0; + binres[0] = addrtype; + t = 0; + c = 0; + gettimeofday(&tvstart, NULL); + while (1) { + if (++npoints >= rekey_at) { + /* Generate a new random private key */ + EC_KEY_generate_key(pkey); + npoints = 0; + + /* Determine rekey interval */ + EC_GROUP_get_order(pgroup, &bntmp, bnctx); + BN_sub(&bntmp2, + &bntmp, + EC_KEY_get0_private_key(pkey)); + rekey_at = BN_get_word(&bntmp2); + if ((rekey_at == BN_MASK2) || (rekey_at > 1000000)) + rekey_at = 1000000; + assert(rekey_at > 0); + + if (ppnt) + EC_POINT_free(ppnt); + ppnt = EC_POINT_dup(EC_KEY_get0_public_key(pkey), + pgroup); + + } else { + /* Common case: next point */ + EC_POINT_add(pgroup, ppnt, ppnt, pgen, bnctx); + } + + /* Hash the public key */ + i = EC_POINT_point2oct(pgroup, ppnt, + POINT_CONVERSION_UNCOMPRESSED, + eckey_buf, sizeof(eckey_buf), bnctx); + SHA256(eckey_buf, i, hash1); + RIPEMD160(hash1, sizeof(hash1), &binres[1]); + + /* + * We constrain the prefix so that we can check for a match + * without generating the lower four byte check code. + */ + + BN_bin2bn(binres, sizeof(binres), &bntarg); + + if ((check_upper && + (BN_cmp(&bnlow2, &bntarg) <= 0) && + (BN_cmp(&bnhigh2, &bntarg) > 0)) || + ((BN_cmp(&bnlow, &bntarg) <= 0) && + (BN_cmp(&bnhigh, &bntarg) > 0))) { + + printf("\n"); + + if (npoints) { + BN_clear(&bntmp); + BN_set_word(&bntmp, npoints); + BN_add(&bntmp2, + EC_KEY_get0_private_key(pkey), + &bntmp); + EC_KEY_set_private_key(pkey, &bntmp2); + } + + EC_KEY_set_public_key(pkey, ppnt); + + output_match(pkey, addrtype, privtype); + break; + } + + if (++c >= 20000) { + long long rate; + gettimeofday(&tvnow, NULL); + timersub(&tvnow, &tvstart, &tv); + memcpy(&tvstart, &tvnow, sizeof(tvstart)); + rate = tv.tv_usec + (1000000 * tv.tv_sec); + rate = (1000000ULL * c) / rate; + t += c; + c = 0; + printf("\r%lld K/s, total %d ", rate, t); + fflush(stdout); + } + } + + BN_clear_free(&bntarg); + BN_clear_free(&bnceil); + BN_clear_free(&bnfloor); + BN_clear_free(&bnbase); + BN_clear_free(&bnhigh); + BN_clear_free(&bnlow); + BN_clear_free(&bnhigh2); + BN_clear_free(&bnlow2); + BN_clear_free(&bntmp); + BN_clear_free(&bntmp2); + BN_CTX_free(bnctx); + EC_KEY_free(pkey); + EC_POINT_free(ppnt); +} + + +/* + * Search for a key for which the encoded address matches a regular + * expression. + * Equivalent behavior to the bitcoin vanity address patch. + */ +void +generate_address_regex(int addrtype, int privtype, const char *re) +{ + unsigned char eckey_buf[128]; + unsigned char hash1[32], hash2[32]; + unsigned char binres[25] = {0,}; + char b58[40]; + + int t, c, zpfx, p, d, re_vec[9]; + + BN_ULONG npoints, rekey_at; + + BN_CTX *bnctx; + BIGNUM bna, bnb, bnbase, bnrem, bntmp, bntmp2; + BIGNUM *bn, *bndiv, *bnptmp; + + EC_KEY *pkey; + const EC_GROUP *pgroup; + const EC_POINT *pgen; + EC_POINT *ppnt = NULL; + + pcre *regex; + pcre_extra *regex_extra; + const char *pcre_errptr; + int pcre_erroffset; + + struct timeval tvstart, tvnow, tv; + + regex = pcre_compile(re, 0, &pcre_errptr, &pcre_erroffset, NULL); + if (!regex) { + const char *spaces = " "; + printf("%s\n", re); + while (pcre_erroffset > 16) { + printf("%s", spaces); + pcre_erroffset -= 16; + } + if (pcre_erroffset > 0) + printf("%s", &spaces[16 - pcre_erroffset]); + printf("^\nRegex error: %s\n", pcre_errptr); + return; + } + regex_extra = pcre_study(regex, 0, &pcre_errptr); + if (!regex_extra) { + printf("Regex error: %s\n", pcre_errptr); + pcre_free(regex); + return; + } + + bnctx = BN_CTX_new(); + + BN_init(&bna); + BN_init(&bnb); + BN_init(&bnbase); + BN_init(&bnrem); + BN_init(&bntmp); + BN_init(&bntmp2); + + BN_set_word(&bnbase, 58); + + pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + pgroup = EC_KEY_get0_group(pkey); + pgen = EC_GROUP_get0_generator(pgroup); + + EC_KEY_precompute_mult(pkey, bnctx); + + npoints = 0; + rekey_at = 0; + binres[0] = addrtype; + t = 0; + c = 0; + gettimeofday(&tvstart, NULL); + + while (1) { + if (++npoints >= rekey_at) { + /* Generate a new random private key */ + EC_KEY_generate_key(pkey); + npoints = 0; + + /* Determine rekey interval */ + EC_GROUP_get_order(pgroup, &bntmp, bnctx); + BN_sub(&bntmp2, + &bntmp, + EC_KEY_get0_private_key(pkey)); + rekey_at = BN_get_word(&bntmp2); + if ((rekey_at == BN_MASK2) || (rekey_at > 1000000)) + rekey_at = 1000000; + assert(rekey_at > 0); + + if (ppnt) + EC_POINT_free(ppnt); + ppnt = EC_POINT_dup(EC_KEY_get0_public_key(pkey), + pgroup); + + } else { + /* Common case: next point */ + EC_POINT_add(pgroup, ppnt, ppnt, pgen, bnctx); + } + + /* Hash the public key */ + d = EC_POINT_point2oct(pgroup, ppnt, + POINT_CONVERSION_UNCOMPRESSED, + eckey_buf, sizeof(eckey_buf), bnctx); + SHA256(eckey_buf, d, hash1); + RIPEMD160(hash1, sizeof(hash1), &binres[1]); + + /* Hash the hash and write the four byte check code */ + SHA256(binres, 21, hash1); + SHA256(hash1, sizeof(hash1), hash2); + memcpy(hash2, &binres[21], 4); + + bn = &bna; + bndiv = &bnb; + + BN_bin2bn(binres, sizeof(binres), bn); + + /* Compute the complete encoded address */ + for (zpfx = 0; zpfx < 25 && binres[zpfx] == 0; zpfx++); + p = sizeof(b58) - 1; + b58[p] = '\0'; + while (!BN_is_zero(bn)) { + BN_div(bndiv, &bnrem, bn, &bnbase, bnctx); + bnptmp = bn; + bn = bndiv; + bndiv = bnptmp; + d = BN_get_word(&bnrem); + b58[--p] = b58_alphabet[d]; + } + while (zpfx--) { + b58[--p] = b58_alphabet[0]; + } + + /* Run the regular expression on it */ + d = pcre_exec(regex, regex_extra, + &b58[p], sizeof(b58) - (p+1), 0, + 0, + re_vec, sizeof(re_vec)/sizeof(re_vec[0])); + + if (d > 0) { + printf("\n"); + + if (npoints) { + BN_clear(&bntmp); + BN_set_word(&bntmp, npoints); + BN_add(&bntmp2, + EC_KEY_get0_private_key(pkey), + &bntmp); + EC_KEY_set_private_key(pkey, &bntmp2); + } + + EC_KEY_set_public_key(pkey, ppnt); + + output_match(pkey, addrtype, privtype); + break; + } + + if (d != PCRE_ERROR_NOMATCH) { + printf("PCRE error: %d\n", d); + break; + } + + if (++c >= 10000) { + long long rate; + gettimeofday(&tvnow, NULL); + timersub(&tvnow, &tvstart, &tv); + memcpy(&tvstart, &tvnow, sizeof(tvstart)); + rate = tv.tv_usec + (1000000 * tv.tv_sec); + rate = (1000000ULL * c) / rate; + t += c; + + c = 0; + printf("\r%lld K/s, total %d ", rate, t); + fflush(stdout); + } + } + + BN_clear_free(&bna); + BN_clear_free(&bnb); + BN_clear_free(&bnbase); + BN_clear_free(&bnrem); + BN_clear_free(&bntmp); + BN_clear_free(&bntmp2); + BN_CTX_free(bnctx); + EC_KEY_free(pkey); + EC_POINT_free(ppnt); + pcre_free(regex_extra); + pcre_free(regex); +} + +void +usage(const char *name) +{ + printf( +"Usage: %s [-rNT] \n" +"Generates a bitcoin receiving address matching , 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, is interpreted as an exact prefix.\n" +"\n" +"Options:\n" +"-r Use regular expression match instead of prefix\n" +" (Feasibility of expression is not checked)\n" +"-N Generate namecoin address\n" +"-T Generate bitcoin testnet address\n", name); +} + +int +main(int argc, char **argv) +{ + int addrtype = 0; + int privtype = 128; + int regex = 0; + int opt; + const char *pattern = argv[1]; + + while ((opt = getopt(argc, argv, "rNTh?")) != -1) { + switch (opt) { + case 'r': + regex = 1; + break; + case 'N': + addrtype = 52; + break; + case 'T': + addrtype = 111; + privtype = 239; + break; + default: + usage(argv[0]); + return 1; + } + } + + if (optind >= argc) { + usage(argv[0]); + return 1; + } + + pattern = argv[optind]; + + if (regex) + generate_address_regex(addrtype, privtype, pattern); + else + generate_address_prefix(addrtype, privtype, pattern); + + return 0; +}