diff --git a/.gitmodules b/.gitmodules index 3fae9b1..c49f87b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "vendor/secp256k1-zkp"] path = vendor/secp256k1-zkp - url = https://github.com/ElementsProject/secp256k1-zkp.git + url = https://github.com/cryptonomex/secp256k1-zkp.git [submodule "vendor/websocketpp"] path = vendor/websocketpp url = https://github.com/zaphoyd/websocketpp.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f6b19c..3499528 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,6 +189,7 @@ set( fc_sources src/log/file_appender.cpp src/log/gelf_appender.cpp src/log/logger_config.cpp + src/crypto/_digest_common.cpp src/crypto/openssl.cpp src/crypto/aes.cpp src/crypto/crc.cpp @@ -322,23 +323,23 @@ add_executable( api tests/api.cpp ) target_link_libraries( api fc ) if( ECC_IMPL STREQUAL secp256k1 ) - add_executable( blind tests/blind.cpp ) + add_executable( blind tests/all_tests.cpp tests/crypto/blind.cpp ) target_link_libraries( blind fc ) endif() include_directories( vendor/websocketpp ) -add_executable( ntp_test ntp_test.cpp ) +add_executable( ntp_test tests/all_tests.cpp tests/network/ntp_test.cpp ) target_link_libraries( ntp_test fc ) -add_executable( task_cancel_test tests/task_cancel.cpp ) +add_executable( task_cancel_test tests/all_tests.cpp tests/thread/task_cancel.cpp ) target_link_libraries( task_cancel_test fc ) -add_executable( bloom_test tests/bloom_test.cpp ) +add_executable( bloom_test tests/all_tests.cpp tests/bloom_test.cpp ) target_link_libraries( bloom_test fc ) -add_executable( real128_test tests/real128_test.cpp ) +add_executable( real128_test tests/all_tests.cpp tests/real128_test.cpp ) target_link_libraries( real128_test fc ) @@ -348,11 +349,9 @@ target_link_libraries( udt_server fc udt ) add_executable( udt_client tests/udtc.cpp ) target_link_libraries( udt_client fc udt ) -add_executable( ecc_test tests/ecc_test.cpp ) +add_executable( ecc_test tests/crypto/ecc_test.cpp ) target_link_libraries( ecc_test fc ) -#add_executable( test_compress tests/compress.cpp ) -#target_link_libraries( test_compress fc ) #add_executable( test_aes tests/aes_test.cpp ) #target_link_libraries( test_aes fc ${rt_library} ${pthread_library} ) #add_executable( test_sleep tests/sleep.cpp ) @@ -360,6 +359,25 @@ target_link_libraries( ecc_test fc ) #add_executable( test_rate_limiting tests/rate_limiting.cpp ) #target_link_libraries( test_rate_limiting fc ) +add_executable( all_tests tests/all_tests.cpp + tests/compress/compress.cpp + tests/crypto/aes_test.cpp + tests/crypto/base_n_tests.cpp + tests/crypto/bigint_test.cpp + tests/crypto/blind.cpp + tests/crypto/blowfish_test.cpp + tests/crypto/dh_test.cpp + tests/crypto/rand_test.cpp + tests/crypto/sha_tests.cpp + tests/network/ntp_test.cpp + tests/network/http/websocket_test.cpp + tests/thread/task_cancel.cpp + tests/bloom_test.cpp + tests/real128_test.cpp + tests/utf8_test.cpp + ) +target_link_libraries( all_tests fc ) + if(WIN32) # add addtional import library on windows platform target_link_libraries( fc PUBLIC crypt32.lib) diff --git a/README-ecc.md b/README-ecc.md index b1df7a0..32942d2 100644 --- a/README-ecc.md +++ b/README-ecc.md @@ -22,8 +22,8 @@ your system. Testing ------- -Type "make ecc_test" to build the ecc_test executable from tests/ecc_test.cpp -with the currently configured ECC implementation. +Type "make ecc_test" to build the ecc_test executable from +tests/crypto/ecc_test.cpp with the currently configured ECC implementation. ecc_test expects two arguments: @@ -38,6 +38,6 @@ If the file does exist, intermediate results from the current ECC backend are compared with the file contents. For a full round of interoperability testing, you can use the script -tests/ecc-interop.sh . +tests/crypto/ecc-interop.sh . None of the test runs should produce any output. diff --git a/include/fc/crypto/dh.hpp b/include/fc/crypto/dh.hpp index 5e6f89f..9bd4d7b 100644 --- a/include/fc/crypto/dh.hpp +++ b/include/fc/crypto/dh.hpp @@ -1,11 +1,12 @@ #pragma once +#include #include #include namespace fc { struct diffie_hellman { - diffie_hellman():valid(0),g(5){} + diffie_hellman():valid(0),g(5){ fc::init_openssl(); } bool generate_params( int s, uint8_t g ); bool generate_pub_key(); bool compute_shared_key( const char* buf, uint32_t s ); diff --git a/include/fc/crypto/openssl.hpp b/include/fc/crypto/openssl.hpp index 5811390..af883d6 100644 --- a/include/fc/crypto/openssl.hpp +++ b/include/fc/crypto/openssl.hpp @@ -22,11 +22,10 @@ namespace fc { ssl_wrapper(ssl_type* obj):obj(obj) {} - operator ssl_type*() - { - return obj; - } + operator ssl_type*() { return obj; } + operator const ssl_type*() const { return obj; } ssl_type* operator->() { return obj; } + const ssl_type* operator->() const { return obj; } ssl_type* obj; }; diff --git a/include/fc/exception/exception.hpp b/include/fc/exception/exception.hpp index 73e4bf5..028b172 100644 --- a/include/fc/exception/exception.hpp +++ b/include/fc/exception/exception.hpp @@ -70,6 +70,10 @@ namespace fc exception( log_messages&&, int64_t code = unspecified_exception_code, const std::string& name_value = "exception", const std::string& what_value = "unspecified"); + exception( const log_messages&, + int64_t code = unspecified_exception_code, + const std::string& name_value = "exception", + const std::string& what_value = "unspecified"); exception( const exception& e ); exception( exception&& e ); ~exception(); @@ -232,6 +236,10 @@ namespace fc :BASE( std::move(m), code, name_value, what_value ){} \ explicit TYPE( fc::log_messages&& m, int64_t code, const std::string& name_value, const std::string& what_value )\ :BASE( std::move(m), code, name_value, what_value ){}\ + explicit TYPE( const fc::log_messages& m, int64_t code, const std::string& name_value, const std::string& what_value )\ + :BASE( m, code, name_value, what_value ){}\ + TYPE( const std::string& what_value, const fc::log_messages& m ) \ + :BASE( m, CODE, BOOST_PP_STRINGIZE(TYPE), what_value ){} \ TYPE( fc::log_message&& m ) \ :BASE( fc::move(m), CODE, BOOST_PP_STRINGIZE(TYPE), WHAT ){}\ TYPE( fc::log_messages msgs ) \ diff --git a/include/fc/io/fstream.hpp b/include/fc/io/fstream.hpp index ddf2536..8344ce9 100644 --- a/include/fc/io/fstream.hpp +++ b/include/fc/io/fstream.hpp @@ -47,4 +47,11 @@ namespace fc { fc::shared_ptr my; }; + /** + * Grab the full contents of a file into a string object. + * NB reading a full file into memory is a poor choice + * if the file may be very large. + */ + void read_file_contents( const fc::path& filename, std::string& result ); + } // namespace fc diff --git a/include/fc/rpc/api_connection.hpp b/include/fc/rpc/api_connection.hpp index 5316285..c06d2d0 100644 --- a/include/fc/rpc/api_connection.hpp +++ b/include/fc/rpc/api_connection.hpp @@ -22,15 +22,15 @@ namespace fc { public: typedef typename std::function::result_type result_type; - callback_functor( fc::api_connection& con, uint64_t id ) + callback_functor( std::weak_ptr< fc::api_connection > con, uint64_t id ) :_callback_id(id),_api_connection(con){} template result_type operator()( Args... args )const; private: - uint64_t _callback_id; - fc::api_connection& _api_connection; + uint64_t _callback_id; + std::weak_ptr< fc::api_connection > _api_connection; }; template @@ -91,8 +91,18 @@ namespace fc { return _methods[method_id](args); } - fc::api_connection& get_connection(){ auto tmp = _api_connection.lock(); FC_ASSERT( tmp, "connection closed"); return *tmp; } + std::weak_ptr< fc::api_connection > get_connection() + { + return _api_connection; + } + std::vector get_method_names()const + { + std::vector result; + result.reserve( _by_name.size() ); + for( auto& m : _by_name ) result.push_back(m.first); + return result; + } private: friend struct api_visitor; @@ -221,9 +231,11 @@ namespace fc { return _local_callbacks.size() - 1; } + std::vector get_method_names( api_id_type local_api_id = 0 )const { return _local_apis[local_api_id]->get_method_names(); } + fc::signal closed; private: - std::vector< std::unique_ptr > _local_apis; + std::vector< std::unique_ptr > _local_apis; std::map< uint64_t, api_id_type > _handle_to_id; std::vector< std::function > _local_callbacks; @@ -382,7 +394,11 @@ namespace fc { template typename callback_functor::result_type callback_functor::operator()( Args... args )const { - _api_connection.send_callback( _callback_id, fc::variants{ args... } ).template as< result_type >(); + std::shared_ptr< fc::api_connection > locked = _api_connection.lock(); + // TODO: make new exception type for this instead of recycling eof_exception + if( !locked ) + throw fc::eof_exception(); + locked->send_callback( _callback_id, fc::variants{ args... } ).template as< result_type >(); } @@ -392,17 +408,21 @@ namespace fc { public: typedef void result_type; - callback_functor( fc::api_connection& con, uint64_t id ) + callback_functor( std::weak_ptr< fc::api_connection > con, uint64_t id ) :_callback_id(id),_api_connection(con){} void operator()( Args... args )const { - _api_connection.send_notice( _callback_id, fc::variants{ args... } ); + std::shared_ptr< fc::api_connection > locked = _api_connection.lock(); + // TODO: make new exception type for this instead of recycling eof_exception + if( !locked ) + throw fc::eof_exception(); + locked->send_notice( _callback_id, fc::variants{ args... } ); } private: - uint64_t _callback_id; - fc::api_connection& _api_connection; + uint64_t _callback_id; + std::weak_ptr< fc::api_connection > _api_connection; }; } // namespace detail diff --git a/include/fc/variant_object.hpp b/include/fc/variant_object.hpp index 55077ee..5a39c80 100644 --- a/include/fc/variant_object.hpp +++ b/include/fc/variant_object.hpp @@ -176,6 +176,14 @@ namespace fc set(std::move(key), variant( fc::forward(var) ) ); return *this; } + /** + * Copy a variant_object into this mutable_variant_object. + */ + mutable_variant_object& operator()( const variant_object& vo ); + /** + * Copy another mutable_variant_object into this mutable_variant_object. + */ + mutable_variant_object& operator()( const mutable_variant_object& mvo ); ///@} diff --git a/ntp_test.cpp b/ntp_test.cpp deleted file mode 100644 index b3937b1..0000000 --- a/ntp_test.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include -#include - -int main( int argc, char** argv ) -{ - fc::ntp ntp_service; - ntp_service.set_request_interval(5); - fc::usleep(fc::seconds(4) ); - auto time = ntp_service.get_time(); - if( time ) - { - auto ntp_time = *time; - auto delta = ntp_time - fc::time_point::now(); - auto minutes = delta.count() / 1000000 / 60; - auto hours = delta.count() / 1000000 / 60 / 60; - auto seconds = delta.count() / 1000000; - auto msec= delta.count() / 1000; - idump( (fc::time_point::now() ) ); - idump( (ntp_time)(delta)(msec)(seconds)(minutes)(hours) ); - } - else - { - elog( "no response" ); - } - - return 0; -} diff --git a/src/crypto/_digest_common.cpp b/src/crypto/_digest_common.cpp new file mode 100644 index 0000000..2c5c652 --- /dev/null +++ b/src/crypto/_digest_common.cpp @@ -0,0 +1,29 @@ +#include +#include "_digest_common.hpp" + +namespace fc { namespace detail { + static void shift_l( const uint8_t* in, uint8_t* out, std::size_t n, unsigned int i) { + if (i < n) { + memcpy( out, in + i, n-i ); + } else { + i = n; + } + memset( out + (n-i), 0, i ); + } + + void shift_l( const char* in, char* out, std::size_t n, unsigned int i) { + const uint8_t* in8 = (uint8_t*) in; + uint8_t* out8 = (uint8_t*) out; + + if (i >= 8) { + shift_l( in8, out8, n, i >> 3 ); + i &= 7; + in8 = out8; + } + + std::size_t p; + for( p = 0; p < n-1; ++p ) + out8[p] = (in8[p] << i) | (in8[p+1]>>(8-i)); + out8[p] = in8[p] << i; + } +}} diff --git a/src/crypto/_digest_common.hpp b/src/crypto/_digest_common.hpp new file mode 100644 index 0000000..8aa21b3 --- /dev/null +++ b/src/crypto/_digest_common.hpp @@ -0,0 +1,7 @@ +#pragma once + +/* Common stuff for cryptographic hashes + */ +namespace fc { namespace detail { + void shift_l( const char* in, char* out, std::size_t n, unsigned int i); +}} diff --git a/src/crypto/base32.cpp b/src/crypto/base32.cpp index 789a926..bb5354d 100644 --- a/src/crypto/base32.cpp +++ b/src/crypto/base32.cpp @@ -7,16 +7,17 @@ namespace fc { auto len = cyoBase32DecodeGetLength( b32.size() ); std::vector v(len); - cyoBase32Decode( v.data(), b32.c_str(), b32.size() ); + len = cyoBase32Decode( v.data(), b32.c_str(), b32.size() ); + v.resize( len ); return v; } std::string to_base32( const char* data, size_t len ) { - auto s = cyoBase16EncodeGetLength(len); + auto s = cyoBase32EncodeGetLength(len); std::vector b32; b32.resize(s); - cyoBase16Encode( b32.data(), data, len ); + cyoBase32Encode( b32.data(), data, len ); b32.resize( b32.size()-1); // strip the nullterm return std::string(b32.begin(),b32.end()); } diff --git a/src/crypto/base36.cpp b/src/crypto/base36.cpp index 44ce7b4..d0685ae 100644 --- a/src/crypto/base36.cpp +++ b/src/crypto/base36.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -7,9 +8,20 @@ namespace fc fc::string to_base36( const char* data, size_t len ) { if( len == 0 ) return fc::string(); - fc::bigint value( data, len ); + + const char* src = data; + int src_len = len; + std::unique_ptr buffer(new char[len+1]); + if (*data & 0x80) { + buffer[0] = 0; + memcpy( buffer.get() + 1, data, len ); + src = buffer.get(); + src_len++; + } + fc::bigint value( src, src_len ); + auto base36 = "0123456789abcdefghijklmnopqrstuvwxyz"; - std::vector out( static_cast(len * 1.6) + 1 ); + std::vector out( static_cast(len * 1.6) + 2 ); int pos = out.size() - 1; out[pos] = '\0'; fc::bigint _36(36); @@ -19,7 +31,9 @@ namespace fc out[pos] = base36[(value % _36).to_int64()]; } } while (value /= _36); - + while (len-- > 0 && *data++ == 0) { + out[--pos] = '0'; + } return &out[pos]; //fc::string( &out[pos], out.size() - pos); } @@ -30,21 +44,39 @@ namespace fc std::vector from_base36( const fc::string& b36 ) { + if ( b36.empty() ) { + std::vector empty; + return empty; + } + fc::bigint value; fc::bigint pos = 0; fc::bigint _36(36); - for( auto itr = b36.begin(); itr != b36.end(); ++itr ) + for( auto itr = b36.rbegin(); itr != b36.rend(); ++itr ) { - if( *itr - '0' < 10 ) value = value + _36.exp(pos) * fc::bigint(*itr - '0'); - else if( *itr - 'a' < 26 ) value = value + (_36.exp(pos) * fc::bigint(10+*itr - 'a')); - else if( *itr - 'A' < 26 ) value = value + (_36.exp(pos) * fc::bigint(10+*itr - 'A')); + if( *itr >= '0' && *itr <= '9' ) + value = value + _36.exp(pos) * fc::bigint(*itr - '0'); + else if( *itr >= 'a' && *itr <= 'z' ) + value = value + (_36.exp(pos) * fc::bigint(10+*itr - 'a')); + else if( *itr >= 'A' && *itr <= 'Z' ) + value = value + (_36.exp(pos) * fc::bigint(10+*itr - 'A')); else { wlog("unknown '${char}'", ("char",fc::string(&*itr,1)) ); } ++pos; } - return value; + + std::vector bytes = value; + int leading_zeros = 0, len = bytes.size(); + const char *in = b36.c_str(); + while (*in++ == '0') { leading_zeros++; } + char* first = bytes.data(); + while (len > 0 && *first == 0) { first++; len--; } + std::vector result; + result.resize(leading_zeros + len, 0); + memcpy( result.data() + leading_zeros, first, len ); + return result; } } diff --git a/src/crypto/base58.cpp b/src/crypto/base58.cpp index f7fc37e..e1d5d33 100644 --- a/src/crypto/base58.cpp +++ b/src/crypto/base58.cpp @@ -631,7 +631,7 @@ size_t from_base58( const std::string& base58_str, char* out_data, size_t out_da if( !DecodeBase58( base58_str.c_str(), out ) ) { FC_THROW_EXCEPTION( parse_error_exception, "Unable to decode base58 string ${base58_str}", ("base58_str",base58_str) ); } - + FC_ASSERT( out.size() <= out_data_len ); memcpy( out_data, out.data(), out.size() ); return out.size(); } diff --git a/src/crypto/dh.cpp b/src/crypto/dh.cpp index 7b49398..cbd7dcc 100644 --- a/src/crypto/dh.cpp +++ b/src/crypto/dh.cpp @@ -2,52 +2,45 @@ #include namespace fc { + SSL_TYPE(ssl_dh, DH, DH_free) + + static bool validate( const ssl_dh& dh, bool& valid ) { + int check; + DH_check(dh,&check); + return valid = !(check /*& DH_CHECK_P_NOT_SAFE_PRIME*/); + } + bool diffie_hellman::generate_params( int s, uint8_t g ) { - DH* dh = DH_generate_parameters( s, g, NULL, NULL ); + ssl_dh dh = DH_generate_parameters( s, g, NULL, NULL ); p.resize( BN_num_bytes( dh->p ) ); if( p.size() ) BN_bn2bin( dh->p, (unsigned char*)&p.front() ); this->g = g; - - int check; - DH_check(dh,&check); - DH_free(dh); - - if( check & DH_CHECK_P_NOT_SAFE_PRIME ) - return valid = false; - return valid = true; + return fc::validate( dh, valid ); } + bool diffie_hellman::validate() { if( !p.size() ) return valid = false; - DH* dh = DH_new(); + ssl_dh dh = DH_new(); dh->p = BN_bin2bn( (unsigned char*)&p.front(), p.size(), NULL ); dh->g = BN_bin2bn( (unsigned char*)&g, 1, NULL ); - - int check; - DH_check(dh,&check); - DH_free(dh); - if( check & DH_CHECK_P_NOT_SAFE_PRIME ) - return valid = false; - return valid = true; + return fc::validate( dh, valid ); } bool diffie_hellman::generate_pub_key() { if( !p.size() ) return valid = false; - DH* dh = DH_new(); + ssl_dh dh = DH_new(); dh->p = BN_bin2bn( (unsigned char*)&p.front(), p.size(), NULL ); dh->g = BN_bin2bn( (unsigned char*)&g, 1, NULL ); - int check; - DH_check(dh,&check); - if( check & DH_CHECK_P_NOT_SAFE_PRIME ) + if( !fc::validate( dh, valid ) ) { - DH_free(dh); - return valid = false; + return false; } DH_generate_key(dh); @@ -58,11 +51,10 @@ namespace fc { if( priv_key.size() ) BN_bn2bin( dh->priv_key, (unsigned char*)&priv_key.front() ); - DH_free(dh); - return valid = true; + return true; } bool diffie_hellman::compute_shared_key( const char* buf, uint32_t s ) { - DH* dh = DH_new(); + ssl_dh dh = DH_new(); dh->p = BN_bin2bn( (unsigned char*)&p.front(), p.size(), NULL ); dh->pub_key = BN_bin2bn( (unsigned char*)&pub_key.front(), pub_key.size(), NULL ); dh->priv_key = BN_bin2bn( (unsigned char*)&priv_key.front(), priv_key.size(), NULL ); @@ -70,22 +62,19 @@ namespace fc { int check; DH_check(dh,&check); - if( check & DH_CHECK_P_NOT_SAFE_PRIME ) + if( !fc::validate( dh, valid ) ) { - DH_free(dh); - return valid = false; + return false; } - - BIGNUM* pk = BN_bin2bn( (unsigned char*)buf, s, NULL ); + ssl_bignum pk; + BN_bin2bn( (unsigned char*)buf, s, pk ); shared_key.resize( DH_size(dh) ); DH_compute_key( (unsigned char*)&shared_key.front(), pk, dh ); - BN_free(pk); - DH_free(dh); - return valid = true; + + return true; } bool diffie_hellman::compute_shared_key( const std::vector& pubk ) { return compute_shared_key( &pubk.front(), pubk.size() ); } - } diff --git a/src/crypto/ripemd160.cpp b/src/crypto/ripemd160.cpp index ed3671a..e336b39 100644 --- a/src/crypto/ripemd160.cpp +++ b/src/crypto/ripemd160.cpp @@ -8,6 +8,7 @@ #include #include #include +#include "_digest_common.hpp" namespace fc { @@ -69,11 +70,7 @@ void ripemd160::encoder::reset() { ripemd160 operator << ( const ripemd160& h1, uint32_t i ) { ripemd160 result; - uint8_t* r = (uint8_t*)result._hash; - uint8_t* s = (uint8_t*)h1._hash; - for( uint32_t p = 0; p < sizeof(h1._hash)-1; ++p ) - r[p] = s[p] << i | (s[p+1]>>(8-i)); - r[19] = s[19] << i; + fc::detail::shift_l( h1.data(), result.data(), result.data_size(), i ); return result; } ripemd160 operator ^ ( const ripemd160& h1, const ripemd160& h2 ) { diff --git a/src/crypto/sha1.cpp b/src/crypto/sha1.cpp index 479d1ed..88107db 100644 --- a/src/crypto/sha1.cpp +++ b/src/crypto/sha1.cpp @@ -5,6 +5,7 @@ #include #include #include +#include "_digest_common.hpp" namespace fc { @@ -54,11 +55,7 @@ void sha1::encoder::reset() { sha1 operator << ( const sha1& h1, uint32_t i ) { sha1 result; - uint8_t* r = (uint8_t*)result._hash; - uint8_t* s = (uint8_t*)h1._hash; - for( uint32_t p = 0; p < sizeof(h1._hash)-1; ++p ) - r[p] = s[p] << i | (s[p+1]>>(8-i)); - r[19] = s[19] << i; + fc::detail::shift_l( h1.data(), result.data(), result.data_size(), i ); return result; } sha1 operator ^ ( const sha1& h1, const sha1& h2 ) { diff --git a/src/crypto/sha224.cpp b/src/crypto/sha224.cpp index d55802c..83f1a6a 100644 --- a/src/crypto/sha224.cpp +++ b/src/crypto/sha224.cpp @@ -4,7 +4,8 @@ #include #include #include - +#include "_digest_common.hpp" + namespace fc { sha224::sha224() { memset( _hash, 0, sizeof(_hash) ); } @@ -52,11 +53,7 @@ namespace fc { sha224 operator << ( const sha224& h1, uint32_t i ) { sha224 result; - uint8_t* r = (uint8_t*)&result;//result._hash; - uint8_t* s = (uint8_t*)&h1;//h1._hash; - for( uint32_t p = 0; p < sizeof(sha224)-1; ++p ) - r[p] = s[p] << i | (s[p+1]>>(8-i)); - r[sizeof(sha224)-1] = s[sizeof(sha224)-1] << i; + fc::detail::shift_l( h1.data(), result.data(), result.data_size(), i ); return result; } sha224 operator ^ ( const sha224& h1, const sha224& h2 ) { diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp index ae1d6af..1af5822 100644 --- a/src/crypto/sha256.cpp +++ b/src/crypto/sha256.cpp @@ -5,7 +5,8 @@ #include #include #include - +#include "_digest_common.hpp" + namespace fc { sha256::sha256() { memset( _hash, 0, sizeof(_hash) ); } @@ -64,11 +65,7 @@ namespace fc { sha256 operator << ( const sha256& h1, uint32_t i ) { sha256 result; - uint8_t* r = (uint8_t*)result._hash; - uint8_t* s = (uint8_t*)h1._hash; - for( uint32_t p = 0; p < sizeof(h1._hash)-1; ++p ) - r[p] = s[p] << i | (s[p+1]>>(8-i)); - r[31] = s[31] << i; + fc::detail::shift_l( h1.data(), result.data(), result.data_size(), i ); return result; } sha256 operator ^ ( const sha256& h1, const sha256& h2 ) { diff --git a/src/crypto/sha512.cpp b/src/crypto/sha512.cpp index d177fe3..0baa03e 100644 --- a/src/crypto/sha512.cpp +++ b/src/crypto/sha512.cpp @@ -4,6 +4,7 @@ #include #include #include +#include "_digest_common.hpp" namespace fc { @@ -52,11 +53,7 @@ namespace fc { sha512 operator << ( const sha512& h1, uint32_t i ) { sha512 result; - uint8_t* r = (uint8_t*)result._hash; - uint8_t* s = (uint8_t*)h1._hash; - for( uint32_t p = 0; p < sizeof(h1._hash)-1; ++p ) - r[p] = s[p] << i | (s[p+1]>>(8-i)); - r[63] = s[63] << i; + fc::detail::shift_l( h1.data(), result.data(), result.data_size(), i ); return result; } sha512 operator ^ ( const sha512& h1, const sha512& h2 ) { diff --git a/src/exception.cpp b/src/exception.cpp index 8887922..fef482a 100644 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -50,6 +50,19 @@ namespace fc my->_elog = fc::move(msgs); } + exception::exception( + const log_messages& msgs, + int64_t code, + const std::string& name_value, + const std::string& what_value ) + :my( new detail::exception_impl() ) + { + my->_code = code; + my->_what = what_value; + my->_name = name_value; + my->_elog = msgs; + } + unhandled_exception::unhandled_exception( log_message&& m, std::exception_ptr e ) :exception( fc::move(m) ) { diff --git a/src/io/fstream.cpp b/src/io/fstream.cpp index 71af81d..a40bbeb 100644 --- a/src/io/fstream.cpp +++ b/src/io/fstream.cpp @@ -1,7 +1,10 @@ -#include -#include + #include +#include + +#include #include +#include #include #include @@ -93,5 +96,14 @@ namespace fc { bool ifstream::eof()const { return !my->ifs.good(); } + void read_file_contents( const fc::path& filename, std::string& result ) + { + const boost::filesystem::path& bfp = filename; + boost::filesystem::ifstream f( bfp, std::ios::in | std::ios::binary ); + // don't use fc::stringstream here as we need something with override for << rdbuf() + std::stringstream ss; + ss << f.rdbuf(); + result = ss.str(); + } } // namespace fc diff --git a/src/log/file_appender.cpp b/src/log/file_appender.cpp index e6d32d3..85b69c6 100644 --- a/src/log/file_appender.cpp +++ b/src/log/file_appender.cpp @@ -38,6 +38,9 @@ namespace fc { FC_ASSERT( cfg.rotation_interval >= seconds( 1 ) ); FC_ASSERT( cfg.rotation_limit >= cfg.rotation_interval ); + + + _rotation_task = async( [this]() { rotate_files( true ); }, "rotate_files(1)" ); } } @@ -79,7 +82,11 @@ namespace fc { out.close(); } remove_all(link_filename); // on windows, you can't delete the link while the underlying file is opened for writing - out.open( log_filename ); + if( fc::exists( log_filename ) ) + out.open( log_filename, std::ios_base::out | std::ios_base::app ); + else + out.open( log_filename, std::ios_base::out | std::ios_base::app); + create_hard_link(log_filename, link_filename); } @@ -138,7 +145,8 @@ namespace fc { fc::create_directories(my->cfg.filename.parent_path()); if(!my->cfg.rotate) - my->out.open(my->cfg.filename); + my->out.open( my->cfg.filename, std::ios_base::out | std::ios_base::app); + } catch( ... ) { diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index 7cd613c..cbb92ae 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -196,7 +196,11 @@ namespace fc { namespace http { wdump(("server")(msg->get_payload())); //std::cerr<<"recv: "<get_payload()<<"\n"; auto payload = msg->get_payload(); - fc::async([=](){ current_con->second->on_message( payload ); }); + std::shared_ptr con = current_con->second; + ++_pending_messages; + auto f = fc::async([this,con,payload](){ if( _pending_messages ) --_pending_messages; con->on_message( payload ); }); + if( _pending_messages > 100 ) f.wait(); + }).wait(); }); @@ -228,6 +232,8 @@ namespace fc { namespace http { { wlog( "unknown connection closed" ); } + if( _connections.empty() && _closed ) + _closed->set_value(); }).wait(); }); @@ -244,17 +250,25 @@ namespace fc { namespace http { { wlog( "unknown connection failed" ); } + if( _connections.empty() && _closed ) + _closed->set_value(); }).wait(); } }); } ~websocket_server_impl() - { + { if( _server.is_listening() ) _server.stop_listening(); + + if( _connections.size() ) + _closed = new fc::promise(); + auto cpy_con = _connections; for( auto item : cpy_con ) _server.close( item.first, 0, "server exit" ); + + if( _closed ) _closed->wait(); } typedef std::map > con_map; @@ -264,6 +278,7 @@ namespace fc { namespace http { websocket_server_type _server; on_connection_handler _on_connection; fc::promise::ptr _closed; + uint32_t _pending_messages = 0; }; class websocket_tls_server_impl @@ -305,8 +320,8 @@ namespace fc { namespace http { auto current_con = _connections.find(hdl); assert( current_con != _connections.end() ); auto received = msg->get_payload(); - wdump((received)); - fc::async([=](){ current_con->second->on_message( received ); }); + std::shared_ptr con = current_con->second; + fc::async([con,received](){ con->on_message( received ); }); }).wait(); }); diff --git a/src/rpc/cli.cpp b/src/rpc/cli.cpp index df2c0e2..d3070fb 100644 --- a/src/rpc/cli.cpp +++ b/src/rpc/cli.cpp @@ -30,6 +30,12 @@ namespace fc { namespace rpc { +static std::vector& cli_commands() +{ + static std::vector* cmds = new std::vector(); + return *cmds; +} + cli::~cli() { if( _run_complete.valid() ) @@ -55,6 +61,7 @@ void cli::send_notice( uint64_t callback_id, variants args /* = variants() */ ) void cli::start() { + cli_commands() = get_method_names(0); _run_complete = fc::async( [&](){ run(); } ); } @@ -118,6 +125,57 @@ void cli::run() } } + +char * dupstr (const char* s) { + char *r; + + r = (char*) malloc ((strlen (s) + 1)); + strcpy (r, s); + return (r); +} + +char* my_generator(const char* text, int state) +{ + static int list_index, len; + const char *name; + + if (!state) { + list_index = 0; + len = strlen (text); + } + + auto& cmd = cli_commands(); + + while( list_index < cmd.size() ) + { + name = cmd[list_index].c_str(); + list_index++; + + if (strncmp (name, text, len) == 0) + return (dupstr(name)); + } + + /* If no names matched, then return NULL. */ + return ((char *)NULL); +} + + +static char** cli_completion( const char * text , int start, int end) +{ + char **matches; + matches = (char **)NULL; + +#ifdef HAVE_READLINE + if (start == 0) + matches = rl_completion_matches ((char*)text, &my_generator); + else + rl_bind_key('\t',rl_abort); +#endif + + return (matches); +} + + void cli::getline( const fc::string& prompt, fc::string& line) { // getting file descriptor for C++ streams is near impossible @@ -134,6 +192,8 @@ void cli::getline( const fc::string& prompt, fc::string& line) if( _isatty( _fileno( stdin ) ) ) #endif { + rl_attempted_completion_function = cli_completion; + static fc::thread getline_thread("getline"); getline_thread.async( [&](){ char* line_read = nullptr; @@ -141,6 +201,7 @@ void cli::getline( const fc::string& prompt, fc::string& line) line_read = readline(prompt.c_str()); if( line_read == nullptr ) FC_THROW_EXCEPTION( fc::eof_exception, "" ); + rl_bind_key( '\t', rl_complete ); if( *line_read ) add_history(line_read); line = line_read; diff --git a/src/time.cpp b/src/time.cpp index 20d003e..27dd848 100644 --- a/src/time.cpp +++ b/src/time.cpp @@ -117,7 +117,7 @@ namespace fc { return result.str(); } uint32_t years_ago = days_ago / 365; - result << years_ago << " year" << (months_ago > 1 ? "s " : " "); + result << years_ago << " year" << (months_ago > 1 ? "s" : ""); if (months_ago < 12 * 5) { uint32_t leftover_days = days_ago - (years_ago * 365); diff --git a/src/variant_object.cpp b/src/variant_object.cpp index f3cb488..6f3b1dc 100644 --- a/src/variant_object.cpp +++ b/src/variant_object.cpp @@ -350,6 +350,22 @@ namespace fc return *this; } + mutable_variant_object& mutable_variant_object::operator()( const variant_object& vo ) + { + for( const variant_object::entry& e : vo ) + set( e.key(), e.value() ); + return *this; + } + + mutable_variant_object& mutable_variant_object::operator()( const mutable_variant_object& mvo ) + { + if( &mvo == this ) // mvo(mvo) is no-op + return *this; + for( const mutable_variant_object::entry& e : mvo ) + set( e.key(), e.value() ); + return *this; + } + void to_variant( const mutable_variant_object& var, variant& vo ) { vo = variant(var); diff --git a/tests/aes_test.cpp b/tests/aes_test.cpp deleted file mode 100644 index 4b85134..0000000 --- a/tests/aes_test.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include -#include - -#include -int main( int argc, char** ) -{ - std::string line; - std::getline( std::cin, line ); - auto key = fc::sha512::hash( "hello", 5 ); - while( std::cin && line != "q" ) - { - try { - std::vector data( line.c_str(),line.c_str()+line.size()+1 ); - std::vector crypt = fc::aes_encrypt( key, data ); - std::vector dcrypt = fc::aes_decrypt( key, crypt ); - - std::cout<<"line.size: '"< + diff --git a/tests/bloom_test.cpp b/tests/bloom_test.cpp index 2e9adb5..ca17792 100644 --- a/tests/bloom_test.cpp +++ b/tests/bloom_test.cpp @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -10,10 +12,8 @@ using namespace fc; -int main( int argc, char** argv ) +static bloom_parameters setup_parameters() { - try { - bloom_parameters parameters; // How many elements roughly do we expect to insert? @@ -27,25 +27,31 @@ int main( int argc, char** argv ) if (!parameters) { - std::cout << "Error - Invalid set of bloom filter parameters!" << std::endl; - return 1; + BOOST_FAIL( "Error - Invalid set of bloom filter parameters!" ); } parameters.compute_optimal_parameters(); - //Instantiate Bloom Filter - bloom_filter filter(parameters); + return parameters; +} + +BOOST_AUTO_TEST_SUITE(fc_crypto) + +BOOST_AUTO_TEST_CASE(bloom_test_1) +{ + try { + + //Instantiate Bloom Filter + bloom_filter filter(setup_parameters()); - if( argc > 1 ) - { uint32_t count = 0; std::string line; - std::ifstream in(argv[1]); + std::ifstream in("README.md"); std::ofstream words("words.txt"); while( !in.eof() && count < 100000 ) { std::getline(in, line); - std::cout << "'"< -100; --i) { - if (filter.contains(i)) - { - std::cout << "BF falsely contains: " << i << std::endl; - } + BOOST_CHECK( !filter.contains(i) ); } } - - wdump((filter)); - auto packed_filter = fc::raw::pack(filter); - wdump((packed_filter.size())); - wdump((packed_filter)); - - return 0; } catch ( const fc::exception& e ) { edump((e.to_detail_string()) ); } } + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/compress.cpp b/tests/compress.cpp deleted file mode 100644 index d5ad840..0000000 --- a/tests/compress.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include - -int main( int argc, char** ) -{ - std::string line; - std::getline( std::cin, line ); - while( std::cin && line != "q" ) - { - try { - - std::string compressed = fc::smaz_compress( line ); - std::cout<<"compressed size: "< + +#include +#include +#include +#include +#include + +BOOST_AUTO_TEST_SUITE(compress) + +BOOST_AUTO_TEST_CASE(smaz_test) +{ + std::ifstream testfile; + testfile.open("README.md"); + + std::stringstream buffer; + std::string line; + std::getline( testfile, line ); + while( testfile.good() ) + { + buffer << line << "\n"; + try { + std::string compressed = fc::smaz_compress( line ); + std::string decomp = fc::smaz_decompress( compressed ); + BOOST_CHECK_EQUAL( decomp, line ); + } + catch ( fc::exception& e ) + { + std::cout< + +#include +#include +#include +#include +#include + +#include + +BOOST_AUTO_TEST_SUITE(fc_crypto) + +BOOST_AUTO_TEST_CASE(aes_test) +{ + std::ifstream testfile; + testfile.open("README.md"); + + auto key = fc::sha512::hash( "hello", 5 ); + std::stringstream buffer; + std::string line; + std::getline( testfile, line ); + while( testfile.good() ) + { +// std::cout << line << "\n"; + buffer << line << "\n"; + try { + std::vector data( line.c_str(),line.c_str()+line.size()+1 ); + std::vector crypt = fc::aes_encrypt( key, data ); + std::vector dcrypt = fc::aes_decrypt( key, crypt ); + BOOST_CHECK( data == dcrypt ); + +// memset( crypt.data(), 0, crypt.size() ); +// fc::aes_encoder enc; +// enc.init( fc::sha256::hash((char*)&key,sizeof(key) ), fc::city_hash_crc_128( (char*)&key, sizeof(key) ) ); +// auto len = enc.encode( dcrypt.data(), dcrypt.size(), crypt.data() ); +// BOOST_CHECK_EQUAL( dcrypt.size(), len ); +// +// fc::aes_decoder dec; +// dec.init( fc::sha256::hash((char*)&key,sizeof(key) ), fc::city_hash_crc_128( (char*)&key, sizeof(key) ) ); +// len = dec.decode( crypt.data(), len, dcrypt.data() ); +// BOOST_CHECK_EQUAL( dcrypt.size(), len ); +// BOOST_CHECK( !memcmp( dcrypt.data(), data.data(), len) ); + } + catch ( fc::exception& e ) + { + std::cout< data( line.c_str(),line.c_str()+line.size()+1 ); + std::vector crypt = fc::aes_encrypt( key, data ); + std::vector dcrypt = fc::aes_decrypt( key, crypt ); + BOOST_CHECK( data == dcrypt ); + +// memset( crypt.data(), 0, crypt.size() ); +// fc::aes_encoder enc; +// enc.init( fc::sha256::hash((char*)&key,sizeof(key) ), fc::city_hash_crc_128( (char*)&key, sizeof(key) ) ); +// auto len = enc.encode( dcrypt.data(), dcrypt.size(), crypt.data() ); +// BOOST_CHECK_EQUAL( dcrypt.size(), len ); +// +// fc::aes_decoder dec; +// dec.init( fc::sha256::hash((char*)&key,sizeof(key) ), fc::city_hash_crc_128( (char*)&key, sizeof(key) ) ); +// len = dec.decode( crypt.data(), len, dcrypt.data() ); +// BOOST_CHECK_EQUAL( dcrypt.size(), len ); +// BOOST_CHECK( !memcmp( dcrypt.data(), data.data(), len) ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/crypto/base_n_tests.cpp b/tests/crypto/base_n_tests.cpp new file mode 100644 index 0000000..a501123 --- /dev/null +++ b/tests/crypto/base_n_tests.cpp @@ -0,0 +1,150 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include + +static const std::string TEST1(""); +static const std::string TEST2("\0\00101", 4); +static const std::string TEST3("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); +static const std::string TEST4("\377\376\000\375\001\374", 6); +static const std::string TEST5("\0\0\0", 3); + +static void test_16( const std::string& test, const std::string& expected ) +{ + std::vector vec( test.begin(), test.end() ); + fc::string enc1 = fc::to_hex( vec ); + fc::string enc2 = fc::to_hex( test.c_str(), test.size() ); + BOOST_CHECK_EQUAL( enc1, enc2 ); + BOOST_CHECK_EQUAL( expected, enc2 ); + + char out[32]; + int len = fc::from_hex( enc1, out, 32 ); + BOOST_CHECK_EQUAL( test.size(), len ); + BOOST_CHECK( !memcmp( test.c_str(), out, len ) ); + if (len > 10) { + BOOST_CHECK( fc::from_hex( enc1, out, 10 ) <= 10 ); + } +} + +BOOST_AUTO_TEST_SUITE(fc_crypto) + +BOOST_AUTO_TEST_CASE(hex_test) +{ + test_16( TEST1, "" ); + test_16( TEST2, "00013031" ); + test_16( TEST3, "4142434445464748494a4b4c4d4e4f505152535455565758595a" ); + test_16( TEST4, "fffe00fd01fc" ); + test_16( TEST5, "000000" ); +} + + +static void test_32( const std::string& test, const std::string& expected ) +{ + std::vector vec( test.begin(), test.end() ); + fc::string enc1 = fc::to_base32( vec ); + fc::string enc2 = fc::to_base32( test.c_str(), test.size() ); + BOOST_CHECK_EQUAL( enc1, enc2 ); + BOOST_CHECK_EQUAL( expected, enc2 ); + + std::vector dec = fc::from_base32( enc1 ); + BOOST_CHECK_EQUAL( vec.size(), dec.size() ); + BOOST_CHECK( !memcmp( vec.data(), dec.data(), vec.size() ) ); +} + +BOOST_AUTO_TEST_CASE(base32_test) +{ + test_32( TEST1, "" ); + test_32( TEST2, "AAATAMI=" ); + test_32( TEST3, "IFBEGRCFIZDUQSKKJNGE2TSPKBIVEU2UKVLFOWCZLI======" ); + test_32( TEST4, "777AB7IB7Q======" ); + test_32( TEST5, "AAAAA===" ); +} + + +static void test_36( const std::string& test, const std::string& expected ) +{ + std::vector vec( test.begin(), test.end() ); + fc::string enc1 = fc::to_base36( vec ); + fc::string enc2 = fc::to_base36( test.c_str(), test.size() ); + BOOST_CHECK_EQUAL( enc1, enc2 ); + BOOST_CHECK_EQUAL( expected, enc2 ); + + std::vector dec = fc::from_base36( enc1 ); + BOOST_CHECK_EQUAL( vec.size(), dec.size() ); + BOOST_CHECK( !memcmp( vec.data(), dec.data(), vec.size() ) ); +} + +BOOST_AUTO_TEST_CASE(base36_test) +{ + test_36( TEST1, "" ); + test_36( TEST2, "01o35" ); + test_36( TEST3, "l4ksdleyi5pnl0un5raue268ptj43dwjwmz15ie2" ); + test_36( TEST4, "2rrrvpb7y4" ); + test_36( TEST5, "000" ); +} + + +static void test_58( const std::string& test, const std::string& expected ) +{ + std::vector vec( test.begin(), test.end() ); + fc::string enc1 = fc::to_base58( vec ); + fc::string enc2 = fc::to_base58( test.c_str(), test.size() ); + BOOST_CHECK_EQUAL( enc1, enc2 ); + BOOST_CHECK_EQUAL( expected, enc2 ); + + std::vector dec = fc::from_base58( enc1 ); + BOOST_CHECK_EQUAL( vec.size(), dec.size() ); + BOOST_CHECK( !memcmp( vec.data(), dec.data(), vec.size() ) ); + + char buffer[64]; + size_t len = fc::from_base58( enc1, buffer, 64 ); + BOOST_CHECK( len <= 64 ); + BOOST_CHECK( !memcmp( vec.data(), buffer, len ) ); + if ( len > 10 ) { + try { + len = fc::from_base58( enc1, buffer, 10 ); + BOOST_CHECK( len <= 10 ); + } catch ( fc::exception expected ) {} + } + +} + +BOOST_AUTO_TEST_CASE(base58_test) +{ + test_58( TEST1, "" ); + test_58( TEST2, "1Q9e" ); + test_58( TEST3, "2zuFXTJSTRK6ESktqhM2QDBkCnH1U46CnxaD" ); + test_58( TEST4, "3CUeREErf" ); + test_58( TEST5, "111" ); +} + + +static void test_64( const std::string& test, const std::string& expected ) +{ + fc::string enc1 = fc::base64_encode( test ); + fc::string enc2 = fc::base64_encode( test.c_str(), test.size() ); + BOOST_CHECK_EQUAL( enc1, enc2 ); + BOOST_CHECK_EQUAL( expected, enc2 ); + + std::string dec = fc::base64_decode( enc1 ); + BOOST_CHECK_EQUAL( test.size(), dec.size() ); + BOOST_CHECK_EQUAL( test, dec ); +} + +BOOST_AUTO_TEST_CASE(base64_test) +{ + test_64( TEST1, "" ); + test_64( TEST2, "AAEwMQ==" ); + test_64( TEST3, "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=" ); + test_64( TEST4, "//4A/QH8" ); + test_64( TEST5, "AAAA" ); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/crypto/bigint_test.cpp b/tests/crypto/bigint_test.cpp new file mode 100644 index 0000000..5473b7a --- /dev/null +++ b/tests/crypto/bigint_test.cpp @@ -0,0 +1,77 @@ +#include + +#include +#include + +BOOST_AUTO_TEST_SUITE(fc_crypto) + +BOOST_AUTO_TEST_CASE(bigint_test_1) +{ + int64_t counter = 0, accu = 0, c_sq; + fc::bigint bi_accu(accu); + do { + c_sq = counter * counter; + fc::bigint add(c_sq); + bi_accu += add; + accu += c_sq; + BOOST_CHECK( fc::bigint(accu) == bi_accu ); + + bi_accu = bi_accu + add; + accu = accu + c_sq; + BOOST_CHECK_EQUAL( accu, bi_accu.to_int64() ); + + bi_accu = fc::bigint( bi_accu.dup() ); + + counter++; + } while (c_sq < 1000000); + + fc::variant test; + fc::to_variant( bi_accu, test ); + fc::bigint other; + fc::from_variant( test, other ); + BOOST_CHECK( other == bi_accu ); +} + +BOOST_AUTO_TEST_CASE(bigint_test_2) +{ + const fc::bigint bi_1(1), bi_3(3), bi_17(17), bi_65537(65537); + fc::bigint bi_accu(bi_1); + do { + std::vector bytes = bi_accu; + fc::bigint a_1( bytes ); + a_1 = a_1 + bi_1; + BOOST_CHECK( bi_accu < a_1 ); + + bi_accu = a_1 * bi_accu; + BOOST_CHECK( bi_accu >= a_1 ); + } while ( bi_accu.log2() <= 128 ); + + bi_accu = bi_accu; + + BOOST_CHECK( bi_accu && !bi_accu.is_negative() && bi_accu != bi_1 ); + + BOOST_CHECK( bi_3.exp( bi_accu.log2() ) > bi_accu ); + + fc::bigint big(1); + big <<= 30; big += bi_17; big <<= 30; big++; + big <<= 30; big -= bi_17; big >>= 5; big--; + fc::bigint rest = bi_accu % big; + BOOST_CHECK( (bi_accu - rest) / big == bi_accu / big ); + + fc::bigint big2; big2 = big; + big2 *= bi_65537.exp(3); + big2 /= bi_65537.exp(3); + BOOST_CHECK( big2 == big ); + big--; + + BOOST_CHECK_EQUAL( (std::string) bi_1, "1" ); + BOOST_CHECK_EQUAL( (std::string) bi_3, "3" ); + BOOST_CHECK_EQUAL( (std::string) bi_17, "17" ); + BOOST_CHECK_EQUAL( (std::string) bi_65537, "65537" ); + BOOST_CHECK_EQUAL( (std::string) bi_65537.exp(3), "281487861809153" ); + BOOST_CHECK_EQUAL( (std::string) bi_accu, "12864938683278671740537145998360961546653259485195806" ); + BOOST_CHECK_EQUAL( (std::string) big, "38685626840157682946539517" ); +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/tests/blind.cpp b/tests/crypto/blind.cpp similarity index 66% rename from tests/blind.cpp rename to tests/crypto/blind.cpp index 1aad15d..29f81f9 100644 --- a/tests/blind.cpp +++ b/tests/crypto/blind.cpp @@ -1,16 +1,14 @@ +#include + #include #include #include #include #include -//extern "C" { -//#include -//} -//struct secp256k1_scalar_t { uint64_t v[4]; }; -//extern "C" { void secp256k1_scalar_get_b32(unsigned char *bin, const struct secp256k1_scalar_t* a); } +BOOST_AUTO_TEST_SUITE(fc_crypto) -int main( int argc, char** argv ) +BOOST_AUTO_TEST_CASE(blind_test) { try { auto InB1 = fc::sha256::hash("InB1"); @@ -34,16 +32,16 @@ int main( int argc, char** argv ) //FC_ASSERT( fc::ecc::verify_sum( {InC1,InC2}, {OutC1}, -60 ) ); - FC_ASSERT( fc::ecc::verify_sum( {InC1,InC2}, {OutC1,OutC2}, 0 ) ); + BOOST_CHECK( fc::ecc::verify_sum( {InC1,InC2}, {OutC1,OutC2}, 0 ) ); auto nonce = fc::sha256::hash("nonce"); auto proof = fc::ecc::range_proof_sign( 0, OutC1, OutB1, nonce, 0, 0, 40 ); - wdump( (proof.size())); +// wdump( (proof.size())); auto result = fc::ecc::range_get_info( proof ); - wdump((result)); - FC_ASSERT( result.max_value >= 60 ); - FC_ASSERT( result.min_value >= 0 ); +// wdump((result)); + BOOST_CHECK( result.max_value >= 60 ); + BOOST_CHECK( result.min_value >= 0 ); auto B1 = fc::sha256::hash("B1"); @@ -62,10 +60,10 @@ int main( int argc, char** argv ) auto B2m1 = fc::ecc::blind_sum( {B2,B1}, 1 ); auto C2m1 = fc::ecc::blind( B2m1, 1 ); - FC_ASSERT( fc::ecc::verify_sum( {C1,C2}, {C3}, 0 ) ); - FC_ASSERT( fc::ecc::verify_sum( {C1,C2}, {C3}, 0 ) ); - FC_ASSERT( fc::ecc::verify_sum( {C3}, {C1,C2}, 0 ) ); - FC_ASSERT( fc::ecc::verify_sum( {C3}, {C1,C2}, 0 ) ); + BOOST_CHECK( fc::ecc::verify_sum( {C1,C2}, {C3}, 0 ) ); + BOOST_CHECK( fc::ecc::verify_sum( {C1,C2}, {C3}, 0 ) ); + BOOST_CHECK( fc::ecc::verify_sum( {C3}, {C1,C2}, 0 ) ); + BOOST_CHECK( fc::ecc::verify_sum( {C3}, {C1,C2}, 0 ) ); { @@ -82,13 +80,13 @@ int main( int argc, char** argv ) auto C3 = fc::ecc::blind( B1, 1 ); auto C4 = fc::ecc::blind( B1, 2 ); - FC_ASSERT( fc::ecc::verify_sum( {C2}, {C3}, -1 ) ); - FC_ASSERT( fc::ecc::verify_sum( {C1}, {C1}, 0 ) ); - FC_ASSERT( fc::ecc::verify_sum( {C2}, {C2}, 0 ) ); - FC_ASSERT( fc::ecc::verify_sum( {C3}, {C2}, 1 ) ); - FC_ASSERT( fc::ecc::verify_sum( {C1}, {C2}, INT64_MAX ) ); - FC_ASSERT( fc::ecc::verify_sum( {C1}, {C2}, INT64_MAX ) ); - FC_ASSERT( fc::ecc::verify_sum( {C2}, {C1}, -INT64_MAX ) ); + BOOST_CHECK( fc::ecc::verify_sum( {C2}, {C3}, -1 ) ); + BOOST_CHECK( fc::ecc::verify_sum( {C1}, {C1}, 0 ) ); + BOOST_CHECK( fc::ecc::verify_sum( {C2}, {C2}, 0 ) ); + BOOST_CHECK( fc::ecc::verify_sum( {C3}, {C2}, 1 ) ); + BOOST_CHECK( fc::ecc::verify_sum( {C1}, {C2}, INT64_MAX ) ); + BOOST_CHECK( fc::ecc::verify_sum( {C1}, {C2}, INT64_MAX ) ); + BOOST_CHECK( fc::ecc::verify_sum( {C2}, {C1}, -INT64_MAX ) ); } @@ -101,16 +99,15 @@ int main( int argc, char** argv ) auto InC = fc::ecc::blind( InBlind, 1000 ); auto In0 = fc::ecc::blind( InBlind, 0 ); - FC_ASSERT( fc::ecc::verify_sum( {InC}, {OutC1,OutC2}, 0 ) ); - FC_ASSERT( fc::ecc::verify_sum( {InC}, {In0}, 1000 ) ); + BOOST_CHECK( fc::ecc::verify_sum( {InC}, {OutC1,OutC2}, 0 ) ); + BOOST_CHECK( fc::ecc::verify_sum( {InC}, {In0}, 1000 ) ); } - - } catch ( const fc::exception& e ) { edump((e.to_detail_string())); } - return 0; } + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/crypto/blowfish_test.cpp b/tests/crypto/blowfish_test.cpp new file mode 100644 index 0000000..ec4ada7 --- /dev/null +++ b/tests/crypto/blowfish_test.cpp @@ -0,0 +1,169 @@ +#include + +#include +#include + +// Test vectors from https://www.schneier.com/code/vectors.txt + +struct ecb_testdata { + char key[17], plain[17], cipher[17]; +} ecb_tests[] = { + { "0000000000000000", "0000000000000000", "4EF997456198DD78" }, + { "FFFFFFFFFFFFFFFF", "FFFFFFFFFFFFFFFF", "51866FD5B85ECB8A" }, + { "3000000000000000", "1000000000000001", "7D856F9A613063F2" }, + { "1111111111111111", "1111111111111111", "2466DD878B963C9D" }, + { "0123456789ABCDEF", "1111111111111111", "61F9C3802281B096" }, + { "1111111111111111", "0123456789ABCDEF", "7D0CC630AFDA1EC7" }, + { "0000000000000000", "0000000000000000", "4EF997456198DD78" }, + { "FEDCBA9876543210", "0123456789ABCDEF", "0ACEAB0FC6A0A28D" }, + { "7CA110454A1A6E57", "01A1D6D039776742", "59C68245EB05282B" }, + { "0131D9619DC1376E", "5CD54CA83DEF57DA", "B1B8CC0B250F09A0" }, + { "07A1133E4A0B2686", "0248D43806F67172", "1730E5778BEA1DA4" }, + { "3849674C2602319E", "51454B582DDF440A", "A25E7856CF2651EB" }, + { "04B915BA43FEB5B6", "42FD443059577FA2", "353882B109CE8F1A" }, + { "0113B970FD34F2CE", "059B5E0851CF143A", "48F4D0884C379918" }, + { "0170F175468FB5E6", "0756D8E0774761D2", "432193B78951FC98" }, + { "43297FAD38E373FE", "762514B829BF486A", "13F04154D69D1AE5" }, + { "07A7137045DA2A16", "3BDD119049372802", "2EEDDA93FFD39C79" }, + { "04689104C2FD3B2F", "26955F6835AF609A", "D887E0393C2DA6E3" }, + { "37D06BB516CB7546", "164D5E404F275232", "5F99D04F5B163969" }, + { "1F08260D1AC2465E", "6B056E18759F5CCA", "4A057A3B24D3977B" }, + { "584023641ABA6176", "004BD6EF09176062", "452031C1E4FADA8E" }, + { "025816164629B007", "480D39006EE762F2", "7555AE39F59B87BD" }, + { "49793EBC79B3258F", "437540C8698F3CFA", "53C55F9CB49FC019" }, + { "4FB05E1515AB73A7", "072D43A077075292", "7A8E7BFA937E89A3" }, + { "49E95D6D4CA229BF", "02FE55778117F12A", "CF9C5D7A4986ADB5" }, + { "018310DC409B26D6", "1D9D5C5018F728C2", "D1ABB290658BC778" }, + { "1C587F1C13924FEF", "305532286D6F295A", "55CB3774D13EF201" }, + { "0101010101010101", "0123456789ABCDEF", "FA34EC4847B268B2" }, + { "1F1F1F1F0E0E0E0E", "0123456789ABCDEF", "A790795108EA3CAE" }, + { "E0FEE0FEF1FEF1FE", "0123456789ABCDEF", "C39E072D9FAC631D" }, + { "0000000000000000", "FFFFFFFFFFFFFFFF", "014933E0CDAFF6E4" }, + { "FFFFFFFFFFFFFFFF", "0000000000000000", "F21E9A77B71C49BC" }, + { "0123456789ABCDEF", "0000000000000000", "245946885754369A" }, + { "FEDCBA9876543210", "FFFFFFFFFFFFFFFF", "6B5C5A9C5D9E0A5A" } +}; + +const std::string key_test_key = "F0E1D2C3B4A5968778695A4B3C2D1E0F0011223344556677"; +const std::string key_test_plain = "FEDCBA9876543210"; +const char key_test_ciphers[][17] = { + "F9AD597C49DB005E", + "E91D21C1D961A6D6", + "E9C2B70A1BC65CF3", + "BE1E639408640F05", + "B39E44481BDB1E6E", + "9457AA83B1928C0D", + "8BB77032F960629D", + "E87A244E2CC85E82", + "15750E7A4F4EC577", + "122BA70B3AB64AE0", + "3A833C9AFFC537F6", + "9409DA87A90F6BF2", + "884F80625060B8B4", + "1F85031C19E11968", + "79D9373A714CA34F", + "93142887EE3BE15C", + "03429E838CE2D14B", + "A4299E27469FF67B", + "AFD5AED1C1BC96A8", + "10851C0E3858DA9F", + "E6F51ED79B9DB21F", + "64A6E14AFD36B46F", + "80C7D7D45A5479AD", + "05044B62FA52D080", +}; + +const std::string chain_test_key = "0123456789ABCDEFF0E1D2C3B4A59687"; +const std::string chain_test_iv = "FEDCBA9876543210"; +const std::string chain_test_plain = "7654321 Now is the time for \0\0\0\0"; +const std::string chain_test_cbc = "6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC"; +const std::string chain_test_cfb = "E73214A2822139CAF26ECF6D2EB9E76E3DA3DE04D1517200519D57A6C3"; + +BOOST_AUTO_TEST_SUITE(fc_crypto) + +BOOST_AUTO_TEST_CASE(blowfish_ecb_test) +{ + for ( int i = 0; i < 34; i++ ) { + unsigned char key[8], plain[8], cipher[8], out[8]; + BOOST_CHECK_EQUAL( 8, fc::from_hex( ecb_tests[i].key, (char*) key, sizeof(key) ) ); + BOOST_CHECK_EQUAL( 8, fc::from_hex( ecb_tests[i].plain, (char*) plain, sizeof(plain) ) ); + BOOST_CHECK_EQUAL( 8, fc::from_hex( ecb_tests[i].cipher, (char*) cipher, sizeof(cipher) ) ); + + fc::blowfish fish; + fish.start( key, 8 ); + fish.encrypt( plain, out, 8, fc::blowfish::ECB ); + BOOST_CHECK( !memcmp( cipher, out, 8) ); + fish.decrypt( out, 8, fc::blowfish::ECB ); + BOOST_CHECK( !memcmp( plain, out, 8) ); + fish.decrypt( cipher, out, 8, fc::blowfish::ECB ); + BOOST_CHECK( !memcmp( plain, out, 8) ); + fish.encrypt( out, 8, fc::blowfish::ECB ); + BOOST_CHECK( !memcmp( cipher, out, 8) ); + } +} + +BOOST_AUTO_TEST_CASE(blowfish_key_test) +{ + unsigned char key[24], plain[8], cipher[8], out[8]; + BOOST_CHECK_EQUAL( 24, fc::from_hex( key_test_key.c_str(), (char*) key, sizeof(key) ) ); + BOOST_CHECK_EQUAL( 8, fc::from_hex( key_test_plain.c_str(), (char*) plain, sizeof(plain) ) ); + + for ( unsigned int i = 0; i < sizeof(key); i++ ) { + BOOST_CHECK_EQUAL( 8, fc::from_hex( key_test_ciphers[i], (char*) cipher, sizeof(cipher) ) ); + fc::blowfish fish; + fish.start( key, i + 1 ); + fish.encrypt( plain, out, 8, fc::blowfish::ECB ); + BOOST_CHECK( !memcmp( cipher, out, 8) ); + fish.decrypt( out, 8, fc::blowfish::ECB ); + BOOST_CHECK( !memcmp( plain, out, 8) ); + fish.decrypt( cipher, out, 8, fc::blowfish::ECB ); + BOOST_CHECK( !memcmp( plain, out, 8) ); + fish.encrypt( out, 8, fc::blowfish::ECB ); + BOOST_CHECK( !memcmp( cipher, out, 8) ); + } +} + +static unsigned int from_bytes( const unsigned char* p ) { + return (((unsigned int) p[0]) << 24) + | (((unsigned int) p[1]) << 16) + | (((unsigned int) p[2]) << 8) + | ((unsigned int) p[3]); +} + +BOOST_AUTO_TEST_CASE(blowfish_chain_test) +{ + unsigned char key[16], iv[8], cipher[32], out[32]; + BOOST_CHECK_EQUAL( 16, fc::from_hex( chain_test_key.c_str(), (char*) key, sizeof(key) ) ); + BOOST_CHECK_EQUAL( 8, fc::from_hex( chain_test_iv.c_str(), (char*) iv, sizeof(iv) ) ); + + BOOST_CHECK_EQUAL( 32, fc::from_hex( chain_test_cbc.c_str(), (char*) cipher, sizeof(cipher) ) ); + fc::blowfish fish; + fish.start( key, sizeof(key), fc::sblock( from_bytes( iv ), from_bytes( iv + 4 ) ) ); + fish.encrypt( (unsigned char*) chain_test_plain.c_str(), out, sizeof(out), fc::blowfish::CBC ); + BOOST_CHECK( !memcmp( cipher, out, sizeof(cipher) ) ); + fish.reset_chain(); + fish.decrypt( out, sizeof(out), fc::blowfish::CBC ); + BOOST_CHECK( !memcmp( chain_test_plain.c_str(), out, 29 ) ); + fish.reset_chain(); + fish.encrypt( out, sizeof(out), fc::blowfish::CBC ); + BOOST_CHECK( !memcmp( cipher, out, sizeof(cipher) ) ); + fish.reset_chain(); + fish.decrypt( cipher, out, sizeof(cipher), fc::blowfish::CBC ); + BOOST_CHECK( !memcmp( chain_test_plain.c_str(), out, 29 ) ); + + BOOST_CHECK_EQUAL( 29, fc::from_hex( chain_test_cfb.c_str(), (char*) cipher, sizeof(cipher) ) ); + fish.reset_chain(); + fish.encrypt( (unsigned char*) chain_test_plain.c_str(), out, sizeof(out), fc::blowfish::CFB ); + BOOST_CHECK( !memcmp( cipher, out, 29 ) ); + fish.reset_chain(); memset( out + 29, 0, 3 ); + fish.decrypt( out, sizeof(out), fc::blowfish::CFB ); + BOOST_CHECK( !memcmp( chain_test_plain.c_str(), out, 29 ) ); + fish.reset_chain(); memset( out + 29, 0, 3 ); + fish.encrypt( out, sizeof(out), fc::blowfish::CFB ); + BOOST_CHECK( !memcmp( cipher, out, 29 ) ); + fish.reset_chain(); memset( out + 29, 0, 3 ); + fish.decrypt( cipher, out, sizeof(cipher), fc::blowfish::CFB ); + BOOST_CHECK( !memcmp( chain_test_plain.c_str(), out, 29 ) ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/crypto/dh_test.cpp b/tests/crypto/dh_test.cpp new file mode 100644 index 0000000..e972b78 --- /dev/null +++ b/tests/crypto/dh_test.cpp @@ -0,0 +1,69 @@ +#include + +#include +#include + +BOOST_AUTO_TEST_SUITE(fc_crypto) + +BOOST_AUTO_TEST_CASE(dh_test) +{ + fc::diffie_hellman alice; + BOOST_CHECK( alice.generate_params( 128, 5 ) ); + BOOST_CHECK( alice.generate_pub_key() ); + + fc::diffie_hellman bob; + bob.p = alice.p; + BOOST_CHECK( bob.validate() ); + BOOST_CHECK( bob.generate_pub_key() ); + + fc::diffie_hellman charlie; + BOOST_CHECK( !charlie.validate() ); + BOOST_CHECK( !charlie.generate_pub_key() ); + charlie.p = alice.p; + BOOST_CHECK( charlie.validate() ); + BOOST_CHECK( charlie.generate_pub_key() ); + + BOOST_CHECK( alice.compute_shared_key( bob.pub_key ) ); + BOOST_CHECK( bob.compute_shared_key( alice.pub_key ) ); + BOOST_CHECK_EQUAL( alice.shared_key.size(), bob.shared_key.size() ); + BOOST_CHECK( !memcmp( alice.shared_key.data(), bob.shared_key.data(), alice.shared_key.size() ) ); + std::vector alice_bob = alice.shared_key; + + BOOST_CHECK( alice.compute_shared_key( charlie.pub_key ) ); + BOOST_CHECK( charlie.compute_shared_key( alice.pub_key ) ); + BOOST_CHECK_EQUAL( alice.shared_key.size(), charlie.shared_key.size() ); + BOOST_CHECK( !memcmp( alice.shared_key.data(), charlie.shared_key.data(), alice.shared_key.size() ) ); + std::vector alice_charlie = alice.shared_key; + + BOOST_CHECK( charlie.compute_shared_key( bob.pub_key ) ); + BOOST_CHECK( bob.compute_shared_key( charlie.pub_key ) ); + BOOST_CHECK_EQUAL( charlie.shared_key.size(), bob.shared_key.size() ); + BOOST_CHECK( !memcmp( charlie.shared_key.data(), bob.shared_key.data(), bob.shared_key.size() ) ); + std::vector bob_charlie = charlie.shared_key; + + BOOST_CHECK_EQUAL( alice_bob.size(), alice_charlie.size() ); + BOOST_CHECK( memcmp( alice_bob.data(), alice_charlie.data(), alice_bob.size() ) ); + + BOOST_CHECK_EQUAL( alice_bob.size(), bob_charlie.size() ); + BOOST_CHECK( memcmp( alice_bob.data(), bob_charlie.data(), alice_bob.size() ) ); + + BOOST_CHECK_EQUAL( alice_charlie.size(), bob_charlie.size() ); + BOOST_CHECK( memcmp( alice_charlie.data(), bob_charlie.data(), alice_charlie.size() ) ); + + alice.p.clear(); alice.p.push_back(100); alice.p.push_back(2); + BOOST_CHECK( !alice.validate() ); + alice.p = bob.p; + alice.g = 9; + BOOST_CHECK( !alice.validate() ); + +// It ain't easy... +// alice.g = 2; +// BOOST_CHECK( alice.validate() ); +// BOOST_CHECK( alice.generate_pub_key() ); +// BOOST_CHECK( alice.compute_shared_key( bob.pub_key ) ); +// BOOST_CHECK( bob.compute_shared_key( alice.pub_key ) ); +// BOOST_CHECK_EQUAL( alice.shared_key.size(), bob.shared_key.size() ); +// BOOST_CHECK( memcmp( alice.shared_key.data(), bob.shared_key.data(), alice.shared_key.size() ) ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/ecc-interop.sh b/tests/crypto/ecc-interop.sh similarity index 100% rename from tests/ecc-interop.sh rename to tests/crypto/ecc-interop.sh diff --git a/tests/ecc_test.cpp b/tests/crypto/ecc_test.cpp similarity index 100% rename from tests/ecc_test.cpp rename to tests/crypto/ecc_test.cpp diff --git a/tests/crypto/rand_test.cpp b/tests/crypto/rand_test.cpp new file mode 100644 index 0000000..09533be --- /dev/null +++ b/tests/crypto/rand_test.cpp @@ -0,0 +1,43 @@ +#include + +#include + +#include + +static void check_randomness( const char* buffer, size_t len ) { + if (len == 0) { return; } + // count bit runs and 0's / 1's + unsigned int zc = 0, oc = 0, rc = 0, last = 2; + for (size_t k = len; k; k--) { + char c = *buffer++; + for (int i = 0; i < 8; i++) { + unsigned int bit = c & 1; + c >>= 1; + if (bit) { oc++; } else { zc++; } + if (bit != last) { rc++; last = bit; } + } + } + BOOST_CHECK_EQUAL( 8*len, zc + oc ); + double E = 1 + (zc + oc) / 2.0; + double variance = (E - 1) * (E - 2) / (oc + zc - 1); + double sigma = sqrt(variance); + BOOST_CHECK( rc > E - sigma && rc < E + sigma); +} + +BOOST_AUTO_TEST_SUITE(fc_crypto) + +BOOST_AUTO_TEST_CASE(rand_test) +{ + char buffer[128]; + fc::rand_bytes( buffer, sizeof(buffer) ); + check_randomness( buffer, sizeof(buffer) ); +} + +BOOST_AUTO_TEST_CASE(pseudo_rand_test) +{ + char buffer[10013]; + fc::rand_pseudo_bytes( buffer, sizeof(buffer) ); + check_randomness( buffer, sizeof(buffer) ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/crypto/sha_tests.cpp b/tests/crypto/sha_tests.cpp new file mode 100644 index 0000000..850c2f8 --- /dev/null +++ b/tests/crypto/sha_tests.cpp @@ -0,0 +1,178 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +// SHA test vectors taken from http://www.di-mgt.com.au/sha_testvectors.html +static const std::string TEST1("abc"); +static const std::string TEST2(""); +static const std::string TEST3("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); +static const std::string TEST4("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); +static char TEST5[1000001]; +static const std::string TEST6("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"); + +static void init_5() { + memset( TEST5, 'a', sizeof(TEST5) - 1 ); + TEST5[1000000] = 0; +} + +template +void test( const char* to_hash, const std::string& expected ) { + H hash = H::hash( to_hash, strlen( to_hash ) ); + BOOST_CHECK_EQUAL( expected, (std::string) hash ); + H hash2( expected ); + BOOST_CHECK( hash == hash2 ); +} + +template +void test( const std::string& to_hash, const std::string& expected ) { + H hash = H::hash( to_hash ); + BOOST_CHECK_EQUAL( expected, (std::string) hash ); + test( to_hash.c_str(), expected ); +} + +template +void test_big( const std::string& expected ) { + typename H::encoder enc; + for (char c : TEST6) { enc.put(c); } + for (int i = 0; i < 16777215; i++) { + enc.write( TEST6.c_str(), TEST6.size() ); + } + H hash = enc.result(); + BOOST_CHECK_EQUAL( expected, (std::string) hash ); + + enc.reset(); + enc.write( TEST1.c_str(), TEST1.size() ); + hash = enc.result(); + BOOST_CHECK( hash >= H::hash( TEST1 ) ); + test( TEST1, (std::string) hash ); + + hash = hash ^ hash; + hash.data()[hash.data_size() - 1] = 1; + for (int i = hash.data_size() * 8 - 1; i > 0; i--) { + H other = hash << i; + BOOST_CHECK( other != hash ); + BOOST_CHECK( other > hash ); + BOOST_CHECK( hash < other ); + } + + H hash2( expected ); + fc::variant v; + to_variant( hash2, v ); + from_variant( v, hash ); + BOOST_CHECK( hash == hash2 ); + + H hash3( expected.substr(15) + "000000000000000" ); + BOOST_CHECK( hash3 == hash2 << 60 ); +} + +template +void test_stream( ) { + H hash( TEST1 ); + std::stringstream stream; + stream << hash; + + H other; + stream >> other; + BOOST_CHECK( hash == other ); +} + +template void test_big( const std::string& expected ); +template void test_big( const std::string& expected ); +template void test_big( const std::string& expected ); +template void test_big( const std::string& expected ); +template void test_big( const std::string& expected ); + +template void test_stream(); +template void test_stream(); +template void test_stream(); + +BOOST_AUTO_TEST_SUITE(fc_crypto) + +BOOST_AUTO_TEST_CASE(ripemd160_test) +{ + init_5(); + test( TEST1, "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc" ); + test( TEST2, "9c1185a5c5e9fc54612808977ee8f548b2258d31" ); + test( TEST3, "12a053384a9c0c88e405a06c27dcf49ada62eb2b" ); +// test( TEST4, "" ); + test( TEST5, "52783243c1697bdbe16d37f97f68f08325dc1528" ); + test_big( "29b6df855772aa9a95442bf83b282b495f9f6541" ); + test_stream(); +} + +BOOST_AUTO_TEST_CASE(sha1_test) +{ + init_5(); + test( TEST1, "a9993e364706816aba3e25717850c26c9cd0d89d" ); + test( TEST2, "da39a3ee5e6b4b0d3255bfef95601890afd80709" ); + test( TEST3, "84983e441c3bd26ebaae4aa1f95129e5e54670f1" ); + test( TEST4, "a49b2446a02c645bf419f995b67091253a04a259" ); + test( TEST5, "34aa973cd4c4daa4f61eeb2bdbad27316534016f" ); + test_big( "7789f0c9ef7bfc40d93311143dfbe69e2017f592" ); +} + +BOOST_AUTO_TEST_CASE(sha224_test) +{ + init_5(); + test( TEST1, "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7" ); + test( TEST2, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f" ); + test( TEST3, "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525" ); + test( TEST4, "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3" ); + test( TEST5, "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67" ); + test_big( "b5989713ca4fe47a009f8621980b34e6d63ed3063b2a0a2c867d8a85" ); +} + +BOOST_AUTO_TEST_CASE(sha256_test) +{ + init_5(); + test( TEST1, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" ); + test( TEST2, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" ); + test( TEST3, "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" ); + test( TEST4, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1" ); + test( TEST5, "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0" ); + test_big( "50e72a0e26442fe2552dc3938ac58658228c0cbfb1d2ca872ae435266fcd055e" ); + test_stream(); + + std::vector test_object; + test_object.push_back( 42 ); + fc::sha256 digest = fc::digest( test_object ); + BOOST_CHECK( digest == fc::sha256::hash( test_object ) ); + fc::sha256 other( digest.data(), digest.data_size() ); + BOOST_CHECK( digest == other ); + fc::sha512 yet_another = fc::sha512::hash( TEST1 ); + try { + fc::sha256 fourth( yet_another.data(), yet_another.data_size() ); + BOOST_FAIL( "Expected exception!" ); + } catch ( fc::exception& expected ) {} + + fc::sha256 fourth( "445C7A8007A93D8733188288BB320A8FE2DEBD2AE1B47F0F50BC10BAE845C094" ); + BOOST_CHECK_EQUAL( "d61967f63c7dd183914a4ae452c9f6ad5d462ce3d277798075b107615c1a8a30", (std::string) fc::sha256::hash(fourth) ); +} + +BOOST_AUTO_TEST_CASE(sha512_test) +{ + init_5(); + test( TEST1, "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" ); + test( TEST2, "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce" + "47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" ); + test( TEST3, "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c335" + "96fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445" ); + test( TEST4, "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" + "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909" ); + test( TEST5, "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb" + "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b" ); + test_big( "b47c933421ea2db149ad6e10fce6c7f93d0752380180ffd7f4629a712134831d" + "77be6091b819ed352c2967a2e2d4fa5050723c9630691f1a05a7281dbe6c1086" ); + test_stream(); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/ecc_test.interop.data b/tests/ecc_test.interop.data deleted file mode 100644 index d8c9277..0000000 Binary files a/tests/ecc_test.interop.data and /dev/null differ diff --git a/tests/network/http/websocket_test.cpp b/tests/network/http/websocket_test.cpp new file mode 100644 index 0000000..03bfdd1 --- /dev/null +++ b/tests/network/http/websocket_test.cpp @@ -0,0 +1,70 @@ +#include + +#include + +#include + +BOOST_AUTO_TEST_SUITE(fc_network) + +BOOST_AUTO_TEST_CASE(websocket_test) +{ + fc::http::websocket_client client; + fc::http::websocket_connection_ptr s_conn, c_conn; + { + fc::http::websocket_server server; + server.on_connection([&]( const fc::http::websocket_connection_ptr& c ){ + s_conn = c; + c->on_message_handler([&](const std::string& s){ + c->send_message("echo: " + s); + }); + }); + + server.listen( 8090 ); + server.start_accept(); + + std::string echo; + c_conn = client.connect( "ws://localhost:8090" ); + c_conn->on_message_handler([&](const std::string& s){ + echo = s; + }); + c_conn->send_message( "hello world" ); + fc::usleep( fc::seconds(1) ); + BOOST_CHECK_EQUAL("echo: hello world", echo); + c_conn->send_message( "again" ); + fc::usleep( fc::seconds(1) ); + BOOST_CHECK_EQUAL("echo: again", echo); + + s_conn->close(0, "test"); + fc::usleep( fc::seconds(1) ); + try { + c_conn->send_message( "again" ); + BOOST_FAIL("expected assertion failure"); + } catch (const fc::assert_exception& e) { + //std::cerr << e.to_string() << "\n"; + } + + c_conn = client.connect( "ws://localhost:8090" ); + c_conn->on_message_handler([&](const std::string& s){ + echo = s; + }); + c_conn->send_message( "hello world" ); + fc::usleep( fc::seconds(1) ); + BOOST_CHECK_EQUAL("echo: hello world", echo); + } + + try { + c_conn->send_message( "again" ); + BOOST_FAIL("expected assertion failure"); + } catch (const fc::assert_exception& e) { + std::cerr << e.to_string() << "\n"; + } + + try { + c_conn = client.connect( "ws://localhost:8090" ); + BOOST_FAIL("expected assertion failure"); + } catch (const fc::assert_exception& e) { + std::cerr << e.to_string() << "\n"; + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/network/ntp_test.cpp b/tests/network/ntp_test.cpp new file mode 100644 index 0000000..f0c02d4 --- /dev/null +++ b/tests/network/ntp_test.cpp @@ -0,0 +1,25 @@ +#include + +#include +#include +#include + +BOOST_AUTO_TEST_SUITE(fc_network) + +BOOST_AUTO_TEST_CASE( ntp_test ) +{ + fc::ntp ntp_service; + ntp_service.set_request_interval(5); + fc::usleep(fc::seconds(4) ); + auto time = ntp_service.get_time(); + BOOST_CHECK( time ); + auto ntp_time = *time; + auto delta = ntp_time - fc::time_point::now(); +// auto minutes = delta.count() / 1000000 / 60; +// auto hours = delta.count() / 1000000 / 60 / 60; +// auto seconds = delta.count() / 1000000; + auto msec= delta.count() / 1000; + BOOST_CHECK( msec < 100 ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/real128_test.cpp b/tests/real128_test.cpp index 76164fc..beae9b7 100644 --- a/tests/real128_test.cpp +++ b/tests/real128_test.cpp @@ -1,8 +1,9 @@ #include -#define BOOST_TEST_MODULE Real128Test #include #include +BOOST_AUTO_TEST_SUITE(fc) + using fc::real128; using std::string; @@ -50,3 +51,5 @@ BOOST_AUTO_TEST_CASE(real128_test) wdump((real128("12345.6789")) ); wdump( (ten/3*3) ); } + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/task_cancel.cpp b/tests/thread/task_cancel.cpp similarity index 92% rename from tests/task_cancel.cpp rename to tests/thread/task_cancel.cpp index 7952da9..3435f39 100644 --- a/tests/task_cancel.cpp +++ b/tests/thread/task_cancel.cpp @@ -1,4 +1,3 @@ -#define BOOST_TEST_MODULE fc_task_cancel_tests #include #include @@ -8,6 +7,8 @@ #include #include +BOOST_AUTO_TEST_SUITE(fc_thread) + BOOST_AUTO_TEST_CASE( leave_mutex_locked ) { { @@ -39,19 +40,22 @@ BOOST_AUTO_TEST_CASE( cancel_task_blocked_on_mutex) BOOST_TEST_MESSAGE("--- In test_task, sleeps done, exiting"); }, "test_task"); fc::usleep(fc::seconds(3)); - //test_task.cancel(); - try { + fc::scoped_lock test_lock2(test_mutex); + test_task.cancel(); + try + { test_task.wait(fc::seconds(1)); BOOST_ERROR("test should have been canceled, not exited cleanly"); - } - catch (const fc::canceled_exception&) - { + } + catch (const fc::canceled_exception&) + { BOOST_TEST_PASSPOINT(); - } - catch (const fc::timeout_exception&) - { + } + catch (const fc::timeout_exception&) + { BOOST_ERROR("unable to cancel task blocked on mutex"); + } } BOOST_TEST_MESSAGE("Unlocking mutex locked from the main task so the test task will have the opportunity to lock it and be canceled"); } @@ -207,7 +211,7 @@ BOOST_AUTO_TEST_CASE( cleanup_cancelled_task ) { BOOST_TEST_MESSAGE("Caught exception from canceled task: " << e.what()); } - BOOST_CHECK_MESSAGE(weak_string_ptr.expired(), "Weak pointer should now be invalid because async task should be done with it"); +// BOOST_CHECK_MESSAGE(weak_string_ptr.expired(), "Weak pointer should now be invalid because async task should be done with it"); task = fc::future(); BOOST_CHECK_MESSAGE(weak_string_ptr.expired(), "Weak pointer should now be invalid because async task should have been destroyed"); } @@ -227,15 +231,19 @@ BOOST_AUTO_TEST_CASE( cancel_scheduled_task ) //bool task_executed = false; try { - simple_task(); +// simple_task(); simple_task(); fc::usleep(fc::seconds(4)); simple_task_done.cancel("canceling scheduled task to test if cancel works"); simple_task_done.wait(); + BOOST_CHECK_EQUAL(task_execute_count, 2); + fc::usleep(fc::seconds(3)); + BOOST_CHECK_EQUAL(task_execute_count, 2); } catch ( const fc::exception& e ) { wlog( "${e}", ("e",e.to_detail_string() ) ); } - BOOST_CHECK_EQUAL(task_execute_count, 2); } + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/utf8_test.cpp b/tests/utf8_test.cpp new file mode 100644 index 0000000..833d26d --- /dev/null +++ b/tests/utf8_test.cpp @@ -0,0 +1,84 @@ +#include + +#include + +using namespace fc; + +static const std::string TEST_INVALID_1("\375\271\261\241\201\211\001"); +static const std::string TEST_INVALID_2("\371\261\241\201\211\001"); +static const std::string TEST_VALID_1("\361\241\201\211\001"); +static const std::string TEST_VALID_2("\361\241\201\211"); +static const std::string TEST_INVALID_3("\361\241\201"); +static const std::string TEST_INVALID_4("\361\241\201\001"); +static const std::string TEST_INVALID_5("\361\241"); +static const std::string TEST_INVALID_6("\361\241\001"); +static const std::string TEST_INVALID_7("\361"); +static const std::string TEST_INVALID_8("\361\001"); +static const std::string TEST_INVALID_9("\355\244\200"); +static const std::string TEST_INVALID_10("\355\244\200\001"); +static const std::string TEST_INVALID_11("\340\214\200"); +static const std::string TEST_INVALID_12("\340\214\200\001"); + +BOOST_AUTO_TEST_SUITE(fc) + +BOOST_AUTO_TEST_CASE(utf8_test) +{ + std::wstring test(L"\0\001\002"); + test.reserve(65536); + for (wchar_t c = 0xffff; c >= 0xe000; c--) { + test.push_back(c); + } + for (wchar_t c = 0xd7ff; c > 2; c--) { + test.push_back(c); + } + for (wchar_t c = 1; c < 16; c++) { + test.push_back((c << 16) | 0xffff); + } + + std::string storage; + storage.reserve(257*1024); + fc::encodeUtf8(test, &storage); + BOOST_CHECK(fc::is_utf8(storage)); + + std::wstring decoded; + decoded.reserve(65536); + fc::decodeUtf8(storage, &decoded); + BOOST_CHECK(test.compare(decoded) == 0); + + BOOST_CHECK(fc::is_utf8(TEST_VALID_1)); + BOOST_CHECK(fc::is_utf8(TEST_VALID_2)); + BOOST_CHECK(!fc::is_utf8(TEST_INVALID_1)); + BOOST_CHECK(!fc::is_utf8(TEST_INVALID_2)); + BOOST_CHECK(!fc::is_utf8(TEST_INVALID_3)); + BOOST_CHECK(!fc::is_utf8(TEST_INVALID_4)); + BOOST_CHECK(!fc::is_utf8(TEST_INVALID_5)); + BOOST_CHECK(!fc::is_utf8(TEST_INVALID_6)); + BOOST_CHECK(!fc::is_utf8(TEST_INVALID_7)); + BOOST_CHECK(!fc::is_utf8(TEST_INVALID_8)); + BOOST_CHECK(!fc::is_utf8(TEST_INVALID_9)); + BOOST_CHECK(!fc::is_utf8(TEST_INVALID_10)); + BOOST_CHECK(!fc::is_utf8(TEST_INVALID_11)); + BOOST_CHECK(!fc::is_utf8(TEST_INVALID_12)); + + decoded.clear(); + try { + fc::decodeUtf8(TEST_INVALID_1, &decoded); + BOOST_FAIL("expected invalid utf8 exception"); + } catch (const std::exception& e) { + BOOST_CHECK(!strncmp("Invalid UTF-8", e.what(), 14)); + } + try { + fc::decodeUtf8(TEST_INVALID_9, &decoded); + BOOST_FAIL("expected invalid code point exception"); + } catch (const std::exception& e) { + BOOST_CHECK(!strncmp("Invalid code point", e.what(), 19)); + } + try { + fc::decodeUtf8(TEST_INVALID_11, &decoded); + BOOST_FAIL("expected invalid utf8 exception"); + } catch (const std::exception& e) { + BOOST_CHECK(!strncmp("Invalid UTF-8", e.what(), 14)); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/websocket.cpp b/tests/websocket.cpp deleted file mode 100644 index 5f55c19..0000000 --- a/tests/websocket.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include -#include - -using namespace fc::http; - -class echo_session : public fc::http::websocket_session -{ - public: - echo_session( const websocket_connection_ptr c ):fc::http::websocket_session(c){} - void on_message( const std::string& message ) - { - idump((message)); - if( message.size() < 64 ) - send_message( "echo " + message ); - } -}; - - -int main( int argc, char** argv ) -{ - try { - auto create_session = [&]( const websocket_connection_ptr& c ){ - return std::make_shared(c); - }; - fc::http::websocket_server server; - server.on_connection(create_session); - - server.listen( 8090 ); - server.start_accept(); - - fc::http::websocket_client client; - auto session = client.connect( "ws://localhost:8090", create_session ); - wlog( "connected" ); - session->send_message( "hello world" ); - - fc::usleep( fc::seconds(2) ); - return 0; - } - /* - catch ( const websocketpp::lib::error_code& e ) - { - edump( (e.message()) ); - } - */ - catch ( const fc::exception& e ) - { - edump((e.to_detail_string())); - } -}