I wrote a separate utility to convert minikeys to private keys. If anyone wants to try it, I'll post the code here.
/*
Compile with:
gcc minikey.c -lcrypto -lssl -lgmp -o minikey
*/
#include
#include
#include
#include
/*
returns 0 if not valid, 1 if valid
expects null termination
*/
int is_valid_minikey(char *minikey)
{
char *tmpbuf = (char *)malloc(sizeof(char) * (strlen(minikey) + 2));
unsigned char hash[EVP_MAX_MD_SIZE];
EVP_MD_CTX ctx;
int ret;
strcpy(tmpbuf, minikey);
strcat(tmpbuf, "?");
EVP_DigestInit(&ctx, EVP_sha256());
EVP_DigestUpdate(&ctx, tmpbuf, strlen(tmpbuf));
EVP_DigestFinal(&ctx, hash, &ret);
free(tmpbuf);
// If hash[0] is 0x00, return 1, else 0
if(!hash[0]) return(1);
else return(0);
}
/*
Assumes privkey has enough room
Does not check minikey for validity
Expects minikey to be NULL terminated
Returns length of private key (not NULL terminated)
*/
int minikey_to_private_key(char *minikey, unsigned char *privkey)
{
EVP_MD_CTX ctx;
int ret;
EVP_DigestInit(&ctx, EVP_sha256());
EVP_DigestUpdate(&ctx, minikey, strlen(minikey));
EVP_DigestFinal(&ctx, privkey, &ret);
return(ret);
}
unsigned char base58[] =
{
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L',
'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'm', 'n', 'o', 'p', 'q', 'r',
's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
int private_key_to_wif(unsigned char **wifkey, unsigned char *privkey, int keylen)
{
mpz_t key, tmp;
EVP_MD_CTX ctx;
int i, ret, zeroes;
unsigned char *extkey, hash[EVP_MAX_MD_SIZE];
// 1 for the 0x80, 4 for the csum, one for shit happens
extkey = (unsigned char *)malloc(sizeof(unsigned char) * (keylen + 6));
extkey[0] = 0x80;
memcpy(extkey + 1, privkey, keylen);
// keylen is now the length of ext key
keylen++;
EVP_DigestInit(&ctx, EVP_sha256());
EVP_DigestUpdate(&ctx, extkey, keylen);
EVP_DigestFinal(&ctx, hash, &ret);
EVP_DigestInit(&ctx, EVP_sha256());
EVP_DigestUpdate(&ctx, hash, ret);
EVP_DigestFinal(&ctx, hash, &ret);
// Sanity check
if(ret < 4)
{
free(extkey);
return(-1);
}
memcpy(extkey + keylen, hash, 4);
keylen += 4;
for(i = 0, zeroes = 0; i < keylen; i++)
{
if(!extkey[i]) zeroes++;
else break;
}
mpz_init(key);
mpz_init(tmp);
mpz_import(key, keylen, 1, 1, 0, 0, extkey);
for(i = 0; mpz_cmp_ui(key, 0); i++)
{
ret = mpz_mod_ui(tmp, key, 58);
mpz_tdiv_q_ui(tmp, key, 58);
mpz_set(key, tmp);
extkey[i] = base58[ret];
}
mpz_clear(tmp);
mpz_clear(key);
while(zeroes--)
extkey[i++] = base58[0];
// Note that the i++ adds an extra 1; it must be subtracted.
keylen = i - 1;
// Allocate space for final key
*wifkey = (unsigned char *)malloc(sizeof(unsigned char) * (keylen + 2));
// Copy string in reverse
for(i = 0, ret = keylen; i <= keylen && ret >= 0; i++, ret--)
(*wifkey)[i] = extkey[ret];
// NULL terminate
*wifkey[i] = 0x00;
return(i);
}
int main(int argc, char **argv)
{
unsigned char privkey[EVP_MAX_MD_SIZE], *wifkey;
int i, len;
if(argc < 2)
{
printf("Usage: %s \n", argv[0]);
return(0);
}
if(is_valid_minikey(argv[1]))
{
printf("Minikey is valid.\n");
len = minikey_to_private_key(argv[1], privkey);
len = private_key_to_wif(&wifkey, privkey, len);
printf("Corresponding private key in wallet import format:\n");
for(i = 0; i < len; i++)
printf("%c", wifkey[i]);
}
else
{
printf("Minikey is invalid.");
}
putchar('\n');
return(0);
}