From 055f932e67614dfaa24abfa5f1f6bcdf9f48bf42 Mon Sep 17 00:00:00 2001 From: 10gic <2391796+10gic@users.noreply.github.com> Date: Sat, 2 Jan 2021 23:29:35 +0800 Subject: [PATCH] Support customizing prefix of private key (binary) --- Makefile | 1 + README.md | 29 +++++++++++++++++++++++++- oclengine.c | 22 +++++++++++--------- oclvanitygen.c | 29 +++++++++++++++++++++++--- pattern.h | 2 +- util.c | 18 +++++++++++++++++ util.h | 1 + vanitygen.c | 55 +++++++++++++++++++++++++++++++++++++++----------- 8 files changed, 131 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index 3f34473..d11fb1f 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ ## If compiling on mac, comment out LIBS and CFLAGS below, and use the MacOS ones below LIBS=-lpcre -lcrypto -lm -lpthread CFLAGS=-ggdb -O3 -Wall +# CFLAGS=-ggdb -O3 -Wall -I /usr/local/cuda-10.2/include/ ## If compiling on a mac make sure you install and use homebrew and run the following command `brew install pcre pcre++` ## Uncomment lines below and run `make all` diff --git a/README.md b/README.md index bb4b2a2..7b7fbeb 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,13 @@ Vanity address generator for BTC, ETH, LTC, etc (more than 100 crypto currencies). # Build -Run: +Intall building dependencies in Redhat/CentOS: +``` +$ yum install openssl-devel +$ yum install libcurl-devel +``` + +Build executable file: ``` $ make # build: vanitygen++ keyconv $ make all # build: vanitygen++ keyconv oclvanitygen++ oclvanityminer @@ -52,6 +58,27 @@ ETH Privkey: 0xdb3813534c0c9595f9b8b35d6f544827065b33930ae42c38a9d7ce41a1d74669 If you have OpenCL-compatible GPU, please use `oclvanitygen++`, it's faster. +# Solve Puzzle +This tool can be used for solving the [Bitcoin puzzle](https://bitcointalk.org/index.php?topic=1306983.0). + +For example, solve puzzle 6: +``` +$ ./vanitygen++ -F compressed -Z 0000000000000000000000000000000000000000000000000000000000000000 -l $((256-6)) 1PitScNLyp2HCygzad +Difficulty: 376259307977702824629384382540 +Pattern: 1PitScNLyp2HCygzad +Address: 1PitScNLyp2HCygzadCh7FveTnfmpPbfp8 +Privkey: KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU7Tmu6qHxS +``` + +Solve puzzle 20: +``` +$ ./vanitygen++ -F compressed -Z 0000000000000000000000000000000000000000000000000000000000000000 -l $((256-20)) 1HsMJxNiV7TLxmoF6u +Difficulty: 376259307977702824629384382540 +Pattern: 1HsMJxNiV7TLxmoF6u +Address: 1HsMJxNiV7TLxmoF6uJNkydxPFDog4NQum +Privkey: KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rHfuE2Tg4nJW +``` + # Credit Many thanks to following projects: 1. https://github.com/samr7/vanitygen diff --git a/oclengine.c b/oclengine.c index bee2473..086663b 100644 --- a/oclengine.c +++ b/oclengine.c @@ -2100,24 +2100,28 @@ vg_opencl_loop(vg_exec_context_t *arg) vg_exec_context_upgrade_lock(vxcp); pattern_generation = vcp->vc_pattern_generation; - +regen_key: /* Generate a new random private key */ EC_KEY_generate_key(pkey); npoints = 0; - if (vcp->vc_privkey_prefix_length > 0) { + if (vcp->vc_privkey_prefix_nbits > 0) { + /* Adjust private key to meet the requirement of privkey prefix (specified by option -Z) */ BIGNUM *pkbn = BN_dup(EC_KEY_get0_private_key(pkey)); unsigned char pkey_arr[32]; assert(BN_bn2bin(pkbn, pkey_arr) < 33); - memcpy((char *) pkey_arr, vcp->vc_privkey_prefix, vcp->vc_privkey_prefix_length); - for (i = 0; i < vcp->vc_privkey_prefix_length / 2; i++) { - int k = pkey_arr[i]; - pkey_arr[i] = pkey_arr[vcp->vc_privkey_prefix_length - 1 - i]; - pkey_arr[vcp->vc_privkey_prefix_length - 1 - i] = k; - } + copy_nbits((unsigned char *) pkey_arr, (unsigned char *)vcp->vc_privkey_prefix, vcp->vc_privkey_prefix_nbits); BN_bin2bn(pkey_arr, 32, pkbn); - EC_KEY_set_private_key(pkey, pkbn); + if (BN_is_zero(pkbn)) { + fprintf(stderr, "the generated private key is zero, regenerate it\n"); + goto regen_key; + } + // FIXME: private key (pbkn) may be too big if prefix specified by -Z has many FF + EC_KEY_set_private_key(pkey, pkbn); /* set private key in pkey */ EC_POINT *origin = EC_POINT_new(pgroup); + /* EC_POINT_mul: compute public_key = k * private_key + here, origin is public_key, pkbn is private_key + save public_key into 2nd param (origin) */ EC_POINT_mul(pgroup, origin, pkbn, NULL, NULL, vxcp->vxc_bnctx); EC_KEY_set_public_key(pkey, origin); } diff --git a/oclvanitygen.c b/oclvanitygen.c index e40a96b..5a5cb0f 100644 --- a/oclvanitygen.c +++ b/oclvanitygen.c @@ -88,6 +88,7 @@ usage(const char *name) "-o Write pattern matches to \n" "-s Seed random number generator from \n" "-Z Private key prefix in hex (1Address.io Dapp front-running protection)\n" +"-l Specify the bits of prefix, only relevant when -Z is specified\n" "-z Format output of matches in CSV(disables verbose mode)\n" " Output as [COIN],[PREFIX],[ADDRESS],[PRIVKEY]\n", version, name); @@ -131,6 +132,7 @@ main(int argc, char **argv) int opened = 0; char privkey_prefix[32]; int privkey_prefix_length = 0; + int privkey_prefix_nbits = 0; FILE *pattfp[MAX_FILE], *fp; int pattfpi[MAX_FILE]; @@ -142,7 +144,7 @@ main(int argc, char **argv) int i; while ((opt = getopt(argc, argv, - "vqrik1zC:X:Y:F:eE:p:P:d:w:t:g:b:VSh?f:o:s:D:Z:a:")) != -1) { + "vqrik1zC:X:Y:F:eE:p:P:d:w:t:g:b:VSh?f:o:s:D:Z:a:l:")) != -1) { switch (opt) { case 'r': regex = 1; @@ -368,9 +370,12 @@ main(int argc, char **argv) for (i = 0; i < privkey_prefix_length; i++) { int value; // Can't sscanf directly to char array because of overlapping on Win32 sscanf(&optarg[i*2], "%2x", &value); - privkey_prefix[privkey_prefix_length - 1 - i] = value; + privkey_prefix[i] = value; } break; + case 'l': + privkey_prefix_nbits = atoi(optarg); + break; default: usage(argv[0]); return 1; @@ -386,6 +391,24 @@ main(int argc, char **argv) } #endif + /* Option -Z can be used with or without option -l + but, option -l must use together with option -Z */ + if (privkey_prefix_length == 0) { /* -Z not specified */ + if (privkey_prefix_nbits > 0) { /* -l specified */ + fprintf(stderr, "-l must use together with -Z)\n"); + return 1; + } + } else if (privkey_prefix_length > 0) { /* -Z specified */ + if (privkey_prefix_nbits == 0) { /* -l not specified */ + privkey_prefix_nbits = privkey_prefix_length * 8; + } else if (privkey_prefix_nbits > 0) { /* -l specified */ + if (privkey_prefix_nbits > privkey_prefix_length * 8) { + fprintf(stderr, "bits (specified by -l) is too big, must small than bits of prefix (%d bits)\n", privkey_prefix_length * 8); + return 1; + } + } + } + if (caseinsensitive && regex) fprintf(stderr, "WARNING: case insensitive mode incompatible with " @@ -430,7 +453,7 @@ main(int argc, char **argv) vcp->vc_pubkeytype = addrtype; vcp->vc_pubkey_base = pubkey_base; memcpy(vcp->vc_privkey_prefix, privkey_prefix, privkey_prefix_length); - vcp->vc_privkey_prefix_length = privkey_prefix_length; + vcp->vc_privkey_prefix_nbits = privkey_prefix_nbits; vcp->vc_output_match = vg_output_match_console; vcp->vc_output_timing = vg_output_timing_console; diff --git a/pattern.h b/pattern.h index 5b4089e..5373b0d 100644 --- a/pattern.h +++ b/pattern.h @@ -114,7 +114,7 @@ struct _vg_context_s { int vc_pubkeytype; EC_POINT *vc_pubkey_base; char vc_privkey_prefix[32]; - int vc_privkey_prefix_length; + int vc_privkey_prefix_nbits; int vc_halt; vg_exec_context_t *vc_threads; diff --git a/util.c b/util.c index 0f46044..8c87bb3 100644 --- a/util.c +++ b/util.c @@ -1455,3 +1455,21 @@ eth_encode_checksum_addr(void * input, int inlen, char *output, int outlen) } } } + +// Like memcpy, but length specified by bits (rather than bytes) +void copy_nbits(unsigned char *dst, unsigned char *src, int nbits) { + // An example: + // dst(input): MMMMMMMM NNNNNNNN + // src: IIIIIIII JJJJJJJJ + // nbits: 11 + // dst(output): IIIIIIII JJJNNNNN + int nbytes = (nbits / 8) + 1; // (11 / 8) + 1 = 2 + int extra_nbits = nbytes * 8 - nbits; // 2 * 8 - 11 = 5 + char tab[8] = {0, 1, 3 /* 2 bits 1 */, 7 /* 3 bits 1 */, 15 /* 4 bits 1 */, 31 /* 5 bits 1 */, + 63 /* 6 bits 1 */, 127 /* 7 bits 1 */}; + unsigned char backup = dst[nbytes - 1]; // NNNNNNNN + memcpy(dst, src, nbytes); + unsigned char after = dst[nbytes - 1]; // JJJJJJJJ + dst[nbytes - 1] = (backup & tab[extra_nbits]) // 000NNNNN + | (after & ~tab[extra_nbits]); // JJJ00000 +} diff --git a/util.h b/util.h index e4523ed..cea08b4 100644 --- a/util.h +++ b/util.h @@ -92,4 +92,5 @@ extern void eth_pubkey2addr(const unsigned char* pubkey_buf, int addrformat, uns extern void eth_encode_checksum_addr(void *input, int inlen, char *output, int outlen); +extern void copy_nbits(unsigned char *dst, unsigned char *src, int nbits); #endif /* !defined (__VG_UTIL_H__) */ diff --git a/vanitygen.c b/vanitygen.c index c481610..ea19ff9 100644 --- a/vanitygen.c +++ b/vanitygen.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "pattern.h" #include "util.h" @@ -127,24 +128,29 @@ vg_thread_loop(void *arg) while (!vcp->vc_halt) { if (++npoints >= rekey_at) { vg_exec_context_upgrade_lock(vxcp); + regen_key: /* Generate a new random private key */ EC_KEY_generate_key(pkey); - if (vcp->vc_privkey_prefix_length > 0) { + if (vcp->vc_privkey_prefix_nbits > 0) { + /* Adjust private key to meet the requirement of privkey prefix (specified by option -Z) */ BIGNUM *pkbn = BN_dup(EC_KEY_get0_private_key(pkey)); unsigned char pkey_arr[32]; assert(BN_bn2bin(pkbn, pkey_arr) < 33); - memcpy((char *) pkey_arr, vcp->vc_privkey_prefix, vcp->vc_privkey_prefix_length); - for (i = 0; i < vcp->vc_privkey_prefix_length / 2; i++) { - int k = pkey_arr[i]; - pkey_arr[i] = pkey_arr[vcp->vc_privkey_prefix_length - 1 - i]; - pkey_arr[vcp->vc_privkey_prefix_length - 1 - i] = k; - } + copy_nbits((unsigned char *) pkey_arr, (unsigned char *)vcp->vc_privkey_prefix, vcp->vc_privkey_prefix_nbits); BN_bin2bn(pkey_arr, 32, pkbn); - EC_KEY_set_private_key(pkey, pkbn); + if (BN_is_zero(pkbn)) { + fprintf(stderr, "the generated private key is zero, regenerate it\n"); + goto regen_key; + } + // FIXME: private key (pbkn) may be too big if prefix specified by -Z has many FF + EC_KEY_set_private_key(pkey, pkbn); /* set private key in pkey */ EC_POINT *origin = EC_POINT_new(pgroup); + /* EC_POINT_mul: compute public_key = k * private_key + here, origin is public_key, pkbn is private_key + save public_key into 2nd param (origin) */ EC_POINT_mul(pgroup, origin, pkbn, NULL, NULL, vxcp->vxc_bnctx); - EC_KEY_set_public_key(pkey, origin); + EC_KEY_set_public_key(pkey, origin); /* set public key in pkey */ } npoints = 0; @@ -194,6 +200,8 @@ vg_thread_loop(void *arg) for (nbatch = 0; (nbatch < ptarraysize) && (npoints < rekey_at); nbatch++, npoints++) { + /* compute public keys from continuous private key, + save public keys into array ppnt */ EC_POINT_add(pgroup, ppnt[nbatch], ppnt[nbatch], @@ -332,6 +340,7 @@ usage(const char *name) "-o Write pattern matches to \n" "-s Seed random number generator from \n" "-Z Private key prefix in hex (1Address.io Dapp front-running protection)\n" +"-l Specify the bits of prefix, only relevant when -Z is specified\n" "-z Format output of matches in CSV(disables verbose mode)\n" " Output as [COIN],[PREFIX],[ADDRESS],[PRIVKEY]\n", version, name); @@ -368,6 +377,7 @@ main(int argc, char **argv) EC_POINT *pubkey_base = NULL; char privkey_prefix[32]; int privkey_prefix_length = 0; + int privkey_prefix_nbits = 0; FILE *pattfp[MAX_FILE], *fp; int pattfpi[MAX_FILE]; @@ -377,7 +387,7 @@ main(int argc, char **argv) int i; - while ((opt = getopt(argc, argv, "vqnrik1ezE:P:C:X:Y:F:t:h?f:o:s:Z:a:")) != -1) { + while ((opt = getopt(argc, argv, "vqnrik1ezE:P:C:X:Y:F:t:h?f:o:s:Z:a:l:")) != -1) { switch (opt) { case 'c': compressed = 1; @@ -565,9 +575,12 @@ main(int argc, char **argv) for (i = 0; i < privkey_prefix_length; i++) { int value; // Can't sscanf directly to char array because of overlapping on Win32 sscanf(&optarg[i*2], "%2x", &value); - privkey_prefix[privkey_prefix_length - 1 - i] = value; + privkey_prefix[i] = value; } break; + case 'l': + privkey_prefix_nbits = atoi(optarg); + break; default: usage(argv[0]); return 1; @@ -658,6 +671,24 @@ main(int argc, char **argv) return 0; } + /* Option -Z can be used with or without option -l + but, option -l must use together with option -Z */ + if (privkey_prefix_length == 0) { /* -Z not specified */ + if (privkey_prefix_nbits > 0) { /* -l specified */ + fprintf(stderr, "-l must use together with -Z)\n"); + return 1; + } + } else if (privkey_prefix_length > 0) { /* -Z specified */ + if (privkey_prefix_nbits == 0) { /* -l not specified */ + privkey_prefix_nbits = privkey_prefix_length * 8; + } else if (privkey_prefix_nbits > 0) { /* -l specified */ + if (privkey_prefix_nbits > privkey_prefix_length * 8) { + fprintf(stderr, "bits (specified by -l) is too big, must small than bits of prefix (%d bits)\n", privkey_prefix_length * 8); + return 1; + } + } + } + if (caseinsensitive && regex) fprintf(stderr, "WARNING: case insensitive mode incompatible with " @@ -714,7 +745,7 @@ main(int argc, char **argv) vcp->vc_pubkeytype = pubkeytype; vcp->vc_pubkey_base = pubkey_base; memcpy(vcp->vc_privkey_prefix, privkey_prefix, privkey_prefix_length); - vcp->vc_privkey_prefix_length = privkey_prefix_length; + vcp->vc_privkey_prefix_nbits = privkey_prefix_nbits; vcp->vc_output_match = vg_output_match_console; vcp->vc_output_timing = vg_output_timing_console;