diff options
Diffstat (limited to 'libdevcore')
-rw-r--r-- | libdevcore/ABI.h | 100 | ||||
-rw-r--r-- | libdevcore/Assertions.h | 111 | ||||
-rw-r--r-- | libdevcore/Base64.cpp | 146 | ||||
-rw-r--r-- | libdevcore/Base64.h | 42 | ||||
-rw-r--r-- | libdevcore/CMakeLists.txt | 16 | ||||
-rw-r--r-- | libdevcore/Common.cpp | 27 | ||||
-rw-r--r-- | libdevcore/Common.h | 210 | ||||
-rw-r--r-- | libdevcore/CommonData.cpp | 107 | ||||
-rw-r--r-- | libdevcore/CommonData.h | 182 | ||||
-rw-r--r-- | libdevcore/CommonIO.cpp | 90 | ||||
-rw-r--r-- | libdevcore/CommonIO.h | 54 | ||||
-rw-r--r-- | libdevcore/Exceptions.h | 87 | ||||
-rw-r--r-- | libdevcore/FixedHash.cpp | 50 | ||||
-rw-r--r-- | libdevcore/FixedHash.h | 306 | ||||
-rw-r--r-- | libdevcore/Hash.cpp | 440 | ||||
-rw-r--r-- | libdevcore/Hash.h | 38 | ||||
-rw-r--r-- | libdevcore/SHA3.cpp | 223 | ||||
-rw-r--r-- | libdevcore/SHA3.h | 59 | ||||
-rw-r--r-- | libdevcore/UndefMacros.h | 46 | ||||
-rw-r--r-- | libdevcore/debugbreak.h | 125 | ||||
-rw-r--r-- | libdevcore/picosha2.h | 360 | ||||
-rw-r--r-- | libdevcore/vector_ref.h | 120 |
22 files changed, 2939 insertions, 0 deletions
diff --git a/libdevcore/ABI.h b/libdevcore/ABI.h new file mode 100644 index 00000000..5b7d160d --- /dev/null +++ b/libdevcore/ABI.h @@ -0,0 +1,100 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** @file ABI.h + * @author Gav Wood <i@gavwood.com> + * @date 2014 + */ + +#pragma once + +#include <libdevcore/Common.h> +#include <libdevcore/FixedHash.h> +#include <libdevcore/CommonData.h> +#include <libdevcore/SHA3.h> + +namespace dev +{ +namespace eth +{ + +inline string32 toString32(std::string const& _s) +{ + string32 ret; + for (unsigned i = 0; i < 32; ++i) + ret[i] = i < _s.size() ? _s[i] : 0; + return ret; +} + +template <class T> struct ABISerialiser {}; +template <unsigned N> struct ABISerialiser<FixedHash<N>> { static bytes serialise(FixedHash<N> const& _t) { static_assert(N <= 32, "Cannot serialise hash > 32 bytes."); static_assert(N > 0, "Cannot serialise zero-length hash."); return bytes(32 - N, 0) + _t.asBytes(); } }; +template <> struct ABISerialiser<u256> { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } }; +template <> struct ABISerialiser<u160> { static bytes serialise(u160 const& _t) { return bytes(12, 0) + h160(_t).asBytes(); } }; +template <> struct ABISerialiser<string32> { static bytes serialise(string32 const& _t) { bytes ret; bytesConstRef((byte const*)_t.data(), 32).populate(bytesRef(&ret)); return ret; } }; +template <> struct ABISerialiser<std::string> +{ + static bytes serialise(std::string const& _t) + { + bytes ret = h256(u256(32)).asBytes() + h256(u256(_t.size())).asBytes(); + ret.resize(ret.size() + (_t.size() + 31) / 32 * 32); + bytesConstRef(&_t).populate(bytesRef(&ret).cropped(64)); + return ret; + } +}; + +inline bytes abiInAux() { return {}; } +template <class T, class ... U> bytes abiInAux(T const& _t, U const& ... _u) +{ + return ABISerialiser<T>::serialise(_t) + abiInAux(_u ...); +} + +template <class ... T> bytes abiIn(std::string _id, T const& ... _t) +{ + return sha3(_id).ref().cropped(0, 4).toBytes() + abiInAux(_t ...); +} + +template <class T> struct ABIDeserialiser {}; +template <unsigned N> struct ABIDeserialiser<FixedHash<N>> { static FixedHash<N> deserialise(bytesConstRef& io_t) { static_assert(N <= 32, "Parameter sizes must be at most 32 bytes."); FixedHash<N> ret; io_t.cropped(32 - N, N).populate(ret.ref()); io_t = io_t.cropped(32); return ret; } }; +template <> struct ABIDeserialiser<u256> { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian<u256>(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } }; +template <> struct ABIDeserialiser<u160> { static u160 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian<u160>(io_t.cropped(12, 20)); io_t = io_t.cropped(32); return ret; } }; +template <> struct ABIDeserialiser<string32> { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(bytesRef((byte*)ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; +template <> struct ABIDeserialiser<std::string> +{ + static std::string deserialise(bytesConstRef& io_t) + { + unsigned o = (uint16_t)u256(h256(io_t.cropped(0, 32))); + unsigned s = (uint16_t)u256(h256(io_t.cropped(o, 32))); + std::string ret; + ret.resize(s); + io_t.cropped(o + 32, s).populate(bytesRef((byte*)ret.data(), s)); + io_t = io_t.cropped(32); + return ret; + } +}; + +template <class T> T abiOut(bytes const& _data) +{ + bytesConstRef o(&_data); + return ABIDeserialiser<T>::deserialise(o); +} + +template <class T> T abiOut(bytesConstRef& _data) +{ + return ABIDeserialiser<T>::deserialise(_data); +} + +} +} diff --git a/libdevcore/Assertions.h b/libdevcore/Assertions.h new file mode 100644 index 00000000..7b4a4a76 --- /dev/null +++ b/libdevcore/Assertions.h @@ -0,0 +1,111 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @file Assertions.h + * @author Christian <c@ethdev.com> + * @date 2015 + * + * Assertion handling. + */ + +#pragma once + +#include "Exceptions.h" +#include "debugbreak.h" + +namespace dev +{ + +#if defined(_MSC_VER) +#define ETH_FUNC __FUNCSIG__ +#elif defined(__GNUC__) +#define ETH_FUNC __PRETTY_FUNCTION__ +#else +#define ETH_FUNC __func__ +#endif + +#define asserts(A) ::dev::assertAux(A, #A, __LINE__, __FILE__, ETH_FUNC) +#define assertsEqual(A, B) ::dev::assertEqualAux(A, B, #A, #B, __LINE__, __FILE__, ETH_FUNC) + +inline bool assertAux(bool _a, char const* _aStr, unsigned _line, char const* _file, char const* _func) +{ + bool ret = _a; + if (!ret) + { + std::cerr << "Assertion failed:" << _aStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl; +#if ETH_DEBUG + debug_break(); +#endif + } + return !ret; +} + +template<class A, class B> +inline bool assertEqualAux(A const& _a, B const& _b, char const* _aStr, char const* _bStr, unsigned _line, char const* _file, char const* _func) +{ + bool ret = _a == _b; + if (!ret) + { + std::cerr << "Assertion failed: " << _aStr << " == " << _bStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl; + std::cerr << " Fail equality: " << _a << "==" << _b << std::endl; +#if ETH_DEBUG + debug_break(); +#endif + } + return !ret; +} + +/// Assertion that throws an exception containing the given description if it is not met. +/// Use it as assertThrow(1 == 1, ExceptionType, "Mathematics is wrong."); +/// Do NOT supply an exception object as the second parameter. +#define assertThrow(_condition, _ExceptionType, _description) \ + ::dev::assertThrowAux<_ExceptionType>(_condition, _description, __LINE__, __FILE__, ETH_FUNC) + +using errinfo_comment = boost::error_info<struct tag_comment, std::string>; + +template <class _ExceptionType> +inline void assertThrowAux( + bool _condition, + ::std::string const& _errorDescription, + unsigned _line, + char const* _file, + char const* _function +) +{ + if (!_condition) + ::boost::throw_exception( + _ExceptionType() << + ::dev::errinfo_comment(_errorDescription) << + ::boost::throw_function(_function) << + ::boost::throw_file(_file) << + ::boost::throw_line(_line) + ); +} + +template <class _ExceptionType> +inline void assertThrowAux( + void const* _pointer, + ::std::string const& _errorDescription, + unsigned _line, + char const* _file, + char const* _function +) +{ + assertThrowAux<_ExceptionType>(_pointer != nullptr, _errorDescription, _line, _file, _function); +} + +} diff --git a/libdevcore/Base64.cpp b/libdevcore/Base64.cpp new file mode 100644 index 00000000..8ee2b29f --- /dev/null +++ b/libdevcore/Base64.cpp @@ -0,0 +1,146 @@ +/* + base64.cpp and base64.h + + Copyright (C) 2004-2008 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch +*/ +/// Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c +/// Originally by René Nyffenegger, modified by some other guy and then devified by Gav Wood. + +#include "Base64.h" + +using namespace std; +using namespace dev; + +static inline bool is_base64(byte c) +{ + return (isalnum(c) || (c == '+') || (c == '/')); +} + +static inline byte find_base64_char_index(byte c) +{ + if ('A' <= c && c <= 'Z') return c - 'A'; + else if ('a' <= c && c <= 'z') return c - 'a' + 1 + find_base64_char_index('Z'); + else if ('0' <= c && c <= '9') return c - '0' + 1 + find_base64_char_index('z'); + else if (c == '+') return 1 + find_base64_char_index('9'); + else if (c == '/') return 1 + find_base64_char_index('+'); + else return 1 + find_base64_char_index('/'); +} + +string dev::toBase64(bytesConstRef _in) +{ + static const char base64_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + string ret; + int i = 0; + int j = 0; + byte char_array_3[3]; + byte char_array_4[4]; + + auto buf = _in.data(); + auto bufLen = _in.size(); + + while (bufLen--) + { + char_array_3[i++] = *(buf++); + if (i == 3) + { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (i = 0; i < 4; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) + { + for (j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; j < i + 1; j++) + ret += base64_chars[char_array_4[j]]; + + while (i++ < 3) + ret += '='; + } + + return ret; +} + +bytes dev::fromBase64(string const& encoded_string) +{ + auto in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + byte char_array_3[3]; + byte char_array_4[4]; + bytes ret; + + while (in_len-- && encoded_string[in_] != '=' && is_base64(encoded_string[in_])) + { + char_array_4[i++] = encoded_string[in_]; in_++; + if (i == 4) + { + for (i = 0; i < 4; i++) + char_array_4[i] = find_base64_char_index(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + ret.push_back(char_array_3[i]); + i = 0; + } + } + + if (i) + { + for (j = i; j < 4; j++) + char_array_4[j] = 0; + + for (j = 0; j < 4; j++) + char_array_4[j] = find_base64_char_index(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; j < i - 1; j++) + ret.push_back(char_array_3[j]); + } + + return ret; +} diff --git a/libdevcore/Base64.h b/libdevcore/Base64.h new file mode 100644 index 00000000..d5481570 --- /dev/null +++ b/libdevcore/Base64.h @@ -0,0 +1,42 @@ +/* + base64.cpp and base64.h + + Copyright (C) 2004-2008 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch +*/ +/// Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c +/// Originally by René Nyffenegger. +/// DEVified by Gav Wood. +#pragma once + +#include <string> +#include "Common.h" +#include "FixedHash.h" + +namespace dev +{ + +std::string toBase64(bytesConstRef _in); +bytes fromBase64(std::string const& _in); + + +} diff --git a/libdevcore/CMakeLists.txt b/libdevcore/CMakeLists.txt new file mode 100644 index 00000000..43dd71c3 --- /dev/null +++ b/libdevcore/CMakeLists.txt @@ -0,0 +1,16 @@ +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") + +aux_source_directory(. SRC_LIST) + +set(EXECUTABLE devcore) + +file(GLOB HEADERS "*.h") + +include_directories(..) +add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) + +eth_use(${EXECUTABLE} REQUIRED Jsoncpp Dev::base) + +install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) + diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp new file mode 100644 index 00000000..579e0f62 --- /dev/null +++ b/libdevcore/Common.cpp @@ -0,0 +1,27 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** @file Common.cpp + * @author Gav Wood <i@gavwood.com> + * @date 2014 + */ + +#include "Common.h" + +namespace dev +{ +const u256 Invalid256 = ~(u256)0; +} diff --git a/libdevcore/Common.h b/libdevcore/Common.h new file mode 100644 index 00000000..7d301833 --- /dev/null +++ b/libdevcore/Common.h @@ -0,0 +1,210 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** @file Common.h + * @author Gav Wood <i@gavwood.com> + * @date 2014 + * + * Very common stuff (i.e. that every other header needs except vector_ref.h). + */ + +#pragma once + +// way to many unsigned to size_t warnings in 32 bit build +#ifdef _M_IX86 +#pragma warning(disable:4244) +#endif + +#if _MSC_VER && _MSC_VER < 1900 +#define _ALLOW_KEYWORD_MACROS +#define noexcept throw() +#endif + +#ifdef __INTEL_COMPILER +#pragma warning(disable:3682) //call through incomplete class +#endif + +#include <map> +#include <unordered_map> +#include <vector> +#include <set> +#include <unordered_set> +#include <functional> +#include <string> +#include <chrono> + +#if defined(__GNUC__) +#pragma warning(push) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif // defined(__GNUC__) + +// See https://github.com/ethereum/libweb3core/commit/90680a8c25bfb48b24371b4abcacde56c181517c +// See https://svn.boost.org/trac/boost/ticket/11328 +// Bob comment - perhaps we should just HARD FAIL here with Boost-1.58.00? +// It is quite old now, and requiring end-users to use a newer Boost release is probably not unreasonable. +#include <boost/version.hpp> +#if (BOOST_VERSION == 105800) + #include "boost_multiprecision_number_compare_bug_workaround.hpp" +#endif // (BOOST_VERSION == 105800) + +#include <boost/multiprecision/cpp_int.hpp> + +#if defined(__GNUC__) +#pragma warning(pop) +#pragma GCC diagnostic pop +#endif // defined(__GNUC__) + +#include "vector_ref.h" + +// CryptoPP defines byte in the global namespace, so must we. +using byte = uint8_t; + +// Quote a given token stream to turn it into a string. +#define DEV_QUOTED_HELPER(s) #s +#define DEV_QUOTED(s) DEV_QUOTED_HELPER(s) + +#define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} + +namespace dev +{ + +// Binary data types. +using bytes = std::vector<byte>; +using bytesRef = vector_ref<byte>; +using bytesConstRef = vector_ref<byte const>; + +template <class T> +class secure_vector +{ +public: + secure_vector() {} + secure_vector(secure_vector<T> const& /*_c*/) = default; // See https://github.com/ethereum/libweb3core/pull/44 + explicit secure_vector(unsigned _size): m_data(_size) {} + explicit secure_vector(unsigned _size, T _item): m_data(_size, _item) {} + explicit secure_vector(std::vector<T> const& _c): m_data(_c) {} + explicit secure_vector(vector_ref<T> _c): m_data(_c.data(), _c.data() + _c.size()) {} + explicit secure_vector(vector_ref<const T> _c): m_data(_c.data(), _c.data() + _c.size()) {} + ~secure_vector() { ref().cleanse(); } + + secure_vector<T>& operator=(secure_vector<T> const& _c) + { + if (&_c == this) + return *this; + + ref().cleanse(); + m_data = _c.m_data; + return *this; + } + std::vector<T>& writable() { clear(); return m_data; } + std::vector<T> const& makeInsecure() const { return m_data; } + + void clear() { ref().cleanse(); } + + vector_ref<T> ref() { return vector_ref<T>(&m_data); } + vector_ref<T const> ref() const { return vector_ref<T const>(&m_data); } + + size_t size() const { return m_data.size(); } + bool empty() const { return m_data.empty(); } + + void swap(secure_vector<T>& io_other) { m_data.swap(io_other.m_data); } + +private: + std::vector<T> m_data; +}; + +using bytesSec = secure_vector<byte>; + +// Numeric types. +using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>; +using u64 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<64, 64, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>; +using u128 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<128, 128, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>; +using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>; +using s256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>; +using u160 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<160, 160, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>; +using s160 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<160, 160, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>; +using u512 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<512, 512, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>; +using s512 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<512, 512, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>; +using u256s = std::vector<u256>; +using u160s = std::vector<u160>; +using u256Set = std::set<u256>; +using u160Set = std::set<u160>; + +// Map types. +using StringMap = std::map<std::string, std::string>; + +// Hash types. +using StringHashMap = std::unordered_map<std::string, std::string>; + +// String types. +using strings = std::vector<std::string>; +// Fixed-length string types. +using string32 = std::array<char, 32>; + +// Null/Invalid values for convenience. +static const bytes NullBytes; +extern const u256 Invalid256; + +/// Interprets @a _u as a two's complement signed number and returns the resulting s256. +inline s256 u2s(u256 _u) +{ + static const bigint c_end = bigint(1) << 256; + if (boost::multiprecision::bit_test(_u, 255)) + return s256(-(c_end - _u)); + else + return s256(_u); +} + +/// @returns the two's complement signed representation of the signed number _u. +inline u256 s2u(s256 _u) +{ + static const bigint c_end = bigint(1) << 256; + if (_u >= 0) + return u256(_u); + else + return u256(c_end + _u); +} + +template <size_t n> inline u256 exp10() +{ + return exp10<n - 1>() * u256(10); +} + +template <> inline u256 exp10<0>() +{ + return u256(1); +} + +/// RAII utility class whose destructor calls a given function. +class ScopeGuard +{ +public: + ScopeGuard(std::function<void(void)> _f): m_f(_f) {} + ~ScopeGuard() { m_f(); } + +private: + std::function<void(void)> m_f; +}; + +enum class WithExisting: int +{ + Trust = 0, + Verify, + Rescue, + Kill +}; + +} diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp new file mode 100644 index 00000000..fc438276 --- /dev/null +++ b/libdevcore/CommonData.cpp @@ -0,0 +1,107 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** @file CommonData.cpp + * @author Gav Wood <i@gavwood.com> + * @date 2014 + */ + +#include "CommonData.h" +#include <random> + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4724) // potential mod by 0, line 78 of boost/random/uniform_int_distribution.hpp (boost 1.55) +#endif +#include <boost/random/uniform_int_distribution.hpp> +#if defined(_MSC_VER) +#pragma warning(pop) +#endif +#include "Exceptions.h" +using namespace std; +using namespace dev; + +std::string dev::escaped(std::string const& _s, bool _all) +{ + static const map<char, char> prettyEscapes{{'\r', 'r'}, {'\n', 'n'}, {'\t', 't'}, {'\v', 'v'}}; + std::string ret; + ret.reserve(_s.size() + 2); + ret.push_back('"'); + for (auto i: _s) + if (i == '"' && !_all) + ret += "\\\""; + else if (i == '\\' && !_all) + ret += "\\\\"; + else if (prettyEscapes.count(i) && !_all) + { + ret += '\\'; + ret += prettyEscapes.find(i)->second; + } + else if (i < ' ' || _all) + { + ret += "\\x"; + ret.push_back("0123456789abcdef"[(uint8_t)i / 16]); + ret.push_back("0123456789abcdef"[(uint8_t)i % 16]); + } + else + ret.push_back(i); + ret.push_back('"'); + return ret; +} + +int dev::fromHex(char _i, WhenError _throw) +{ + if (_i >= '0' && _i <= '9') + return _i - '0'; + if (_i >= 'a' && _i <= 'f') + return _i - 'a' + 10; + if (_i >= 'A' && _i <= 'F') + return _i - 'A' + 10; + if (_throw == WhenError::Throw) + BOOST_THROW_EXCEPTION(BadHexCharacter() << errinfo_invalidSymbol(_i)); + else + return -1; +} + +bytes dev::fromHex(std::string const& _s, WhenError _throw) +{ + unsigned s = (_s.size() >= 2 && _s[0] == '0' && _s[1] == 'x') ? 2 : 0; + std::vector<uint8_t> ret; + ret.reserve((_s.size() - s + 1) / 2); + + if (_s.size() % 2) + { + int h = fromHex(_s[s++], WhenError::DontThrow); + if (h != -1) + ret.push_back(h); + else if (_throw == WhenError::Throw) + BOOST_THROW_EXCEPTION(BadHexCharacter()); + else + return bytes(); + } + for (unsigned i = s; i < _s.size(); i += 2) + { + int h = fromHex(_s[i], WhenError::DontThrow); + int l = fromHex(_s[i + 1], WhenError::DontThrow); + if (h != -1 && l != -1) + ret.push_back((byte)(h * 16 + l)); + else if (_throw == WhenError::Throw) + BOOST_THROW_EXCEPTION(BadHexCharacter()); + else + return bytes(); + } + return ret; +} diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h new file mode 100644 index 00000000..5ffcdcca --- /dev/null +++ b/libdevcore/CommonData.h @@ -0,0 +1,182 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** @file CommonData.h + * @author Gav Wood <i@gavwood.com> + * @date 2014 + * + * Shared algorithms and data types. + */ + +#pragma once + +#include <vector> +#include <algorithm> +#include <unordered_set> +#include <type_traits> +#include <cstring> +#include <string> +#include "Common.h" + +namespace dev +{ + +// String conversion functions, mainly to/from hex/nibble/byte representations. + +enum class WhenError +{ + DontThrow = 0, + Throw = 1, +}; + +enum class HexPrefix +{ + DontAdd = 0, + Add = 1, +}; +/// Convert a series of bytes to the corresponding string of hex duplets. +/// @param _w specifies the width of the first of the elements. Defaults to two - enough to represent a byte. +/// @example toHex("A\x69") == "4169" +template <class T> +std::string toHex(T const& _data, int _w = 2, HexPrefix _prefix = HexPrefix::DontAdd) +{ + std::ostringstream ret; + unsigned ii = 0; + for (auto i: _data) + ret << std::hex << std::setfill('0') << std::setw(ii++ ? 2 : _w) << (int)(typename std::make_unsigned<decltype(i)>::type)i; + return (_prefix == HexPrefix::Add) ? "0x" + ret.str() : ret.str(); +} + +/// Converts a (printable) ASCII hex character into the correspnding integer value. +/// @example fromHex('A') == 10 && fromHex('f') == 15 && fromHex('5') == 5 +int fromHex(char _i, WhenError _throw); + +/// Converts a (printable) ASCII hex string into the corresponding byte stream. +/// @example fromHex("41626261") == asBytes("Abba") +/// If _throw = ThrowType::DontThrow, it replaces bad hex characters with 0's, otherwise it will throw an exception. +bytes fromHex(std::string const& _s, WhenError _throw = WhenError::DontThrow); +/// Converts byte array to a string containing the same (binary) data. Unless +/// the byte array happens to contain ASCII data, this won't be printable. +inline std::string asString(bytes const& _b) +{ + return std::string((char const*)_b.data(), (char const*)(_b.data() + _b.size())); +} + +/// Converts byte array ref to a string containing the same (binary) data. Unless +/// the byte array happens to contain ASCII data, this won't be printable. +inline std::string asString(bytesConstRef _b) +{ + return std::string((char const*)_b.data(), (char const*)(_b.data() + _b.size())); +} + +/// Converts a string to a byte array containing the string's (byte) data. +inline bytes asBytes(std::string const& _b) +{ + return bytes((byte const*)_b.data(), (byte const*)(_b.data() + _b.size())); +} + +// Big-endian to/from host endian conversion functions. + +/// Converts a templated integer value to the big-endian byte-stream represented on a templated collection. +/// The size of the collection object will be unchanged. If it is too small, it will not represent the +/// value properly, if too big then the additional elements will be zeroed out. +/// @a Out will typically be either std::string or bytes. +/// @a T will typically by unsigned, u160, u256 or bigint. +template <class T, class Out> +inline void toBigEndian(T _val, Out& o_out) +{ + static_assert(std::is_same<bigint, T>::value || !std::numeric_limits<T>::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift + for (auto i = o_out.size(); i != 0; _val >>= 8, i--) + { + T v = _val & (T)0xff; + o_out[i - 1] = (typename Out::value_type)(uint8_t)v; + } +} + +/// Converts a big-endian byte-stream represented on a templated collection to a templated integer value. +/// @a _In will typically be either std::string or bytes. +/// @a T will typically by unsigned, u160, u256 or bigint. +template <class T, class _In> +inline T fromBigEndian(_In const& _bytes) +{ + T ret = (T)0; + for (auto i: _bytes) + ret = (T)((ret << 8) | (byte)(typename std::make_unsigned<typename _In::value_type>::type)i); + return ret; +} +inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; } +inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; } + +/// Convenience function for toBigEndian. +/// @returns a byte array just big enough to represent @a _val. +template <class T> +inline bytes toCompactBigEndian(T _val, unsigned _min = 0) +{ + static_assert(std::is_same<bigint, T>::value || !std::numeric_limits<T>::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift + int i = 0; + for (T v = _val; v; ++i, v >>= 8) {} + bytes ret(std::max<unsigned>(_min, i), 0); + toBigEndian(_val, ret); + return ret; +} +inline bytes toCompactBigEndian(byte _val, unsigned _min = 0) +{ + return (_min || _val) ? bytes{ _val } : bytes{}; +} + +/// Convenience function for conversion of a u256 to hex +inline std::string toHex(u256 val, HexPrefix prefix = HexPrefix::DontAdd) +{ + std::string str = toHex(toBigEndian(val)); + return (prefix == HexPrefix::Add) ? "0x" + str : str; +} + +// Algorithms for string and string-like collections. + +/// Escapes a string into the C-string representation. +/// @p _all if true will escape all characters, not just the unprintable ones. +std::string escaped(std::string const& _s, bool _all = true); +/// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero. +template <class T> +inline unsigned bytesRequired(T _i) +{ + static_assert(std::is_same<bigint, T>::value || !std::numeric_limits<T>::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift + unsigned i = 0; + for (; _i != 0; ++i, _i >>= 8) {} + return i; +} +/// Concatenate the contents of a container onto a vector +template <class T, class U> std::vector<T>& operator+=(std::vector<T>& _a, U const& _b) +{ + for (auto const& i: _b) + _a.push_back(i); + return _a; +} +/// Concatenate two vectors of elements. +template <class T> +inline std::vector<T> operator+(std::vector<T> const& _a, std::vector<T> const& _b) +{ + std::vector<T> ret(_a); + return ret += _b; +} + +template <class T, class V> +bool contains(T const& _t, V const& _v) +{ + return std::end(_t) != std::find(std::begin(_t), std::end(_t), _v); +} + +} diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp new file mode 100644 index 00000000..60ac518d --- /dev/null +++ b/libdevcore/CommonIO.cpp @@ -0,0 +1,90 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** @file CommonIO.cpp + * @author Gav Wood <i@gavwood.com> + * @date 2014 + */ + +#include "CommonIO.h" +#include <iostream> +#include <cstdlib> +#include <fstream> +#include <stdio.h> +#if defined(_WIN32) +#include <windows.h> +#else +#include <termios.h> +#endif +#include <boost/filesystem.hpp> +#include "Exceptions.h" +using namespace std; +using namespace dev; + + +template <typename _T> +inline _T contentsGeneric(std::string const& _file) +{ + _T ret; + size_t const c_elementSize = sizeof(typename _T::value_type); + std::ifstream is(_file, std::ifstream::binary); + if (!is) + return ret; + + // get length of file: + is.seekg(0, is.end); + streamoff length = is.tellg(); + if (length == 0) + return ret; // do not read empty file (MSVC does not like it) + is.seekg(0, is.beg); + + ret.resize((length + c_elementSize - 1) / c_elementSize); + is.read(const_cast<char*>(reinterpret_cast<char const*>(ret.data())), length); + return ret; +} + +string dev::contentsString(string const& _file) +{ + return contentsGeneric<string>(_file); +} + +void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDeleteRename) +{ + namespace fs = boost::filesystem; + if (_writeDeleteRename) + { + fs::path tempPath = fs::unique_path(_file + "-%%%%%%"); + writeFile(tempPath.string(), _data, false); + // will delete _file if it exists + fs::rename(tempPath, _file); + } + else + { + // create directory if not existent + fs::path p(_file); + if (!fs::exists(p.parent_path())) + { + fs::create_directories(p.parent_path()); + DEV_IGNORE_EXCEPTIONS(fs::permissions(p.parent_path(), fs::owner_all)); + } + + ofstream s(_file, ios::trunc | ios::binary); + s.write(reinterpret_cast<char const*>(_data.data()), _data.size()); + if (!s) + BOOST_THROW_EXCEPTION(FileError() << errinfo_comment("Could not write to file: " + _file)); + DEV_IGNORE_EXCEPTIONS(fs::permissions(_file, fs::owner_read|fs::owner_write)); + } +} diff --git a/libdevcore/CommonIO.h b/libdevcore/CommonIO.h new file mode 100644 index 00000000..8238fe0f --- /dev/null +++ b/libdevcore/CommonIO.h @@ -0,0 +1,54 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** @file CommonIO.h + * @author Gav Wood <i@gavwood.com> + * @date 2014 + * + * File & stream I/O routines. + */ + +#pragma once + +#include <sstream> +#include <string> +#include "Common.h" + +namespace dev +{ + +/// Retrieve and returns the contents of the given file as a std::string. +/// If the file doesn't exist or isn't readable, returns an empty container / bytes. +std::string contentsString(std::string const& _file); + +/// Write the given binary data into the given file, replacing the file if it pre-exists. +/// Throws exception on error. +/// @param _writeDeleteRename useful not to lose any data: If set, first writes to another file in +/// the same directory and then moves that file. +void writeFile(std::string const& _file, bytesConstRef _data, bool _writeDeleteRename = false); +/// Write the given binary data into the given file, replacing the file if it pre-exists. +inline void writeFile(std::string const& _file, bytes const& _data, bool _writeDeleteRename = false) { writeFile(_file, bytesConstRef(&_data), _writeDeleteRename); } +inline void writeFile(std::string const& _file, std::string const& _data, bool _writeDeleteRename = false) { writeFile(_file, bytesConstRef(_data), _writeDeleteRename); } +/// Converts arbitrary value to string representation using std::stringstream. +template <class _T> +std::string toString(_T const& _t) +{ + std::ostringstream o; + o << _t; + return o.str(); +} + +} diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h new file mode 100644 index 00000000..a6c1f9ab --- /dev/null +++ b/libdevcore/Exceptions.h @@ -0,0 +1,87 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** @file Exceptions.h + * @author Gav Wood <i@gavwood.com> + * @date 2014 + */ + +#pragma once + +#include <exception> +#include <string> +#include <boost/exception/exception.hpp> +#include <boost/exception/info.hpp> +#include <boost/exception/info_tuple.hpp> +#include <boost/exception/diagnostic_information.hpp> +#include <boost/throw_exception.hpp> +#include <boost/tuple/tuple.hpp> +#include "CommonData.h" +#include "FixedHash.h" + +namespace dev +{ + +/// Base class for all exceptions. +struct Exception: virtual std::exception, virtual boost::exception +{ + Exception(std::string _message = std::string()): m_message(std::move(_message)) {} + const char* what() const noexcept override { return m_message.empty() ? std::exception::what() : m_message.c_str(); } + +private: + std::string m_message; +}; + +#define DEV_SIMPLE_EXCEPTION(X) struct X: virtual Exception { const char* what() const noexcept override { return #X; } } + +/// Base class for all RLP exceptions. +struct RLPException: virtual Exception { RLPException(std::string _message = std::string()): Exception(_message) {} }; +#define DEV_SIMPLE_EXCEPTION_RLP(X) struct X: virtual RLPException { const char* what() const noexcept override { return #X; } } + +DEV_SIMPLE_EXCEPTION_RLP(BadCast); +DEV_SIMPLE_EXCEPTION_RLP(BadRLP); +DEV_SIMPLE_EXCEPTION_RLP(OversizeRLP); +DEV_SIMPLE_EXCEPTION_RLP(UndersizeRLP); + +DEV_SIMPLE_EXCEPTION(BadHexCharacter); +DEV_SIMPLE_EXCEPTION(NoNetworking); +DEV_SIMPLE_EXCEPTION(NoUPnPDevice); +DEV_SIMPLE_EXCEPTION(RootNotFound); +struct BadRoot: virtual Exception { public: BadRoot(h256 const& _root): Exception("BadRoot " + _root.hex()), root(_root) {} h256 root; }; +DEV_SIMPLE_EXCEPTION(FileError); +DEV_SIMPLE_EXCEPTION(Overflow); +DEV_SIMPLE_EXCEPTION(FailedInvariant); +DEV_SIMPLE_EXCEPTION(ValueTooLarge); + +struct InterfaceNotSupported: virtual Exception { public: InterfaceNotSupported(std::string _f): Exception("Interface " + _f + " not supported.") {} }; +struct ExternalFunctionFailure: virtual Exception { public: ExternalFunctionFailure(std::string _f): Exception("Function " + _f + "() failed.") {} }; + +// error information to be added to exceptions +using errinfo_invalidSymbol = boost::error_info<struct tag_invalidSymbol, char>; +using errinfo_wrongAddress = boost::error_info<struct tag_address, std::string>; +using errinfo_comment = boost::error_info<struct tag_comment, std::string>; +using errinfo_required = boost::error_info<struct tag_required, bigint>; +using errinfo_got = boost::error_info<struct tag_got, bigint>; +using errinfo_min = boost::error_info<struct tag_min, bigint>; +using errinfo_max = boost::error_info<struct tag_max, bigint>; +using RequirementError = boost::tuple<errinfo_required, errinfo_got>; +using errinfo_hash256 = boost::error_info<struct tag_hash, h256>; +using errinfo_required_h256 = boost::error_info<struct tag_required_h256, h256>; +using errinfo_got_h256 = boost::error_info<struct tag_get_h256, h256>; +using Hash256RequirementError = boost::tuple<errinfo_required_h256, errinfo_got_h256>; +using errinfo_extraData = boost::error_info<struct tag_extraData, bytes>; + +} diff --git a/libdevcore/FixedHash.cpp b/libdevcore/FixedHash.cpp new file mode 100644 index 00000000..420e2bb1 --- /dev/null +++ b/libdevcore/FixedHash.cpp @@ -0,0 +1,50 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** @file FixedHash.cpp + * @author Gav Wood <i@gavwood.com> + * @date 2014 + */ + +#include "FixedHash.h" +#include <ctime> +#include <boost/algorithm/string.hpp> + +using namespace std; +using namespace dev; + +boost::random_device dev::s_fixedHashEngine; + +h128 dev::fromUUID(std::string const& _uuid) +{ + try + { + return h128(boost::replace_all_copy(_uuid, "-", "")); + } + catch (...) + { + return h128(); + } +} + +std::string dev::toUUID(h128 const& _uuid) +{ + std::string ret = toHex(_uuid.ref()); + for (unsigned i: {20, 16, 12, 8}) + ret.insert(ret.begin() + i, '-'); + return ret; +} + diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h new file mode 100644 index 00000000..cf79bab0 --- /dev/null +++ b/libdevcore/FixedHash.h @@ -0,0 +1,306 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** @file FixedHash.h + * @author Gav Wood <i@gavwood.com> + * @date 2014 + * + * The FixedHash fixed-size "hash" container type. + */ + +#pragma once + +#include <array> +#include <cstdint> +#include <algorithm> +#include <boost/random/random_device.hpp> +#include <boost/random/uniform_int_distribution.hpp> +#include <boost/functional/hash.hpp> +#include "CommonData.h" + +namespace dev +{ + +/// Compile-time calculation of Log2 of constant values. +template <unsigned N> struct StaticLog2 { enum { result = 1 + StaticLog2<N/2>::result }; }; +template <> struct StaticLog2<1> { enum { result = 0 }; }; + +extern boost::random_device s_fixedHashEngine; + +/// Fixed-size raw-byte array container type, with an API optimised for storing hashes. +/// Transparently converts to/from the corresponding arithmetic type; this will +/// assume the data contained in the hash is big-endian. +template <unsigned N> +class FixedHash +{ +public: + /// The corresponding arithmetic type. + using Arith = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>; + + /// The size of the container. + enum { size = N }; + + /// A dummy flag to avoid accidental construction from pointer. + enum ConstructFromPointerType { ConstructFromPointer }; + + /// Method to convert from a string. + enum ConstructFromStringType { FromHex, FromBinary }; + + /// Method to convert from a string. + enum ConstructFromHashType { AlignLeft, AlignRight, FailIfDifferent }; + + /// Construct an empty hash. + FixedHash() { m_data.fill(0); } + + /// Construct from another hash, filling with zeroes or cropping as necessary. + template <unsigned M> explicit FixedHash(FixedHash<M> const& _h, ConstructFromHashType _t = AlignLeft) { m_data.fill(0); unsigned c = std::min(M, N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i]; } + + /// Convert from the corresponding arithmetic type. + FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); } + + /// Convert from unsigned + explicit FixedHash(unsigned _u) { toBigEndian(_u, m_data); } + + /// Explicitly construct, copying from a byte array. + explicit FixedHash(bytes const& _b, ConstructFromHashType _t = FailIfDifferent) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<unsigned>(_b.size(), N)); else { m_data.fill(0); if (_t != FailIfDifferent) { auto c = std::min<unsigned>(_b.size(), N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i]; } } } + + /// Explicitly construct, copying from a byte array. + explicit FixedHash(bytesConstRef _b, ConstructFromHashType _t = FailIfDifferent) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<unsigned>(_b.size(), N)); else { m_data.fill(0); if (_t != FailIfDifferent) { auto c = std::min<unsigned>(_b.size(), N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i]; } } } + + /// Explicitly construct, copying from a bytes in memory with given pointer. + explicit FixedHash(byte const* _bs, ConstructFromPointerType) { memcpy(m_data.data(), _bs, N); } + + /// Explicitly construct, copying from a string. + explicit FixedHash(std::string const& _s, ConstructFromStringType _t = FromHex, ConstructFromHashType _ht = FailIfDifferent): FixedHash(_t == FromHex ? fromHex(_s, WhenError::Throw) : dev::asBytes(_s), _ht) {} + + /// Convert to arithmetic type. + operator Arith() const { return fromBigEndian<Arith>(m_data); } + + /// @returns true iff this is the empty hash. + explicit operator bool() const { return std::any_of(m_data.begin(), m_data.end(), [](byte _b) { return _b != 0; }); } + + // The obvious comparison operators. + bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; } + bool operator!=(FixedHash const& _c) const { return m_data != _c.m_data; } + bool operator<(FixedHash const& _c) const { for (unsigned i = 0; i < N; ++i) if (m_data[i] < _c.m_data[i]) return true; else if (m_data[i] > _c.m_data[i]) return false; return false; } + bool operator>=(FixedHash const& _c) const { return !operator<(_c); } + bool operator<=(FixedHash const& _c) const { return operator==(_c) || operator<(_c); } + bool operator>(FixedHash const& _c) const { return !operator<=(_c); } + + // The obvious binary operators. + FixedHash& operator^=(FixedHash const& _c) { for (unsigned i = 0; i < N; ++i) m_data[i] ^= _c.m_data[i]; return *this; } + FixedHash operator^(FixedHash const& _c) const { return FixedHash(*this) ^= _c; } + FixedHash& operator|=(FixedHash const& _c) { for (unsigned i = 0; i < N; ++i) m_data[i] |= _c.m_data[i]; return *this; } + FixedHash operator|(FixedHash const& _c) const { return FixedHash(*this) |= _c; } + FixedHash& operator&=(FixedHash const& _c) { for (unsigned i = 0; i < N; ++i) m_data[i] &= _c.m_data[i]; return *this; } + FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; } + FixedHash operator~() const { FixedHash ret; for (unsigned i = 0; i < N; ++i) ret[i] = ~m_data[i]; return ret; } + + // Big-endian increment. + FixedHash& operator++() { for (unsigned i = size; i > 0 && !++m_data[--i]; ) {} return *this; } + + /// @returns true if all one-bits in @a _c are set in this object. + bool contains(FixedHash const& _c) const { return (*this & _c) == _c; } + + /// @returns a particular byte from the hash. + byte& operator[](unsigned _i) { return m_data[_i]; } + /// @returns a particular byte from the hash. + byte operator[](unsigned _i) const { return m_data[_i]; } + + /// @returns an abridged version of the hash as a user-readable hex string. + std::string abridged() const { return toHex(ref().cropped(0, 4)) + "\342\200\246"; } + + /// @returns a version of the hash as a user-readable hex string that leaves out the middle part. + std::string abridgedMiddle() const { return toHex(ref().cropped(0, 4)) + "\342\200\246" + toHex(ref().cropped(N - 4)); } + + /// @returns the hash as a user-readable hex string. + std::string hex() const { return toHex(ref()); } + + /// @returns a mutable byte vector_ref to the object's data. + bytesRef ref() { return bytesRef(m_data.data(), N); } + + /// @returns a constant byte vector_ref to the object's data. + bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); } + + /// @returns a mutable byte pointer to the object's data. + byte* data() { return m_data.data(); } + + /// @returns a constant byte pointer to the object's data. + byte const* data() const { return m_data.data(); } + + /// @returns a copy of the object's data as a byte vector. + bytes asBytes() const { return bytes(data(), data() + N); } + + /// @returns a mutable reference to the object's data as an STL array. + std::array<byte, N>& asArray() { return m_data; } + + /// @returns a constant reference to the object's data as an STL array. + std::array<byte, N> const& asArray() const { return m_data; } + + /// Populate with random data. + template <class Engine> + void randomize(Engine& _eng) + { + for (auto& i: m_data) + i = (uint8_t)boost::random::uniform_int_distribution<uint16_t>(0, 255)(_eng); + } + + /// @returns a random valued object. + static FixedHash random() { FixedHash ret; ret.randomize(s_fixedHashEngine); return ret; } + + struct hash + { + /// Make a hash of the object's data. + size_t operator()(FixedHash const& _value) const { return boost::hash_range(_value.m_data.cbegin(), _value.m_data.cend()); } + }; + + template <unsigned P, unsigned M> inline FixedHash& shiftBloom(FixedHash<M> const& _h) + { + return (*this |= _h.template bloomPart<P, N>()); + } + + template <unsigned P, unsigned M> inline bool containsBloom(FixedHash<M> const& _h) + { + return contains(_h.template bloomPart<P, N>()); + } + + template <unsigned P, unsigned M> inline FixedHash<M> bloomPart() const + { + unsigned const c_bloomBits = M * 8; + unsigned const c_mask = c_bloomBits - 1; + unsigned const c_bloomBytes = (StaticLog2<c_bloomBits>::result + 7) / 8; + + static_assert((M & (M - 1)) == 0, "M must be power-of-two"); + static_assert(P * c_bloomBytes <= N, "out of range"); + + FixedHash<M> ret; + byte const* p = data(); + for (unsigned i = 0; i < P; ++i) + { + unsigned index = 0; + for (unsigned j = 0; j < c_bloomBytes; ++j, ++p) + index = (index << 8) | *p; + index &= c_mask; + ret[M - 1 - index / 8] |= (1 << (index % 8)); + } + return ret; + } + + /// Returns the index of the first bit set to one, or size() * 8 if no bits are set. + inline unsigned firstBitSet() const + { + unsigned ret = 0; + for (auto d: m_data) + if (d) + for (;; ++ret, d <<= 1) + if (d & 0x80) + return ret; + else {} + else + ret += 8; + return ret; + } + + void clear() { m_data.fill(0); } + +private: + std::array<byte, N> m_data; ///< The binary data. +}; + +/// Fast equality operator for h256. +template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) const +{ + const uint64_t* hash1 = (const uint64_t*)data(); + const uint64_t* hash2 = (const uint64_t*)_other.data(); + return (hash1[0] == hash2[0]) && (hash1[1] == hash2[1]) && (hash1[2] == hash2[2]) && (hash1[3] == hash2[3]); +} + +/// Fast std::hash compatible hash function object for h256. +template<> inline size_t FixedHash<32>::hash::operator()(FixedHash<32> const& value) const +{ + uint64_t const* data = reinterpret_cast<uint64_t const*>(value.data()); + return boost::hash_range(data, data + 4); +} + +/// Stream I/O for the FixedHash class. +template <unsigned N> +inline std::ostream& operator<<(std::ostream& _out, FixedHash<N> const& _h) +{ + _out << std::noshowbase << std::hex << std::setfill('0'); + for (unsigned i = 0; i < N; ++i) + _out << std::setw(2) << (int)_h[i]; + _out << std::dec; + return _out; +} + +// Common types of FixedHash. +using h2048 = FixedHash<256>; +using h1024 = FixedHash<128>; +using h520 = FixedHash<65>; +using h512 = FixedHash<64>; +using h256 = FixedHash<32>; +using h160 = FixedHash<20>; +using h128 = FixedHash<16>; +using h64 = FixedHash<8>; +using h512s = std::vector<h512>; +using h256s = std::vector<h256>; +using h160s = std::vector<h160>; +using h256Set = std::set<h256>; +using h160Set = std::set<h160>; +using h256Hash = std::unordered_set<h256>; +using h160Hash = std::unordered_set<h160>; + +/// Convert the given value into h160 (160-bit unsigned integer) using the right 20 bytes. +inline h160 right160(h256 const& _t) +{ + h160 ret; + memcpy(ret.data(), _t.data() + 12, 20); + return ret; +} + +/// Convert the given value into h160 (160-bit unsigned integer) using the left 20 bytes. +inline h160 left160(h256 const& _t) +{ + h160 ret; + memcpy(&ret[0], _t.data(), 20); + return ret; +} + +h128 fromUUID(std::string const& _uuid); + +std::string toUUID(h128 const& _uuid); + +inline std::string toString(h256s const& _bs) +{ + std::ostringstream out; + out << "[ "; + for (auto i: _bs) + out << i.abridged() << ", "; + out << "]"; + return out.str(); +} + +} + +namespace std +{ + /// Forward std::hash<dev::FixedHash> to dev::FixedHash::hash. + template<> struct hash<dev::h64>: dev::h64::hash {}; + template<> struct hash<dev::h128>: dev::h128::hash {}; + template<> struct hash<dev::h160>: dev::h160::hash {}; + template<> struct hash<dev::h256>: dev::h256::hash {}; + template<> struct hash<dev::h512>: dev::h512::hash {}; +} diff --git a/libdevcore/Hash.cpp b/libdevcore/Hash.cpp new file mode 100644 index 00000000..c6b917b9 --- /dev/null +++ b/libdevcore/Hash.cpp @@ -0,0 +1,440 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** @file Hash.cpp + * @author Gav Wood <i@gavwood.com> + * @date 2014 + */ + +#include "Hash.h" +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include "picosha2.h" +using namespace std; +using namespace dev; + +namespace dev +{ + +h256 sha256(bytesConstRef _input) +{ + h256 ret; + picosha2::hash256(_input.begin(), _input.end(), ret.data(), ret.data() + 32); + return ret; +} + +namespace rmd160 +{ + +/********************************************************************\ + * + * FILE: rmd160.h + * FILE: rmd160.c + * + * CONTENTS: Header file for a sample C-implementation of the + * RIPEMD-160 hash-function. + * TARGET: any computer with an ANSI C compiler + * + * AUTHOR: Antoon Bosselaers, ESAT-COSIC + * DATE: 1 March 1996 + * VERSION: 1.0 + * + * Copyright (c) Katholieke Universiteit Leuven + * 1996, All Rights Reserved + * + \********************************************************************/ + +// Adapted into "header-only" format by Gav Wood. + +/* macro definitions */ + +#define RMDsize 160 + +/* collect four bytes into one word: */ +#define BYTES_TO_DWORD(strptr) \ +(((uint32_t) *((strptr)+3) << 24) | \ +((uint32_t) *((strptr)+2) << 16) | \ +((uint32_t) *((strptr)+1) << 8) | \ +((uint32_t) *(strptr))) + +/* ROL(x, n) cyclically rotates x over n bits to the left */ +/* x must be of an unsigned 32 bits type and 0 <= n < 32. */ +#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* the five basic functions F(), G() and H() */ +#define F(x, y, z) ((x) ^ (y) ^ (z)) +#define G(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define H(x, y, z) (((x) | ~(y)) ^ (z)) +#define I(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define J(x, y, z) ((x) ^ ((y) | ~(z))) + +/* the ten basic operations FF() through III() */ +#define FF(a, b, c, d, e, x, s) {\ +(a) += F((b), (c), (d)) + (x);\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define GG(a, b, c, d, e, x, s) {\ +(a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define HH(a, b, c, d, e, x, s) {\ +(a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define II(a, b, c, d, e, x, s) {\ +(a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define JJ(a, b, c, d, e, x, s) {\ +(a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define FFF(a, b, c, d, e, x, s) {\ +(a) += F((b), (c), (d)) + (x);\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define GGG(a, b, c, d, e, x, s) {\ +(a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define HHH(a, b, c, d, e, x, s) {\ +(a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define III(a, b, c, d, e, x, s) {\ +(a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define JJJ(a, b, c, d, e, x, s) {\ +(a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} + +void MDinit(uint32_t *MDbuf) +{ + MDbuf[0] = 0x67452301UL; + MDbuf[1] = 0xefcdab89UL; + MDbuf[2] = 0x98badcfeUL; + MDbuf[3] = 0x10325476UL; + MDbuf[4] = 0xc3d2e1f0UL; + + return; +} + +/********************************************************************/ + +void MDcompress(uint32_t *MDbuf, uint32_t *X) +{ + uint32_t aa = MDbuf[0], bb = MDbuf[1], cc = MDbuf[2], + dd = MDbuf[3], ee = MDbuf[4]; + uint32_t aaa = MDbuf[0], bbb = MDbuf[1], ccc = MDbuf[2], + ddd = MDbuf[3], eee = MDbuf[4]; + + /* round 1 */ + FF(aa, bb, cc, dd, ee, X[ 0], 11); + FF(ee, aa, bb, cc, dd, X[ 1], 14); + FF(dd, ee, aa, bb, cc, X[ 2], 15); + FF(cc, dd, ee, aa, bb, X[ 3], 12); + FF(bb, cc, dd, ee, aa, X[ 4], 5); + FF(aa, bb, cc, dd, ee, X[ 5], 8); + FF(ee, aa, bb, cc, dd, X[ 6], 7); + FF(dd, ee, aa, bb, cc, X[ 7], 9); + FF(cc, dd, ee, aa, bb, X[ 8], 11); + FF(bb, cc, dd, ee, aa, X[ 9], 13); + FF(aa, bb, cc, dd, ee, X[10], 14); + FF(ee, aa, bb, cc, dd, X[11], 15); + FF(dd, ee, aa, bb, cc, X[12], 6); + FF(cc, dd, ee, aa, bb, X[13], 7); + FF(bb, cc, dd, ee, aa, X[14], 9); + FF(aa, bb, cc, dd, ee, X[15], 8); + + /* round 2 */ + GG(ee, aa, bb, cc, dd, X[ 7], 7); + GG(dd, ee, aa, bb, cc, X[ 4], 6); + GG(cc, dd, ee, aa, bb, X[13], 8); + GG(bb, cc, dd, ee, aa, X[ 1], 13); + GG(aa, bb, cc, dd, ee, X[10], 11); + GG(ee, aa, bb, cc, dd, X[ 6], 9); + GG(dd, ee, aa, bb, cc, X[15], 7); + GG(cc, dd, ee, aa, bb, X[ 3], 15); + GG(bb, cc, dd, ee, aa, X[12], 7); + GG(aa, bb, cc, dd, ee, X[ 0], 12); + GG(ee, aa, bb, cc, dd, X[ 9], 15); + GG(dd, ee, aa, bb, cc, X[ 5], 9); + GG(cc, dd, ee, aa, bb, X[ 2], 11); + GG(bb, cc, dd, ee, aa, X[14], 7); + GG(aa, bb, cc, dd, ee, X[11], 13); + GG(ee, aa, bb, cc, dd, X[ 8], 12); + + /* round 3 */ + HH(dd, ee, aa, bb, cc, X[ 3], 11); + HH(cc, dd, ee, aa, bb, X[10], 13); + HH(bb, cc, dd, ee, aa, X[14], 6); + HH(aa, bb, cc, dd, ee, X[ 4], 7); + HH(ee, aa, bb, cc, dd, X[ 9], 14); + HH(dd, ee, aa, bb, cc, X[15], 9); + HH(cc, dd, ee, aa, bb, X[ 8], 13); + HH(bb, cc, dd, ee, aa, X[ 1], 15); + HH(aa, bb, cc, dd, ee, X[ 2], 14); + HH(ee, aa, bb, cc, dd, X[ 7], 8); + HH(dd, ee, aa, bb, cc, X[ 0], 13); + HH(cc, dd, ee, aa, bb, X[ 6], 6); + HH(bb, cc, dd, ee, aa, X[13], 5); + HH(aa, bb, cc, dd, ee, X[11], 12); + HH(ee, aa, bb, cc, dd, X[ 5], 7); + HH(dd, ee, aa, bb, cc, X[12], 5); + + /* round 4 */ + II(cc, dd, ee, aa, bb, X[ 1], 11); + II(bb, cc, dd, ee, aa, X[ 9], 12); + II(aa, bb, cc, dd, ee, X[11], 14); + II(ee, aa, bb, cc, dd, X[10], 15); + II(dd, ee, aa, bb, cc, X[ 0], 14); + II(cc, dd, ee, aa, bb, X[ 8], 15); + II(bb, cc, dd, ee, aa, X[12], 9); + II(aa, bb, cc, dd, ee, X[ 4], 8); + II(ee, aa, bb, cc, dd, X[13], 9); + II(dd, ee, aa, bb, cc, X[ 3], 14); + II(cc, dd, ee, aa, bb, X[ 7], 5); + II(bb, cc, dd, ee, aa, X[15], 6); + II(aa, bb, cc, dd, ee, X[14], 8); + II(ee, aa, bb, cc, dd, X[ 5], 6); + II(dd, ee, aa, bb, cc, X[ 6], 5); + II(cc, dd, ee, aa, bb, X[ 2], 12); + + /* round 5 */ + JJ(bb, cc, dd, ee, aa, X[ 4], 9); + JJ(aa, bb, cc, dd, ee, X[ 0], 15); + JJ(ee, aa, bb, cc, dd, X[ 5], 5); + JJ(dd, ee, aa, bb, cc, X[ 9], 11); + JJ(cc, dd, ee, aa, bb, X[ 7], 6); + JJ(bb, cc, dd, ee, aa, X[12], 8); + JJ(aa, bb, cc, dd, ee, X[ 2], 13); + JJ(ee, aa, bb, cc, dd, X[10], 12); + JJ(dd, ee, aa, bb, cc, X[14], 5); + JJ(cc, dd, ee, aa, bb, X[ 1], 12); + JJ(bb, cc, dd, ee, aa, X[ 3], 13); + JJ(aa, bb, cc, dd, ee, X[ 8], 14); + JJ(ee, aa, bb, cc, dd, X[11], 11); + JJ(dd, ee, aa, bb, cc, X[ 6], 8); + JJ(cc, dd, ee, aa, bb, X[15], 5); + JJ(bb, cc, dd, ee, aa, X[13], 6); + + /* parallel round 1 */ + JJJ(aaa, bbb, ccc, ddd, eee, X[ 5], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[14], 9); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 7], 9); + JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13); + JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15); + JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 4], 5); + JJJ(ccc, ddd, eee, aaa, bbb, X[13], 7); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 6], 7); + JJJ(aaa, bbb, ccc, ddd, eee, X[15], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14); + JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12); + JJJ(aaa, bbb, ccc, ddd, eee, X[12], 6); + + /* parallel round 2 */ + III(eee, aaa, bbb, ccc, ddd, X[ 6], 9); + III(ddd, eee, aaa, bbb, ccc, X[11], 13); + III(ccc, ddd, eee, aaa, bbb, X[ 3], 15); + III(bbb, ccc, ddd, eee, aaa, X[ 7], 7); + III(aaa, bbb, ccc, ddd, eee, X[ 0], 12); + III(eee, aaa, bbb, ccc, ddd, X[13], 8); + III(ddd, eee, aaa, bbb, ccc, X[ 5], 9); + III(ccc, ddd, eee, aaa, bbb, X[10], 11); + III(bbb, ccc, ddd, eee, aaa, X[14], 7); + III(aaa, bbb, ccc, ddd, eee, X[15], 7); + III(eee, aaa, bbb, ccc, ddd, X[ 8], 12); + III(ddd, eee, aaa, bbb, ccc, X[12], 7); + III(ccc, ddd, eee, aaa, bbb, X[ 4], 6); + III(bbb, ccc, ddd, eee, aaa, X[ 9], 15); + III(aaa, bbb, ccc, ddd, eee, X[ 1], 13); + III(eee, aaa, bbb, ccc, ddd, X[ 2], 11); + + /* parallel round 3 */ + HHH(ddd, eee, aaa, bbb, ccc, X[15], 9); + HHH(ccc, ddd, eee, aaa, bbb, X[ 5], 7); + HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15); + HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11); + HHH(eee, aaa, bbb, ccc, ddd, X[ 7], 8); + HHH(ddd, eee, aaa, bbb, ccc, X[14], 6); + HHH(ccc, ddd, eee, aaa, bbb, X[ 6], 6); + HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14); + HHH(aaa, bbb, ccc, ddd, eee, X[11], 12); + HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13); + HHH(ddd, eee, aaa, bbb, ccc, X[12], 5); + HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14); + HHH(bbb, ccc, ddd, eee, aaa, X[10], 13); + HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13); + HHH(eee, aaa, bbb, ccc, ddd, X[ 4], 7); + HHH(ddd, eee, aaa, bbb, ccc, X[13], 5); + + /* parallel round 4 */ + GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15); + GGG(bbb, ccc, ddd, eee, aaa, X[ 6], 5); + GGG(aaa, bbb, ccc, ddd, eee, X[ 4], 8); + GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11); + GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14); + GGG(ccc, ddd, eee, aaa, bbb, X[11], 14); + GGG(bbb, ccc, ddd, eee, aaa, X[15], 6); + GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14); + GGG(eee, aaa, bbb, ccc, ddd, X[ 5], 6); + GGG(ddd, eee, aaa, bbb, ccc, X[12], 9); + GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12); + GGG(bbb, ccc, ddd, eee, aaa, X[13], 9); + GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12); + GGG(eee, aaa, bbb, ccc, ddd, X[ 7], 5); + GGG(ddd, eee, aaa, bbb, ccc, X[10], 15); + GGG(ccc, ddd, eee, aaa, bbb, X[14], 8); + + /* parallel round 5 */ + FFF(bbb, ccc, ddd, eee, aaa, X[12] , 8); + FFF(aaa, bbb, ccc, ddd, eee, X[15] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12); + FFF(ddd, eee, aaa, bbb, ccc, X[ 4] , 9); + FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12); + FFF(bbb, ccc, ddd, eee, aaa, X[ 5] , 5); + FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14); + FFF(eee, aaa, bbb, ccc, ddd, X[ 7] , 6); + FFF(ddd, eee, aaa, bbb, ccc, X[ 6] , 8); + FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13); + FFF(bbb, ccc, ddd, eee, aaa, X[13] , 6); + FFF(aaa, bbb, ccc, ddd, eee, X[14] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15); + FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13); + FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11); + FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11); + + /* combine results */ + ddd += cc + MDbuf[1]; /* final result for MDbuf[0] */ + MDbuf[1] = MDbuf[2] + dd + eee; + MDbuf[2] = MDbuf[3] + ee + aaa; + MDbuf[3] = MDbuf[4] + aa + bbb; + MDbuf[4] = MDbuf[0] + bb + ccc; + MDbuf[0] = ddd; + + return; +} + +void MDfinish(uint32_t *MDbuf, byte const *strptr, uint32_t lswlen, uint32_t mswlen) +{ + unsigned int i; /* counter */ + uint32_t X[16]; /* message words */ + + memset(X, 0, 16*sizeof(uint32_t)); + + /* put bytes from strptr into X */ + for (i=0; i<(lswlen&63); i++) { + /* byte i goes into word X[i div 4] at pos. 8*(i mod 4) */ + X[i>>2] ^= (uint32_t) *strptr++ << (8 * (i&3)); + } + + /* append the bit m_n == 1 */ + X[(lswlen>>2)&15] ^= (uint32_t)1 << (8*(lswlen&3) + 7); + + if ((lswlen & 63) > 55) { + /* length goes to next block */ + MDcompress(MDbuf, X); + memset(X, 0, 16*sizeof(uint32_t)); + } + + /* append length in bits*/ + X[14] = lswlen << 3; + X[15] = (lswlen >> 29) | (mswlen << 3); + MDcompress(MDbuf, X); + + return; +} + +#undef ROL +#undef F +#undef G +#undef H +#undef I +#undef J +#undef FF +#undef GG +#undef HH +#undef II +#undef JJ +#undef FFF +#undef GGG +#undef HHH +#undef III +#undef JJJ + +} + +/* + * @returns RMD(_input) + */ +h160 ripemd160(bytesConstRef _input) +{ + h160 hashcode; + uint32_t buffer[RMDsize / 32]; // contains (A, B, C, D(, E)) + uint32_t current[16]; // current 16-word chunk + + // initialize + rmd160::MDinit(buffer); + byte const* message = _input.data(); + uint32_t remaining = _input.size(); // # of bytes not yet processed + + // process message in 16x 4-byte chunks + for (; remaining >= 64; remaining -= 64) + { + for (unsigned i = 0; i < 16; i++) + { + current[i] = BYTES_TO_DWORD(message); + message += 4; + } + rmd160::MDcompress(buffer, current); + } + // length mod 64 bytes left + + // finish: + rmd160::MDfinish(buffer, message, _input.size(), 0); + + for (unsigned i = 0; i < RMDsize / 8; i += 4) + { + hashcode[i] = buffer[i >> 2]; // implicit cast to byte + hashcode[i + 1] = (buffer[i >> 2] >> 8); //extracts the 8 least + hashcode[i + 2] = (buffer[i >> 2] >> 16); // significant bits. + hashcode[i + 3] = (buffer[i >> 2] >> 24); + } + + return hashcode; +} + +#undef BYTES_TO_DWORD +#undef RMDsize + +} diff --git a/libdevcore/Hash.h b/libdevcore/Hash.h new file mode 100644 index 00000000..d4401014 --- /dev/null +++ b/libdevcore/Hash.h @@ -0,0 +1,38 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** @file Hash.h + * @author Gav Wood <i@gavwood.com> + * @date 2014 + * + * The FixedHash fixed-size "hash" container type. + */ + +#pragma once + +#include <string> +#include "FixedHash.h" +#include "vector_ref.h" +#include "SHA3.h" + +namespace dev +{ + +h256 sha256(bytesConstRef _input); + +h160 ripemd160(bytesConstRef _input); + +} diff --git a/libdevcore/SHA3.cpp b/libdevcore/SHA3.cpp new file mode 100644 index 00000000..584ef07e --- /dev/null +++ b/libdevcore/SHA3.cpp @@ -0,0 +1,223 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** @file SHA3.cpp + * @author Gav Wood <i@gavwood.com> + * @date 2014 + */ + +#include "SHA3.h" +#include <cstdint> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include "picosha2.h" +using namespace std; +using namespace dev; + +namespace dev +{ + +namespace keccak +{ + +/** libkeccak-tiny + * + * A single-file implementation of SHA-3 and SHAKE. + * + * Implementor: David Leon Gil + * License: CC0, attribution kindly requested. Blame taken too, + * but not liability. + */ + +#define decshake(bits) \ + int shake##bits(uint8_t*, size_t, const uint8_t*, size_t); + +#define decsha3(bits) \ + int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t); + +decshake(128) +decshake(256) +decsha3(224) +decsha3(256) +decsha3(384) +decsha3(512) + +/******** The Keccak-f[1600] permutation ********/ + +/*** Constants. ***/ +static const uint8_t rho[24] = \ + { 1, 3, 6, 10, 15, 21, + 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, + 62, 18, 39, 61, 20, 44}; +static const uint8_t pi[24] = \ + {10, 7, 11, 17, 18, 3, + 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, + 20, 14, 22, 9, 6, 1}; +static const uint64_t RC[24] = \ + {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, + 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, + 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, + 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, + 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, + 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; + +/*** Helper macros to unroll the permutation. ***/ +#define rol(x, s) (((x) << s) | ((x) >> (64 - s))) +#define REPEAT6(e) e e e e e e +#define REPEAT24(e) REPEAT6(e e e e) +#define REPEAT5(e) e e e e e +#define FOR5(v, s, e) \ + v = 0; \ + REPEAT5(e; v += s;) + +/*** Keccak-f[1600] ***/ +static inline void keccakf(void* state) { + uint64_t* a = (uint64_t*)state; + uint64_t b[5] = {0}; + uint64_t t = 0; + uint8_t x, y; + + for (int i = 0; i < 24; i++) { + // Theta + FOR5(x, 1, + b[x] = 0; + FOR5(y, 5, + b[x] ^= a[x + y]; )) + FOR5(x, 1, + FOR5(y, 5, + a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) + // Rho and pi + t = a[1]; + x = 0; + REPEAT24(b[0] = a[pi[x]]; + a[pi[x]] = rol(t, rho[x]); + t = b[0]; + x++; ) + // Chi + FOR5(y, + 5, + FOR5(x, 1, + b[x] = a[y + x];) + FOR5(x, 1, + a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) + // Iota + a[0] ^= RC[i]; + } +} + +/******** The FIPS202-defined functions. ********/ + +/*** Some helper macros. ***/ + +#define _(S) do { S } while (0) +#define FOR(i, ST, L, S) \ + _(for (size_t i = 0; i < L; i += ST) { S; }) +#define mkapply_ds(NAME, S) \ + static inline void NAME(uint8_t* dst, \ + const uint8_t* src, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } +#define mkapply_sd(NAME, S) \ + static inline void NAME(const uint8_t* src, \ + uint8_t* dst, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } + +mkapply_ds(xorin, dst[i] ^= src[i]) // xorin +mkapply_sd(setout, dst[i] = src[i]) // setout + +#define P keccakf +#define Plen 200 + +// Fold P*F over the full blocks of an input. +#define foldP(I, L, F) \ + while (L >= rate) { \ + F(a, I, rate); \ + P(a); \ + I += rate; \ + L -= rate; \ + } + +/** The sponge-based hash construction. **/ +static inline int hash(uint8_t* out, size_t outlen, + const uint8_t* in, size_t inlen, + size_t rate, uint8_t delim) { + if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) { + return -1; + } + uint8_t a[Plen] = {0}; + // Absorb input. + foldP(in, inlen, xorin); + // Xor in the DS and pad frame. + a[inlen] ^= delim; + a[rate - 1] ^= 0x80; + // Xor in the last block. + xorin(a, in, inlen); + // Apply P + P(a); + // Squeeze output. + foldP(out, outlen, setout); + setout(a, out, outlen); + memset(a, 0, 200); + return 0; +} + +/*** Helper macros to define SHA3 and SHAKE instances. ***/ +#define defshake(bits) \ + int shake##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x1f); \ + } +#define defsha3(bits) \ + int sha3_##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + if (outlen > (bits/8)) { \ + return -1; \ + } \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \ + } + +/*** FIPS202 SHAKE VOFs ***/ +defshake(128) +defshake(256) + +/*** FIPS202 SHA3 FOFs ***/ +defsha3(224) +defsha3(256) +defsha3(384) +defsha3(512) + +} + +unsigned g_sha3Counter = 0; + +bool sha3(bytesConstRef _input, bytesRef o_output) +{ + // FIXME: What with unaligned memory? + if (o_output.size() != 32) + return false; + ++g_sha3Counter; + keccak::sha3_256(o_output.data(), 32, _input.data(), _input.size()); +// keccak::keccak(ret.data(), 32, (uint64_t const*)_input.data(), _input.size()); + return true; +} + +} diff --git a/libdevcore/SHA3.h b/libdevcore/SHA3.h new file mode 100644 index 00000000..5393952f --- /dev/null +++ b/libdevcore/SHA3.h @@ -0,0 +1,59 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** @file SHA3.h + * @author Gav Wood <i@gavwood.com> + * @date 2014 + * + * The FixedHash fixed-size "hash" container type. + */ + +#pragma once + +#include <string> +#include "FixedHash.h" +#include "vector_ref.h" + +namespace dev +{ + +// SHA-3 convenience routines. + +/// Calculate SHA3-256 hash of the given input and load it into the given output. +/// @returns false if o_output.size() != 32. +bool sha3(bytesConstRef _input, bytesRef o_output); + +/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. +inline h256 sha3(bytesConstRef _input) { h256 ret; sha3(_input, ret.ref()); return ret; } + +/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. +inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef(&_input)); } + +/// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. +inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } + +/// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash. +template<unsigned N> inline h256 sha3(FixedHash<N> const& _input) { return sha3(_input.ref()); } + +/// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data. +inline std::string sha3(std::string const& _input, bool _isNibbles) { return asString((_isNibbles ? sha3(fromHex(_input)) : sha3(bytesConstRef(&_input))).asBytes()); } + +/// Calculate SHA3-256 MAC +inline void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) { sha3(_secret.toBytes() + _plain.toBytes()).ref().populate(_output); } + +extern unsigned g_sha3Counter; + +} diff --git a/libdevcore/UndefMacros.h b/libdevcore/UndefMacros.h new file mode 100644 index 00000000..91249523 --- /dev/null +++ b/libdevcore/UndefMacros.h @@ -0,0 +1,46 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** @file UndefMacros.h + * @author Lefteris <lefteris@ethdev.com> + * @date 2015 + * + * This header should be used to #undef some really evil macros defined by + * windows.h which result in conflict with our libsolidity/Token.h + */ +#pragma once + +#if defined(_MSC_VER) || defined(__MINGW32__) + +#undef DELETE +#undef IN +#undef VOID +#undef THIS +#undef CONST + +// Conflicting define on MinGW in windows.h +// windows.h(19): #define interface struct +#ifdef interface +#undef interface +#endif + +#elif defined(DELETE) || defined(IN) || defined(VOID) || defined(THIS) || defined(CONST) || defined(interface) + +#error "The preceding macros in this header file are reserved for V8's "\ +"TOKEN_LIST. Please add a platform specific define above to undefine "\ +"overlapping macros." + +#endif diff --git a/libdevcore/debugbreak.h b/libdevcore/debugbreak.h new file mode 100644 index 00000000..65612a34 --- /dev/null +++ b/libdevcore/debugbreak.h @@ -0,0 +1,125 @@ +/* Copyright (c) 2013, Scott Tsai + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DEBUG_BREAK_H +#define DEBUG_BREAK_H + +#if defined(_MSC_VER) || defined(__MINGW32__) + +#define debug_break __debugbreak + +#else + +#include <signal.h> +#include <unistd.h> +#include <sys/syscall.h> + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* gcc optimizers consider code after __builtin_trap() dead. + * Making __builtin_trap() unsuitable for breaking into the debugger */ + DEBUG_BREAK_PREFER_BUILTIN_TRAP_TO_SIGTRAP = 0, +}; + +#if defined(__i386__) || defined(__x86_64__) +enum { HAVE_TRAP_INSTRUCTION = 1, }; +__attribute__((gnu_inline, always_inline)) +static void __inline__ trap_instruction(void) +{ + __asm__ volatile("int $0x03"); +} +#elif defined(__thumb__) +enum { HAVE_TRAP_INSTRUCTION = 1, }; +/* FIXME: handle __THUMB_INTERWORK__ */ +__attribute__((gnu_inline, always_inline)) +static void __inline__ trap_instruction(void) +{ + /* See 'arm-linux-tdep.c' in GDB source. + * Both instruction sequences below works. */ +#if 1 + /* 'eabi_linux_thumb_le_breakpoint' */ + __asm__ volatile(".inst 0xde01"); +#else + /* 'eabi_linux_thumb2_le_breakpoint' */ + __asm__ volatile(".inst.w 0xf7f0a000"); +#endif + + /* Known problem: + * After a breakpoint hit, can't stepi, step, or continue in GDB. + * 'step' stuck on the same instruction. + * + * Workaround: a new GDB command, + * 'debugbreak-step' is defined in debugbreak-gdb.py + * that does: + * (gdb) set $instruction_len = 2 + * (gdb) tbreak *($pc + $instruction_len) + * (gdb) jump *($pc + $instruction_len) + */ +} +#elif defined(__arm__) && !defined(__thumb__) +enum { HAVE_TRAP_INSTRUCTION = 1, }; +__attribute__((gnu_inline, always_inline)) +static void __inline__ trap_instruction(void) +{ + /* See 'arm-linux-tdep.c' in GDB source, + * 'eabi_linux_arm_le_breakpoint' */ + __asm__ volatile(".inst 0xe7f001f0"); + /* Has same known problem and workaround + * as Thumb mode */ +} +#else +enum { HAVE_TRAP_INSTRUCTION = 0, }; +#endif + +__attribute__((gnu_inline, always_inline)) +static void __inline__ debug_break(void) +{ + if (HAVE_TRAP_INSTRUCTION) { +#if defined(ETH_EMSCRIPTEN) + asm("debugger"); +#else + trap_instruction(); +#endif + } else if (DEBUG_BREAK_PREFER_BUILTIN_TRAP_TO_SIGTRAP) { + /* raises SIGILL on Linux x86{,-64}, to continue in gdb: + * (gdb) handle SIGILL stop nopass + * */ + __builtin_trap(); + } else { + raise(SIGTRAP); + } +} + +#ifdef __cplusplus +} +#endif + +#endif + +#endif diff --git a/libdevcore/picosha2.h b/libdevcore/picosha2.h new file mode 100644 index 00000000..44b6bee5 --- /dev/null +++ b/libdevcore/picosha2.h @@ -0,0 +1,360 @@ +/* +The MIT License (MIT) + +Copyright (C) 2014 okdshin + +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. +*/ +#ifndef PICOSHA2_H +#define PICOSHA2_H +//picosha2:20140213 +#include <cstdint> +#include <iostream> +#include <vector> +#include <iterator> +#include <cassert> +#include <sstream> +#include <algorithm> + +namespace picosha2 +{ + +namespace detail +{ + +inline uint8_t mask_8bit(uint8_t x){ + return x&0xff; +} + +inline uint32_t mask_32bit(uint32_t x){ + return x&0xffffffff; +} + +static const uint32_t add_constant[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +static const uint32_t initial_message_digest[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + +inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z){ + return (x&y)^((~x)&z); +} + +inline uint32_t maj(uint32_t x, uint32_t y, uint32_t z){ + return (x&y)^(x&z)^(y&z); +} + +inline uint32_t rotr(uint32_t x, std::size_t n){ + assert(n < 32); + return mask_32bit((x>>n)|(x<<(32-n))); +} + +inline uint32_t bsig0(uint32_t x){ + return rotr(x, 2)^rotr(x, 13)^rotr(x, 22); +} + +inline uint32_t bsig1(uint32_t x){ + return rotr(x, 6)^rotr(x, 11)^rotr(x, 25); +} + +inline uint32_t shr(uint32_t x, std::size_t n){ + assert(n < 32); + return x >> n; +} + +inline uint32_t ssig0(uint32_t x){ + return rotr(x, 7)^rotr(x, 18)^shr(x, 3); +} + +inline uint32_t ssig1(uint32_t x){ + return rotr(x, 17)^rotr(x, 19)^shr(x, 10); +} + +template<typename RaIter1, typename RaIter2> +void hash256_block(RaIter1 message_digest, RaIter2 first, RaIter2 last){ + (void)last; // FIXME: check this is valid + uint32_t w[64]; + std::fill(w, w+64, 0); + for(std::size_t i = 0; i < 16; ++i){ + w[i] = (static_cast<uint32_t>(mask_8bit(*(first+i*4)))<<24) + |(static_cast<uint32_t>(mask_8bit(*(first+i*4+1)))<<16) + |(static_cast<uint32_t>(mask_8bit(*(first+i*4+2)))<<8) + |(static_cast<uint32_t>(mask_8bit(*(first+i*4+3)))); + } + for(std::size_t i = 16; i < 64; ++i){ + w[i] = mask_32bit(ssig1(w[i-2])+w[i-7]+ssig0(w[i-15])+w[i-16]); + } + + uint32_t a = *message_digest; + uint32_t b = *(message_digest+1); + uint32_t c = *(message_digest+2); + uint32_t d = *(message_digest+3); + uint32_t e = *(message_digest+4); + uint32_t f = *(message_digest+5); + uint32_t g = *(message_digest+6); + uint32_t h = *(message_digest+7); + + for(std::size_t i = 0; i < 64; ++i){ + uint32_t temp1 = h+bsig1(e)+ch(e,f,g)+add_constant[i]+w[i]; + uint32_t temp2 = bsig0(a)+maj(a,b,c); + h = g; + g = f; + f = e; + e = mask_32bit(d+temp1); + d = c; + c = b; + b = a; + a = mask_32bit(temp1+temp2); + } + *message_digest += a; + *(message_digest+1) += b; + *(message_digest+2) += c; + *(message_digest+3) += d; + *(message_digest+4) += e; + *(message_digest+5) += f; + *(message_digest+6) += g; + *(message_digest+7) += h; + for(std::size_t i = 0; i < 8; ++i){ + *(message_digest+i) = mask_32bit(*(message_digest+i)); + } +} + +}//namespace detail + +template<typename InIter> +void output_hex(InIter first, InIter last, std::ostream& os){ + os.setf(std::ios::hex, std::ios::basefield); + while(first != last){ + os.width(2); + os.fill('0'); + os << static_cast<unsigned int>(*first); + ++first; + } + os.setf(std::ios::dec, std::ios::basefield); +} + +template<typename InIter> +void bytes_to_hex_string(InIter first, InIter last, std::string& hex_str){ + std::ostringstream oss; + output_hex(first, last, oss); + hex_str.assign(oss.str()); +} + +template<typename InContainer> +void bytes_to_hex_string(const InContainer& bytes, std::string& hex_str){ + bytes_to_hex_string(bytes.begin(), bytes.end(), hex_str); +} + +template<typename InIter> +std::string bytes_to_hex_string(InIter first, InIter last){ + std::string hex_str; + bytes_to_hex_string(first, last, hex_str); + return hex_str; +} + +template<typename InContainer> +std::string bytes_to_hex_string(const InContainer& bytes){ + std::string hex_str; + bytes_to_hex_string(bytes, hex_str); + return hex_str; +} + +class hash256_one_by_one { +public: + hash256_one_by_one(){ + init(); + } + + void init(){ + buffer_.clear(); + std::fill(data_length_digits_, data_length_digits_+4, 0); + std::copy(detail::initial_message_digest, detail::initial_message_digest+8, h_); + } + + template<typename RaIter> + void process(RaIter first, RaIter last){ + add_to_data_length(std::distance(first, last)); + std::copy(first, last, std::back_inserter(buffer_)); + std::size_t i = 0; + for(;i+64 <= buffer_.size(); i+=64){ + detail::hash256_block(h_, buffer_.begin()+i, buffer_.begin()+i+64); + } + buffer_.erase(buffer_.begin(), buffer_.begin()+i); + } + + void finish(){ + uint8_t temp[64]; + std::fill(temp, temp+64, 0); + std::size_t remains = buffer_.size(); + std::copy(buffer_.begin(), buffer_.end(), temp); + temp[remains] = 0x80; + + if(remains > 55){ + std::fill(temp+remains+1, temp+64, 0); + detail::hash256_block(h_, temp, temp+64); + std::fill(temp, temp+64-4, 0); + } + else { + std::fill(temp+remains+1, temp+64-4, 0); + } + + write_data_bit_length(&(temp[56])); + detail::hash256_block(h_, temp, temp+64); + } + + template<typename OutIter> + void get_hash_bytes(OutIter first, OutIter last)const{ + for(const uint32_t* iter = h_; iter != h_+8; ++iter){ + for(std::size_t i = 0; i < 4 && first != last; ++i){ + *(first++) = detail::mask_8bit(static_cast<uint8_t>((*iter >> (24-8*i)))); + } + } + } + +private: + void add_to_data_length(uint32_t n) { + uint32_t carry = 0; + data_length_digits_[0] += n; + for(std::size_t i = 0; i < 4; ++i) { + data_length_digits_[i] += carry; + if(data_length_digits_[i] >= 65536u) { + data_length_digits_[i] -= 65536u; + carry = 1; + } + else { + break; + } + } + } + void write_data_bit_length(uint8_t* begin) { + uint32_t data_bit_length_digits[4]; + std::copy( + data_length_digits_, data_length_digits_+4, + data_bit_length_digits + ); + + // convert byte length to bit length (multiply 8 or shift 3 times left) + uint32_t carry = 0; + for(std::size_t i = 0; i < 4; ++i) { + uint32_t before_val = data_bit_length_digits[i]; + data_bit_length_digits[i] <<= 3; + data_bit_length_digits[i] |= carry; + data_bit_length_digits[i] &= 65535u; + carry = (before_val >> (16-3)) & 65535u; + } + + // write data_bit_length + for(int i = 3; i >= 0; --i) { + (*begin++) = static_cast<uint8_t>(data_bit_length_digits[i] >> 8); + (*begin++) = static_cast<uint8_t>(data_bit_length_digits[i]); + } + } + std::vector<uint8_t> buffer_; + uint32_t data_length_digits_[4]; //as 64bit integer (16bit x 4 integer) + uint32_t h_[8]; +}; + +inline void get_hash_hex_string(const hash256_one_by_one& hasher, std::string& hex_str){ + uint8_t hash[32]; + hasher.get_hash_bytes(hash, hash+32); + return bytes_to_hex_string(hash, hash+32, hex_str); +} + +inline std::string get_hash_hex_string(const hash256_one_by_one& hasher){ + std::string hex_str; + get_hash_hex_string(hasher, hex_str); + return hex_str; +} + +template<typename RaIter, typename OutIter> +void hash256(RaIter first, RaIter last, OutIter first2, OutIter last2){ + hash256_one_by_one hasher; + //hasher.init(); + hasher.process(first, last); + hasher.finish(); + hasher.get_hash_bytes(first2, last2); +} + +template<typename RaIter, typename OutContainer> +void hash256(RaIter first, RaIter last, OutContainer& dst){ + hash256(first, last, dst.begin(), dst.end()); +} + +template<typename RaContainer, typename OutIter> +void hash256(const RaContainer& src, OutIter first, OutIter last){ + hash256(src.begin(), src.end(), first, last); +} + +template<typename RaContainer, typename OutContainer> +void hash256(const RaContainer& src, OutContainer& dst){ + hash256(src.begin(), src.end(), dst.begin(), dst.end()); +} + + +template<typename RaIter> +void hash256_hex_string(RaIter first, RaIter last, std::string& hex_str){ + uint8_t hashed[32]; + hash256(first, last, hashed, hashed+32); + std::ostringstream oss; + output_hex(hashed, hashed+32, oss); + hex_str.assign(oss.str()); +} + +template<typename RaIter> +std::string hash256_hex_string(RaIter first, RaIter last){ + std::string hex_str; + hash256_hex_string(first, last, hex_str); + return hex_str; +} + +inline void hash256_hex_string(const std::string& src, std::string& hex_str){ + hash256_hex_string(src.begin(), src.end(), hex_str); +} + +template<typename RaContainer> +void hash256_hex_string(const RaContainer& src, std::string& hex_str){ + hash256_hex_string(src.begin(), src.end(), hex_str); +} + +template<typename RaContainer> +std::string hash256_hex_string(const RaContainer& src){ + return hash256_hex_string(src.begin(), src.end()); +} + +}//namespace picosha2 + +#endif //PICOSHA2_H diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h new file mode 100644 index 00000000..46d06946 --- /dev/null +++ b/libdevcore/vector_ref.h @@ -0,0 +1,120 @@ +#pragma once + +#include <cstring> +#include <cassert> +#include <type_traits> +#include <vector> +#include <string> + +#ifdef __INTEL_COMPILER +#pragma warning(disable:597) //will not be called for implicit or explicit conversions +#endif + +namespace dev +{ + +/** + * A modifiable reference to an existing object or vector in memory. + */ +template <class _T> +class vector_ref +{ +public: + using value_type = _T; + using element_type = _T; + using mutable_value_type = typename std::conditional<std::is_const<_T>::value, typename std::remove_const<_T>::type, _T>::type; + + static_assert(std::is_pod<value_type>::value, "vector_ref can only be used with PODs due to its low-level treatment of data."); + + vector_ref(): m_data(nullptr), m_count(0) {} + /// Creates a new vector_ref to point to @a _count elements starting at @a _data. + vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {} + /// Creates a new vector_ref pointing to the data part of a string (given as pointer). + vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const*, std::string*>::type _data): m_data(reinterpret_cast<_T*>(_data->data())), m_count(_data->size() / sizeof(_T)) {} + /// Creates a new vector_ref pointing to the data part of a vector (given as pointer). + vector_ref(typename std::conditional<std::is_const<_T>::value, std::vector<typename std::remove_const<_T>::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {} + /// Creates a new vector_ref pointing to the data part of a string (given as reference). + vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const&, std::string&>::type _data): m_data(reinterpret_cast<_T*>(_data.data())), m_count(_data.size() / sizeof(_T)) {} +#if DEV_LDB + vector_ref(ldb::Slice const& _s): m_data(reinterpret_cast<_T*>(_s.data())), m_count(_s.size() / sizeof(_T)) {} +#endif + explicit operator bool() const { return m_data && m_count; } + + bool contentsEqual(std::vector<mutable_value_type> const& _c) const { if (!m_data || m_count == 0) return _c.empty(); else return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count * sizeof(_T)); } + std::vector<mutable_value_type> toVector() const { return std::vector<mutable_value_type>(m_data, m_data + m_count); } + std::vector<unsigned char> toBytes() const { return std::vector<unsigned char>(reinterpret_cast<unsigned char const*>(m_data), reinterpret_cast<unsigned char const*>(m_data) + m_count * sizeof(_T)); } + std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(_T)); } + + template <class _T2> explicit operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>(reinterpret_cast<_T2*>(m_data), m_count * sizeof(_T) / sizeof(_T2)); } + operator vector_ref<_T const>() const { return vector_ref<_T const>(m_data, m_count); } + + _T* data() const { return m_data; } + /// @returns the number of elements referenced (not necessarily number of bytes). + size_t count() const { return m_count; } + /// @returns the number of elements referenced (not necessarily number of bytes). + size_t size() const { return m_count; } + bool empty() const { return !m_count; } + /// @returns a new vector_ref pointing at the next chunk of @a size() elements. + vector_ref<_T> next() const { if (!m_data) return *this; else return vector_ref<_T>(m_data + m_count, m_count); } + /// @returns a new vector_ref which is a shifted and shortened view of the original data. + /// If this goes out of bounds in any way, returns an empty vector_ref. + /// If @a _count is ~size_t(0), extends the view to the end of the data. + vector_ref<_T> cropped(size_t _begin, size_t _count) const { if (m_data && _begin <= m_count && _count <= m_count && _begin + _count <= m_count) return vector_ref<_T>(m_data + _begin, _count == ~size_t(0) ? m_count - _begin : _count); else return vector_ref<_T>(); } + /// @returns a new vector_ref which is a shifted view of the original data (not going beyond it). + vector_ref<_T> cropped(size_t _begin) const { if (m_data && _begin <= m_count) return vector_ref<_T>(m_data + _begin, m_count - _begin); else return vector_ref<_T>(); } + void retarget(_T* _d, size_t _s) { m_data = _d; m_count = _s; } + void retarget(std::vector<_T> const& _t) { m_data = _t.data(); m_count = _t.size(); } + template <class T> bool overlapsWith(vector_ref<T> _t) const { void const* f1 = data(); void const* t1 = data() + size(); void const* f2 = _t.data(); void const* t2 = _t.data() + _t.size(); return f1 < t2 && t1 > f2; } + /// Copies the contents of this vector_ref to the contents of @a _t, up to the max size of @a _t. + void copyTo(vector_ref<typename std::remove_const<_T>::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } + /// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t. + void populate(vector_ref<typename std::remove_const<_T>::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } + /// Securely overwrite the memory. + /// @note adapted from OpenSSL's implementation. + void cleanse() + { + static unsigned char s_cleanseCounter = 0; + uint8_t* p = (uint8_t*)begin(); + size_t const len = (uint8_t*)end() - p; + size_t loop = len; + size_t count = s_cleanseCounter; + while (loop--) + { + *(p++) = (uint8_t)count; + count += (17 + ((size_t)p & 0xf)); + } + p = (uint8_t*)memchr((uint8_t*)begin(), (uint8_t)count, len); + if (p) + count += (63 + (size_t)p); + s_cleanseCounter = (uint8_t)count; + memset((uint8_t*)begin(), 0, len); + } + + _T* begin() { return m_data; } + _T* end() { return m_data + m_count; } + _T const* begin() const { return m_data; } + _T const* end() const { return m_data + m_count; } + + _T& operator[](size_t _i) { assert(m_data); assert(_i < m_count); return m_data[_i]; } + _T const& operator[](size_t _i) const { assert(m_data); assert(_i < m_count); return m_data[_i]; } + + bool operator==(vector_ref<_T> const& _cmp) const { return m_data == _cmp.m_data && m_count == _cmp.m_count; } + bool operator!=(vector_ref<_T> const& _cmp) const { return !operator==(_cmp); } + +#if DEV_LDB + operator ldb::Slice() const { return ldb::Slice((char const*)m_data, m_count * sizeof(_T)); } +#endif + + void reset() { m_data = nullptr; m_count = 0; } + +private: + _T* m_data; + size_t m_count; +}; + +template<class _T> vector_ref<_T const> ref(_T const& _t) { return vector_ref<_T const>(&_t, 1); } +template<class _T> vector_ref<_T> ref(_T& _t) { return vector_ref<_T>(&_t, 1); } +template<class _T> vector_ref<_T const> ref(std::vector<_T> const& _t) { return vector_ref<_T const>(&_t); } +template<class _T> vector_ref<_T> ref(std::vector<_T>& _t) { return vector_ref<_T>(&_t); } + +} |