Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added bip and private key utilities #148

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions contrib/examples/example.c
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: want libdogecoin api to eventually never require pointers, so should replace pointer addr input with parameter.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: same here with pointer intake, should require main/regtest/testnet as option for chainparams not the actual chainparams structure address

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I'll work to wrap the functions with pointers so that they're not necessary.

Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,77 @@ int main() {
}
// END ===========================================

// BIP44 EXAMPLE
printf("\n\nBIP44 EXAMPLE:\n\n");

int result;
dogecoin_hdnode node;
dogecoin_hdnode bip44_key;
char keypath[BIP44_KEY_PATH_MAX_LENGTH + 1] = "";
size_t size;

dogecoin_hdnode_from_seed(utils_hex_to_uint8("000102030405060708090a0b0c0d0e0f"), 16, &node);
printf ("seed: 000102030405060708090a0b0c0d0e0f\n");

char master_key_str[112];

// Print the master key (MAINNET)
dogecoin_hdnode_serialize_public(&node, &dogecoin_chainparams_main, master_key_str, sizeof(master_key_str));
printf("BIP32 master pub key: %s\n", master_key_str);
dogecoin_hdnode_serialize_private(&node, &dogecoin_chainparams_main, master_key_str, sizeof(master_key_str));
printf("BIP32 master prv key: %s\n", master_key_str);

char* change_level = BIP44_CHANGE_EXTERNAL;

// Derive the BIP 44 extended key
result = derive_bip44_extended_private_key(&node, BIP44_FIRST_ACCOUNT_NODE, NULL, change_level, NULL, false, keypath, &bip44_key);

// Print the BIP 44 extended private key
char bip44_private_key[112];
dogecoin_hdnode_serialize_private(&bip44_key, &dogecoin_chainparams_main, bip44_private_key, sizeof(bip44_private_key));
printf("BIP44 extended private key: %s\n", bip44_private_key);

char str[112];

// Print the BIP 44 extended public key
char bip44_public_key[112];
dogecoin_hdnode_serialize_public(&bip44_key, &dogecoin_chainparams_main, bip44_public_key, sizeof(bip44_public_key));
printf("BIP44 extended public key: %s\n", bip44_public_key);

printf("%s", "Derived Addresses\n");

char wifstr[100];
size_t wiflen = 100;

for (uint32_t index = BIP44_FIRST_ACCOUNT_NODE; index < BIP44_ADDRESS_GAP_LIMIT; index++) {
// Derive the addresses
result = derive_bip44_extended_private_key(&node, BIP44_FIRST_ACCOUNT_NODE, &index, change_level, NULL, false, keypath, &bip44_key);

// Print the private key
dogecoin_hdnode_serialize_private(&bip44_key, &dogecoin_chainparams_main, bip44_private_key, sizeof(bip44_private_key));
printf("private key (serialized): %s\n", bip44_private_key);

// Print the public key
dogecoin_hdnode_serialize_public(&bip44_key, &dogecoin_chainparams_main, bip44_public_key, sizeof(bip44_public_key));
printf("public key (serialized): %s\n", bip44_public_key);

// Print the wif private key
dogecoin_privkey_encode_wif((dogecoin_key*) bip44_key.private_key, &dogecoin_chainparams_main, wifstr, &wiflen);
printf("private key (wif): %s\n", wifstr);

// Print the p2pkh address
dogecoin_hdnode_get_p2pkh_address(&bip44_key, &dogecoin_chainparams_main, str, sizeof(str));
printf("Address: %s\n", str);
}

// BASIC TRANSACTION FORMATION EXAMPLE
printf("\n\nBEGIN TRANSACTION FORMATION AND SIGNING:\n\n");
// declare keys and previous hashes
char *external_p2pkh_addr = "nbGfXLskPh7eM1iG5zz5EfDkkNTo9TRmde";
char *myprivkey = "ci5prbqz7jXyFPVWKkHhPq4a9N8Dag3TpeRfuqqC2Nfr7gSqx1fy";
char *mypubkey = "noxKJyGPugPRN4wqvrwsrtYXuQCk7yQEsy";
char *myscriptpubkey = "76a914d8c43e6f68ca4ea1e9b93da2d1e3a95118fa4a7c88ac";
char *hash_2_doge = "b4455e7b7b7acb51fb6feba7a2702c42a5100f61f61abafa31851ed6ae076074";
char *hash_10_doge = "42113bdc65fc2943cf0359ea1a24ced0b6b0b5290db4c63a3329c6601c4616e2";
char myscriptpubkey [100];
dogecoin_p2pkh_address_to_pubkey_hash (str, myscriptpubkey);

// build transaction
int idx = start_transaction();
Expand Down Expand Up @@ -199,17 +261,17 @@ int main() {

// save the finalized unsigned transaction to a new index in the hash table
// save the finalized unsigned transaction to a new index in the hash table
int idx2 = store_raw_transaction(finalize_transaction(idx, external_p2pkh_addr, "0.00226", "12", mypubkey));
int idx2 = store_raw_transaction(finalize_transaction(idx, external_p2pkh_addr, "0.00226", "12", str));
if (idx2 > 0) {
printf("Change returned to address %s and finalized unsigned transaction saved at index %d.\n", mypubkey, idx2);
printf("Change returned to address %s and finalized unsigned transaction saved at index %d.\n", str, idx2);
}
else {
printf("Error occurred.\n");
return -1;
}

// sign transaction
if (sign_transaction(idx, myscriptpubkey, myprivkey)) {
if (sign_transaction(idx, myscriptpubkey, wifstr)) {
printf("\nAll transaction inputs signed successfully. \nFinal transaction hex: %s\n.", get_raw_transaction(idx));
}
else {
Expand Down
91 changes: 87 additions & 4 deletions include/dogecoin/libdogecoin.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,93 @@ dogecoin_bool dogecoin_p2pkh_address_to_pubkey_hash(char* p2pkh, char* scripthas
char* dogecoin_address_to_pubkey_hash(char* p2pkh);
char* dogecoin_private_key_wif_to_pubkey_hash(char* private_key_wif);

/* privkey utilities */
typedef struct dogecoin_key_ {
uint8_t privkey[DOGECOIN_ECKEY_PKEY_LENGTH];
} dogecoin_key;

void dogecoin_privkey_encode_wif(const dogecoin_key* privkey, const dogecoin_chainparams* chain, char* privkey_wif, size_t* strsize_inout);
dogecoin_bool dogecoin_privkey_decode_wif(const char* privkey_wif, const dogecoin_chainparams* chain, dogecoin_key* privkey);

/* bip32 utilities */
#define DOGECOIN_BIP32_CHAINCODE_SIZE 32

typedef struct
{
uint32_t depth;
uint32_t fingerprint;
uint32_t child_num;
uint8_t chain_code[DOGECOIN_BIP32_CHAINCODE_SIZE];
uint8_t private_key[DOGECOIN_ECKEY_PKEY_LENGTH];
uint8_t public_key[DOGECOIN_ECKEY_COMPRESSED_LENGTH];
} dogecoin_hdnode;

dogecoin_hdnode* dogecoin_hdnode_new();
dogecoin_hdnode* dogecoin_hdnode_copy(const dogecoin_hdnode* hdnode);
void dogecoin_hdnode_free(dogecoin_hdnode* node);
dogecoin_bool dogecoin_hdnode_public_ckd(dogecoin_hdnode* inout, uint32_t i);
dogecoin_bool dogecoin_hdnode_from_seed(const uint8_t* seed, int seed_len, dogecoin_hdnode* out);
dogecoin_bool dogecoin_hdnode_private_ckd(dogecoin_hdnode* inout, uint32_t i);
void dogecoin_hdnode_fill_public_key(dogecoin_hdnode* node);
void dogecoin_hdnode_serialize_public(const dogecoin_hdnode* node, const dogecoin_chainparams* chain, char* str, size_t strsize);
void dogecoin_hdnode_serialize_private(const dogecoin_hdnode* node, const dogecoin_chainparams* chain, char* str, size_t strsize);

void dogecoin_hdnode_get_hash160(const dogecoin_hdnode* node, uint160 hash160_out);
void dogecoin_hdnode_get_p2pkh_address(const dogecoin_hdnode* node, const dogecoin_chainparams* chain, char* str, size_t strsize);
dogecoin_bool dogecoin_hdnode_get_pub_hex(const dogecoin_hdnode* node, char* str, size_t* strsize);
dogecoin_bool dogecoin_hdnode_deserialize(const char* str, const dogecoin_chainparams* chain, dogecoin_hdnode* node);

/* bip44 utilities */
#define BIP44_PURPOSE "44" /* Purpose for key derivation according to BIP 44 */
#define BIP44_COIN_TYPE "3" /* Coin type for Dogecoin (3, SLIP 44) */
#define BIP44_COIN_TYPE_TEST "1" /* Coin type for Testnet (1, SLIP44) */
#define BIP44_CHANGE_EXTERNAL "0" /* Change level for external addresses */
#define BIP44_CHANGE_INTERNAL "1" /* Change level for internal addresses */
#define BIP44_CHANGE_LEVEL_SIZE 1 + 1 /* Change level size with a null terminator */

/* BIP 44 literal constants */
#define BIP44_KEY_PATH_MAX_LENGTH 255 /* Maximum length of key path string */
#define BIP44_KEY_PATH_MAX_SIZE BIP44_KEY_PATH_MAX_LENGTH + 1 /* Key path size with a null terminator */
#define BIP44_ADDRESS_GAP_LIMIT 20 /* Maximum gap between unused addresses */
#define BIP44_FIRST_ACCOUNT_NODE 0 /* Index of the first account node */
#define BIP44_FIRST_ADDRESS_INDEX 0 /* Index of the first address */

/* A string representation of change level used to generate a BIP 44 key path */
/* The change level should be a string equal to "0" or "1" with a maximum size of BIP44_CHANGE_LEVEL_SIZE */
typedef char CHANGE_LEVEL [BIP44_CHANGE_LEVEL_SIZE];

/* A string representation of key path used to derive BIP 44 keys */
/* The key path should be a string with a maximum size of BIP44_KEY_PATH_MAX_SIZE */
typedef char KEY_PATH [BIP44_KEY_PATH_MAX_SIZE];

/* Derives a BIP 44 extended private key from a master private key. */
/* Master private key to derive from */
/* Account index (literal) */
/* Derived address index, set to NULL to get an extended key */
/* Change level ("0" for external or "1" for internal addresses */
/* Custom path string (optional, account and change_level ignored) */
/* Test net flag */
/* Key path string generated */
/* BIP 44 extended private key generated */
/* return 0 (success), -1 (fail) */
int derive_bip44_extended_private_key(const dogecoin_hdnode *master_key, const uint32_t account, const uint32_t* address_index, const CHANGE_LEVEL change_level, const KEY_PATH path, const dogecoin_bool is_testnet, KEY_PATH keypath, dogecoin_hdnode *bip44_key);

/* Derives a BIP 44 extended public key from a master public key. */
/* Master public key to derive from */
/* Account index (literal) */
/* Derived address index, set to NULL to get an extended key */
/* Change level ("0" for external or "1" for internal addresses */
/* Custom path string (optional, account and change_level ignored) */
/* Test net flag */
/* Key path string generated */
/* BIP 44 extended public key generated */
/* return 0 (success), -1 (fail) */
int derive_bip44_extended_public_key(const dogecoin_hdnode *master_key, const uint32_t account, const uint32_t* address_index, const CHANGE_LEVEL change_level, const KEY_PATH path, const dogecoin_bool is_testnet, KEY_PATH keypath, dogecoin_hdnode *bip44_key);

/* utilities */
uint8_t* utils_hex_to_uint8(const char* str);
char* utils_uint8_to_hex(const uint8_t* bin, size_t l);

/* Advanced API functions for mnemonic seedphrase generation
--------------------------------------------------------------------------
*/
Expand Down Expand Up @@ -251,10 +338,6 @@ void dogecoin_free(void* ptr);
--------------------------------------------------------------------------
*/

typedef struct dogecoin_key_ {
uint8_t privkey[DOGECOIN_ECKEY_PKEY_LENGTH];
} dogecoin_key;

typedef struct dogecoin_pubkey_ {
dogecoin_bool compressed;
uint8_t pubkey[DOGECOIN_ECKEY_UNCOMPRESSED_LENGTH];
Expand Down