diff --git a/pattern.c b/pattern.c index 1e71444..a72a7e9 100644 --- a/pattern.c +++ b/pattern.c @@ -304,13 +304,16 @@ void vg_output_match(vg_context_t *vcp, EC_KEY *pkey, const char *pattern) { unsigned char key_buf[512], *pend; - char addr_buf[64]; + char addr_buf[64], addr2_buf[64]; char privkey_buf[VG_PROTKEY_MAX_B58]; const char *keytype = "Privkey"; int len; + int isscript = (vcp->vc_format == VCF_SCRIPT); assert(EC_KEY_check_key(pkey)); - vg_encode_address(pkey, vcp->vc_addrtype, addr_buf); + vg_encode_address(pkey, vcp->vc_pubkeytype, addr_buf); + if (isscript) + vg_encode_script_address(pkey, vcp->vc_addrtype, addr2_buf); if (vcp->vc_key_protect_pass) { len = vg_protect_encode_privkey(privkey_buf, @@ -350,6 +353,8 @@ vg_output_match(vg_context_t *vcp, EC_KEY *pkey, const char *pattern) } if (!vcp->vc_result_file || (vcp->vc_verbose > 0)) { + if (isscript) + printf("P2SHAddress: %s\n", addr2_buf); printf("Address: %s\n" "%s: %s\n", addr_buf, keytype, privkey_buf); @@ -364,9 +369,13 @@ vg_output_match(vg_context_t *vcp, EC_KEY *pkey, const char *pattern) } else { fprintf(fp, "Pattern: %s\n" + , pattern); + if (isscript) + fprintf(fp, "P2SHAddress: %s\n", addr2_buf); + fprintf(fp, "Address: %s\n" "%s: %s\n", - pattern, addr_buf, keytype, privkey_buf); + addr_buf, keytype, privkey_buf); fclose(fp); } } @@ -1478,6 +1487,10 @@ vg_prefix_context_add_patterns(vg_context_t *vcp, if (!npfx && impossible) { const char *ats = "bitcoin", *bw = "\"1\""; switch (vcpp->base.vc_addrtype) { + case 5: + ats = "bitcoin script"; + bw = "\"3\""; + break; case 111: ats = "testnet"; bw = "\"m\" or \"n\""; diff --git a/pattern.h b/pattern.h index 5d3cf38..c9cb0e7 100644 --- a/pattern.h +++ b/pattern.h @@ -66,6 +66,11 @@ typedef int (*vg_add_pattern_func_t)(vg_context_t *, typedef int (*vg_test_func_t)(vg_exec_context_t *); typedef int (*vg_hash160_sort_func_t)(vg_context_t *vcp, void *buf); +enum vg_format { + VCF_PUBKEY, + VCF_SCRIPT, +}; + /* Application-level context, incl. parameters and global pattern store */ struct _vg_context_s { int vc_addrtype; @@ -82,6 +87,8 @@ struct _vg_context_s { vg_add_pattern_func_t vc_add_patterns; vg_test_func_t vc_test; vg_hash160_sort_func_t vc_hash160_sort; + enum vg_format vc_format; + int vc_pubkeytype; }; diff --git a/util.c b/util.c index 7a90d84..4f7fee6 100644 --- a/util.c +++ b/util.c @@ -253,6 +253,30 @@ vg_encode_address(const EC_KEY *pkey, int addrtype, char *result) vg_b58_encode_check(binres, sizeof(binres), result); } +void +vg_encode_script_address(const EC_KEY *pkey, int addrtype, char *result) +{ + unsigned char script_buf[69]; + unsigned char *eckey_buf = script_buf + 2; + unsigned char binres[21] = {0,}; + unsigned char hash1[32]; + + script_buf[ 0] = 0x51; // OP_1 + script_buf[ 1] = 0x41; // pubkey length + // gap for pubkey + 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); + + binres[0] = addrtype; + SHA256(script_buf, 69, hash1); + RIPEMD160(hash1, sizeof(hash1), &binres[1]); + + vg_b58_encode_check(binres, sizeof(binres), result); +} + void vg_encode_privkey(const EC_KEY *pkey, int addrtype, char *result) { diff --git a/util.h b/util.h index 3cffb75..e25b313 100644 --- a/util.h +++ b/util.h @@ -37,6 +37,7 @@ 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_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 33c20a2..4d3f39f 100644 --- a/vanitygen.c +++ b/vanitygen.c @@ -205,10 +205,12 @@ vg_exec_upgrade_lock(vg_exec_context_t *vxcp) void * vg_thread_loop(void *arg) { - unsigned char eckey_buf[128]; + unsigned char hash_buf[128]; + unsigned char *eckey_buf; unsigned char hash1[32]; int i, c, len, output_interval; + int hash_len; const BN_ULONG rekey_max = 10000000; BN_ULONG npoints, rekey_at, nbatch; @@ -264,6 +266,20 @@ vg_thread_loop(void *arg) output_interval = 1000; gettimeofday(&tvstart, NULL); + if (vcp->vc_format == VCF_SCRIPT) { + hash_buf[ 0] = 0x51; // OP_1 + hash_buf[ 1] = 0x41; // pubkey length + // gap for pubkey + hash_buf[67] = 0x51; // OP_1 + hash_buf[68] = 0xae; // OP_CHECKMULTISIG + eckey_buf = hash_buf + 2; + hash_len = 69; + + } else { + eckey_buf = hash_buf; + hash_len = 65; + } + while (1) { if (++npoints >= rekey_at) { pthread_mutex_lock(&vg_thread_lock); @@ -336,10 +352,11 @@ vg_thread_loop(void *arg) len = EC_POINT_point2oct(pgroup, ppnt[i], POINT_CONVERSION_UNCOMPRESSED, eckey_buf, - sizeof(eckey_buf), + 65, vxcp->vxc_bnctx); + assert(len == 65); - SHA256(eckey_buf, len, hash1); + SHA256(hash_buf, hash_len, hash1); RIPEMD160(hash1, sizeof(hash1), &vxcp->vxc_binres[1]); switch (test_func(vxcp)) { @@ -450,6 +467,7 @@ usage(const char *name) "-N Generate namecoin address\n" "-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" "-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" @@ -464,7 +482,10 @@ int main(int argc, char **argv) { int addrtype = 0; + int scriptaddrtype = 5; int privtype = 128; + int pubkeytype; + enum vg_format format = VCF_PUBKEY; int regex = 0; int caseinsensitive = 0; int verbose = 1; @@ -481,7 +502,7 @@ main(int argc, char **argv) int nthreads = 0; vg_context_t *vcp = NULL; - while ((opt = getopt(argc, argv, "vqrikeE:NTX:t:h?f:o:s:")) != -1) { + while ((opt = getopt(argc, argv, "vqrikeE:NTXF:t:h?f:o:s:")) != -1) { switch (opt) { case 'v': verbose = 2; @@ -501,14 +522,28 @@ main(int argc, char **argv) case 'N': addrtype = 52; privtype = 180; + scriptaddrtype = -1; break; case 'T': addrtype = 111; privtype = 239; + scriptaddrtype = 196; break; case 'X': addrtype = atoi(optarg); privtype = 128 + addrtype; + scriptaddrtype = addrtype; + break; + case 'F': + if (!strcmp(optarg, "script")) + format = VCF_SCRIPT; + else + if (strcmp(optarg, "pubkey")) + { + fprintf(stderr, + "Invalid format '%s'\n", optarg); + return 1; + } break; case 'e': prompt_password = 1; @@ -578,6 +613,18 @@ main(int argc, char **argv) "WARNING: case insensitive mode incompatible with " "regular expressions\n"); + pubkeytype = addrtype; + if (format == VCF_SCRIPT) + { + if (scriptaddrtype == -1) + { + fprintf(stderr, + "Address type incompatible with script format\n"); + return 1; + } + addrtype = scriptaddrtype; + } + if (seedfile) { opt = -1; #if !defined(_WIN32) @@ -626,6 +673,8 @@ 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_format = format; + vcp->vc_pubkeytype = pubkeytype; if (!vg_context_add_patterns(vcp, patterns, npatterns)) return 1;