diff --git a/include/libeosio/WIF.hpp b/include/libeosio/WIF.hpp index 9632a90..91701b5 100644 --- a/include/libeosio/WIF.hpp +++ b/include/libeosio/WIF.hpp @@ -34,6 +34,11 @@ namespace libeosio { */ std::string wif_priv_encode(const ec_privkey_t& priv); +/** + * Decode an WIF String to EC private key + */ +bool wif_priv_decode(ec_privkey_t& priv, const std::string& data); + /** * Encode an EC public key to WIF String. */ diff --git a/src/WIF.cpp b/src/WIF.cpp index 3f2f94d..af38871 100644 --- a/src/WIF.cpp +++ b/src/WIF.cpp @@ -46,6 +46,33 @@ std::string wif_priv_encode(const ec_privkey_t& priv) { return base58_encode(buf, buf + sizeof(buf)); } +bool wif_priv_decode(ec_privkey_t& priv, const std::string& data) { + + std::vector buf; + + if (!base58_decode(data, buf)) { + return false; + } + + if (buf.size() != 1 + EC_PRIVKEY_SIZE + CHECKSUM_SIZE) { + return false; + } + + // First byte is the prefix + if (buf[0] != PRIV_KEY_PREFIX) { + return false; + } + + // Calculate and validate checksum + if (!checksum_validate(buf.data(), buf.size())) { + return false; + } + + // Copy data to output + memcpy(priv.data(), buf.data() + 1, priv.size()); + return true; +} + std::string wif_pub_encode(const ec_pubkey_t& pub, const std::string& prefix) { checksum_t check = checksum_ripemd160(pub.data(), pub.size()); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index efeffd0..c07706c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,6 +9,7 @@ set(TEST_SRC # WIF WIF/priv_encode.cpp + WIF/priv_decode.cpp ) add_executable(doctest ${TEST_SRC}) diff --git a/tests/WIF/priv_decode.cpp b/tests/WIF/priv_decode.cpp new file mode 100644 index 0000000..7c726df --- /dev/null +++ b/tests/WIF/priv_decode.cpp @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include + +struct wip_decode_testcase { + std::string name; + std::string key; + libeosio::ec_privkey_t expected; +}; + +TEST_CASE("WIF::wif_priv_decode") { + std::vector tests { + { "one", "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ", { 0x0C, 0x28, 0xFC, 0xA3, 0x86, 0xC7, 0xA2, 0x27, 0x60, 0x0B, 0x2F, 0xE5, 0x0B, 0x7C, 0xAE, 0x11, 0xEC, 0x86, 0xD3, 0xBF, 0x1F, 0xBE, 0x47, 0x1B, 0xE8, 0x98, 0x27, 0xE1, 0x9D, 0x72, 0xAA, 0x1D } }, + { "two", "5K2hm8apqz281ANDQdtVzifpxcXFTqG5E7Fc6Q5V2ssqPRQ3urJ", { 0x9F, 0xE3, 0xE3, 0x2B, 0x3C, 0x4B, 0x6B, 0x91, 0x6E, 0x20, 0x6C, 0xB0, 0x91, 0xDF, 0x1F, 0x5E, 0x34, 0x32, 0x88, 0x0B, 0x41, 0x33, 0x86, 0xBD, 0xF2, 0x92, 0xFF, 0x23, 0x06, 0x43, 0xF2, 0x8C } }, + { "three", "5JVanYq9HPvuKgr2FjATYB9NvTsJ4a3CAj5oPYKbr1Ja5MRLsZX", { 0x59, 0x3A, 0x51, 0xB5, 0x5D, 0x56, 0xAA, 0xF0, 0x5B, 0xD9, 0xD1, 0x0E, 0x6B, 0x88, 0x6D, 0xF9, 0xC4, 0x37, 0x09, 0xB2, 0x4C, 0xEC, 0xBB, 0x63, 0x68, 0x92, 0xC2, 0x94, 0x31, 0x48, 0x71, 0x8C } } + }; + + for(auto it = tests.begin(); it != tests.end(); it++) { + + SUBCASE(it->name.c_str()) { + + libeosio::ec_privkey_t result; + + CHECK( libeosio::wif_priv_decode(result, it->key) ); + CHECK( result == it->expected ); + } + } + +} \ No newline at end of file