Bitcoin Forum
April 27, 2024, 04:57:08 AM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: get address from private key  (Read 5225 times)
gimme_bottles (OP)
Sr. Member
****
Offline Offline

Activity: 316
Merit: 250



View Profile
December 08, 2011, 11:30:13 PM
 #1

hey,

i am searching for a documentation describing the process of calculation the corresponding bitcoin address from a private key.
does anyone has a link to such a document?


gimme_bottles
You get merit points when someone likes your post enough to give you some. And for every 2 merit points you receive, you can send 1 merit point to someone else!
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction.
MelMan2002
Sr. Member
****
Offline Offline

Activity: 461
Merit: 251



View Profile
December 08, 2011, 11:41:43 PM
 #2

https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses

19F6veduCZcudwXuWoVosjmzziQz4EhBPS
gimme_bottles (OP)
Sr. Member
****
Offline Offline

Activity: 316
Merit: 250



View Profile
December 08, 2011, 11:57:01 PM
 #3

i read that article, but i don't get how to get the address from a private key, i only see the generation process of a bitcoin address.
casascius
Mike Caldwell
VIP
Legendary
*
Offline Offline

Activity: 1386
Merit: 1136


The Casascius 1oz 10BTC Silver Round (w/ Gold B)


View Profile WWW
December 09, 2011, 12:21:57 AM
 #4

i read that article, but i don't get how to get the address from a private key, i only see the generation process of a bitcoin address.

From the private key, you get the public key.  From the public key, you can get the address, based on the steps in the article.

Are you wondering how to get the public key from the private key?

Companies claiming they got hacked and lost your coins sounds like fraud so perfect it could be called fashionable.  I never believe them.  If I ever experience the misfortune of a real intrusion, I declare I have been honest about the way I have managed the keys in Casascius Coins.  I maintain no ability to recover or reproduce the keys, not even under limitless duress or total intrusion.  Remember that trusting strangers with your coins without any recourse is, as a matter of principle, not a best practice.  Don't keep coins online. Use paper or hardware wallets instead.
gimme_bottles (OP)
Sr. Member
****
Offline Offline

Activity: 316
Merit: 250



View Profile
December 09, 2011, 08:17:01 AM
 #5


Are you wondering how to get the public key from the private key?

yes, i am missing that step Smiley
casascius
Mike Caldwell
VIP
Legendary
*
Offline Offline

Activity: 1386
Merit: 1136


The Casascius 1oz 10BTC Silver Round (w/ Gold B)


View Profile WWW
December 09, 2011, 08:32:46 AM
 #6


Are you wondering how to get the public key from the private key?

yes, i am missing that step Smiley

You multiply the private key by the constant G.  You can find G at https://en.bitcoin.it/wiki/Secp256k1.

G is an elliptic curve point - not a simple number.  So there is special math that redefines what "multiplying" is.  A point times a number equals another point.  You may or may not need to care about the intricate details of that math.  If you are simply trying to write a program and are using crypto code from somewhere else, you simply call the already-defined "point multiply" function and get the answer.

The answer comes as two numbers - X and Y - because it's a point on a sort of graph - and then you can plug them in to the instructions you see that explain how to go from a public key to a Bitcoin address.

Companies claiming they got hacked and lost your coins sounds like fraud so perfect it could be called fashionable.  I never believe them.  If I ever experience the misfortune of a real intrusion, I declare I have been honest about the way I have managed the keys in Casascius Coins.  I maintain no ability to recover or reproduce the keys, not even under limitless duress or total intrusion.  Remember that trusting strangers with your coins without any recourse is, as a matter of principle, not a best practice.  Don't keep coins online. Use paper or hardware wallets instead.
gimme_bottles (OP)
Sr. Member
****
Offline Offline

Activity: 316
Merit: 250



View Profile
December 10, 2011, 01:08:54 AM
 #7

so, based on your help and openssl i hacked some code to calculate the address out of a randomly generated private key.
sadly it doesn't work as expected.

this is my code, the reverse of the string in the base58-encoding function is still missing:
Code:
#include <stdio.h>
#include <stdlib.h>

#include <openssl/sha.h>
#include <openssl/ecdsa.h>
#include <openssl/ripemd.h>
#include <openssl/ec.h>
#include <openssl/obj_mac.h>
#include <openssl/bn.h>


#include "hash.h"


unsigned char* privkey2addr(unsigned char* input)
{
   unsigned char* output;

   int ret;    /* return value of the sign-function */
   ECDSA_SIG *sig;   /* result of the signing process, containing both r and s */
   EC_KEY *eckey = EC_KEY_new();    /* create new key for the signing process */
   EC_GROUP *ecgroup = EC_GROUP_new_by_curve_name(NID_secp256k1);    /* set secp256k1 as the signing method */

   unsigned char *r, *s;

   if(eckey == NULL || ecgroup == NULL) {    /* check for errors */
      printf("Initializing of eckey or ecgroup failed!\n");
      return NULL;
   }

   if(EC_KEY_set_group(eckey,ecgroup) != 1) {   /* set signing method and check for errors */
      printf("Setting group for eckey failed!\n");
      return NULL;
   }

   if(EC_KEY_generate_key(eckey) != 1) {  /* generete key and check for errors */
      printf("Generating eckey failed!\n");
      return NULL;
   }

   sig = ECDSA_do_sign(input, 32, eckey); /* sign the input */

   if(sig==NULL) {   /* error? */
      printf("Signing of input failed!\n");
      return NULL;
   }

   ret = ECDSA_do_verify(input, 32, sig, eckey);   /* verify result */

   if(ret == -1 || ret == 0) {   /* error? */
      printf("Verifying failed!\n");
      return NULL;
   }

   r = malloc(32);   /* allocate 32 bit space for both r and s */
   s = malloc(32);

   if(BN_bn2bin(sig->r, r) != 32) { /* export BIGNUM to array of chars, check for invalid length */
      printf("Invalid result length!\n");
      return NULL;
   }

   if(BN_bn2bin(sig->s, s) != 32) { /* export BIGNUM to array of chars, check for invalid length */
      printf("Invalid result length!\n");
      return NULL;
   }

   int i;

   printf("X: "); /* print both r and s for debug reasons */
   for(i=0; i<32; i++) {
      printf("%02x", (unsigned char) *(r+i));
   }
   putc('\n', stdout);

   printf("Y: ");
   for(i=0; i<32; i++) {
      printf("%02x", (unsigned char) *(s+i));
   }
   putc('\n', stdout);


   unsigned char *pubkey_raw; /* raw public key '*/

   pubkey_raw = malloc(65); /* reserve 65 byte of space for the pubkey */

   *pubkey_raw = 0x04;   /* merge 0x04, r and s to the pubkey */

   for(i=0; i < 32; i++)
      *(pubkey_raw+i+1) = *(r+i);

   for(i = 0; i < 32; i++)
      *(pubkey_raw+i+33) = *(s+i);

   free(r); /* free no longer required memory */
   free(s);
   EC_KEY_free(eckey);
   EC_GROUP_free(ecgroup);
   ECDSA_SIG_free(sig);

   unsigned char *pubkey_stage1; /* public key after first stage */

   pubkey_stage1 = malloc(20);   /* reserve 20 bytes of memory */

   pubkey_stage1 = RIPEMD160(SHA256(pubkey_raw, 65, (unsigned char*) NULL), 32, (unsigned char *) NULL); /* hash it! */

   unsigned char *pubkey_stage2; /* public key after seconf stage */

   pubkey_stage2 = malloc(25);   /* reserve 25 bytes of memory */

   *pubkey_stage2 = 0x00;  /* put 0x00 at the beginning for main network */

   for(i = 0; i < 20; i++) /* add the result of stage one */
      *(pubkey_stage2+i+1) = *(pubkey_stage1+i);

   unsigned char *result;  /* the binary address */

   result = malloc(32); /* reserve 32 bytes of memory */

   result = SHA256(SHA256(pubkey_stage2, 32, (unsigned char*) NULL), 32, (unsigned char*) NULL);   /* calculate checksum */


   for(i = 0; i < 4; i++)  /* append checksum to binary address */
      *(pubkey_stage2+i+21) = *(result+i);

   printf("Binary address: ");   /* print binary address */
   for(i=0; i<25; i++) {
      printf("%02x", (unsigned char) *(pubkey_stage2+i));
   }
   putc('\n', stdout);



   output = malloc(35);

   output = base58(pubkey_stage2);

   return output;
}




unsigned char* base58(unsigned char* input)
{
   unsigned char *output;
   BIGNUM *a;
   BIGNUM *b58;
   BIGNUM *rem;

   int i;

   unsigned char *bc58;
   bc58 = malloc(1);
   *bc58=58;

   unsigned char *rest;
   rest = malloc(1);

   const char *alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

   BN_CTX *ctx = BN_CTX_new();
   BN_CTX_init(ctx);


   a = BN_new();
   BN_init(a);

   b58 = BN_new();
   BN_init(b58);

   rem = BN_new();
   BN_init(rem);

   BN_bin2bn((const unsigned char*) input, 25, a);

   BN_bin2bn((const unsigned char*) bc58 , 1, b58);

   output = malloc(35);

   i = 0;

   while(BN_is_zero(a) != 1) {
      BN_div(a, rem, a, b58, ctx);
      BN_bn2bin(rem, rest);
      *(output+i) = alphabet[*rest];
      i++;
   }

   int n = 0, b = 0;

   for(b = 0; b < 25; b++) {
      if(*(input+b)==0)
         n++;
      if(*(input+b)!=0)
         break;
   }

   printf("%i, %i\n", n, i);

   for(b = 0; b < n; b++) {
      *(output+i+b) = alphabet[0];
   }




   return output;
}

my output looks the following, i also print some debug information:
Code:
Private Key: 1809c5d482b97ec84dd7e94cc4cbed460fd878025b52b1011970a3626e64eda8
X: c2429880bd9be5ebe72f00cc34a878cc6e5060f749b7b37957a2f087817e36c0
Y: 4117f999affb005828fd957cfaccc60530c871a05b7d205746d2ca68082d2d7d
Binary address: 0075c5672c37a9140631a0bf915c0e6aa356a832b04bd05648
1, 33
Address: 5ZL8VhHCBiePTgdNn4uQYanWMMgHFYijB1
355a4c3856684843426965505467644e6e34755159616e574d4d67484659696a423100


all outputs are in HEX-format, except for the encoded address, that you have to reverse in your minds Smiley
when i use bitcointools.appspot.com to get the address from my private key, the result is different to mine...

any suggestions?
casascius
Mike Caldwell
VIP
Legendary
*
Offline Offline

Activity: 1386
Merit: 1136


The Casascius 1oz 10BTC Silver Round (w/ Gold B)


View Profile WWW
December 10, 2011, 01:55:44 AM
 #8

I looked not at your code, but your numbers.

The calculation from private key to public key is wrong.  Why, I don't know.

Private key 1809c5d482b97ec84dd7e94cc4cbed460fd878025b52b1011970a3626e64eda8 (I am assuming this is big-endian, like it usually is)

shoudl have public key 04 AE 64 14 8F B6 68 4D 51 CF 03 C5 60 D7 36 28 2E 86 54 FB 54 D2 21 0D 67 4A F1 32 B1 ED 2D 2E 87 D0 B1 05 D0 97 5D C7 5C 31 91 CF 7E 64 ED FB 06 98 AF 85 7A 4A 0A BF 45 D0 06 01 00 9C 9E B8 8A

which is
04

X = AE 64 14 8F B6 68 4D 51 CF 03 C5 60 D7 36 28 2E 86 54 FB 54 D2 21 0D 67 4A F1 32 B1 ED 2D 2E 87
Y = D0 B1 05 D0 97 5D C7 5C 31 91 CF 7E 64 ED FB 06 98 AF 85 7A 4A 0A BF 45 D0 06 01 00 9C 9E B8 8A

calculated by a known working utility.

Companies claiming they got hacked and lost your coins sounds like fraud so perfect it could be called fashionable.  I never believe them.  If I ever experience the misfortune of a real intrusion, I declare I have been honest about the way I have managed the keys in Casascius Coins.  I maintain no ability to recover or reproduce the keys, not even under limitless duress or total intrusion.  Remember that trusting strangers with your coins without any recourse is, as a matter of principle, not a best practice.  Don't keep coins online. Use paper or hardware wallets instead.
gimme_bottles (OP)
Sr. Member
****
Offline Offline

Activity: 316
Merit: 250



View Profile
December 10, 2011, 02:16:07 AM
 #9

yes, it is all big endian.
thanks for your example, it is great to have some values to work with Smiley
ByteCoin
Sr. Member
****
expert
Offline Offline

Activity: 416
Merit: 277


View Profile
December 10, 2011, 04:58:54 AM
 #10


Code:
   printf("X: "); /* print both r and s for debug reasons */
   for(i=0; i<32; i++) {
      printf("%02x", (unsigned char) *(r+i));
   }

   printf("Y: ");
   for(i=0; i<32; i++) {
      printf("%02x", (unsigned char) *(s+i));
   }

There's a reason why the things you're printing out and calling X and Y are really called r and s. That's because r and s have nothing to do with elliptic curve coordinates. Read the wikipedia article for ECDSA for the details. Generating an address from a public key does not require ECDSA_do_sign or do_verify so you can get rid of that code. The coordinates are likely to be stored in the public key structure in some fashion.

ByteCoin
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!