Generating Bitcoin address from ECDSA Public Key

10,508

Assuming what you're doing is based on this conversion:

enter image description here

I'll describe what you can do in pseudo-code:

First extract x, y from public key.

// get x and y from Public key "point"
EC_POINT_get_affine_coordinates_GFp(group, pub_key, x, y, ctx);
// convert BIGNUMs x, y into binary form
BN_bn2bin(x,x_char);
BN_bn2bin(y,y_char);

Next you need to do message digest several times, including 3 sha256 and 1 ripemd160. In the following pseudo-code I'll show you how to do ripemd160. To do sha256 with EVP_MD, just replace EVP_ripemd160() with EVP_sha256(), and update (input to EVP_MD) your input message with single or several EVP_DigestUpdate().

EVP_MD_CTX ctx;
EVP_MD_CTX_init(&md_ctx);
EVP_DigestInit(&md_ctx, EVP_ripemd160());
// hdr = 0x04
EVP_DigestUpdate(&md_ctx,hdr,1);
EVP_DigestUpdate(&md_ctx,x_char,32);
EVP_DigestUpdate(&md_ctx,y_char,32);
// put message degest into dgst and set length to dgstlen
EVP_DigestFinal(&md_ctx,dgst,&dgstlen); 
EVP_MD_CTX_cleanup(&md_ctx);

Or the easier way, call sha256() and ripemd160() directly. But you need to prepare your input message before calling hash functions sha256() or ripemd160().

The 25-byte binary address is the result of ripemd160, together with the first 4 bytes of 32-byte checksum. You need to find a way to convert it from Base 256 to Base 58. I don't think OpenSSL support that.

Share:
10,508

Related videos on Youtube

TigerInALoop
Author by

TigerInALoop

Updated on June 04, 2022

Comments

  • TigerInALoop
    TigerInALoop almost 2 years

    I'm writing simple code in C++ using OpenSSL to generate valid bitcoin address - private key pair.

    I'm using this snippet to generate public key from given hex-form private key:

    #include <stdio.h>
    #include <stdlib.h>
    #include <openssl/ec.h>
    #include <openssl/obj_mac.h>
    #include <openssl/bn.h>
    
    int main()
    {
         EC_KEY *eckey = NULL;
         EC_POINT *pub_key = NULL;
         const EC_GROUP *group = NULL;
         BIGNUM start;
         BIGNUM *res;
         BN_CTX *ctx;
    
    
    
         BN_init(&start);
         ctx = BN_CTX_new(); // ctx is an optional buffer to save time from allocating and deallocating memory whenever required
    
         res = &start;
         BN_hex2bn(&res,"30caae2fcb7c34ecadfddc45e0a27e9103bd7cfc87730d7818cc096b1266a683");
         eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
         group = EC_KEY_get0_group(eckey);
         pub_key = EC_POINT_new(group);
    
         EC_KEY_set_private_key(eckey, res);
    
         /* pub_key is a new uninitialized `EC_POINT*`.  priv_key res is a `BIGNUM*`. */
         if (!EC_POINT_mul(group, pub_key, res, NULL, NULL, ctx))
           printf("Error at EC_POINT_mul.\n");
    
         EC_KEY_set_public_key(eckey, pub_key);
    
         char *cc = EC_POINT_point2hex(group, pub_key, 4, ctx);
    
         char *c=cc;
    
         int i;
    
         for (i=0; i<130; i++) // 1 byte 0x42, 32 bytes for X coordinate, 32 bytes for Y coordinate
         {
           printf("%c", *c++);
         }
    
         printf("\n");
    
         BN_CTX_free(ctx);
    
         free(cc);
    
         return 0;
    }
    

    What I want is to transform this Public Key to bitcoin address - what is the fastest way to achieve it? I don't know how to create RIPEMD160 from OpenSSL's BIGNUM. Or maybe there is another, better solution?

    • Nande
      Nande
      do you have the resulting code? sounds interesting
  • TigerInALoop
    TigerInALoop almost 11 years
    Thanks! It helped me a lot!