diff --git a/CMakeLists.txt b/CMakeLists.txt index b7210db..41e6cf3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -208,6 +208,7 @@ set( fc_sources src/crypto/hex.cpp src/crypto/sha1.cpp src/crypto/ripemd160.cpp + src/crypto/hash160.cpp src/crypto/sha256.cpp src/crypto/sha224.cpp src/crypto/sha512.cpp diff --git a/include/fc/crypto/hash160.hpp b/include/fc/crypto/hash160.hpp new file mode 100644 index 0000000..28121bc --- /dev/null +++ b/include/fc/crypto/hash160.hpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2018 jmjatlanta and contributors. + * + * The MIT License + * + * 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. + */ +#pragma once +#include +#include +#include +#include + +namespace fc{ + +class hash160 +{ + public: + hash160(); + explicit hash160( const string& hex_str ); + + string str()const; + explicit operator string()const; + + char* data() const; + static constexpr size_t data_size() { return 160/8; } + + static hash160 hash( const char* d, uint32_t dlen ); + static hash160 hash( const string& ); + + template + static hash160 hash( const T& t ) + { + hash160::encoder e; + fc::raw::pack(e,t); + return e.result(); + } + + class encoder + { + public: + encoder(); + ~encoder(); + + void write( const char* d, uint32_t dlen ); + void put( char c ) { write( &c, 1 ); } + void reset(); + hash160 result(); + + private: + class impl; + fc::fwd my; + }; + + template + inline friend T& operator<<( T& ds, const hash160& ep ) { + ds.write( ep.data(), sizeof(ep) ); + return ds; + } + + template + inline friend T& operator>>( T& ds, hash160& ep ) { + ds.read( ep.data(), sizeof(ep) ); + return ds; + } + friend hash160 operator << ( const hash160& h1, uint32_t i ); + friend bool operator == ( const hash160& h1, const hash160& h2 ); + friend bool operator != ( const hash160& h1, const hash160& h2 ); + friend hash160 operator ^ ( const hash160& h1, const hash160& h2 ); + friend bool operator >= ( const hash160& h1, const hash160& h2 ); + friend bool operator > ( const hash160& h1, const hash160& h2 ); + friend bool operator < ( const hash160& h1, const hash160& h2 ); + + boost::endian::little_uint32_buf_t _hash[5]; +}; + +namespace raw { + + template + inline void pack( T& ds, const hash160& ep, uint32_t _max_depth ) { + ds << ep; + } + + template + inline void unpack( T& ds, hash160& ep, uint32_t _max_depth ) { + ds >> ep; + } + +} + + class variant; + void to_variant( const hash160& bi, variant& v, uint32_t max_depth ); + void from_variant( const variant& v, hash160& bi, uint32_t max_depth ); + + template<> struct get_typename { static const char* name() { return "hash160"; } }; +} // namespace fc + +namespace std +{ + template<> + struct hash + { + size_t operator()( const fc::hash160& s )const + { + return *((size_t*)&s); + } + }; +} diff --git a/include/fc/io/raw.hpp b/include/fc/io/raw.hpp index c41cc86..2b96f1e 100644 --- a/include/fc/io/raw.hpp +++ b/include/fc/io/raw.hpp @@ -307,7 +307,7 @@ namespace fc { template inline void pack( Stream& s, const bool& v, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); - fc::raw::pack( s, uint8_t(v), _max_depth - 1 ); + fc::raw::pack( s, v ? uint8_t(1) : uint8_t(0), _max_depth - 1 ); } template inline void unpack( Stream& s, bool& v, uint32_t _max_depth ) { diff --git a/include/fc/static_variant.hpp b/include/fc/static_variant.hpp index 88069d0..452b090 100644 --- a/include/fc/static_variant.hpp +++ b/include/fc/static_variant.hpp @@ -75,7 +75,7 @@ protected: void init_from_tag(tag_type tag) { FC_ASSERT( tag >= 0 ); - FC_ASSERT( tag < count() ); + FC_ASSERT( static_cast(tag) < count() ); _tag = tag; typelist::runtime::dispatch(list(), tag, [this](auto t) { using T = typename decltype(t)::type; @@ -118,7 +118,7 @@ public: template> struct tag { - static constexpr int value = typelist::index_of(); + static constexpr tag_type value = typelist::index_of(); }; struct type_lt { @@ -269,7 +269,7 @@ public: template static typename visitor::result_type visit( tag_type tag, visitor& v, void* data ) { - FC_ASSERT( tag >= 0 && tag < count(), "Unsupported type ${tag}!", ("tag",tag) ); + FC_ASSERT( tag >= 0 && static_cast(tag) < count(), "Unsupported type ${tag}!", ("tag",tag) ); return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) { return v(*reinterpret_cast(data)); }); @@ -278,7 +278,7 @@ public: template static typename visitor::result_type visit( tag_type tag, const visitor& v, void* data ) { - FC_ASSERT( tag >= 0 && tag < count(), "Unsupported type ${tag}!", ("tag",tag) ); + FC_ASSERT( tag >= 0 && static_cast(tag) < count(), "Unsupported type ${tag}!", ("tag",tag) ); return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) { return v(*reinterpret_cast(data)); }); @@ -287,7 +287,7 @@ public: template static typename visitor::result_type visit( tag_type tag, visitor& v, const void* data ) { - FC_ASSERT( tag >= 0 && tag < count(), "Unsupported type ${tag}!", ("tag",tag) ); + FC_ASSERT( tag >= 0 && static_cast(tag) < count(), "Unsupported type ${tag}!", ("tag",tag) ); return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) { return v(*reinterpret_cast(data)); }); @@ -296,18 +296,18 @@ public: template static typename visitor::result_type visit( tag_type tag, const visitor& v, const void* data ) { - FC_ASSERT( tag >= 0 && tag < count(), "Unsupported type ${tag}!", ("tag",tag) ); + FC_ASSERT( tag >= 0 && static_cast(tag) < count(), "Unsupported type ${tag}!", ("tag",tag) ); return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) { return v(*reinterpret_cast(data)); }); } - static constexpr int count() { return typelist::length(); } - void set_which( tag_type w ) { - FC_ASSERT( w >= 0 ); - FC_ASSERT( w < count() ); + static constexpr size_t count() { return typelist::length(); } + void set_which( tag_type tag ) { + FC_ASSERT( tag >= 0 ); + FC_ASSERT( static_cast(tag) < count() ); clean(); - init_from_tag(w); + init_from_tag(tag); } tag_type which() const {return _tag;} diff --git a/include/fc/variant.hpp b/include/fc/variant.hpp index 79d0a04..f0c8f25 100644 --- a/include/fc/variant.hpp +++ b/include/fc/variant.hpp @@ -581,9 +581,7 @@ namespace fc memset( this, 0, sizeof(*this) ); to_variant( val, *this, max_depth ); } - #ifdef __APPLE__ - inline void to_variant( size_t s, variant& v, uint32_t max_depth ) { v = variant(uint64_t(s)); } - #endif + template void to_variant( const std::shared_ptr& var, variant& vo, uint32_t max_depth ) { diff --git a/src/crypto/hash160.cpp b/src/crypto/hash160.cpp new file mode 100644 index 0000000..3c65e81 --- /dev/null +++ b/src/crypto/hash160.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2018 jmjatlanta and contributors. + * + * The MIT License + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "_digest_common.hpp" + +namespace fc +{ + +hash160::hash160() { memset( _hash, 0, sizeof(_hash) ); } + +hash160::hash160( const string& hex_str ) { + fc::from_hex( hex_str, (char*)_hash, sizeof(_hash) ); +} + +string hash160::str()const { + return fc::to_hex( (char*)_hash, sizeof(_hash) ); +} + +hash160::operator string()const { return str(); } + +char* hash160::data()const { return (char*)&_hash[0]; } + +struct hash160::encoder::impl { + SHA256_CTX ctx; +}; + +hash160::encoder::~encoder() {} +hash160::encoder::encoder() { SHA256_Init(&my->ctx); } + +hash160 hash160::hash( const char* d, uint32_t dlen ) { + encoder e; + e.write(d,dlen); + return e.result(); +} + +hash160 hash160::hash( const string& s ) { + return hash( s.c_str(), s.size() ); +} + +void hash160::encoder::write( const char* d, uint32_t dlen ) +{ + SHA256_Update( &my->ctx, d, dlen); +} + +hash160 hash160::encoder::result() { + // finalize the first hash + unsigned char sha_hash[SHA256_DIGEST_LENGTH]; + SHA256_Final( sha_hash, &my->ctx ); + // perform the second hashing function + RIPEMD160_CTX ripe_ctx; + RIPEMD160_Init(&ripe_ctx); + RIPEMD160_Update( &ripe_ctx, sha_hash, SHA256_DIGEST_LENGTH ); + hash160 h; + RIPEMD160_Final( (uint8_t *)h.data(), &ripe_ctx ); + return h; +} + +void hash160::encoder::reset() +{ + SHA256_Init(&my->ctx); +} + +hash160 operator << ( const hash160& h1, uint32_t i ) { + hash160 result; + fc::detail::shift_l( h1.data(), result.data(), result.data_size(), i ); + return result; +} + +hash160 operator ^ ( const hash160& h1, const hash160& h2 ) { + hash160 result; + result._hash[0] = h1._hash[0].value() ^ h2._hash[0].value(); + result._hash[1] = h1._hash[1].value() ^ h2._hash[1].value(); + result._hash[2] = h1._hash[2].value() ^ h2._hash[2].value(); + result._hash[3] = h1._hash[3].value() ^ h2._hash[3].value(); + result._hash[4] = h1._hash[4].value() ^ h2._hash[4].value(); + return result; +} + +bool operator >= ( const hash160& h1, const hash160& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) >= 0; +} + +bool operator > ( const hash160& h1, const hash160& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) > 0; +} + +bool operator < ( const hash160& h1, const hash160& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) < 0; +} + +bool operator != ( const hash160& h1, const hash160& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) != 0; +} + +bool operator == ( const hash160& h1, const hash160& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0; +} + +void to_variant( const hash160& bi, variant& v, uint32_t max_depth ) +{ + to_variant( std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth ); +} + +void from_variant( const variant& v, hash160& bi, uint32_t max_depth ) +{ + std::vector ve = v.as< std::vector >( max_depth ); + memset( &bi, char(0), sizeof(bi) ); + if( ve.size() ) + memcpy( &bi, ve.data(), std::min(ve.size(),sizeof(bi)) ); +} + +} // fc diff --git a/src/exception.cpp b/src/exception.cpp index 01d2615..aff58c9 100644 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -205,12 +205,12 @@ namespace fc ss << "ERROR: Failed to convert log data to string!\n"; } ss << " " << itr->get_context().to_string(); - ++itr; } catch( std::bad_alloc& ) { throw; } catch( ... ) { ss << "<- exception in to_detail_string."; } + ++itr; if( itr != my->_elog.end() ) ss<<"\n"; } } catch( std::bad_alloc& ) { diff --git a/src/variant.cpp b/src/variant.cpp index eaa12d3..a4d09b1 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -701,9 +701,8 @@ void from_variant( const variant& var, uint128_t& vo, uint32_t max_depth ) #endif } -#if defined(__APPLE__) -#elif defined(__OpenBSD__) - void to_variant( size_t s, variant& v, uint32_t max_depth ) { v = variant( int64_t(s) ); } +#if defined(__APPLE__) or defined(__OpenBSD__) + void to_variant( size_t s, variant& v, uint32_t max_depth ) { v = variant( uint64_t(s) ); } #elif !defined(_WIN32) void to_variant( long long int s, variant& v, uint32_t max_depth ) { v = variant( int64_t(s) ); } void to_variant( unsigned long long int s, variant& v, uint32_t max_depth ) { v = variant( uint64_t(s)); } diff --git a/tests/crypto/sha_tests.cpp b/tests/crypto/sha_tests.cpp index 9a5665c..7e3d572 100644 --- a/tests/crypto/sha_tests.cpp +++ b/tests/crypto/sha_tests.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -108,6 +109,18 @@ BOOST_AUTO_TEST_CASE(ripemd160_test) test_stream(); } +BOOST_AUTO_TEST_CASE( hash160_test ) +{ + + test( TEST1, "bb1be98c142444d7a56aa3981c3942a978e4dc33" ); + test( TEST2, "b472a266d0bd89c13706a4132ccfb16f7c3b9fcb" ); + test( TEST3, "69dda8a60e0cfc2353aa776864092c0e5ccb4834" ); + test( TEST4, "dfcc6db6ea54d85d2e3a76573183f7a037a729b0" ); + init_5(); + test( TEST5, "f9be0e104ef2ed83a7ddb4765780951405e56ba4" ); + test( TEST6, "3eca00d3b1fcafb0b74fa07fe890bea9b053a17e" ); +} + BOOST_AUTO_TEST_CASE(sha1_test) { init_5(); diff --git a/tests/stacktrace_test.cpp b/tests/stacktrace_test.cpp index feb5790..cc003d8 100644 --- a/tests/stacktrace_test.cpp +++ b/tests/stacktrace_test.cpp @@ -74,8 +74,10 @@ BOOST_AUTO_TEST_CASE(static_variant_depth_test) int count = 0; for( const auto& line : lines ) if( line.find("_svdt_visitor") != std::string::npos ) count++; - BOOST_CHECK_LT( 1, count ); // The actual count depends on compiler and optimization settings. + BOOST_CHECK_LT( 1, count ); // test.visit(), static_variant::visit, function object, visitor. + // The actual count depends on compiler and optimization settings. BOOST_CHECK_GT( 10, count ); // It *should* be less than the number of static variant components. + // some is implementation-dependent } #endif