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:
#include
#include
#include
#include
#include
#include
#include
#include
#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:
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
when i use
bitcointools.appspot.com to get the address from my private key, the result is different to mine...
any suggestions?