diff --git a/CMakeLists.txt b/CMakeLists.txt index fb52534..2762215 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -212,6 +212,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/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/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 452a63e..ed99542 100644 --- a/tests/stacktrace_test.cpp +++ b/tests/stacktrace_test.cpp @@ -74,7 +74,7 @@ BOOST_AUTO_TEST_CASE(static_variant_depth_test) for( const auto& line : lines ) if( line.find("_svdt_visitor") != std::string::npos ) count++; BOOST_CHECK_LT( 2, count ); // test.visit(), static_variant::visit, function object, visitor - BOOST_CHECK_GT( 8, count ); // some is implementation-dependent + BOOST_CHECK_GT( 10, count ); // some is implementation-dependent } #endif