From 7ee7d9b0aa5b3841d17f0be14d2cc00f719b579f Mon Sep 17 00:00:00 2001 From: Scott Alfter Date: Thu, 16 May 2013 10:29:03 -0700 Subject: [PATCH 1/2] add Litecoin address and compressed address support --- pattern.c | 16 ++++++++++++---- pattern.h | 1 + util.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ util.h | 3 +++ vanitygen.c | 28 +++++++++++++++++++++------- 5 files changed, 81 insertions(+), 11 deletions(-) diff --git a/pattern.c b/pattern.c index 79e2091..b925a47 100644 --- a/pattern.c +++ b/pattern.c @@ -528,9 +528,14 @@ vg_output_match_console(vg_context_t *vcp, EC_KEY *pkey, const char *pattern) } assert(EC_KEY_check_key(pkey)); - vg_encode_address(ppnt, - EC_KEY_get0_group(pkey), - vcp->vc_pubkeytype, addr_buf); + if (vcp->vc_compressed) + vg_encode_address_compressed(ppnt, + EC_KEY_get0_group(pkey), + vcp->vc_pubkeytype, addr_buf); + else + vg_encode_address(ppnt, + EC_KEY_get0_group(pkey), + vcp->vc_pubkeytype, addr_buf); if (isscript) vg_encode_script_address(ppnt, EC_KEY_get0_group(pkey), @@ -550,7 +555,10 @@ vg_output_match_console(vg_context_t *vcp, EC_KEY *pkey, const char *pattern) } } if (!vcp->vc_key_protect_pass) { - vg_encode_privkey(pkey, vcp->vc_privtype, privkey_buf); + if (vcp->vc_compressed) + vg_encode_privkey_compressed(pkey, vcp->vc_privtype, privkey_buf); + else + vg_encode_privkey(pkey, vcp->vc_privtype, privkey_buf); } if (!vcp->vc_result_file || (vcp->vc_verbose > 0)) { diff --git a/pattern.h b/pattern.h index b440751..ffa88c4 100644 --- a/pattern.h +++ b/pattern.h @@ -88,6 +88,7 @@ enum vg_format { /* Application-level context, incl. parameters and global pattern store */ struct _vg_context_s { + int vc_compressed; int vc_addrtype; int vc_privtype; unsigned long vc_npatterns; diff --git a/util.c b/util.c index 165f82c..aa76155 100644 --- a/util.c +++ b/util.c @@ -259,6 +259,30 @@ vg_encode_address(const EC_POINT *ppoint, const EC_GROUP *pgroup, vg_b58_encode_check(binres, sizeof(binres), result); } +void +vg_encode_address_compressed(const EC_POINT *ppoint, const EC_GROUP *pgroup, + int addrtype, char *result) +{ + unsigned char eckey_buf[128], *pend; + unsigned char binres[21] = {0,}; + unsigned char hash1[32]; + + pend = eckey_buf; + + EC_POINT_point2oct(pgroup, + ppoint, + POINT_CONVERSION_COMPRESSED, + eckey_buf, + sizeof(eckey_buf), + NULL); + pend = eckey_buf + 0x21; + binres[0] = addrtype; + SHA256(eckey_buf, pend - eckey_buf, hash1); + RIPEMD160(hash1, sizeof(hash1), &binres[1]); + + vg_b58_encode_check(binres, sizeof(binres), result); +} + void vg_encode_script_address(const EC_POINT *ppoint, const EC_GROUP *pgroup, int addrtype, char *result) @@ -306,6 +330,26 @@ vg_encode_privkey(const EC_KEY *pkey, int addrtype, char *result) vg_b58_encode_check(eckey_buf, 33, result); } +void +vg_encode_privkey_compressed(const 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_num_bytes(bn); + assert(nbytes <= 32); + if (nbytes < 32) + memset(eckey_buf + 1, 0, 32 - nbytes); + BN_bn2bin(bn, &eckey_buf[33 - nbytes]); + eckey_buf[nbytes+1] = 1; + + vg_b58_encode_check(eckey_buf, 34, result); +} + int vg_set_privkey(const BIGNUM *bnpriv, EC_KEY *pkey) { diff --git a/util.h b/util.h index 5969b87..850fad5 100644 --- a/util.h +++ b/util.h @@ -38,10 +38,13 @@ extern int vg_b58_decode_check(const char *input, void *buf, size_t len); extern void vg_encode_address(const EC_POINT *ppoint, const EC_GROUP *pgroup, int addrtype, char *result); +extern void vg_encode_address_compressed(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 void vg_encode_privkey_compressed(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, EC_KEY *pkey, int *addrtype); diff --git a/vanitygen.c b/vanitygen.c index 9d88121..7c66cfb 100644 --- a/vanitygen.c +++ b/vanitygen.c @@ -114,7 +114,7 @@ vg_thread_loop(void *arg) } else { eckey_buf = hash_buf; - hash_len = 65; + hash_len = (vcp->vc_compressed)?33:65; } while (!vcp->vc_halt) { @@ -194,11 +194,11 @@ vg_thread_loop(void *arg) for (i = 0; i < nbatch; i++, vxcp->vxc_delta++) { /* Hash the public key */ len = EC_POINT_point2oct(pgroup, ppnt[i], - POINT_CONVERSION_UNCOMPRESSED, + (vcp->vc_compressed)?POINT_CONVERSION_COMPRESSED:POINT_CONVERSION_UNCOMPRESSED, eckey_buf, - 65, + (vcp->vc_compressed)?33:65, vxcp->vxc_bnctx); - assert(len == 65); + assert(len == 65 || len == 33); SHA256(hash_buf, hash_len, hash1); RIPEMD160(hash1, sizeof(hash1), &vxcp->vxc_binres[1]); @@ -311,10 +311,11 @@ usage(const char *name) "-i Case-insensitive prefix search\n" "-k Keep pattern and continue search after finding a match\n" "-1 Stop after first match\n" +"-L Generate litecoin address\n" "-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" +"-F Generate address with the given format (pubkey, compressed, 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" @@ -358,11 +359,15 @@ main(int argc, char **argv) int pattfpi[MAX_FILE]; int npattfp = 0; int pattstdin = 0; + int compressed = 0; int i; - while ((opt = getopt(argc, argv, "vqnrik1eE:P:NTX:F:t:h?f:o:s:")) != -1) { + while ((opt = getopt(argc, argv, "Lvqnrik1eE:P:NTX:F:t:h?f:o:s:")) != -1) { switch (opt) { + case 'c': + compressed = 1; + break; case 'v': verbose = 2; break; @@ -389,6 +394,11 @@ main(int argc, char **argv) privtype = 180; scriptaddrtype = -1; break; + case 'L': + addrtype = 48; + privtype = 176; + scriptaddrtype = -1; + break; case 'T': addrtype = 111; privtype = 239; @@ -402,7 +412,10 @@ main(int argc, char **argv) case 'F': if (!strcmp(optarg, "script")) format = VCF_SCRIPT; - else + else + if (!strcmp(optarg, "compressed")) + compressed = 1; + else if (strcmp(optarg, "pubkey")) { fprintf(stderr, "Invalid format '%s'\n", optarg); @@ -544,6 +557,7 @@ main(int argc, char **argv) caseinsensitive); } + vcp->vc_compressed = compressed; vcp->vc_verbose = verbose; vcp->vc_result_file = result_file; vcp->vc_remove_on_match = remove_on_match; From 723b76698f2307cca884cc425b072ccd73508b83 Mon Sep 17 00:00:00 2001 From: Joey Hewitt Date: Sat, 25 May 2013 19:50:21 -0600 Subject: [PATCH 2/2] compressed addresses in OpenCL --- calc_addrs.cl | 81 +++++++++++++++++++++++++++++++++----------------- oclengine.c | 3 ++ oclvanitygen.c | 15 +++++++++- pattern.c | 2 +- 4 files changed, 72 insertions(+), 29 deletions(-) diff --git a/calc_addrs.cl b/calc_addrs.cl index 39f087f..82ff04b 100644 --- a/calc_addrs.cl +++ b/calc_addrs.cl @@ -67,7 +67,7 @@ * Steps: * - Compute Px = Pxj * (1/Pz)^2 * - Compute Py = Pyj * (1/Pz)^3 - * - Compute H = RIPEMD160(SHA256(0x04 | Px | Py)) + * - Compute H = RIPEMD160(SHA256({0x02|0x03|0x04} | Px | Py?)) * * Output: * - Array of 20-byte address hash values @@ -94,6 +94,13 @@ #define load_be32(v) bswap32(v) #endif +/* Configuration -- maybe I shouldn't be passing this in preproc */ +#ifdef COMPRESSED_ADDRESS + __constant bool compressed_address = 1; +#else + __constant bool compressed_address = 0; +#endif + /* * Loop unrolling macros * @@ -1234,7 +1241,7 @@ hash_ec_point(uint *hash_out, __global bn_word *xy, __global bn_word *zip) bn_mul_mont(&c, &c, &zzi); /* X / Z^2 */ bn_from_mont(&c, &c); - wh = 0x00000004; /* POINT_CONVERSION_UNCOMPRESSED */ + wh = compressed_address ? 0x00000002 : 0x00000004; /* POINT_CONVERSION_[UN]COMPRESSED */ #define hash_ec_point_inner_3(i) \ wl = wh; \ @@ -1253,12 +1260,30 @@ hash_ec_point(uint *hash_out, __global bn_word *xy, __global bn_word *zip) bn_mul_mont(&c, &c, &zzi); /* Y / Z^3 */ bn_from_mont(&c, &c); -#define hash_ec_point_inner_5(i) \ - wl = wh; \ - wh = c.d[(BN_NWORDS - 1) - i]; \ - hash1[BN_NWORDS + i] = (wl << 24) | (wh >> 8); + if (!compressed_address) { + #define hash_ec_point_inner_5(i) \ + wl = wh; \ + wh = c.d[(BN_NWORDS - 1) - i]; \ + hash1[BN_NWORDS + i] = (wl << 24) | (wh >> 8); - bn_unroll(hash_ec_point_inner_5); + bn_unroll(hash_ec_point_inner_5); + } else { + if (bn_is_odd(c)) { + hash1[0] |= 0x01000000; /* 0x03 for odd y */ + } + + /* + * Put in the last byte + SHA-2 padding. + */ + hash1[8] = wh << 24 | 0x800000; + hash1[9] = 0; + hash1[10] = 0; + hash1[11] = 0; + hash1[12] = 0; + hash1[13] = 0; + hash1[14] = 0; + hash1[15] = 33 * 8; + } /* * Hash the first 64 bytes of the buffer @@ -1266,26 +1291,28 @@ hash_ec_point(uint *hash_out, __global bn_word *xy, __global bn_word *zip) sha2_256_init(hash2); sha2_256_block(hash2, hash1); - /* - * Hash the last byte of the buffer + SHA-2 padding - */ - hash1[0] = wh << 24 | 0x800000; - hash1[1] = 0; - hash1[2] = 0; - hash1[3] = 0; - hash1[4] = 0; - hash1[5] = 0; - hash1[6] = 0; - hash1[7] = 0; - hash1[8] = 0; - hash1[9] = 0; - hash1[10] = 0; - hash1[11] = 0; - hash1[12] = 0; - hash1[13] = 0; - hash1[14] = 0; - hash1[15] = 65 * 8; - sha2_256_block(hash2, hash1); + if (!compressed_address) { + /* + * Hash the last byte of the buffer + SHA-2 padding + */ + hash1[0] = wh << 24 | 0x800000; + hash1[1] = 0; + hash1[2] = 0; + hash1[3] = 0; + hash1[4] = 0; + hash1[5] = 0; + hash1[6] = 0; + hash1[7] = 0; + hash1[8] = 0; + hash1[9] = 0; + hash1[10] = 0; + hash1[11] = 0; + hash1[12] = 0; + hash1[13] = 0; + hash1[14] = 0; + hash1[15] = 65 * 8; + sha2_256_block(hash2, hash1); + } /* * Hash the SHA-2 result with RIPEMD160 diff --git a/oclengine.c b/oclengine.c index 4a6a232..d93329e 100644 --- a/oclengine.c +++ b/oclengine.c @@ -933,6 +933,9 @@ vg_ocl_init(vg_context_t *vcp, vg_ocl_context_t *vocp, cl_device_id did, if (vocp->voc_quirks & VG_OCL_AMD_BFI_INT) end += snprintf(optbuf + end, sizeof(optbuf) - end, "-DAMD_BFI_INT "); + if (vcp->vc_compressed) + end += snprintf(optbuf + end, sizeof(optbuf) - end, + "-DCOMPRESSED_ADDRESS"); if (vocp->voc_quirks & VG_OCL_NV_VERBOSE) end += snprintf(optbuf + end, sizeof(optbuf) - end, "-cl-nv-verbose "); diff --git a/oclvanitygen.c b/oclvanitygen.c index 9755ef6..aa8c24d 100644 --- a/oclvanitygen.c +++ b/oclvanitygen.c @@ -60,6 +60,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, compressed)\n" "-e Encrypt private keys, prompt for password\n" "-E Encrypt private keys with (UNSAFE)\n" "-p Select OpenCL platform\n" @@ -119,11 +120,12 @@ main(int argc, char **argv) int pattfpi[MAX_FILE]; int npattfp = 0; int pattstdin = 0; + int compressed = 0; int i; while ((opt = getopt(argc, argv, - "vqik1NTX:eE:p:P:d:w:t:g:b:VSh?f:o:s:D:")) != -1) { + "vqik1NTX:F:eE:p:P:d:w:t:g:b:VSh?f:o:s:D:")) != -1) { switch (opt) { case 'v': verbose = 2; @@ -152,6 +154,16 @@ main(int argc, char **argv) addrtype = atoi(optarg); privtype = 128 + addrtype; break; + case 'F': + if (!strcmp(optarg, "compressed")) + compressed = 1; + else + if (strcmp(optarg, "pubkey")) { + fprintf(stderr, + "Invalid format '%s'\n", optarg); + return 1; + } + break; case 'e': prompt_password = 1; break; @@ -330,6 +342,7 @@ main(int argc, char **argv) caseinsensitive); } + vcp->vc_compressed = compressed; vcp->vc_verbose = verbose; vcp->vc_result_file = result_file; vcp->vc_remove_on_match = remove_on_match; diff --git a/pattern.c b/pattern.c index b925a47..8c499b4 100644 --- a/pattern.c +++ b/pattern.c @@ -256,7 +256,7 @@ vg_exec_context_calc_address(vg_exec_context_t *vxcp) } len = EC_POINT_point2oct(pgroup, pubkey, - POINT_CONVERSION_UNCOMPRESSED, + vxcp->vxc_vc->vc_compressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED, eckey_buf, sizeof(eckey_buf), vxcp->vxc_bnctx);