diff --git a/keyconv.c b/keyconv.c index a345d45..1283fa1 100644 --- a/keyconv.c +++ b/keyconv.c @@ -24,10 +24,11 @@ usage(const char *progname) { fprintf(stderr, "Vanitygen keyconv %s\n" -"Usage: %s [-8] [-e|-E ] []\n" +"Usage: %s [-8] [-e|-E ] [-c ] []\n" "-8 Output key in PKCS#8 form\n" "-e Encrypt output key, prompt for password\n" -"-E Encrypt output key with (UNSAFE)\n", +"-E Encrypt output key with (UNSAFE)\n" +"-c Combine private key parts to make complete private key", version, progname); } @@ -40,6 +41,7 @@ main(int argc, char **argv) char pbuf[1024]; const char *key_in; const char *pass_in = NULL; + const char *key2_in = NULL; EC_KEY *pkey; int parameter_group = -1; int privtype, addrtype; @@ -48,7 +50,7 @@ main(int argc, char **argv) int opt; int res; - while ((opt = getopt(argc, argv, "8E:e")) != -1) { + while ((opt = getopt(argc, argv, "8E:ec:")) != -1) { switch (opt) { case '8': pkcs8 = 1; @@ -70,6 +72,9 @@ main(int argc, char **argv) } pass_prompt = 1; break; + case 'c': + key2_in = optarg; + break; default: usage(argv[0]); return 1; @@ -101,6 +106,33 @@ main(int argc, char **argv) return 1; } + if (key2_in) { + BIGNUM bntmp; + EC_KEY *pkey2; + + pkey2 = EC_KEY_new_by_curve_name(NID_secp256k1); + res = vg_decode_privkey_any(pkey2, &privtype, key2_in, NULL); + if (res < 0) { + if (EVP_read_pw_string(pwbuf, sizeof(pwbuf), + "Enter import password:", 0) || + !vg_decode_privkey_any(pkey2, &privtype, + key2_in, pwbuf)) + return 1; + } + + if (!res) { + fprintf(stderr, "ERROR: Unrecognized key format\n"); + return 1; + } + BN_init(&bntmp); + BN_add(&bntmp, + EC_KEY_get0_private_key(pkey), + EC_KEY_get0_private_key(pkey2)); + vg_set_privkey(&bntmp, pkey); + EC_KEY_free(pkey2); + BN_clear_free(&bntmp); + } + if (pass_prompt) { res = EVP_read_pw_string(pwbuf, sizeof(pwbuf), "Enter password:", 1); @@ -138,13 +170,17 @@ main(int argc, char **argv) return 1; } - vg_encode_address(pkey, addrtype, pwbuf); + vg_encode_address(EC_KEY_get0_public_key(pkey), + EC_KEY_get0_group(pkey), + addrtype, pwbuf); printf("Address: %s\n", pwbuf); printf("Protkey: %s\n", ecprot); } else { - vg_encode_address(pkey, addrtype, ecprot); + vg_encode_address(EC_KEY_get0_public_key(pkey), + EC_KEY_get0_group(pkey), + addrtype, ecprot); printf("Address: %s\n", ecprot); vg_encode_privkey(pkey, privtype, ecprot); printf("Privkey: %s\n", ecprot); diff --git a/oclvanitygen.c b/oclvanitygen.c index afcece6..7b204fb 100644 --- a/oclvanitygen.c +++ b/oclvanitygen.c @@ -2124,6 +2124,14 @@ l_rekey: EC_POINT_copy(ppbase[0], EC_KEY_get0_public_key(pkey)); + if (vcp->vc_pubkey_base) { + EC_POINT_add(pgroup, + ppbase[0], + ppbase[0], + vcp->vc_pubkey_base, + vxcp->vxc_bnctx); + } + /* Build the base array of sequential points */ for (i = 1; i < ncols; i++) { EC_POINT_add(pgroup, @@ -2590,11 +2598,12 @@ main(int argc, char **argv) int safe_mode = 0; vg_context_t *vcp = NULL; cl_device_id did; + EC_POINT *pubkey_base = NULL; const char *result_file = NULL; const char *key_password = NULL; while ((opt = getopt(argc, argv, - "vqrikNTX:eE:p:d:w:t:g:b:VSh?f:o:s:")) != -1) { + "vqrikNTX:eE:p:P:d:w:t:g:b:VSh?f:o:s:")) != -1) { switch (opt) { case 'v': verbose = 2; @@ -2684,6 +2693,24 @@ main(int argc, char **argv) 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"); @@ -2785,6 +2812,7 @@ main(int argc, char **argv) vcp->vc_verbose = verbose; vcp->vc_result_file = result_file; vcp->vc_remove_on_match = remove_on_match; + vcp->vc_pubkey_base = pubkey_base; if (!vg_context_add_patterns(vcp, patterns, npatterns)) return 1; diff --git a/pattern.c b/pattern.c index a72a7e9..9f874d6 100644 --- a/pattern.c +++ b/pattern.c @@ -39,6 +39,12 @@ * Common code for execution helper */ +EC_KEY * +vg_exec_context_new_key(void) +{ + return EC_KEY_new_by_curve_name(NID_secp256k1); +} + int vg_exec_context_init(vg_context_t *vcp, vg_exec_context_t *vxcp) { @@ -55,7 +61,7 @@ vg_exec_context_init(vg_context_t *vcp, vg_exec_context_t *vxcp) vxcp->vxc_bnctx = BN_CTX_new(); assert(vxcp->vxc_bnctx); - vxcp->vxc_key = EC_KEY_new_by_curve_name(NID_secp256k1); + vxcp->vxc_key = vg_exec_context_new_key(); assert(vxcp->vxc_key); EC_KEY_precompute_mult(vxcp->vxc_key, vxcp->vxc_bnctx); return 1; @@ -89,14 +95,24 @@ vg_exec_context_consolidate_key(vg_exec_context_t *vxcp) void vg_exec_context_calc_address(vg_exec_context_t *vxcp) { + EC_POINT *pubkey; const EC_GROUP *pgroup; unsigned char eckey_buf[96], hash1[32], hash2[20]; int len; vg_exec_context_consolidate_key(vxcp); pgroup = EC_KEY_get0_group(vxcp->vxc_key); + pubkey = EC_POINT_new(pgroup); + EC_POINT_copy(pubkey, EC_KEY_get0_public_key(vxcp->vxc_key)); + if (vxcp->vxc_vc->vc_pubkey_base) { + EC_POINT_add(pgroup, + pubkey, + pubkey, + vxcp->vxc_vc->vc_pubkey_base, + vxcp->vxc_bnctx); + } len = EC_POINT_point2oct(pgroup, - EC_KEY_get0_public_key(vxcp->vxc_key), + pubkey, POINT_CONVERSION_UNCOMPRESSED, eckey_buf, sizeof(eckey_buf), @@ -105,6 +121,7 @@ vg_exec_context_calc_address(vg_exec_context_t *vxcp) RIPEMD160(hash1, sizeof(hash1), hash2); memcpy(&vxcp->vxc_binres[1], hash2, 20); + EC_POINT_free(pubkey); } enum { @@ -310,10 +327,30 @@ vg_output_match(vg_context_t *vcp, EC_KEY *pkey, const char *pattern) int len; int isscript = (vcp->vc_format == VCF_SCRIPT); + EC_POINT *ppnt; + int free_ppnt = 0; + if (vcp->vc_pubkey_base) { + ppnt = EC_POINT_new(EC_KEY_get0_group(pkey)); + EC_POINT_copy(ppnt, EC_KEY_get0_public_key(pkey)); + EC_POINT_add(EC_KEY_get0_group(pkey), + ppnt, + ppnt, + vcp->vc_pubkey_base, + NULL); + free_ppnt = 1; + keytype = "PrivkeyPart"; + } else { + ppnt = (EC_POINT *) EC_KEY_get0_public_key(pkey); + } + assert(EC_KEY_check_key(pkey)); - vg_encode_address(pkey, vcp->vc_pubkeytype, addr_buf); + vg_encode_address(ppnt, + EC_KEY_get0_group(pkey), + vcp->vc_pubkeytype, addr_buf); if (isscript) - vg_encode_script_address(pkey, vcp->vc_addrtype, addr2_buf); + vg_encode_script_address(ppnt, + EC_KEY_get0_group(pkey), + vcp->vc_addrtype, addr2_buf); if (vcp->vc_key_protect_pass) { len = vg_protect_encode_privkey(privkey_buf, @@ -349,7 +386,6 @@ vg_output_match(vg_context_t *vcp, EC_KEY *pkey, const char *pattern) printf("Privkey (ASN1): "); dumphex(key_buf, len); } - } if (!vcp->vc_result_file || (vcp->vc_verbose > 0)) { @@ -379,6 +415,8 @@ vg_output_match(vg_context_t *vcp, EC_KEY *pkey, const char *pattern) fclose(fp); } } + if (free_ppnt) + EC_POINT_free(ppnt); } diff --git a/pattern.h b/pattern.h index c9cb0e7..70f86d6 100644 --- a/pattern.h +++ b/pattern.h @@ -54,12 +54,13 @@ extern int vg_exec_context_init(vg_context_t *vcp, vg_exec_context_t *vxcp); extern void vg_exec_context_del(vg_exec_context_t *vxcp); extern void vg_exec_context_consolidate_key(vg_exec_context_t *vxcp); extern void vg_exec_context_calc_address(vg_exec_context_t *vxcp); +extern EC_KEY *vg_exec_context_new_key(void); + /* Implementation-specific lock/unlock/consolidate */ extern void vg_exec_downgrade_lock(vg_exec_context_t *vxcp); extern int vg_exec_upgrade_lock(vg_exec_context_t *vxcp); - typedef void (*vg_free_func_t)(vg_context_t *); typedef int (*vg_add_pattern_func_t)(vg_context_t *, char ** const patterns, int npatterns); @@ -89,6 +90,7 @@ struct _vg_context_s { vg_hash160_sort_func_t vc_hash160_sort; enum vg_format vc_format; int vc_pubkeytype; + EC_POINT *vc_pubkey_base; }; diff --git a/util.c b/util.c index 4f7fee6..165f82c 100644 --- a/util.c +++ b/util.c @@ -236,7 +236,8 @@ out: } void -vg_encode_address(const EC_KEY *pkey, int addrtype, char *result) +vg_encode_address(const EC_POINT *ppoint, const EC_GROUP *pgroup, + int addrtype, char *result) { unsigned char eckey_buf[128], *pend; unsigned char binres[21] = {0,}; @@ -244,8 +245,13 @@ vg_encode_address(const EC_KEY *pkey, int addrtype, char *result) pend = eckey_buf; - i2o_ECPublicKey((EC_KEY*)pkey, &pend); - + EC_POINT_point2oct(pgroup, + ppoint, + POINT_CONVERSION_UNCOMPRESSED, + eckey_buf, + sizeof(eckey_buf), + NULL); + pend = eckey_buf + 0x41; binres[0] = addrtype; SHA256(eckey_buf, pend - eckey_buf, hash1); RIPEMD160(hash1, sizeof(hash1), &binres[1]); @@ -254,7 +260,8 @@ vg_encode_address(const EC_KEY *pkey, int addrtype, char *result) } void -vg_encode_script_address(const EC_KEY *pkey, int addrtype, char *result) +vg_encode_script_address(const EC_POINT *ppoint, const EC_GROUP *pgroup, + int addrtype, char *result) { unsigned char script_buf[69]; unsigned char *eckey_buf = script_buf + 2; @@ -267,9 +274,12 @@ vg_encode_script_address(const EC_KEY *pkey, int addrtype, char *result) script_buf[67] = 0x51; // OP_1 script_buf[68] = 0xae; // OP_CHECKMULTISIG - i2o_ECPublicKey((EC_KEY*)pkey, &eckey_buf); - assert(eckey_buf - script_buf == 67); - + EC_POINT_point2oct(pgroup, + ppoint, + POINT_CONVERSION_UNCOMPRESSED, + eckey_buf, + 65, + NULL); binres[0] = addrtype; SHA256(script_buf, 69, hash1); RIPEMD160(hash1, sizeof(hash1), &binres[1]); diff --git a/util.h b/util.h index e25b313..5969b87 100644 --- a/util.h +++ b/util.h @@ -36,8 +36,11 @@ extern void dumpbn(const BIGNUM *bn); extern void vg_b58_encode_check(void *buf, size_t len, char *result); extern int vg_b58_decode_check(const char *input, void *buf, size_t len); -extern void vg_encode_address(const EC_KEY *pkey, int addrtype, char *result); -extern void vg_encode_script_address(const EC_KEY *pkey, int addrtype, char *result); +extern void vg_encode_address(const EC_POINT *ppoint, const EC_GROUP *pgroup, + int addrtype, char *result); +extern void vg_encode_script_address(const EC_POINT *ppoint, + const EC_GROUP *pgroup, + int addrtype, char *result); extern void vg_encode_privkey(const EC_KEY *pkey, int addrtype, char *result); extern int vg_set_privkey(const BIGNUM *bnpriv, EC_KEY *pkey); extern int vg_decode_privkey(const char *b58encoded, diff --git a/vanitygen.c b/vanitygen.c index 4d3f39f..d11dd04 100644 --- a/vanitygen.c +++ b/vanitygen.c @@ -304,6 +304,13 @@ vg_thread_loop(void *arg) npoints++; vxcp->vxc_delta = 0; + if (vcp->vc_pubkey_base) + EC_POINT_add(pgroup, + ppnt[0], + ppnt[0], + vcp->vc_pubkey_base, + vxcp->vxc_bnctx); + for (nbatch = 1; (nbatch < ptarraysize) && (npoints < rekey_at); nbatch++, npoints++) { @@ -468,6 +475,7 @@ usage(const char *name) "-T Generate bitcoin testnet address\n" "-X Generate address with the given version\n" "-F Generate address with the given format (pubkey or script)\n" +"-P Specify base public key for piecewise key generation\n" "-e Encrypt private keys, prompt for password\n" "-E Encrypt private keys with (UNSAFE)\n" "-t Set number of worker threads (Default: number of CPUs)\n" @@ -501,8 +509,9 @@ main(int argc, char **argv) int npatterns = 0; int nthreads = 0; vg_context_t *vcp = NULL; + EC_POINT *pubkey_base = NULL; - while ((opt = getopt(argc, argv, "vqrikeE:NTXF:t:h?f:o:s:")) != -1) { + while ((opt = getopt(argc, argv, "vqrikeE:P:NTXF:t:h?f:o:s:")) != -1) { switch (opt) { case 'v': verbose = 2; @@ -538,13 +547,31 @@ main(int argc, char **argv) if (!strcmp(optarg, "script")) format = VCF_SCRIPT; else - if (strcmp(optarg, "pubkey")) - { + if (strcmp(optarg, "pubkey")) { fprintf(stderr, "Invalid format '%s'\n", optarg); return 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 'e': prompt_password = 1; break; @@ -675,6 +702,7 @@ main(int argc, char **argv) vcp->vc_remove_on_match = remove_on_match; vcp->vc_format = format; vcp->vc_pubkeytype = pubkeytype; + vcp->vc_pubkey_base = pubkey_base; if (!vg_context_add_patterns(vcp, patterns, npatterns)) return 1;