Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement BIP13 (P2SH) address support #10

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions pattern.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* along with Vanitygen. If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
Expand Down Expand Up @@ -304,13 +305,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;
bool 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,
Expand Down Expand Up @@ -350,6 +354,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("Address: %s\n", addr2_buf);
printf("Address: %s\n"
"%s: %s\n",
addr_buf, keytype, privkey_buf);
Expand All @@ -364,9 +370,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, "Address: %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);
}
}
Expand Down Expand Up @@ -1478,6 +1488,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\"";
Expand Down
7 changes: 7 additions & 0 deletions pattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
};


Expand Down
24 changes: 24 additions & 0 deletions util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
1 change: 1 addition & 0 deletions util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
61 changes: 57 additions & 4 deletions vanitygen.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* along with Vanitygen. If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
Expand Down Expand Up @@ -205,10 +206,13 @@ vg_exec_upgrade_lock(vg_exec_context_t *vxcp)
void *
vg_thread_loop(void *arg)
{
unsigned char eckey_buf[128];
unsigned char script_buf[69];
unsigned char *eckey_buf = script_buf + 2;
unsigned char *hash_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;
Expand All @@ -222,6 +226,7 @@ vg_thread_loop(void *arg)
EC_POINT *pbatchinc;

vg_test_func_t test_func = vcp->vc_test;
bool doscript = vcp->vc_format == VCF_SCRIPT;
vg_thread_context_t ctx;
vg_exec_context_t *vxcp;

Expand Down Expand Up @@ -331,15 +336,31 @@ vg_thread_loop(void *arg)

EC_POINTs_make_affine(pgroup, nbatch, ppnt, vxcp->vxc_bnctx);

if (doscript)
{
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
hash_buf = script_buf;
hash_len = 69;
}
else
{
hash_buf = eckey_buf;
hash_len = 65;
}
for (i = 0; i < nbatch; i++, vxcp->vxc_delta++) {
/* Hash the public key */
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)) {
Expand Down Expand Up @@ -450,6 +471,7 @@ usage(const char *name)
"-N Generate namecoin address\n"
"-T Generate bitcoin testnet address\n"
"-X <version> Generate address with the given version\n"
"-F <format> Generate address with the given format (pubkey or script)\n"
"-e Encrypt private keys, prompt for password\n"
"-E <password> Encrypt private keys with <password> (UNSAFE)\n"
"-t <threads> Set number of worker threads (Default: number of CPUs)\n"
Expand All @@ -464,7 +486,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;
Expand All @@ -481,7 +506,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;
Expand All @@ -501,14 +526,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;
Expand Down Expand Up @@ -578,6 +617,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)
Expand Down Expand Up @@ -626,6 +677,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;
Expand Down