From fff5af571c68e72aeff09f9db9cad3a3435af4f0 Mon Sep 17 00:00:00 2001 From: kedar Date: Mon, 28 Jan 2019 16:05:46 -0800 Subject: [PATCH] add base58 support --- libraries/eosiolib/base58.hpp | 48 +++++++++ libraries/eosiolib/crypto.cpp | 177 ++++++++++++++++++++++++++++++++++ libraries/eosiolib/crypto.hpp | 6 ++ 3 files changed, 231 insertions(+) create mode 100644 libraries/eosiolib/base58.hpp diff --git a/libraries/eosiolib/base58.hpp b/libraries/eosiolib/base58.hpp new file mode 100644 index 0000000000..3fbba773a4 --- /dev/null +++ b/libraries/eosiolib/base58.hpp @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2012-2014 Luke Dashjr + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Minor modifications by Kedar Iyer (2019) + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +namespace eosio { + + void memzero(void * const pnt, const size_t len); + + const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + const int8_t b58digits_map[] = { + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1, + -1, 9,10,11,12,13,14,15,16,-1,17,18,19,20,21,-1, + 22,23,24,25,26,27,28,29,30,31,32,-1,-1,-1,-1,-1, + -1,33,34,35,36,37,38,39,40,41,42,43,-1,44,45,46, + 47,48,49,50,51,52,53,54,55,56,57,-1,-1,-1,-1,-1, + }; + + bool b58enc(char *b58, size_t *b58sz, const uint8_t *bin, size_t binsz); + + bool b58tobin(void *bin, size_t *binszp, const char *b58); +} diff --git a/libraries/eosiolib/crypto.cpp b/libraries/eosiolib/crypto.cpp index e2103b65c7..3bc3400d84 100644 --- a/libraries/eosiolib/crypto.cpp +++ b/libraries/eosiolib/crypto.cpp @@ -70,6 +70,24 @@ namespace eosio { return pubkey; } + std::string eosio::public_key::to_string() { + // copy public key bytes + std::array datacopy = data; + unsigned char to_encode[37]; + memcpy(to_encode, datacopy.data(), 33); + + // Calculate and concatenate checksum + checksum160 checksum = ripemd160((const char *)datacopy.begin(), 33); + memcpy(to_encode + 33, checksum.extract_as_byte_array().data(), 4); + + // convert to base58 + char b58[51]; + size_t b58sz = 51; + b58enc(b58, &b58sz, (const uint8_t *)to_encode, 37); + + return std::string((const char *)b58); + } + void assert_recover_key( const eosio::checksum256& digest, const eosio::signature& sig, const eosio::public_key& pubkey ) { auto digest_data = digest.extract_as_byte_array(); @@ -88,4 +106,163 @@ namespace eosio { pubkey_begin, (pubkey_ds.pos() - pubkey_begin) ); } + + bool b58enc(char *b58, size_t *b58sz, const uint8_t *bin, size_t binsz) + { + int carry; + ssize_t i, j, high, zcount = 0; + size_t size; + + while (zcount < (ssize_t)binsz && !bin[zcount]) + ++zcount; + + size = (binsz - zcount) * 138 / 100 + 1; + uint8_t buf[size]; + memzero(buf, size); + + for (i = zcount, high = size - 1; i < (ssize_t)binsz; ++i, high = j) + { + for (carry = bin[i], j = size - 1; (j > high) || carry; --j) + { + carry += 256 * buf[j]; + buf[j] = carry % 58; + carry /= 58; + } + } + + for (j = 0; j < (ssize_t)size && !buf[j]; ++j); + + if (*b58sz <= zcount + size - j) + { + *b58sz = zcount + size - j + 1; + return false; + } + + if (zcount) + memset(b58, '1', zcount); + for (i = zcount; j < (ssize_t)size; ++i, ++j) + b58[i] = b58digits_ordered[buf[j]]; + b58[i] = '\0'; + *b58sz = i + 1; + + return true; + } + + bool b58tobin(void *bin, size_t *binszp, const char *b58) + { + size_t binsz = *binszp; + + if (binsz == 0) { + return false; + } + + const unsigned char *b58u = (const unsigned char*)b58; + unsigned char *binu = (unsigned char *)bin; + size_t outisz = (binsz + 3) / 4; + uint32_t outi[outisz]; + uint64_t t; + uint32_t c; + size_t i, j; + uint8_t bytesleft = binsz % 4; + uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0; + unsigned zerocount = 0; + size_t b58sz; + + b58sz = strlen(b58); + + memzero(outi, sizeof(outi)); + + // Leading zeros, just count + for (i = 0; i < b58sz && b58u[i] == '1'; ++i) + ++zerocount; + + for ( ; i < b58sz; ++i) + { + if (b58u[i] & 0x80) + // High-bit set on invalid digit + return false; + if (b58digits_map[b58u[i]] == -1) + // Invalid base58 digit + return false; + c = (unsigned)b58digits_map[b58u[i]]; + for (j = outisz; j--; ) + { + t = ((uint64_t)outi[j]) * 58 + c; + c = (t & 0x3f00000000) >> 32; + outi[j] = t & 0xffffffff; + } + if (c) + // Output number too big (carry to the next int32) + return false; + if (outi[0] & zeromask) + // Output number too big (last int32 filled too far) + return false; + } + + j = 0; + switch (bytesleft) { + case 3: + *(binu++) = (outi[0] & 0xff0000) >> 16; + //-fallthrough + case 2: + *(binu++) = (outi[0] & 0xff00) >> 8; + //-fallthrough + case 1: + *(binu++) = (outi[0] & 0xff); + ++j; + //-fallthrough + default: + break; + } + + for (; j < outisz; ++j) + { + *(binu++) = (outi[j] >> 0x18) & 0xff; + *(binu++) = (outi[j] >> 0x10) & 0xff; + *(binu++) = (outi[j] >> 8) & 0xff; + *(binu++) = (outi[j] >> 0) & 0xff; + } + + // Count canonical base58 byte count + binu = (unsigned char *)bin; + for (i = 0; i < binsz; ++i) + { + if (binu[i]) { + if (zerocount > i) { + /* result too large */ + return false; + } + break; + } + --*binszp; + } + *binszp += zerocount; + + return true; + } + + void memzero(void *const pnt, const size_t len) + { + // I'm pretty sure none of the commented out stuff below + // is needed for WASM but I've left it there in case + // - Kedar Iyer + //#ifdef _WIN32 + // SecureZeroMemory(pnt, len); + //#elif defined(HAVE_MEMSET_S) + // memset_s(pnt, (rsize_t) len, 0, (rsize_t) len); + //#elif defined(HAVE_EXPLICIT_BZERO) + // explicit_bzero(pnt, len); + //#elif defined(HAVE_EXPLICIT_MEMSET) + // explicit_memset(pnt, 0, len); + //#else + volatile unsigned char *volatile pnt_ = + (volatile unsigned char *volatile) pnt; + size_t i = (size_t) 0U; + + while (i < len) { + pnt_[i++] = 0U; + } + //#endif + } + } diff --git a/libraries/eosiolib/crypto.hpp b/libraries/eosiolib/crypto.hpp index 065e38b237..989828a261 100644 --- a/libraries/eosiolib/crypto.hpp +++ b/libraries/eosiolib/crypto.hpp @@ -5,6 +5,7 @@ #pragma once #include "crypto.h" +#include "base58.hpp" #include "fixed_bytes.hpp" #include "varint.hpp" #include "serialize.hpp" @@ -39,6 +40,11 @@ namespace eosio { */ std::array data; + /** + * Human readable EOS-prefixed publickey string + */ + std::string to_string(); + friend bool operator == ( const public_key& a, const public_key& b ) { return std::tie(a.type,a.data) == std::tie(b.type,b.data); }