1
0
Fork 0
mirror of https://github.com/eosswedenorg/libantelope synced 2026-06-17 20:10:03 +02:00

WIF: Support PVT_K1 format.

This commit is contained in:
Henrik Hautakoski 2023-03-25 16:25:02 +01:00
parent ea411793a2
commit 1aa6906ba2
7 changed files with 157 additions and 38 deletions

View file

@ -30,8 +30,6 @@
namespace libeosio {
#define PRIV_KEY_PREFIX 0x80 /* 0x80 for "Bitcoin mainnet". Always used by EOS. */
// Just to make it "harder" the calculated checksum for a signature (k1) and pub/priv keys in k1/r1 format.
// has a suffix that is not present in the WIF encoded string.
// So this function is a quick hack to calculate it.
@ -46,51 +44,48 @@ checksum_t _checksum_suffix(const unsigned char *in, size_t size, const char *su
return checksum_ripemd160(buf, size + 2);
}
std::string wif_priv_encode(const ec_privkey_t& priv) {
std::string wif_priv_encode(const ec_privkey_t& priv, const std::string& prefix) {
checksum_t check;
// 1 byte extra for prefix.
unsigned char buf[1 + EC_PRIVKEY_SIZE + CHECKSUM_SIZE] = { PRIV_KEY_PREFIX };
// 1 byte extra for legacy prefix prefix.
unsigned char buf[1 + EC_PRIVKEY_SIZE + CHECKSUM_SIZE] = { 0 };
size_t len;
memcpy(buf + 1, priv.data(), priv.size());
if (prefix == WIF_PVT_K1) {
len = internal::priv_encoder_k1(priv, buf);
} else if (prefix == WIF_PVT_LEG) {
len = internal::priv_encoder_legacy(priv, buf);
} else {
return "";
}
// Checksum
check = checksum_sha256d(buf, 1 + EC_PRIVKEY_SIZE);
memcpy(buf + 1 + EC_PRIVKEY_SIZE, check.data(), check.size());
return base58_encode(buf, buf + sizeof(buf));
return prefix + base58_encode(buf, buf + len);
}
bool wif_priv_decode(ec_privkey_t& priv, const std::string& data) {
uint8_t offset;
std::vector<unsigned char> buf;
internal::priv_decoder_t decoder = internal::priv_decoder_legacy;
if (!base58_decode(data, buf)) {
// Check prefix
if (data.substr(0, WIF_PVT_K1.size()) == WIF_PVT_K1) {
offset = WIF_PVT_K1.size();
decoder = internal::priv_decoder_k1;
} else {
// Legacy
offset = 0;
}
if (!base58_decode(data.c_str() + offset, 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<checksum_sha256d>(buf.data(), buf.size())) {
return false;
}
// Copy data to output
memcpy(priv.data(), buf.data() + 1, priv.size());
return true;
return decoder(buf, priv);
}
std::string wif_pub_encode(const ec_pubkey_t& pub, const std::string& prefix) {
checksum_t check;
unsigned char buf[EC_PUBKEY_SIZE + CHECKSUM_SIZE];
internal::pub_encoder_t encoder;
@ -136,7 +131,7 @@ bool wif_pub_decode(ec_pubkey_t& pub, const std::string& data) {
void wif_print_key(const struct ec_keypair *key, const std::string& prefix) {
std::cout << "Public: " << wif_pub_encode(key->pub, prefix) << std::endl;
std::cout << "Private: " << wif_priv_encode(key->secret) << std::endl;
std::cout << "Private: " << wif_priv_encode(key->secret, prefix) << std::endl;
}
bool wif_sig_decode(ec_signature_t& sig, const std::string& data) {

View file

@ -47,6 +47,24 @@ bool pub_decoder_legacy(const std::vector<unsigned char>& buf, ec_pubkey_t& key)
bool pub_decoder_k1(const std::vector<unsigned char>& buf, ec_pubkey_t& key);
/**
* Private-key encoders
*/
typedef size_t (*priv_encoder_t)(const ec_privkey_t&, unsigned char *);
size_t priv_encoder_legacy(const ec_privkey_t& priv, unsigned char *buf);
size_t priv_encoder_k1(const ec_privkey_t& priv, unsigned char *buf);
/**
* Private-key decoders
*/
typedef bool (*priv_decoder_t)(const std::vector<unsigned char>&, ec_privkey_t&);
bool priv_decoder_legacy(const std::vector<unsigned char>& buf, ec_privkey_t& priv);
bool priv_decoder_k1(const std::vector<unsigned char>& buf, ec_privkey_t& priv);
}} // namespace libeosio::internal
#endif /* LIBEOSIO_CODEC_H */

View file

@ -61,4 +61,28 @@ bool pub_decoder_k1(const std::vector<unsigned char>& buf, ec_pubkey_t& key) {
return true;
}
size_t priv_encoder_k1(const ec_privkey_t& priv, unsigned char *buf) {
checksum_t check = _checksum_suffix(priv.data(), EC_PRIVKEY_SIZE, "K1");
memcpy(buf, priv.data(), priv.size());
memcpy(buf + EC_PRIVKEY_SIZE, check.data(), check.size());
return EC_PRIVKEY_SIZE + CHECKSUM_SIZE;
}
bool priv_decoder_k1(const std::vector<unsigned char>& buf, ec_privkey_t& priv) {
if (buf.size() != EC_PRIVKEY_SIZE + CHECKSUM_SIZE) {
return false;
}
checksum_t check = _checksum_suffix(buf.data(), EC_PRIVKEY_SIZE, "K1");
if (memcmp(buf.data() + EC_PRIVKEY_SIZE, check.data(), CHECKSUM_SIZE)) {
return false;
}
memcpy(priv.data(), buf.data(), priv.size());
return true;
}
}} // namespace libeosio::internal

View file

@ -27,6 +27,8 @@
namespace libeosio { namespace internal {
#define PRIV_KEY_PREFIX 0x80 /* 0x80 for "Bitcoin mainnet". Always used by EOS. */
void pub_encoder_legacy(const ec_pubkey_t& key, unsigned char *buf) {
checksum_t check = checksum_ripemd160(key.data(), EC_PUBKEY_SIZE);
@ -45,4 +47,32 @@ bool pub_decoder_legacy(const std::vector<unsigned char>& buf, ec_pubkey_t& key)
return true;
}
size_t priv_encoder_legacy(const ec_privkey_t& priv, unsigned char *buf) {
checksum_t check;
buf[0] = PRIV_KEY_PREFIX;
memcpy(buf + 1, priv.data(), EC_PRIVKEY_SIZE);
check = checksum_sha256d(buf, 1 + EC_PRIVKEY_SIZE);
memcpy(buf + 1 + EC_PRIVKEY_SIZE, check.data(), check.size());
return 1 + EC_PRIVKEY_SIZE + CHECKSUM_SIZE;
}
bool priv_decoder_legacy(const std::vector<unsigned char>& buf, ec_privkey_t& priv) {
if (buf[0] != PRIV_KEY_PREFIX) {
return false;
}
if (buf.size() != 1 + EC_PRIVKEY_SIZE + CHECKSUM_SIZE) {
return false;
}
if (!checksum_validate<checksum_sha256d>(buf.data(), buf.size())) {
return false;
}
memcpy(priv.data(), buf.data() + 1, priv.size());
return true;
}
}} // namespace libeosio::internal