Advertisement
Guest User

Brainwallet-style address generator in C

a guest
Mar 7th, 2014
201
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.43 KB | None | 0 0
  1. /* 1b8719b9969ba88d66c3eb20d2e4a52aa5e9eb80cfedf3c4dae49a09c63ad096 */
  2. /* Compile with -lgmp and -lcrypto. */
  3. #include <getopt.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7.  
  8. #include <gmp.h>
  9. #include <openssl/ecdsa.h>
  10. #include <openssl/obj_mac.h>
  11. #include <openssl/ripemd.h>
  12. #include <openssl/sha.h>
  13. #include <openssl/x509v3.h>
  14.  
  15. static char const *base58_charset = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
  16.  
  17. char *base58_encode(const unsigned char *pbegin, const unsigned char *pend)
  18. {
  19.     unsigned char const *p;
  20.     char *retval;
  21.     int i, n_nonzero;
  22.  
  23.     mpz_t n;
  24.  
  25.     mpz_init2(n, (pend - pbegin) * 8);
  26.     mpz_import(n, (pend - pbegin), 1, 1, 0, 0, pbegin);
  27.  
  28.     // Expected size increase from base58 conversion is approximately 137%
  29.     // use 138% to be safe
  30.     retval = malloc((pend - pbegin) * 138 / 100 + 1);
  31.  
  32.     for (i = 0; mpz_cmp_ui(n, 0) > 0; i++) {
  33.         unsigned long r;
  34.  
  35.         r = mpz_fdiv_q_ui(n, n, 58);
  36.         retval[i] = base58_charset[r];
  37.     }
  38.     mpz_clear(n);
  39.  
  40.     // Leading zeroes encoded as base58 zeros
  41.     for (p = pbegin; p < pend && *p == 0; p++) {
  42.         retval[i++] = base58_charset[0];
  43.     }
  44.  
  45.     retval[i] = 0;
  46.  
  47.     // Convert little endian to big endian
  48.     for (n_nonzero = i, i = 0; i < n_nonzero/2; i++) {
  49.         unsigned char t = retval[i];
  50.         retval[i] = retval[n_nonzero-1 - i];
  51.         retval[n_nonzero-1 - i] = t;
  52.     }
  53.  
  54.     return retval;
  55. }
  56.  
  57. static void hash160(unsigned char const *pubkey, size_t pubkey_len, unsigned char *md)
  58. {
  59.     unsigned char pubkey_sha256[32];
  60.  
  61.     SHA256(pubkey, pubkey_len, pubkey_sha256);
  62.     RIPEMD160(pubkey_sha256, 32, md);
  63. }
  64.  
  65. void base58_check_pad(unsigned char *payload_extended, size_t payload_len, unsigned char prefix)
  66. {
  67.     unsigned char buf_sha256[32];
  68.  
  69.     /* Network ID. */
  70.     payload_extended[0] = prefix;
  71.  
  72.     /* Check code: first four bytes of SHA256^2(extended hash160). */
  73.     SHA256(payload_extended, 1 + payload_len, buf_sha256);
  74.     SHA256(buf_sha256, 32, buf_sha256);
  75.     memcpy(1 + payload_extended + payload_len, buf_sha256, 4);
  76. }
  77.  
  78. int generate_key(unsigned char const *seed, size_t seed_len, point_conversion_form_t conv,
  79.          unsigned char **privkey_bytes, unsigned char *md)
  80. {
  81.         BIGNUM bn_seed;
  82.     BN_CTX *ctx;
  83.     EC_KEY *key;
  84.     const EC_GROUP *group;
  85.     EC_POINT *pubkey = NULL;
  86.     unsigned char *pubkey_bytes = NULL;
  87.     int pubkey_len, privkey_len = -1;
  88.  
  89.         BN_init(&bn_seed);
  90.         BN_bin2bn(seed, seed_len, &bn_seed);
  91.  
  92.     ctx = BN_CTX_new();
  93.     if (!ctx) {
  94.         return privkey_len;
  95.     }
  96.  
  97.     key = EC_KEY_new_by_curve_name(NID_secp256k1);
  98.  
  99.     group = EC_KEY_get0_group(key);
  100.     pubkey = EC_POINT_new(group);
  101.  
  102.     if (!pubkey) {
  103.         goto err;
  104.     }
  105.  
  106.     if (!EC_POINT_mul(group, pubkey, &bn_seed, NULL, NULL, ctx)) {
  107.         goto err;
  108.     }
  109.  
  110.     EC_KEY_set_private_key(key, &bn_seed);
  111.     EC_KEY_set_public_key(key, pubkey);
  112.  
  113.     EC_KEY_set_conv_form(key, conv);
  114.     pubkey_len = i2o_ECPublicKey(key, &pubkey_bytes);
  115.     privkey_len = i2d_ECPrivateKey(key, privkey_bytes);
  116.  
  117.     hash160(pubkey_bytes, pubkey_len, md);
  118.  
  119.     OPENSSL_free(pubkey_bytes);
  120. err:
  121.     if (pubkey) {
  122.         EC_POINT_free(pubkey);
  123.     }
  124.     BN_CTX_free(ctx);
  125.     EC_KEY_free(key);
  126.  
  127.     return privkey_len;
  128. }
  129.  
  130. int main(int argc, char *argv[])
  131. {
  132.     point_conversion_form_t convform = POINT_CONVERSION_UNCOMPRESSED;
  133.     unsigned char *pubkey_prefix = NULL;
  134.     long pubkey_prefix_len;
  135.     int verbose = 0;
  136.     int i;
  137.  
  138.     while (1) {
  139.         int c;
  140.  
  141.         c = getopt(argc, argv, "cs:v");
  142.         if (c == -1) {
  143.             break;
  144.         }
  145.  
  146.         switch (c) {
  147.         case 'c':
  148.             convform = POINT_CONVERSION_COMPRESSED;
  149.             break;
  150.         case 's':
  151.             pubkey_prefix = string_to_hex(optarg, &pubkey_prefix_len);
  152.             break;
  153.         case 'v':
  154.             verbose++;
  155.             break;
  156.         default:
  157.             fprintf(stderr, "Usage: %s [-c] [SEED]\n", argv[0]);
  158.             exit(1);
  159.             break;
  160.         }
  161.     }
  162.  
  163.     for (i = optind; i < argc; i++) {
  164.         unsigned char pubkey_hash160[1 + 20 + 4], seed_hash[32];
  165.         unsigned char *privkey_extended;
  166.         unsigned char *privkey_bytes = NULL;
  167.         char const *seed;
  168.         char *address;
  169.         int privkey_len;
  170.  
  171.         seed = argv[i];
  172.  
  173.         SHA256((unsigned char const *) seed, strlen(seed), seed_hash);
  174.  
  175.         privkey_len = generate_key(seed_hash, 32, convform, &privkey_bytes, pubkey_hash160 + 1);
  176.  
  177.         if (pubkey_prefix) {
  178.             if (memcmp(pubkey_hash160 + 1, pubkey_prefix, pubkey_prefix_len < 20 ? pubkey_prefix_len : 20) != 0) {
  179.                 continue;
  180.             }
  181.         }
  182.  
  183.         if (verbose) {
  184.             address = hex_to_string(seed_hash, 32);
  185.             printf("Seed hash = %s\n", address);
  186.             OPENSSL_free(address);
  187.  
  188.             privkey_extended = malloc(1 + privkey_len + 1 + 4);
  189.             memcpy(privkey_extended + 1, seed_hash, 32);
  190.             if (convform == POINT_CONVERSION_COMPRESSED) {
  191.                 privkey_extended[1 + 32] = 0x01;
  192.             }
  193.             base58_check_pad(privkey_extended, 32 + (convform == POINT_CONVERSION_COMPRESSED), 0x80);
  194.             address = base58_encode(privkey_extended, 1 + privkey_extended + (convform == POINT_CONVERSION_COMPRESSED) + 32 + 4);
  195.             printf("Privkey (WIF) = %s\n", address);
  196.             free(address);
  197.             free(privkey_extended);
  198.  
  199.             address = hex_to_string(privkey_bytes, privkey_len);
  200.             printf("Privkey (DER) = %s\n", address);
  201.             OPENSSL_free(address);
  202.         } else {
  203.             printf("Seed = %s, ", seed);
  204.         }
  205.  
  206.         address = hex_to_string(pubkey_hash160 + 1, 20);
  207.         printf("Pubkey hash = %s\n", address);
  208.         OPENSSL_free(address);
  209.  
  210.         if (verbose) {
  211.             base58_check_pad(pubkey_hash160, 20, 0);
  212.             address = base58_encode(pubkey_hash160, 1 + pubkey_hash160 + 20 + 4);
  213.             printf("%s\n", address);
  214.             free(address);
  215.         }
  216.     }
  217.  
  218.     if (pubkey_prefix) {
  219.         OPENSSL_free(pubkey_prefix);
  220.     }
  221.  
  222.     return 0;
  223. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement