Skip to content

Commit

Permalink
Add getDerivedHDAddressAsP2PKH function
Browse files Browse the repository at this point in the history
This derives a key from a given public or private key and returns the derived
key in P2PKH form.
  • Loading branch information
chromatic committed Jun 15, 2024
1 parent 404b539 commit b403f69
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 0 deletions.
3 changes: 3 additions & 0 deletions include/dogecoin/address.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ LIBDOGECOIN_API dogecoin_hdnode* getHDNodeAndExtKeyByPath(const char* masterkey,
/* generate an extended hd public/private child address */
LIBDOGECOIN_API int getDerivedHDAddress(const char* masterkey, uint32_t account, bool ischange, uint32_t addressindex, char* outaddress, bool outprivkey);

/* generate an extended hd public/private child address as a P2PKH */
LIBDOGECOIN_API int getDerivedHDAddressAsP2PKH(const char* masterkey, uint32_t account, bool ischange, uint32_t addressindex, char* outp2pkh);

/* generate an extended hd public/private child address with a more flexible derived path */
LIBDOGECOIN_API int getDerivedHDAddressByPath(const char* masterkey, const char* derived_path, char* outaddress);

Expand Down
30 changes: 30 additions & 0 deletions src/address.c
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,36 @@ int getDerivedHDAddress(const char* masterkey, uint32_t account, bool ischange,
return ret;
}

/**
* @brief This function generates a derived child address from a masterkey using
* a BIP44 standardized static, non hardened path comprised of an account, a change or
* receiving address and an address index.
*
* @param masterkey The master key from which children are derived from.
* @param account The account that the derived address would belong to.
* @param ischange Boolean value representing either a change or receiving address.
* @param addressindex The index of the receiving/change address per account.
* @param outp2pkh The derived address in P2PSH form.
*
* @return 1 if a derived address was successfully generated, 0 otherwise.
*/
int getDerivedHDAddressAsP2PKH(const char* masterkey, uint32_t account, bool ischange, uint32_t addressindex, char* outp2pkh) {
if (!masterkey) {
debug_print("%s", "no extended key\n");
return false;
}

char derived_path[DERIVED_PATH_STRINGLEN];
int derived_path_size = snprintf(derived_path, sizeof(derived_path), "m/44'/3'/%u'/%u/%u", account, ischange, addressindex);

if (derived_path_size >= (int)sizeof(derived_path)) {
debug_print("%s", "derivation path overflow\n");
return false;
}

return getDerivedHDAddressByPath(masterkey, derived_path, outp2pkh);
}

/**
* @brief This function generates a new dogecoin address from a mnemonic by the slip44 key path.
*
Expand Down
26 changes: 26 additions & 0 deletions test/address_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,32 @@ void test_address()
u_assert_int_eq(res, true);
u_assert_str_eq(extout, "dgub8wfrZMXz8ojFcPziSubEoQ65sB4PYPyYTMo3PqFwf2Vx5zZ6ia17Nk2Py25c3dvq1e7ZnfBrurCS5wuagzRoBCXhJ2NeGU54NBytvuUuRyA");

/* ckd p2pkh generation */
res = getDerivedHDAddressAsP2PKH(masterkey_main_ext, 0, false, 0, extout);
u_assert_int_eq(res, true);
u_assert_str_eq(extout, "DCm7oSg95sxwn3sWxYUDHgKKbB2mDmuR3B");
res = getDerivedHDAddressAsP2PKH(masterkey_main_ext, 0, true, 0, extout);
u_assert_int_eq(res, true);
u_assert_str_eq(extout, "D91jVi3CVGhRmyt83fhMdL4UJWtDuiTZET");
res = getDerivedHDAddressAsP2PKH(masterkey_main_ext, 0, false, 0, extout);
u_assert_int_eq(res, true);
u_assert_str_eq(extout, "DCm7oSg95sxwn3sWxYUDHgKKbB2mDmuR3B");
res = getDerivedHDAddressAsP2PKH(masterkey_main_ext, 0, true, 0, extout);
u_assert_int_eq(res, true);
u_assert_str_eq(extout, "D91jVi3CVGhRmyt83fhMdL4UJWtDuiTZET");
res = getDerivedHDAddressAsP2PKH(masterkey_main_ext, 1, false, 1, extout);
u_assert_int_eq(res, true);
u_assert_str_eq(extout, "D5Se361tds246n9Bm6diMQwkg7PfQrME65");
res = getDerivedHDAddressAsP2PKH(masterkey_main_ext, 1, true, 1, extout);
u_assert_int_eq(res, true);
u_assert_str_eq(extout, "DD5ztaSL3pscXYL6XXcRFTvbdghKppsKDn");
res = getDerivedHDAddressAsP2PKH(masterkey_main_ext, 1, false, 1, extout);
u_assert_int_eq(res, true);
u_assert_str_eq(extout, "D5Se361tds246n9Bm6diMQwkg7PfQrME65");
res = getDerivedHDAddressAsP2PKH(masterkey_main_ext, 1, true, 1, extout);
u_assert_int_eq(res, true);
u_assert_str_eq(extout, "DD5ztaSL3pscXYL6XXcRFTvbdghKppsKDn");

// hardened paths (unabstracted as this is called by getDerivedHDAddress)
res = getDerivedHDKeyByPath(masterkey_main_ext, "m/44'/3'/0'/0/0", extout, true);
u_assert_int_eq(res, true);
Expand Down

0 comments on commit b403f69

Please sign in to comment.