diff --git a/configure.ac b/configure.ac index 45e5b4fe4ea3315e49033cdbc5b4fd0520f94400..16f2bf429572cb9faaba7cfa01cc5a3371f8d2ff 100644 --- a/configure.ac +++ b/configure.ac @@ -632,6 +632,8 @@ AC_CONFIG_FILES([Makefile \ src/sip/Makefile \ src/im/Makefile \ src/ringdht/Makefile \ + src/ringdht/eth/libdevcore/Makefile \ + src/ringdht/eth/libdevcrypto/Makefile \ src/media/Makefile \ src/media/audio/Makefile \ src/media/audio/pulseaudio/Makefile \ diff --git a/src/ringdht/Makefile.am b/src/ringdht/Makefile.am index 1b9219f452758236b474502e1e3a2f855d9e8079..4654df9a7379c1c95ef190c6c99d9d97d2e9f0ed 100644 --- a/src/ringdht/Makefile.am +++ b/src/ringdht/Makefile.am @@ -1,9 +1,21 @@ include $(top_srcdir)/globals.mak +SUBDIRS = eth/libdevcore eth/libdevcrypto + +AM_CPPFLAGS += -I$(top_srcdir)/src/ringdht/eth $(BOOST_CPPFLAGS) noinst_LTLIBRARIES = libringacc.la -libringacc_la_CXXFLAGS = @CXXFLAGS@ -libringacc_la_LIBADD = $(DHT_LIBS) +AM_LDFLAGS = $(BOOST_LDFLAGS) + +libringacc_la_CXXFLAGS = @CXXFLAGS@ @JSONCPP_CFLAGS@ + +libringacc_la_LIBADD = $(DHT_LIBS) \ + $(BOOST_SYSTEM_LIB) \ + $(BOOST_FILESYSTEM_LIB) \ + $(BOOST_RANDOM_LIB) \ + $(BOOST_THREAD_LIB) \ + ./eth/libdevcore/libdevcore.la \ + ./eth/libdevcrypto/libdevcrypto.la libringacc_la_SOURCES = \ ringaccount.cpp \ diff --git a/src/ringdht/eth/libdevcore/Common.cpp b/src/ringdht/eth/libdevcore/Common.cpp new file mode 100644 index 0000000000000000000000000000000000000000..22c60e44c10081c256700b97745167c0208d9cdd --- /dev/null +++ b/src/ringdht/eth/libdevcore/Common.cpp @@ -0,0 +1,93 @@ +/* + 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" +#include "Exceptions.h" +using namespace std; +using namespace dev; + +namespace dev +{ + +char const* Version = "1.2.4"; + +const u256 Invalid256 = ~(u256)0; + +void InvariantChecker::checkInvariants(HasInvariants const* _this, char const* _fn, char const* _file, int _line, bool _pre) +{ + if (!_this->invariants()) + { + ::boost::exception_detail::throw_exception_(FailedInvariant(), _fn, _file, _line); + } +} + +TimerHelper::~TimerHelper() +{ +} + +uint64_t utcTime() +{ + // TODO: Fix if possible to not use time(0) and merge only after testing in all platforms + // time_t t = time(0); + // return mktime(gmtime(&t)); + return time(0); +} + +string inUnits(bigint const& _b, strings const& _units) +{ + ostringstream ret; + u256 b; + if (_b < 0) + { + ret << "-"; + b = (u256)-_b; + } + else + b = (u256)_b; + + u256 biggest = 1; + for (unsigned i = _units.size() - 1; !!i; --i) + biggest *= 1000; + + if (b > biggest * 1000) + { + ret << (b / biggest) << " " << _units.back(); + return ret.str(); + } + ret << setprecision(3); + + u256 unit = biggest; + for (auto it = _units.rbegin(); it != _units.rend(); ++it) + { + auto i = *it; + if (i != _units.front() && b >= unit) + { + ret << (double(b / (unit / 1000)) / 1000.0) << " " << i; + return ret.str(); + } + else + unit /= 1000; + } + ret << b << " " << _units.front(); + return ret.str(); +} + +} diff --git a/src/ringdht/eth/libdevcore/Common.h b/src/ringdht/eth/libdevcore/Common.h new file mode 100644 index 0000000000000000000000000000000000000000..cf8cf4535d38c477f4af082c74abd401df76e12c --- /dev/null +++ b/src/ringdht/eth/libdevcore/Common.h @@ -0,0 +1,334 @@ +/* + 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> +#pragma warning(push) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include <boost/version.hpp> +#if (BOOST_VERSION == 105800) + #include "boost_multiprecision_number_compare_bug_workaround.hpp" +#endif +#include <boost/multiprecision/cpp_int.hpp> +#pragma warning(pop) +#pragma GCC diagnostic pop +#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 (...) {} + +#define DEV_IF_NO_ELSE(X) if(!(X)){}else +#define DEV_IF_THROWS(X) try{X;}catch(...) + +namespace dev +{ + +extern char const* Version; + +static const std::string EmptyString; + +// 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>; +using BytesMap = std::map<bytes, bytes>; +using u256Map = std::map<u256, u256>; +using HexMap = std::map<bytes, bytes>; + +// Hash types. +using StringHashMap = std::unordered_map<std::string, std::string>; +using u256HashMap = std::unordered_map<u256, u256>; + +// String types. +using strings = std::vector<std::string>; + +// Fixed-length string types. +using string32 = std::array<char, 32>; +static const string32 ZeroString32 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}; + +// Null/Invalid values for convenience. +static const bytes NullBytes; +static const std::map<u256, u256> EmptyMapU256U256; +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); +} + +/// Converts given int to a string and appends one of a series of units according to its size. +std::string inUnits(bigint const& _b, strings const& _units); + +/// @returns the smallest n >= 0 such that (1 << n) >= _x +inline unsigned int toLog2(u256 _x) +{ + unsigned ret; + for (ret = 0; _x >>= 1; ++ret) {} + return ret; +} + +template <size_t n> inline u256 exp10() +{ + return exp10<n - 1>() * u256(10); +} + +template <> inline u256 exp10<0>() +{ + return u256(1); +} + +/// @returns the absolute distance between _a and _b. +template <class N> +inline N diff(N const& _a, N const& _b) +{ + return std::max(_a, _b) - std::min(_a, _b); +} + +/// 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; +}; + +/// Inheritable for classes that have invariants. +class HasInvariants +{ +public: + /// Reimplement to specify the invariants. + virtual bool invariants() const = 0; +}; + +/// RAII checker for invariant assertions. +class InvariantChecker +{ +public: + InvariantChecker(HasInvariants* _this, char const* _fn, char const* _file, int _line): m_this(_this), m_function(_fn), m_file(_file), m_line(_line) { checkInvariants(_this, _fn , _file, _line, true); } + ~InvariantChecker() { checkInvariants(m_this, m_function, m_file, m_line, false); } + /// Check invariants are met, throw if not. + static void checkInvariants(HasInvariants const* _this, char const* _fn, char const* _file, int line, bool _pre); + +private: + HasInvariants const* m_this; + char const* m_function; + char const* m_file; + int m_line; +}; + +/// Scope guard for invariant check in a class derived from HasInvariants. +#if ETH_DEBUG +#define DEV_INVARIANT_CHECK ::dev::InvariantChecker __dev_invariantCheck(this, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__) +#define DEV_INVARIANT_CHECK_HERE ::dev::InvariantChecker::checkInvariants(this, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__, true) +#else +#define DEV_INVARIANT_CHECK (void)0; +#define DEV_INVARIANT_CHECK_HERE (void)0; +#endif + +/// Simple scope-based timer helper. +class TimerHelper +{ +public: + TimerHelper(std::string const& _id, unsigned _msReportWhenGreater = 0): m_t(std::chrono::high_resolution_clock::now()), m_id(_id), m_ms(_msReportWhenGreater) {} + ~TimerHelper(); + +private: + std::chrono::high_resolution_clock::time_point m_t; + std::string m_id; + unsigned m_ms; +}; + +class Timer +{ +public: + Timer() { restart(); } + + std::chrono::high_resolution_clock::duration duration() const { return std::chrono::high_resolution_clock::now() - m_t; } + double elapsed() const { return std::chrono::duration_cast<std::chrono::microseconds>(duration()).count() / 1000000.0; } + void restart() { m_t = std::chrono::high_resolution_clock::now(); } + +private: + std::chrono::high_resolution_clock::time_point m_t; +}; + +#define DEV_TIMED(S) for (::std::pair<::dev::TimerHelper, bool> __eth_t(S, true); __eth_t.second; __eth_t.second = false) +#define DEV_TIMED_SCOPE(S) ::dev::TimerHelper __eth_t(S) +#if defined(_WIN32) +#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__FUNCSIG__) +#else +#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__PRETTY_FUNCTION__) +#endif + +#define DEV_TIMED_ABOVE(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(S, MS), true); __eth_t.second; __eth_t.second = false) +#define DEV_TIMED_SCOPE_ABOVE(S, MS) ::dev::TimerHelper __eth_t(S, MS) +#if defined(_WIN32) +#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__FUNCSIG__, MS) +#else +#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__PRETTY_FUNCTION__, MS) +#endif + +#ifdef _MSC_VER +// TODO. +#define DEV_UNUSED +#else +#define DEV_UNUSED __attribute__((unused)) +#endif + +enum class WithExisting: int +{ + Trust = 0, + Verify, + Rescue, + Kill +}; + +/// Get the current time in seconds since the epoch in UTC +uint64_t utcTime(); + +} + +namespace std +{ + +inline dev::WithExisting max(dev::WithExisting _a, dev::WithExisting _b) +{ + return static_cast<dev::WithExisting>(max(static_cast<int>(_a), static_cast<int>(_b))); +} + +template <> struct hash<dev::u256> +{ + size_t operator()(dev::u256 const& _a) const + { + unsigned size = _a.backend().size(); + auto limbs = _a.backend().limbs(); + return boost::hash_range(limbs, limbs + size); + } +}; + +} diff --git a/src/ringdht/eth/libdevcore/CommonData.cpp b/src/ringdht/eth/libdevcore/CommonData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..372f299ae56752c041a7c950e65c45626ea68b59 --- /dev/null +++ b/src/ringdht/eth/libdevcore/CommonData.cpp @@ -0,0 +1,147 @@ +/* + 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; + +bool dev::isHex(string const& _s) +{ + unsigned i = (_s.size() >= 2 && _s.substr(0, 2) == "0x") ? 2 : 0; + for (; i < _s.size(); ++i) + if (fromHex(_s[i], WhenError::DontThrow) == -1) + return false; + return true; +} + +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; +} + +std::string dev::randomWord() +{ + static std::mt19937_64 s_eng(0); + std::string ret(boost::random::uniform_int_distribution<int>(1, 5)(s_eng), ' '); + char const n[] = "qwertyuiop";//asdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890"; + boost::random::uniform_int_distribution<int> d(0, sizeof(n) - 2); + for (char& c: ret) + c = n[d(s_eng)]; + 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; +} + +bytes dev::asNibbles(bytesConstRef const& _s) +{ + std::vector<uint8_t> ret; + ret.reserve(_s.size() * 2); + for (auto i: _s) + { + ret.push_back(i / 16); + ret.push_back(i % 16); + } + return ret; +} + +std::string dev::toString(string32 const& _s) +{ + std::string ret; + for (unsigned i = 0; i < 32 && _s[i]; ++i) + ret.push_back(_s[i]); + return ret; +} diff --git a/src/ringdht/eth/libdevcore/CommonData.h b/src/ringdht/eth/libdevcore/CommonData.h new file mode 100644 index 0000000000000000000000000000000000000000..fbd6c06a8c48428ddfe1479b49280f386328dada --- /dev/null +++ b/src/ringdht/eth/libdevcore/CommonData.h @@ -0,0 +1,388 @@ +/* + 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); + +/// @returns true if @a _s is a hex string. +bool isHex(std::string const& _s); + +/// @returns true if @a _hash is a hash conforming to FixedHash type @a T. +template <class T> static bool isHash(std::string const& _hash) +{ + return (_hash.size() == T::size * 2 || (_hash.size() == T::size * 2 + 2 && _hash.substr(0, 2) == "0x")) && isHex(_hash); +} + +/// 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())); +} + +/// Converts a string into the big-endian base-16 stream of integers (NOT ASCII). +/// @example asNibbles("A")[0] == 4 && asNibbles("A")[1] == 1 +bytes asNibbles(bytesConstRef const& _s); + + +// 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; +} + +/// Convenience functions for toBigEndian +inline std::string toBigEndianString(u256 _val) { std::string ret(32, '\0'); toBigEndian(_val, ret); return ret; } +inline std::string toBigEndianString(u160 _val) { std::string ret(20, '\0'); toBigEndian(_val, ret); 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 toBigEndian. +/// @returns a string just big enough to represent @a _val. +template <class T> +inline std::string toCompactBigEndianString(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) {} + std::string ret(std::max<unsigned>(_min, i), '\0'); + toBigEndian(_val, ret); + return ret; +} + +/// 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; +} + +inline std::string toCompactHex(u256 val, HexPrefix prefix = HexPrefix::DontAdd, unsigned _min = 0) +{ + std::string str = toHex(toCompactBigEndian(val, _min)); + 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); + +/// Determines the length of the common prefix of the two collections given. +/// @returns the number of elements both @a _t and @a _u share, in order, at the beginning. +/// @example commonPrefix("Hello world!", "Hello, world!") == 5 +template <class T, class U> +unsigned commonPrefix(T const& _t, U const& _u) +{ + unsigned s = std::min<unsigned>(_t.size(), _u.size()); + for (unsigned i = 0;; ++i) + if (i == s || _t[i] != _u[i]) + return i; + return s; +} + +/// Creates a random, printable, word. +std::string randomWord(); + +/// 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; +} + +/// Trims a given number of elements from the front of a collection. +/// Only works for POD element types. +template <class T> +void trimFront(T& _t, unsigned _elements) +{ + static_assert(std::is_pod<typename T::value_type>::value, ""); + memmove(_t.data(), _t.data() + _elements, (_t.size() - _elements) * sizeof(_t[0])); + _t.resize(_t.size() - _elements); +} + +/// Pushes an element on to the front of a collection. +/// Only works for POD element types. +template <class T, class U> +void pushFront(T& _t, U _e) +{ + static_assert(std::is_pod<typename T::value_type>::value, ""); + _t.push_back(_e); + memmove(_t.data() + 1, _t.data(), (_t.size() - 1) * sizeof(_e)); + _t[0] = _e; +} + +/// Concatenate two vectors of elements of POD types. +template <class T> +inline std::vector<T>& operator+=(std::vector<typename std::enable_if<std::is_pod<T>::value, T>::type>& _a, std::vector<T> const& _b) +{ + auto s = _a.size(); + _a.resize(_a.size() + _b.size()); + memcpy(_a.data() + s, _b.data(), _b.size() * sizeof(T)); + return _a; + +} + +/// Concatenate two vectors of elements. +template <class T> +inline std::vector<T>& operator+=(std::vector<typename std::enable_if<!std::is_pod<T>::value, T>::type>& _a, std::vector<T> const& _b) +{ + _a.reserve(_a.size() + _b.size()); + for (auto& i: _b) + _a.push_back(i); + return _a; +} + +/// Insert the contents of a container into a set +template <class T, class U> std::set<T>& operator+=(std::set<T>& _a, U const& _b) +{ + for (auto const& i: _b) + _a.insert(i); + return _a; +} + +/// Insert the contents of a container into an unordered_set +template <class T, class U> std::unordered_set<T>& operator+=(std::unordered_set<T>& _a, U const& _b) +{ + for (auto const& i: _b) + _a.insert(i); + return _a; +} + +/// 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; +} + +/// Insert the contents of a container into a set +template <class T, class U> std::set<T> operator+(std::set<T> _a, U const& _b) +{ + return _a += _b; +} + +/// Insert the contents of a container into an unordered_set +template <class T, class U> std::unordered_set<T> operator+(std::unordered_set<T> _a, U const& _b) +{ + return _a += _b; +} + +/// 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) +{ + return _a += _b; +} + +/// 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; +} + +/// Merge two sets of elements. +template <class T> +inline std::set<T>& operator+=(std::set<T>& _a, std::set<T> const& _b) +{ + for (auto& i: _b) + _a.insert(i); + return _a; +} + +/// Merge two sets of elements. +template <class T> +inline std::set<T> operator+(std::set<T> const& _a, std::set<T> const& _b) +{ + std::set<T> ret(_a); + return ret += _b; +} + +template <class A, class B> +std::unordered_map<A, B>& operator+=(std::unordered_map<A, B>& _x, std::unordered_map<A, B> const& _y) +{ + for (auto const& i: _y) + _x.insert(i); + return _x; +} + +template <class A, class B> +std::unordered_map<A, B> operator+(std::unordered_map<A, B> const& _x, std::unordered_map<A, B> const& _y) +{ + std::unordered_map<A, B> ret(_x); + return ret += _y; +} + +/// Make normal string from fixed-length string. +std::string toString(string32 const& _s); + +template<class T, class U> +std::vector<T> keysOf(std::map<T, U> const& _m) +{ + std::vector<T> ret; + for (auto const& i: _m) + ret.push_back(i.first); + return ret; +} + +template<class T, class U> +std::vector<T> keysOf(std::unordered_map<T, U> const& _m) +{ + std::vector<T> ret; + for (auto const& i: _m) + ret.push_back(i.first); + return ret; +} + +template<class T, class U> +std::vector<U> valuesOf(std::map<T, U> const& _m) +{ + std::vector<U> ret; + ret.reserve(_m.size()); + for (auto const& i: _m) + ret.push_back(i.second); + return ret; +} + +template<class T, class U> +std::vector<U> valuesOf(std::unordered_map<T, U> const& _m) +{ + std::vector<U> ret; + ret.reserve(_m.size()); + for (auto const& i: _m) + ret.push_back(i.second); + return ret; +} + +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/src/ringdht/eth/libdevcore/Exceptions.h b/src/ringdht/eth/libdevcore/Exceptions.h new file mode 100644 index 0000000000000000000000000000000000000000..a6c1f9aba04a8ee142d3747aa5b36d3ebeaba5eb --- /dev/null +++ b/src/ringdht/eth/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/src/ringdht/eth/libdevcore/FixedHash.cpp b/src/ringdht/eth/libdevcore/FixedHash.cpp new file mode 100644 index 0000000000000000000000000000000000000000..420e2bb165c1103f071c482fff13e363053fbe66 --- /dev/null +++ b/src/ringdht/eth/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/src/ringdht/eth/libdevcore/FixedHash.h b/src/ringdht/eth/libdevcore/FixedHash.h new file mode 100644 index 0000000000000000000000000000000000000000..6c1429d3d6be4e11efb780cdd932600c46ff00c0 --- /dev/null +++ b/src/ringdht/eth/libdevcore/FixedHash.h @@ -0,0 +1,392 @@ +/* + 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. +}; + +template <unsigned T> +class SecureFixedHash: private FixedHash<T> +{ +public: + using ConstructFromHashType = typename FixedHash<T>::ConstructFromHashType; + using ConstructFromStringType = typename FixedHash<T>::ConstructFromStringType; + using ConstructFromPointerType = typename FixedHash<T>::ConstructFromPointerType; + SecureFixedHash() = default; + explicit SecureFixedHash(bytes const& _b, ConstructFromHashType _t = FixedHash<T>::FailIfDifferent): FixedHash<T>(_b, _t) {} + explicit SecureFixedHash(bytesConstRef _b, ConstructFromHashType _t = FixedHash<T>::FailIfDifferent): FixedHash<T>(_b, _t) {} + explicit SecureFixedHash(bytesSec const& _b, ConstructFromHashType _t = FixedHash<T>::FailIfDifferent): FixedHash<T>(_b.ref(), _t) {} + template <unsigned M> explicit SecureFixedHash(FixedHash<M> const& _h, ConstructFromHashType _t = FixedHash<T>::AlignLeft): FixedHash<T>(_h, _t) {} + template <unsigned M> explicit SecureFixedHash(SecureFixedHash<M> const& _h, ConstructFromHashType _t = FixedHash<T>::AlignLeft): FixedHash<T>(_h.makeInsecure(), _t) {} + explicit SecureFixedHash(std::string const& _s, ConstructFromStringType _t = FixedHash<T>::FromHex, ConstructFromHashType _ht = FixedHash<T>::FailIfDifferent): FixedHash<T>(_s, _t, _ht) {} + explicit SecureFixedHash(bytes const* _d, ConstructFromPointerType _t): FixedHash<T>(_d, _t) {} + ~SecureFixedHash() { ref().cleanse(); } + + SecureFixedHash<T>& operator=(SecureFixedHash<T> const& _c) + { + if (&_c == this) + return *this; + ref().cleanse(); + FixedHash<T>::operator=(static_cast<FixedHash<T> const&>(_c)); + return *this; + } + + using FixedHash<T>::size; + + bytesSec asBytesSec() const { return bytesSec(ref()); } + + FixedHash<T> const& makeInsecure() const { return static_cast<FixedHash<T> const&>(*this); } + FixedHash<T>& writable() { clear(); return static_cast<FixedHash<T>&>(*this); } + + using FixedHash<T>::operator bool; + + // The obvious comparison operators. + bool operator==(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator==(static_cast<FixedHash<T> const&>(_c)); } + bool operator!=(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator!=(static_cast<FixedHash<T> const&>(_c)); } + bool operator<(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator<(static_cast<FixedHash<T> const&>(_c)); } + bool operator>=(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator>=(static_cast<FixedHash<T> const&>(_c)); } + bool operator<=(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator<=(static_cast<FixedHash<T> const&>(_c)); } + bool operator>(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator>(static_cast<FixedHash<T> const&>(_c)); } + + using FixedHash<T>::operator==; + using FixedHash<T>::operator!=; + using FixedHash<T>::operator<; + using FixedHash<T>::operator>=; + using FixedHash<T>::operator<=; + using FixedHash<T>::operator>; + + // The obvious binary operators. + SecureFixedHash& operator^=(FixedHash<T> const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(_c); return *this; } + SecureFixedHash operator^(FixedHash<T> const& _c) const { return SecureFixedHash(*this) ^= _c; } + SecureFixedHash& operator|=(FixedHash<T> const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(_c); return *this; } + SecureFixedHash operator|(FixedHash<T> const& _c) const { return SecureFixedHash(*this) |= _c; } + SecureFixedHash& operator&=(FixedHash<T> const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(_c); return *this; } + SecureFixedHash operator&(FixedHash<T> const& _c) const { return SecureFixedHash(*this) &= _c; } + + SecureFixedHash& operator^=(SecureFixedHash const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(static_cast<FixedHash<T> const&>(_c)); return *this; } + SecureFixedHash operator^(SecureFixedHash const& _c) const { return SecureFixedHash(*this) ^= _c; } + SecureFixedHash& operator|=(SecureFixedHash const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(static_cast<FixedHash<T> const&>(_c)); return *this; } + SecureFixedHash operator|(SecureFixedHash const& _c) const { return SecureFixedHash(*this) |= _c; } + SecureFixedHash& operator&=(SecureFixedHash const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(static_cast<FixedHash<T> const&>(_c)); return *this; } + SecureFixedHash operator&(SecureFixedHash const& _c) const { return SecureFixedHash(*this) &= _c; } + SecureFixedHash operator~() const { auto r = ~static_cast<FixedHash<T> const&>(*this); return static_cast<SecureFixedHash const&>(r); } + + using FixedHash<T>::abridged; + using FixedHash<T>::abridgedMiddle; + + bytesConstRef ref() const { return FixedHash<T>::ref(); } + byte const* data() const { return FixedHash<T>::data(); } + + static SecureFixedHash<T> random() { SecureFixedHash<T> ret; ret.randomize(s_fixedHashEngine); return ret; } + using FixedHash<T>::firstBitSet; + + void clear() { ref().cleanse(); } +}; + +/// 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; +} + +/// Stream I/O for the SecureFixedHash class. +template <unsigned N> +inline std::ostream& operator<<(std::ostream& _out, SecureFixedHash<N> const& _h) +{ + _out << "SecureFixedHash#" << std::hex << typename FixedHash<N>::hash()(_h.makeInsecure()) << 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/src/ringdht/eth/libdevcore/Guards.cpp b/src/ringdht/eth/libdevcore/Guards.cpp new file mode 100644 index 0000000000000000000000000000000000000000..69ae6c03a49f14e5315e9f223bf0ea1fad88c216 --- /dev/null +++ b/src/ringdht/eth/libdevcore/Guards.cpp @@ -0,0 +1,29 @@ +/* + 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 Guards.cpp + * @author Gav Wood <i@gavwood.com> + * @date 2014 + */ + +#include "Guards.h" +using namespace std; +using namespace dev; + +namespace dev +{ + +} diff --git a/src/ringdht/eth/libdevcore/Guards.h b/src/ringdht/eth/libdevcore/Guards.h new file mode 100644 index 0000000000000000000000000000000000000000..e7d8c35089530d65e785413f4e95206a5484a566 --- /dev/null +++ b/src/ringdht/eth/libdevcore/Guards.h @@ -0,0 +1,159 @@ +/* + 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 Guards.h + * @author Gav Wood <i@gavwood.com> + * @date 2014 + */ + +#pragma once + +#include <mutex> +#include <condition_variable> +#include <atomic> +#pragma warning(push) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include <boost/thread.hpp> +#pragma warning(pop) +#pragma GCC diagnostic pop + +namespace dev +{ + +using Mutex = std::mutex; +using RecursiveMutex = std::recursive_mutex; +using SharedMutex = boost::shared_mutex; + +using Guard = std::lock_guard<std::mutex>; +using UniqueGuard = std::unique_lock<std::mutex>; +using RecursiveGuard = std::lock_guard<std::recursive_mutex>; +using ReadGuard = boost::shared_lock<boost::shared_mutex>; +using UpgradableGuard = boost::upgrade_lock<boost::shared_mutex>; +using UpgradeGuard = boost::upgrade_to_unique_lock<boost::shared_mutex>; +using WriteGuard = boost::unique_lock<boost::shared_mutex>; + +template <class GuardType, class MutexType> +struct GenericGuardBool: GuardType +{ + GenericGuardBool(MutexType& _m): GuardType(_m) {} + bool b = true; +}; +template <class MutexType> +struct GenericUnguardBool +{ + GenericUnguardBool(MutexType& _m): m(_m) { m.unlock(); } + ~GenericUnguardBool() { m.lock(); } + bool b = true; + MutexType& m; +}; +template <class MutexType> +struct GenericUnguardSharedBool +{ + GenericUnguardSharedBool(MutexType& _m): m(_m) { m.unlock_shared(); } + ~GenericUnguardSharedBool() { m.lock_shared(); } + bool b = true; + MutexType& m; +}; + +/** @brief Simple lock that waits for release without making context switch */ +class SpinLock +{ +public: + SpinLock() { m_lock.clear(); } + void lock() { while (m_lock.test_and_set(std::memory_order_acquire)) {} } + void unlock() { m_lock.clear(std::memory_order_release); } +private: + std::atomic_flag m_lock; +}; +using SpinGuard = std::lock_guard<SpinLock>; + +template <class N> +class Notified +{ +public: + Notified() {} + Notified(N const& _v): m_value(_v) {} + Notified(Notified const&) = delete; + Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } + + operator N() const { UniqueGuard l(m_mutex); return m_value; } + + void wait() const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(old); } + void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } + void waitNot(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value != _v;}); } + template <class F> void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } + + template <class R, class P> void wait(std::chrono::duration<R, P> _d) const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(_d, old); } + template <class R, class P> void wait(std::chrono::duration<R, P> _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value == _v;}); } + template <class R, class P> void waitNot(std::chrono::duration<R, P> _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value != _v;}); } + template <class R, class P, class F> void wait(std::chrono::duration<R, P> _d, F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, _f); } + +private: + mutable Mutex m_mutex; + mutable std::condition_variable m_cv; + N m_value; +}; + +/** @brief Simple block guard. + * The expression/block following is guarded though the given mutex. + * Usage: + * @code + * Mutex m; + * unsigned d; + * ... + * ETH_(m) d = 1; + * ... + * ETH_(m) { for (auto d = 10; d > 0; --d) foo(d); d = 0; } + * @endcode + * + * There are several variants of this basic mechanism for different Mutex types and Guards. + * + * There is also the UNGUARD variant which allows an unguarded expression/block to exist within a + * guarded expression. eg: + * + * @code + * Mutex m; + * int d; + * ... + * ETH_GUARDED(m) + * { + * for (auto d = 50; d > 25; --d) + * foo(d); + * ETH_UNGUARDED(m) + * bar(); + * for (; d > 0; --d) + * foo(d); + * } + * @endcode + */ + +#define DEV_GUARDED(MUTEX) \ + for (GenericGuardBool<Guard, Mutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define DEV_READ_GUARDED(MUTEX) \ + for (GenericGuardBool<ReadGuard, SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define DEV_WRITE_GUARDED(MUTEX) \ + for (GenericGuardBool<WriteGuard, SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define DEV_RECURSIVE_GUARDED(MUTEX) \ + for (GenericGuardBool<RecursiveGuard, RecursiveMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define DEV_UNGUARDED(MUTEX) \ + for (GenericUnguardBool<Mutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define DEV_READ_UNGUARDED(MUTEX) \ + for (GenericUnguardSharedBool<SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define DEV_WRITE_UNGUARDED(MUTEX) \ + for (GenericUnguardBool<SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) + +} diff --git a/src/ringdht/eth/libdevcore/Hash.cpp b/src/ringdht/eth/libdevcore/Hash.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c6b917b9033502d97f07b61479749c64f9c1634e --- /dev/null +++ b/src/ringdht/eth/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/src/ringdht/eth/libdevcore/Hash.h b/src/ringdht/eth/libdevcore/Hash.h new file mode 100644 index 0000000000000000000000000000000000000000..d4401014f91daf1b596824f2572eb120de5b684b --- /dev/null +++ b/src/ringdht/eth/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/src/ringdht/eth/libdevcore/Makefile.am b/src/ringdht/eth/libdevcore/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..24aebec25bc27f76f3642fc9d49a91b9bd5a674c --- /dev/null +++ b/src/ringdht/eth/libdevcore/Makefile.am @@ -0,0 +1,21 @@ +include $(top_srcdir)/globals.mak + +noinst_LTLIBRARIES = libdevcore.la +libdevcore_la_CPPFLAGS = @CPPFLAGS@ -DBOOST_SYSTEM_NO_DEPRECATED +libdevcore_la_CXXFLAGS = @CXXFLAGS@ + +libdevcore_la_SOURCES = FixedHash.cpp \ + Hash.cpp \ + Guards.cpp \ + Common.cpp \ + RLP.cpp \ + SHA3.cpp \ + CommonData.cpp + +noinst_HEADERS = FixedHash.h \ + Hash.h \ + Guards.h \ + Common.h \ + RLP.h \ + SHA3.h \ + CommonData.h diff --git a/src/ringdht/eth/libdevcore/RLP.cpp b/src/ringdht/eth/libdevcore/RLP.cpp new file mode 100644 index 0000000000000000000000000000000000000000..45b3a2db0e16bd888250c370cbdaf51bfcfc092e --- /dev/null +++ b/src/ringdht/eth/libdevcore/RLP.cpp @@ -0,0 +1,378 @@ +/* + 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 RLP.cpp + * @author Gav Wood <i@gavwood.com> + * @date 2014 + */ + +#include "RLP.h" +using namespace std; +using namespace dev; + +bytes dev::RLPNull = rlp(""); +bytes dev::RLPEmptyList = rlpList(); + +RLP::RLP(bytesConstRef _d, Strictness _s): + m_data(_d) +{ + if ((_s & FailIfTooBig) && actualSize() < _d.size()) + { + if (_s & ThrowOnFail) + BOOST_THROW_EXCEPTION(OversizeRLP()); + else + m_data.reset(); + } + if ((_s & FailIfTooSmall) && actualSize() > _d.size()) + { + if (_s & ThrowOnFail) + BOOST_THROW_EXCEPTION(UndersizeRLP()); + else + m_data.reset(); + } +} + +RLP::iterator& RLP::iterator::operator++() +{ + if (m_remaining) + { + m_currentItem.retarget(m_currentItem.next().data(), m_remaining); + m_currentItem = m_currentItem.cropped(0, sizeAsEncoded(m_currentItem)); + m_remaining -= std::min<size_t>(m_remaining, m_currentItem.size()); + } + else + m_currentItem.retarget(m_currentItem.next().data(), 0); + return *this; +} + +RLP::iterator::iterator(RLP const& _parent, bool _begin) +{ + if (_begin && _parent.isList()) + { + auto pl = _parent.payload(); + m_currentItem = pl.cropped(0, sizeAsEncoded(pl)); + m_remaining = pl.size() - m_currentItem.size(); + } + else + { + m_currentItem = _parent.data().cropped(_parent.data().size()); + m_remaining = 0; + } +} + +RLP RLP::operator[](size_t _i) const +{ + if (_i < m_lastIndex) + { + m_lastEnd = sizeAsEncoded(payload()); + m_lastItem = payload().cropped(0, m_lastEnd); + m_lastIndex = 0; + } + for (; m_lastIndex < _i && m_lastItem.size(); ++m_lastIndex) + { + m_lastItem = payload().cropped(m_lastEnd); + m_lastItem = m_lastItem.cropped(0, sizeAsEncoded(m_lastItem)); + m_lastEnd += m_lastItem.size(); + } + return RLP(m_lastItem, ThrowOnFail | FailIfTooSmall); +} + +RLPs RLP::toList(int _flags) const +{ + RLPs ret; + if (!isList()) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return ret; + } + for (auto const& i: *this) + ret.push_back(i); + return ret; +} + +size_t RLP::actualSize() const +{ + if (isNull()) + return 0; + if (isSingleByte()) + return 1; + if (isData() || isList()) + return payloadOffset() + length(); + return 0; +} + +void RLP::requireGood() const +{ + if (isNull()) + BOOST_THROW_EXCEPTION(BadRLP()); + byte n = m_data[0]; + if (n != c_rlpDataImmLenStart + 1) + return; + if (m_data.size() < 2) + BOOST_THROW_EXCEPTION(BadRLP()); + if (m_data[1] < c_rlpDataImmLenStart) + BOOST_THROW_EXCEPTION(BadRLP()); +} + +bool RLP::isInt() const +{ + if (isNull()) + return false; + requireGood(); + byte n = m_data[0]; + if (n < c_rlpDataImmLenStart) + return !!n; + else if (n == c_rlpDataImmLenStart) + return true; + else if (n <= c_rlpDataIndLenZero) + { + if (m_data.size() <= 1) + BOOST_THROW_EXCEPTION(BadRLP()); + return m_data[1] != 0; + } + else if (n < c_rlpListStart) + { + if (m_data.size() <= size_t(1 + n - c_rlpDataIndLenZero)) + BOOST_THROW_EXCEPTION(BadRLP()); + return m_data[1 + n - c_rlpDataIndLenZero] != 0; + } + else + return false; + return false; +} + +size_t RLP::length() const +{ + if (isNull()) + return 0; + requireGood(); + size_t ret = 0; + byte const n = m_data[0]; + if (n < c_rlpDataImmLenStart) + return 1; + else if (n <= c_rlpDataIndLenZero) + return n - c_rlpDataImmLenStart; + else if (n < c_rlpListStart) + { + if (m_data.size() <= size_t(n - c_rlpDataIndLenZero)) + BOOST_THROW_EXCEPTION(BadRLP()); + if (m_data.size() > 1) + if (m_data[1] == 0) + BOOST_THROW_EXCEPTION(BadRLP()); + unsigned lengthSize = n - c_rlpDataIndLenZero; + if (lengthSize > sizeof(ret)) + // We did not check, but would most probably not fit in our memory. + BOOST_THROW_EXCEPTION(UndersizeRLP()); + // No leading zeroes. + if (!m_data[1]) + BOOST_THROW_EXCEPTION(BadRLP()); + for (unsigned i = 0; i < lengthSize; ++i) + ret = (ret << 8) | m_data[i + 1]; + // Must be greater than the limit. + if (ret < c_rlpListStart - c_rlpDataImmLenStart - c_rlpMaxLengthBytes) + BOOST_THROW_EXCEPTION(BadRLP()); + } + else if (n <= c_rlpListIndLenZero) + return n - c_rlpListStart; + else + { + unsigned lengthSize = n - c_rlpListIndLenZero; + if (m_data.size() <= lengthSize) + BOOST_THROW_EXCEPTION(BadRLP()); + if (m_data.size() > 1) + if (m_data[1] == 0) + BOOST_THROW_EXCEPTION(BadRLP()); + if (lengthSize > sizeof(ret)) + // We did not check, but would most probably not fit in our memory. + BOOST_THROW_EXCEPTION(UndersizeRLP()); + if (!m_data[1]) + BOOST_THROW_EXCEPTION(BadRLP()); + for (unsigned i = 0; i < lengthSize; ++i) + ret = (ret << 8) | m_data[i + 1]; + if (ret < 0x100 - c_rlpListStart - c_rlpMaxLengthBytes) + BOOST_THROW_EXCEPTION(BadRLP()); + } + // We have to be able to add payloadOffset to length without overflow. + // This rejects roughly 4GB-sized RLPs on some platforms. + if (ret >= std::numeric_limits<size_t>::max() - 0x100) + BOOST_THROW_EXCEPTION(UndersizeRLP()); + return ret; +} + +size_t RLP::items() const +{ + if (isList()) + { + bytesConstRef d = payload(); + size_t i = 0; + for (; d.size(); ++i) + d = d.cropped(sizeAsEncoded(d)); + return i; + } + return 0; +} + +RLPStream& RLPStream::appendRaw(bytesConstRef _s, size_t _itemCount) +{ + m_out.insert(m_out.end(), _s.begin(), _s.end()); + noteAppended(_itemCount); + return *this; +} + +void RLPStream::noteAppended(size_t _itemCount) +{ + if (!_itemCount) + return; +// cdebug << "noteAppended(" << _itemCount << ")"; + while (m_listStack.size()) + { + if (m_listStack.back().first < _itemCount) + BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large") << RequirementError((bigint)m_listStack.back().first, (bigint)_itemCount)); + m_listStack.back().first -= _itemCount; + if (m_listStack.back().first) + break; + else + { + auto p = m_listStack.back().second; + m_listStack.pop_back(); + size_t s = m_out.size() - p; // list size + auto brs = bytesRequired(s); + unsigned encodeSize = s < c_rlpListImmLenCount ? 1 : (1 + brs); +// cdebug << "s: " << s << ", p: " << p << ", m_out.size(): " << m_out.size() << ", encodeSize: " << encodeSize << " (br: " << brs << ")"; + auto os = m_out.size(); + m_out.resize(os + encodeSize); + memmove(m_out.data() + p + encodeSize, m_out.data() + p, os - p); + if (s < c_rlpListImmLenCount) + m_out[p] = (byte)(c_rlpListStart + s); + else if (c_rlpListIndLenZero + brs <= 0xff) + { + m_out[p] = (byte)(c_rlpListIndLenZero + brs); + byte* b = &(m_out[p + brs]); + for (; s; s >>= 8) + *(b--) = (byte)s; + } + else + BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large for RLP")); + } + _itemCount = 1; // for all following iterations, we've effectively appended a single item only since we completed a list. + } +} + +RLPStream& RLPStream::appendList(size_t _items) +{ +// cdebug << "appendList(" << _items << ")"; + if (_items) + m_listStack.push_back(std::make_pair(_items, m_out.size())); + else + appendList(bytes()); + return *this; +} + +RLPStream& RLPStream::appendList(bytesConstRef _rlp) +{ + if (_rlp.size() < c_rlpListImmLenCount) + m_out.push_back((byte)(_rlp.size() + c_rlpListStart)); + else + pushCount(_rlp.size(), c_rlpListIndLenZero); + appendRaw(_rlp, 1); + return *this; +} + +RLPStream& RLPStream::append(bytesConstRef _s, bool _compact) +{ + size_t s = _s.size(); + byte const* d = _s.data(); + if (_compact) + for (size_t i = 0; i < _s.size() && !*d; ++i, --s, ++d) {} + + if (s == 1 && *d < c_rlpDataImmLenStart) + m_out.push_back(*d); + else + { + if (s < c_rlpDataImmLenCount) + m_out.push_back((byte)(s + c_rlpDataImmLenStart)); + else + pushCount(s, c_rlpDataIndLenZero); + appendRaw(bytesConstRef(d, s), 0); + } + noteAppended(); + return *this; +} + +RLPStream& RLPStream::append(bigint _i) +{ + if (!_i) + m_out.push_back(c_rlpDataImmLenStart); + else if (_i < c_rlpDataImmLenStart) + m_out.push_back((byte)_i); + else + { + unsigned br = bytesRequired(_i); + if (br < c_rlpDataImmLenCount) + m_out.push_back((byte)(br + c_rlpDataImmLenStart)); + else + { + auto brbr = bytesRequired(br); + if (c_rlpDataIndLenZero + brbr > 0xff) + BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Number too large for RLP")); + m_out.push_back((byte)(c_rlpDataIndLenZero + brbr)); + pushInt(br, brbr); + } + pushInt(_i, br); + } + noteAppended(); + return *this; +} + +void RLPStream::pushCount(size_t _count, byte _base) +{ + auto br = bytesRequired(_count); + if (int(br) + _base > 0xff) + BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Count too large for RLP")); + m_out.push_back((byte)(br + _base)); // max 8 bytes. + pushInt(_count, br); +} + +static void streamOut(std::ostream& _out, dev::RLP const& _d, unsigned _depth = 0) +{ + if (_depth > 64) + _out << "<max-depth-reached>"; + else if (_d.isNull()) + _out << "null"; + else if (_d.isInt()) + _out << std::showbase << std::hex << std::nouppercase << _d.toInt<bigint>(RLP::LaissezFaire) << dec; + else if (_d.isData()) + _out << escaped(_d.toString(), false); + else if (_d.isList()) + { + _out << "["; + int j = 0; + for (auto i: _d) + { + _out << (j++ ? ", " : " "); + streamOut(_out, i, _depth + 1); + } + _out << " ]"; + } +} + +std::ostream& dev::operator<<(std::ostream& _out, RLP const& _d) +{ + streamOut(_out, _d); + return _out; +} diff --git a/src/ringdht/eth/libdevcore/RLP.h b/src/ringdht/eth/libdevcore/RLP.h new file mode 100644 index 0000000000000000000000000000000000000000..1416c4acd49c05ed482a345462376cfcc39edeb4 --- /dev/null +++ b/src/ringdht/eth/libdevcore/RLP.h @@ -0,0 +1,487 @@ +/* + 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 RLP.h + * @author Gav Wood <i@gavwood.com> + * @date 2014 + * + * RLP (de-)serialisation. + */ + +#pragma once + +#include <vector> +#include <array> +#include <exception> +#include <iostream> +#include <iomanip> +#include "vector_ref.h" +#include "Common.h" +#include "Exceptions.h" +#include "FixedHash.h" + +namespace dev +{ + +class RLP; +using RLPs = std::vector<RLP>; + +template <class _T> struct intTraits { static const unsigned maxSize = sizeof(_T); }; +template <> struct intTraits<u160> { static const unsigned maxSize = 20; }; +template <> struct intTraits<u256> { static const unsigned maxSize = 32; }; +template <> struct intTraits<bigint> { static const unsigned maxSize = ~(unsigned)0; }; + +static const byte c_rlpMaxLengthBytes = 8; +static const byte c_rlpDataImmLenStart = 0x80; +static const byte c_rlpListStart = 0xc0; + +static const byte c_rlpDataImmLenCount = c_rlpListStart - c_rlpDataImmLenStart - c_rlpMaxLengthBytes; +static const byte c_rlpDataIndLenZero = c_rlpDataImmLenStart + c_rlpDataImmLenCount - 1; +static const byte c_rlpListImmLenCount = 256 - c_rlpListStart - c_rlpMaxLengthBytes; +static const byte c_rlpListIndLenZero = c_rlpListStart + c_rlpListImmLenCount - 1; + +template <class T> struct Converter { static T convert(RLP const&, int) { BOOST_THROW_EXCEPTION(BadCast()); } }; + +/** + * @brief Class for interpreting Recursive Linear-Prefix Data. + * @by Gav Wood, 2013 + * + * Class for reading byte arrays of data in RLP format. + */ +class RLP +{ +public: + /// Conversion flags + enum + { + AllowNonCanon = 1, + ThrowOnFail = 4, + FailIfTooBig = 8, + FailIfTooSmall = 16, + Strict = ThrowOnFail | FailIfTooBig, + VeryStrict = ThrowOnFail | FailIfTooBig | FailIfTooSmall, + LaissezFaire = AllowNonCanon + }; + + using Strictness = int; + + /// Construct a null node. + RLP() {} + + /// Construct a node of value given in the bytes. + explicit RLP(bytesConstRef _d, Strictness _s = VeryStrict); + + /// Construct a node of value given in the bytes. + explicit RLP(bytes const& _d, Strictness _s = VeryStrict): RLP(&_d, _s) {} + + /// Construct a node to read RLP data in the bytes given. + RLP(byte const* _b, unsigned _s, Strictness _st = VeryStrict): RLP(bytesConstRef(_b, _s), _st) {} + + /// Construct a node to read RLP data in the string. + explicit RLP(std::string const& _s, Strictness _st = VeryStrict): RLP(bytesConstRef((byte const*)_s.data(), _s.size()), _st) {} + + /// The bare data of the RLP. + bytesConstRef data() const { return m_data; } + + /// @returns true if the RLP is non-null. + explicit operator bool() const { return !isNull(); } + + /// No value. + bool isNull() const { return m_data.size() == 0; } + + /// Contains a zero-length string or zero-length list. + bool isEmpty() const { return !isNull() && (m_data[0] == c_rlpDataImmLenStart || m_data[0] == c_rlpListStart); } + + /// String value. + bool isData() const { return !isNull() && m_data[0] < c_rlpListStart; } + + /// List value. + bool isList() const { return !isNull() && m_data[0] >= c_rlpListStart; } + + /// Integer value. Must not have a leading zero. + bool isInt() const; + + /// @returns the number of items in the list, or zero if it isn't a list. + size_t itemCount() const { return isList() ? items() : 0; } + size_t itemCountStrict() const { if (!isList()) BOOST_THROW_EXCEPTION(BadCast()); return items(); } + + /// @returns the number of bytes in the data, or zero if it isn't data. + size_t size() const { return isData() ? length() : 0; } + size_t sizeStrict() const { if (!isData()) BOOST_THROW_EXCEPTION(BadCast()); return length(); } + + /// Equality operators; does best-effort conversion and checks for equality. + bool operator==(char const* _s) const { return isData() && toString() == _s; } + bool operator!=(char const* _s) const { return isData() && toString() != _s; } + bool operator==(std::string const& _s) const { return isData() && toString() == _s; } + bool operator!=(std::string const& _s) const { return isData() && toString() != _s; } + template <unsigned N> bool operator==(FixedHash<N> const& _h) const { return isData() && toHash<N>() == _h; } + template <unsigned N> bool operator!=(FixedHash<N> const& _s) const { return isData() && toHash<N>() != _s; } + bool operator==(unsigned const& _i) const { return isInt() && toInt<unsigned>() == _i; } + bool operator!=(unsigned const& _i) const { return isInt() && toInt<unsigned>() != _i; } + bool operator==(u256 const& _i) const { return isInt() && toInt<u256>() == _i; } + bool operator!=(u256 const& _i) const { return isInt() && toInt<u256>() != _i; } + bool operator==(bigint const& _i) const { return isInt() && toInt<bigint>() == _i; } + bool operator!=(bigint const& _i) const { return isInt() && toInt<bigint>() != _i; } + + /// Subscript operator. + /// @returns the list item @a _i if isList() and @a _i < listItems(), or RLP() otherwise. + /// @note if used to access items in ascending order, this is efficient. + RLP operator[](size_t _i) const; + + using element_type = RLP; + + /// @brief Iterator class for iterating through items of RLP list. + class iterator + { + friend class RLP; + + public: + using value_type = RLP; + using element_type = RLP; + + iterator& operator++(); + iterator operator++(int) { auto ret = *this; operator++(); return ret; } + RLP operator*() const { return RLP(m_currentItem); } + bool operator==(iterator const& _cmp) const { return m_currentItem == _cmp.m_currentItem; } + bool operator!=(iterator const& _cmp) const { return !operator==(_cmp); } + + private: + iterator() {} + iterator(RLP const& _parent, bool _begin); + + size_t m_remaining = 0; + bytesConstRef m_currentItem; + }; + + /// @brief Iterator into beginning of sub-item list (valid only if we are a list). + iterator begin() const { return iterator(*this, true); } + + /// @brief Iterator into end of sub-item list (valid only if we are a list). + iterator end() const { return iterator(*this, false); } + + template <class T> inline T convert(int _flags) const; + + /// Best-effort conversion operators. + explicit operator std::string() const { return toString(); } + explicit operator bytes() const { return toBytes(); } + explicit operator RLPs() const { return toList(); } + explicit operator uint8_t() const { return toInt<uint8_t>(); } + explicit operator uint16_t() const { return toInt<uint16_t>(); } + explicit operator uint32_t() const { return toInt<uint32_t>(); } + explicit operator uint64_t() const { return toInt<uint64_t>(); } + explicit operator u160() const { return toInt<u160>(); } + explicit operator u256() const { return toInt<u256>(); } + explicit operator bigint() const { return toInt<bigint>(); } + template <unsigned N> explicit operator FixedHash<N>() const { return toHash<FixedHash<N>>(); } + template <class T, class U> explicit operator std::pair<T, U>() const { return toPair<T, U>(); } + template <class T> explicit operator std::vector<T>() const { return toVector<T>(); } + template <class T> explicit operator std::set<T>() const { return toSet<T>(); } + template <class T, size_t N> explicit operator std::array<T, N>() const { return toArray<T, N>(); } + + /// Converts to bytearray. @returns the empty byte array if not a string. + bytes toBytes(int _flags = LaissezFaire) const { if (!isData()) { if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); else return bytes(); } return bytes(payload().data(), payload().data() + length()); } + /// Converts to bytearray. @returns the empty byte array if not a string. + bytesConstRef toBytesConstRef(int _flags = LaissezFaire) const { if (!isData()) { if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); else return bytesConstRef(); } return payload().cropped(0, length()); } + /// Converts to string. @returns the empty string if not a string. + std::string toString(int _flags = LaissezFaire) const { if (!isData()) { if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); else return std::string(); } return payload().cropped(0, length()).toString(); } + /// Converts to string. @throws BadCast if not a string. + std::string toStringStrict() const { return toString(Strict); } + + template <class T> + std::vector<T> toVector(int _flags = LaissezFaire) const + { + std::vector<T> ret; + if (isList()) + { + ret.reserve(itemCount()); + for (auto const& i: *this) + ret.push_back(i.convert<T>(_flags)); + } + else if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + return ret; + } + + template <class T> + std::set<T> toSet(int _flags = LaissezFaire) const + { + std::set<T> ret; + if (isList()) + for (auto const& i: *this) + ret.insert(i.convert<T>(_flags)); + else if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + return ret; + } + + template <class T> + std::unordered_set<T> toUnorderedSet(int _flags = LaissezFaire) const + { + std::unordered_set<T> ret; + if (isList()) + for (auto const& i: *this) + ret.insert(i.convert<T>(_flags)); + else if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + return ret; + } + + template <class T, class U> + std::pair<T, U> toPair(int _flags = Strict) const + { + std::pair<T, U> ret; + if (itemCountStrict() != 2) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return ret; + } + ret.first = (*this)[0].convert<T>(_flags); + ret.second = (*this)[1].convert<U>(_flags); + return ret; + } + + template <class T, size_t N> + std::array<T, N> toArray(int _flags = LaissezFaire) const + { + if (itemCountStrict() != N) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return std::array<T, N>(); + } + std::array<T, N> ret; + for (size_t i = 0; i < N; ++i) + ret[i] = operator[](i).convert<T>(_flags); + return ret; + } + + /// Converts to int of type given; if isString(), decodes as big-endian bytestream. @returns 0 if not an int or string. + template <class T = unsigned> T toInt(int _flags = Strict) const + { + requireGood(); + if ((!isInt() && !(_flags & AllowNonCanon)) || isList() || isNull()) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return 0; + } + + auto p = payload(); + if (p.size() > intTraits<T>::maxSize && (_flags & FailIfTooBig)) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return 0; + } + + return fromBigEndian<T>(p); + } + + template <class N> N toHash(int _flags = Strict) const + { + requireGood(); + auto p = payload(); + auto l = p.size(); + if (!isData() || (l > N::size && (_flags & FailIfTooBig)) || (l < N::size && (_flags & FailIfTooSmall))) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return N(); + } + + N ret; + size_t s = std::min<size_t>(N::size, l); + memcpy(ret.data() + N::size - s, p.data(), s); + return ret; + } + + /// Converts to RLPs collection object. Useful if you need random access to sub items or will iterate over multiple times. + RLPs toList(int _flags = Strict) const; + + /// @returns the data payload. Valid for all types. + bytesConstRef payload() const { auto l = length(); if (l > m_data.size()) BOOST_THROW_EXCEPTION(BadRLP()); return m_data.cropped(payloadOffset(), l); } + + /// @returns the theoretical size of this item as encoded in the data. + /// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work. + size_t actualSize() const; + +private: + /// Disable construction from rvalue + explicit RLP(bytes const&&) {} + + /// Throws if is non-canonical data (i.e. single byte done in two bytes that could be done in one). + void requireGood() const; + + /// Single-byte data payload. + bool isSingleByte() const { return !isNull() && m_data[0] < c_rlpDataImmLenStart; } + + /// @returns the amount of bytes used to encode the length of the data. Valid for all types. + unsigned lengthSize() const { if (isData() && m_data[0] > c_rlpDataIndLenZero) return m_data[0] - c_rlpDataIndLenZero; if (isList() && m_data[0] > c_rlpListIndLenZero) return m_data[0] - c_rlpListIndLenZero; return 0; } + + /// @returns the size in bytes of the payload, as given by the RLP as opposed to as inferred from m_data. + size_t length() const; + + /// @returns the number of bytes into the data that the payload starts. + size_t payloadOffset() const { return isSingleByte() ? 0 : (1 + lengthSize()); } + + /// @returns the number of data items. + size_t items() const; + + /// @returns the size encoded into the RLP in @a _data and throws if _data is too short. + static size_t sizeAsEncoded(bytesConstRef _data) { return RLP(_data, ThrowOnFail | FailIfTooSmall).actualSize(); } + + /// Our byte data. + bytesConstRef m_data; + + /// The list-indexing cache. + mutable size_t m_lastIndex = (size_t)-1; + mutable size_t m_lastEnd = 0; + mutable bytesConstRef m_lastItem; +}; + +template <> struct Converter<std::string> { static std::string convert(RLP const& _r, int _flags) { return _r.toString(_flags); } }; +template <> struct Converter<bytes> { static bytes convert(RLP const& _r, int _flags) { return _r.toBytes(_flags); } }; +template <> struct Converter<RLPs> { static RLPs convert(RLP const& _r, int _flags) { return _r.toList(_flags); } }; +template <> struct Converter<uint8_t> { static uint8_t convert(RLP const& _r, int _flags) { return _r.toInt<uint8_t>(_flags); } }; +template <> struct Converter<uint16_t> { static uint16_t convert(RLP const& _r, int _flags) { return _r.toInt<uint16_t>(_flags); } }; +template <> struct Converter<uint32_t> { static uint32_t convert(RLP const& _r, int _flags) { return _r.toInt<uint32_t>(_flags); } }; +template <> struct Converter<uint64_t> { static uint64_t convert(RLP const& _r, int _flags) { return _r.toInt<uint64_t>(_flags); } }; +template <> struct Converter<u160> { static u160 convert(RLP const& _r, int _flags) { return _r.toInt<u160>(_flags); } }; +template <> struct Converter<u256> { static u256 convert(RLP const& _r, int _flags) { return _r.toInt<u256>(_flags); } }; +template <> struct Converter<bigint> { static bigint convert(RLP const& _r, int _flags) { return _r.toInt<bigint>(_flags); } }; +template <unsigned N> struct Converter<FixedHash<N>> { static FixedHash<N> convert(RLP const& _r, int _flags) { return _r.toHash<FixedHash<N>>(_flags); } }; +template <class T, class U> struct Converter<std::pair<T, U>> { static std::pair<T, U> convert(RLP const& _r, int _flags) { return _r.toPair<T, U>(_flags); } }; +template <class T> struct Converter<std::vector<T>> { static std::vector<T> convert(RLP const& _r, int _flags) { return _r.toVector<T>(_flags); } }; +template <class T> struct Converter<std::set<T>> { static std::set<T> convert(RLP const& _r, int _flags) { return _r.toSet<T>(_flags); } }; +template <class T> struct Converter<std::unordered_set<T>> { static std::unordered_set<T> convert(RLP const& _r, int _flags) { return _r.toUnorderedSet<T>(_flags); } }; +template <class T, size_t N> struct Converter<std::array<T, N>> { static std::array<T, N> convert(RLP const& _r, int _flags) { return _r.toArray<T, N>(_flags); } }; + +template <class T> inline T RLP::convert(int _flags) const { return Converter<T>::convert(*this, _flags); } + +/** + * @brief Class for writing to an RLP bytestream. + */ +class RLPStream +{ +public: + /// Initializes empty RLPStream. + RLPStream() {} + + /// Initializes the RLPStream as a list of @a _listItems items. + explicit RLPStream(size_t _listItems) { appendList(_listItems); } + + ~RLPStream() {} + + /// Append given datum to the byte stream. + RLPStream& append(unsigned _s) { return append(bigint(_s)); } + RLPStream& append(u160 _s) { return append(bigint(_s)); } + RLPStream& append(u256 _s) { return append(bigint(_s)); } + RLPStream& append(bigint _s); + RLPStream& append(bytesConstRef _s, bool _compact = false); + RLPStream& append(bytes const& _s) { return append(bytesConstRef(&_s)); } + RLPStream& append(std::string const& _s) { return append(bytesConstRef(_s)); } + RLPStream& append(char const* _s) { return append(std::string(_s)); } + template <unsigned N> RLPStream& append(FixedHash<N> _s, bool _compact = false, bool _allOrNothing = false) { return _allOrNothing && !_s ? append(bytesConstRef()) : append(_s.ref(), _compact); } + + /// Appends an arbitrary RLP fragment - this *must* be a single item unless @a _itemCount is given. + RLPStream& append(RLP const& _rlp, size_t _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); } + + /// Appends a sequence of data to the stream as a list. + template <class _T> RLPStream& append(std::vector<_T> const& _s) { return appendVector(_s); } + template <class _T> RLPStream& appendVector(std::vector<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } + template <class _T, size_t S> RLPStream& append(std::array<_T, S> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } + template <class _T> RLPStream& append(std::set<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } + template <class _T> RLPStream& append(std::unordered_set<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } + template <class T, class U> RLPStream& append(std::pair<T, U> const& _s) { appendList(2); append(_s.first); append(_s.second); return *this; } + + /// Appends a list. + RLPStream& appendList(size_t _items); + RLPStream& appendList(bytesConstRef _rlp); + RLPStream& appendList(bytes const& _rlp) { return appendList(&_rlp); } + RLPStream& appendList(RLPStream const& _s) { return appendList(&_s.out()); } + + /// Appends raw (pre-serialised) RLP data. Use with caution. + RLPStream& appendRaw(bytesConstRef _rlp, size_t _itemCount = 1); + RLPStream& appendRaw(bytes const& _rlp, size_t _itemCount = 1) { return appendRaw(&_rlp, _itemCount); } + + /// Shift operators for appending data items. + template <class T> RLPStream& operator<<(T _data) { return append(_data); } + + /// Clear the output stream so far. + void clear() { m_out.clear(); m_listStack.clear(); } + + /// Read the byte stream. + bytes const& out() const { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return m_out; } + + /// Invalidate the object and steal the output byte stream. + bytes&& invalidate() { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return std::move(m_out); } + + /// Swap the contents of the output stream out for some other byte array. + void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); } + +private: + void noteAppended(size_t _itemCount = 1); + + /// Push the node-type byte (using @a _base) along with the item count @a _count. + /// @arg _count is number of characters for strings, data-bytes for ints, or items for lists. + void pushCount(size_t _count, byte _offset); + + /// Push an integer as a raw big-endian byte-stream. + template <class _T> void pushInt(_T _i, size_t _br) + { + m_out.resize(m_out.size() + _br); + byte* b = &m_out.back(); + for (; _i; _i >>= 8) + *(b--) = (byte)_i; + } + + /// Our output byte stream. + bytes m_out; + + std::vector<std::pair<size_t, size_t>> m_listStack; +}; + +template <class _T> void rlpListAux(RLPStream& _out, _T _t) { _out << _t; } +template <class _T, class ... _Ts> void rlpListAux(RLPStream& _out, _T _t, _Ts ... _ts) { rlpListAux(_out << _t, _ts...); } + +/// Export a single item in RLP format, returning a byte array. +template <class _T> bytes rlp(_T _t) { return (RLPStream() << _t).out(); } + +/// Export a list of items in RLP format, returning a byte array. +inline bytes rlpList() { return RLPStream(0).out(); } +template <class ... _Ts> bytes rlpList(_Ts ... _ts) +{ + RLPStream out(sizeof ...(_Ts)); + rlpListAux(out, _ts...); + return out.out(); +} + +/// The empty string in RLP format. +extern bytes RLPNull; + +/// The empty list in RLP format. +extern bytes RLPEmptyList; + +/// Human readable version of RLP. +std::ostream& operator<<(std::ostream& _out, dev::RLP const& _d); + +} diff --git a/src/ringdht/eth/libdevcore/SHA3.cpp b/src/ringdht/eth/libdevcore/SHA3.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5072cc2110ffe44c904b28a5d999d439da36d596 --- /dev/null +++ b/src/ringdht/eth/libdevcore/SHA3.cpp @@ -0,0 +1,227 @@ +/* + 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 "RLP.h" +#include "picosha2.h" +using namespace std; +using namespace dev; + +namespace dev +{ + +h256 EmptySHA3 = sha3(bytesConstRef()); +h256 EmptyListSHA3 = sha3(rlpList()); + +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/src/ringdht/eth/libdevcore/SHA3.h b/src/ringdht/eth/libdevcore/SHA3.h new file mode 100644 index 0000000000000000000000000000000000000000..6ceb6f890d548fe7a32a7f09cea7fbe00df1c264 --- /dev/null +++ b/src/ringdht/eth/libdevcore/SHA3.h @@ -0,0 +1,73 @@ +/* + 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; } +inline SecureFixedHash<32> sha3Secure(bytesConstRef _input) { SecureFixedHash<32> ret; sha3(_input, ret.writable().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)); } +inline SecureFixedHash<32> sha3Secure(bytes const& _input) { return sha3Secure(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)); } +inline SecureFixedHash<32> sha3Secure(std::string const& _input) { return sha3Secure(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()); } +template<unsigned N> inline SecureFixedHash<32> sha3Secure(FixedHash<N> const& _input) { return sha3Secure(_input.ref()); } + +/// Fully secure variants are equivalent for sha3 and sha3Secure. +inline SecureFixedHash<32> sha3(bytesSec const& _input) { return sha3Secure(_input.ref()); } +inline SecureFixedHash<32> sha3Secure(bytesSec const& _input) { return sha3Secure(_input.ref()); } +template<unsigned N> inline SecureFixedHash<32> sha3(SecureFixedHash<N> const& _input) { return sha3Secure(_input.ref()); } +template<unsigned N> inline SecureFixedHash<32> sha3Secure(SecureFixedHash<N> const& _input) { return sha3Secure(_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 h256 EmptySHA3; + +extern h256 EmptyListSHA3; + +extern unsigned g_sha3Counter; + +} diff --git a/src/ringdht/eth/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp b/src/ringdht/eth/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dae591dfb884121584f2816abf979c60562ffc0c --- /dev/null +++ b/src/ringdht/eth/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp @@ -0,0 +1,520 @@ + +// This is a copy of boost/multiprecision/detail/number_compare.hpp from boost 1.59 to replace buggy version from 1.58. + +#ifdef BOOST_MP_COMPARE_HPP +#error This bug workaround header must be included before original boost/multiprecision/detail/number_compare.hpp +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Copyright 2012 John Maddock. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MP_COMPARE_HPP +#define BOOST_MP_COMPARE_HPP + +// A copy of boost/multiprecision/traits/is_backend.hpp +#ifndef BOOST_MP_IS_BACKEND_HPP +#define BOOST_MP_IS_BACKEND_HPP + +#include <boost/mpl/has_xxx.hpp> +#include <boost/type_traits/conditional.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/multiprecision/detail/number_base.hpp> +#include <boost/multiprecision/detail/generic_interconvert.hpp> + +namespace boost{ namespace multiprecision{ namespace detail{ + + BOOST_MPL_HAS_XXX_TRAIT_DEF(signed_types) + BOOST_MPL_HAS_XXX_TRAIT_DEF(unsigned_types) + BOOST_MPL_HAS_XXX_TRAIT_DEF(float_types) + + template <class T> + struct is_backend + { + static const bool value = has_signed_types<T>::value && has_unsigned_types<T>::value && has_float_types<T>::value; + }; + + template <class Backend> + struct other_backend + { + typedef typename boost::conditional< + boost::is_same<number<Backend>, number<Backend, et_on> >::value, + number<Backend, et_off>, number<Backend, et_on> >::type type; + }; + + template <class B, class V> + struct number_from_backend + { + typedef typename boost::conditional < + boost::is_convertible<V, number<B> >::value, + number<B>, + typename other_backend<B>::type > ::type type; + }; + + template <bool b, class T, class U> + struct is_first_backend_imp{ static const bool value = false; }; + template <class T, class U> + struct is_first_backend_imp<true, T, U>{ static const bool value = is_convertible<U, number<T, et_on> >::value || is_convertible<U, number<T, et_off> >::value; }; + + template <class T, class U> + struct is_first_backend : is_first_backend_imp<is_backend<T>::value, T, U> {}; + + template <bool b, class T, class U> + struct is_second_backend_imp{ static const bool value = false; }; + template <class T, class U> + struct is_second_backend_imp<true, T, U>{ static const bool value = is_convertible<T, number<U> >::value || is_convertible<T, number<U, et_off> >::value; }; + + template <class T, class U> + struct is_second_backend : is_second_backend_imp<is_backend<U>::value, T, U> {}; + +} +} +} + +#endif // BOOST_MP_IS_BACKEND_HPP + +// +// Comparison operators for number. +// + +namespace boost{ namespace multiprecision{ + +namespace default_ops{ + +template <class B> +inline bool eval_eq(const B& a, const B& b) +{ + return a.compare(b) == 0; +} +template <class T, class U> +inline typename enable_if_c<boost::multiprecision::detail::is_first_backend<T, U>::value, bool>::type eval_eq(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend<T, U>::type t(b); + return eval_eq(a, t.backend()); +} +template <class T, class U> +inline typename enable_if_c<boost::multiprecision::detail::is_second_backend<T, U>::value, bool>::type eval_eq(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend<U, T>::type t(a); + return eval_eq(t.backend(), b); +} + +template <class B> +inline bool eval_lt(const B& a, const B& b) +{ + return a.compare(b) < 0; +} +template <class T, class U> +inline typename enable_if_c<boost::multiprecision::detail::is_first_backend<T, U>::value, bool>::type eval_lt(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend<T, U>::type t(b); + return eval_lt(a, t.backend()); +} +template <class T, class U> +inline typename enable_if_c<boost::multiprecision::detail::is_second_backend<T, U>::value, bool>::type eval_lt(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend<U, T>::type t(a); + return eval_lt(t.backend(), b); +} + +template <class B> +inline bool eval_gt(const B& a, const B& b) +{ + return a.compare(b) > 0; +} +template <class T, class U> +inline typename enable_if_c<boost::multiprecision::detail::is_first_backend<T, U>::value, bool>::type eval_gt(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend<T, U>::type t(b); + return eval_gt(a, t.backend()); +} +template <class T, class U> +inline typename enable_if_c<boost::multiprecision::detail::is_second_backend<T, U>::value, bool>::type eval_gt(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend<U, T>::type t(a); + return eval_gt(t.backend(), b); +} + +} // namespace default_ops + +namespace detail{ + +template <class Num, class Val> +struct is_valid_mixed_compare : public mpl::false_ {}; + +template <class B, expression_template_option ET, class Val> +struct is_valid_mixed_compare<number<B, ET>, Val> : public is_convertible<Val, number<B, ET> > {}; + +template <class B, expression_template_option ET> +struct is_valid_mixed_compare<number<B, ET>, number<B, ET> > : public mpl::false_ {}; + +template <class B, expression_template_option ET, class tag, class Arg1, class Arg2, class Arg3, class Arg4> +struct is_valid_mixed_compare<number<B, ET>, expression<tag, Arg1, Arg2, Arg3, Arg4> > + : public mpl::bool_<is_convertible<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >::value> {}; + +template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET> +struct is_valid_mixed_compare<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> > + : public mpl::bool_<is_convertible<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >::value> {}; + +template <class Backend, expression_template_option ExpressionTemplates> +inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Backend>::value != number_kind_floating_point, bool>::type is_unordered_value(const number<Backend, ExpressionTemplates>&) +{ + return false; +} +template <class Backend, expression_template_option ExpressionTemplates> +inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Backend>::value == number_kind_floating_point, bool>::type is_unordered_value(const number<Backend, ExpressionTemplates>& a) +{ + using default_ops::eval_fpclassify; + return eval_fpclassify(a.backend()) == FP_NAN; +} + +template <class Arithmetic> +inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Arithmetic>::value != number_kind_floating_point, bool>::type is_unordered_value(const Arithmetic&) +{ + return false; +} +template <class Arithmetic> +inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Arithmetic>::value == number_kind_floating_point, bool>::type is_unordered_value(const Arithmetic& a) +{ + return (boost::math::isnan)(a); +} + +template <class T, class U> +inline BOOST_CONSTEXPR bool is_unordered_comparison(const T& a, const U& b) +{ + return is_unordered_value(a) || is_unordered_value(b); +} + +} + +template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2> +inline bool operator == (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_eq(a.backend(), b.backend()); +} +template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type + operator == (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_eq(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b)); +} +template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type + operator == (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_eq(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a)); +} +template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type + operator == (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) +{ + typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; + using default_ops::eval_eq; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return false; + return eval_eq(t.backend(), result_type::canonical_value(a)); +} +template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type + operator == (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) +{ + typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; + using default_ops::eval_eq; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return false; + return eval_eq(t.backend(), result_type::canonical_value(b)); +} +template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> +inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type + operator == (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) +{ + using default_ops::eval_eq; + typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a); + typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return false; + return eval_eq(t.backend(), t2.backend()); +} + +template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2> +inline bool operator != (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return true; + return !eval_eq(a.backend(), b.backend()); +} +template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type + operator != (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return true; + return !eval_eq(a.backend(), number<Backend, et_on>::canonical_value(b)); +} +template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type + operator != (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return true; + return !eval_eq(b.backend(), number<Backend, et_on>::canonical_value(a)); +} +template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type + operator != (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) +{ + typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; + using default_ops::eval_eq; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return true; + return !eval_eq(t.backend(), result_type::canonical_value(a)); +} +template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type + operator != (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) +{ + typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; + using default_ops::eval_eq; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return true; + return !eval_eq(t.backend(), result_type::canonical_value(b)); +} +template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> +inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type + operator != (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) +{ + using default_ops::eval_eq; + typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a); + typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return true; + return !eval_eq(t.backend(), t2.backend()); +} + +template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2> +inline bool operator < (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_lt(a.backend(), b.backend()); +} +template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type + operator < (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_lt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b)); +} +template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type + operator < (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_gt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a)); +} +template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type + operator < (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) +{ + typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; + using default_ops::eval_gt; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return false; + return eval_gt(t.backend(), result_type::canonical_value(a)); +} +template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type + operator < (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) +{ + typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; + using default_ops::eval_lt; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return false; + return eval_lt(t.backend(), result_type::canonical_value(b)); +} +template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> +inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type + operator < (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) +{ + using default_ops::eval_lt; + typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a); + typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return false; + return eval_lt(t.backend(), t2.backend()); +} + +template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2> +inline bool operator > (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_gt(a.backend(), b.backend()); +} +template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type + operator > (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_gt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b)); +} +template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type + operator > (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_lt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a)); +} +template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type + operator > (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) +{ + typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; + using default_ops::eval_lt; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return false; + return a > t; +} +template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type + operator > (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) +{ + typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; + using default_ops::eval_gt; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return false; + return t > b; +} +template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> +inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type + operator > (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) +{ + using default_ops::eval_gt; + typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a); + typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return false; + return t > t2; +} + +template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2> +inline bool operator <= (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_gt(a.backend(), b.backend()); +} +template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type + operator <= (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_gt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b)); +} +template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type + operator <= (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_lt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a)); +} +template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type + operator <= (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) +{ + typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; + using default_ops::eval_lt; + if(detail::is_unordered_value(a) || detail::is_unordered_value(b)) + return false; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return false; + return !eval_lt(t.backend(), result_type::canonical_value(a)); +} +template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type + operator <= (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) +{ + typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; + using default_ops::eval_gt; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return false; + return !eval_gt(t.backend(), result_type::canonical_value(b)); +} +template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> +inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type + operator <= (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) +{ + using default_ops::eval_gt; + typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a); + typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return false; + return !eval_gt(t.backend(), t2.backend()); +} + +template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2> +inline bool operator >= (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_lt(a.backend(), b.backend()); +} +template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type + operator >= (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_lt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b)); +} +template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type + operator >= (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_gt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a)); +} +template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type + operator >= (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) +{ + typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; + using default_ops::eval_gt; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return false; + return !eval_gt(t.backend(), result_type::canonical_value(a)); +} +template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type + operator >= (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) +{ + typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; + using default_ops::eval_lt; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return false; + return !eval_lt(t.backend(), result_type::canonical_value(b)); +} +template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> +inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type + operator >= (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) +{ + using default_ops::eval_lt; + typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a); + typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return false; + return !eval_lt(t.backend(), t2.backend()); +} + + +}} // namespaces + +#endif // BOOST_MP_COMPARE_HPP diff --git a/src/ringdht/eth/libdevcore/picosha2.h b/src/ringdht/eth/libdevcore/picosha2.h new file mode 100644 index 0000000000000000000000000000000000000000..44b6bee5947a69500c199d7f5fb4e193ed7ffee1 --- /dev/null +++ b/src/ringdht/eth/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/src/ringdht/eth/libdevcore/vector_ref.h b/src/ringdht/eth/libdevcore/vector_ref.h new file mode 100644 index 0000000000000000000000000000000000000000..46d06946299f3bd6434818652eae21b482fd6e63 --- /dev/null +++ b/src/ringdht/eth/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); } + +} diff --git a/src/ringdht/eth/libdevcrypto/AES.cpp b/src/ringdht/eth/libdevcrypto/AES.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bec2ba137c7468dfe6dbfbd7fda43cc658592e4f --- /dev/null +++ b/src/ringdht/eth/libdevcrypto/AES.cpp @@ -0,0 +1,57 @@ +/* + 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 AES.cpp + * @author Alex Leverington <nessence@gmail.com> + * @date 2014 + */ + +#include "AES.h" +#include <libdevcore/Common.h> +#include "CryptoPP.h" +using namespace std; +using namespace dev; +using namespace dev::crypto; +using namespace CryptoPP; + +bytes dev::aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned _rounds, bytesConstRef _salt) +{ + bytes pw = asBytes(_password); + + if (!_salt.size()) + _salt = &pw; + + bytes target(64); + CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA256>().DeriveKey(target.data(), target.size(), 0, pw.data(), pw.size(), _salt.data(), _salt.size(), _rounds); + + try + { + CryptoPP::AES::Decryption aesDecryption(target.data(), 16); + auto cipher = _ivCipher.cropped(16); + auto iv = _ivCipher.cropped(0, 16); + CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data()); + std::string decrypted; + CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(decrypted)); + stfDecryptor.Put(cipher.data(), cipher.size()); + stfDecryptor.MessageEnd(); + return asBytes(decrypted); + } + catch (exception const& e) + { + cerr << e.what() << endl; + return bytes(); + } +} diff --git a/src/ringdht/eth/libdevcrypto/AES.h b/src/ringdht/eth/libdevcrypto/AES.h new file mode 100644 index 0000000000000000000000000000000000000000..6f72369f6347bfd995b25b2b71b2b114c9d04ac1 --- /dev/null +++ b/src/ringdht/eth/libdevcrypto/AES.h @@ -0,0 +1,34 @@ +/* + 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 AES.h + * @author Alex Leverington <nessence@gmail.com> + * @date 2014 + * + * AES + * todo: use openssl + */ + +#pragma once + +#include "Common.h" + +namespace dev +{ + +bytes aesDecrypt(bytesConstRef _cipher, std::string const& _password, unsigned _rounds = 2000, bytesConstRef _salt = bytesConstRef()); + +} diff --git a/src/ringdht/eth/libdevcrypto/Common.cpp b/src/ringdht/eth/libdevcrypto/Common.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aaa6fa917babdce26343e825fe194f069b7672f8 --- /dev/null +++ b/src/ringdht/eth/libdevcrypto/Common.cpp @@ -0,0 +1,327 @@ +/* + 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 Alex Leverington <nessence@gmail.com> + * @author Gav Wood <i@gavwood.com> + * @date 2014 + */ + +#include "Common.h" +#include <cstdint> +#include <chrono> +#include <thread> +#include <mutex> +#include <libdevcore/Guards.h> +#include <libdevcore/SHA3.h> +#include <libdevcore/RLP.h> +#if ETH_HAVE_SECP256K1 +#include <secp256k1/include/secp256k1.h> +#endif +#include "AES.h" +#include "CryptoPP.h" +#include "Exceptions.h" +using namespace std; +using namespace dev; +using namespace dev::crypto; + +#ifdef ETH_HAVE_SECP256K1 +class Secp256k1Context +{ +public: + static secp256k1_context_t const* get() { if (!s_this) s_this = new Secp256k1Context; return s_this->m_ctx; } + +private: + Secp256k1Context() { m_ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); } + ~Secp256k1Context() { secp256k1_context_destroy(m_ctx); } + + secp256k1_context_t* m_ctx; + + static Secp256k1Context* s_this; +}; +Secp256k1Context* Secp256k1Context::s_this = nullptr; +#endif + +bool dev::SignatureStruct::isValid() const noexcept +{ + if (v > 1 || + r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") || + s >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") || + s < h256(1) || + r < h256(1)) + return false; + return true; +} + +Public SignatureStruct::recover(h256 const& _hash) const +{ + return dev::recover((Signature)*this, _hash); +} + +Address dev::ZeroAddress = Address(); + +Public dev::toPublic(Secret const& _secret) +{ +#ifdef ETH_HAVE_SECP256K1 + bytes o(65); + int pubkeylen; + if (!secp256k1_ec_pubkey_create(Secp256k1Context::get(), o.data(), &pubkeylen, _secret.data(), false)) + return Public(); + return FixedHash<64>(o.data()+1, Public::ConstructFromPointer); +#else + Public p; + Secp256k1PP::get()->toPublic(_secret, p); + return p; +#endif +} + +Address dev::toAddress(Public const& _public) +{ + return right160(sha3(_public.ref())); +} + +Address dev::toAddress(Secret const& _secret) +{ + Public p; + Secp256k1PP::get()->toPublic(_secret, p); + return toAddress(p); +} + +Address dev::toAddress(Address const& _from, u256 const& _nonce) +{ + return right160(sha3(rlpList(_from, _nonce))); +} + +void dev::encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher) +{ + bytes io = _plain.toBytes(); + Secp256k1PP::get()->encrypt(_k, io); + o_cipher = std::move(io); +} + +bool dev::decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext) +{ + bytes io = _cipher.toBytes(); + Secp256k1PP::get()->decrypt(_k, io); + if (io.empty()) + return false; + o_plaintext = std::move(io); + return true; +} + +void dev::encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher) +{ + encryptECIES(_k, bytesConstRef(), _plain, o_cipher); +} + +void dev::encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytesConstRef _plain, bytes& o_cipher) +{ + bytes io = _plain.toBytes(); + Secp256k1PP::get()->encryptECIES(_k, _sharedMacData, io); + o_cipher = std::move(io); +} + +bool dev::decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext) +{ + return decryptECIES(_k, bytesConstRef(), _cipher, o_plaintext); +} + +bool dev::decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytesConstRef _cipher, bytes& o_plaintext) +{ + bytes io = _cipher.toBytes(); + if (!Secp256k1PP::get()->decryptECIES(_k, _sharedMacData, io)) + return false; + o_plaintext = std::move(io); + return true; +} + +void dev::encryptSym(Secret const& _k, bytesConstRef _plain, bytes& o_cipher) +{ + // TOOD: @alex @subtly do this properly. + encrypt(KeyPair(_k).pub(), _plain, o_cipher); +} + +bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain) +{ + // TODO: @alex @subtly do this properly. + return decrypt(_k, _cipher, o_plain); +} + +std::pair<bytes, h128> dev::encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain) +{ + h128 iv(Nonce::get().makeInsecure()); + return make_pair(encryptSymNoAuth(_k, iv, _plain), iv); +} + +bytes dev::encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain) +{ + if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32) + return bytes(); + SecByteBlock key(_k.data(), _k.size()); + try + { + CTR_Mode<AES>::Encryption e; + e.SetKeyWithIV(key, key.size(), _iv.data()); + bytes ret(_plain.size()); + e.ProcessData(ret.data(), _plain.data(), _plain.size()); + return ret; + } + catch (CryptoPP::Exception& _e) + { + cerr << _e.what() << endl; + return bytes(); + } +} + +bytesSec dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher) +{ + if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32) + return bytesSec(); + SecByteBlock key(_k.data(), _k.size()); + try + { + CTR_Mode<AES>::Decryption d; + d.SetKeyWithIV(key, key.size(), _iv.data()); + bytesSec ret(_cipher.size()); + d.ProcessData(ret.writable().data(), _cipher.data(), _cipher.size()); + return ret; + } + catch (CryptoPP::Exception& _e) + { + cerr << _e.what() << endl; + return bytesSec(); + } +} + +static const Public c_zeroKey("3f17f1962b36e491b30a40b2405849e597ba5fb5"); + +Public dev::recover(Signature const& _sig, h256 const& _message) +{ + Public ret; +#ifdef ETH_HAVE_SECP256K1 + bytes o(65); + int pubkeylen; + if (_sig[64] > 3 || !secp256k1_ecdsa_recover_compact(Secp256k1Context::get(), _message.data(), _sig.data(), o.data(), &pubkeylen, false, _sig[64])) + return Public(); + ret = FixedHash<64>(o.data() + 1, Public::ConstructFromPointer); +#else + ret = Secp256k1PP::get()->recover(_sig, _message.ref()); +#endif + if (ret == c_zeroKey) + return Public(); + return ret; +} + +static const u256 c_secp256k1n("115792089237316195423570985008687907852837564279074904382605163141518161494337"); + +Signature dev::sign(Secret const& _k, h256 const& _hash) +{ + Signature s; + SignatureStruct& ss = *reinterpret_cast<SignatureStruct*>(&s); + +#ifdef ETH_HAVE_SECP256K1 + int v; + if (!secp256k1_ecdsa_sign_compact(Secp256k1Context::get(), _hash.data(), s.data(), _k.data(), NULL, NULL, &v)) + return Signature(); + ss.v = v; +#else + s = Secp256k1PP::get()->sign(_k, _hash); +#endif + if (ss.s > c_secp256k1n / 2) + { + ss.v = ss.v ^ 1; + ss.s = h256(c_secp256k1n - u256(ss.s)); + } + assert(ss.s <= c_secp256k1n / 2); + return s; +} + +bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash) +{ + if (!_p) + return false; +#ifdef ETH_HAVE_SECP256K1 + return _p == recover(_s, _hash); +#else + return Secp256k1PP::get()->verify(_p, _s, _hash.ref(), true); +#endif +} + +bytesSec dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen) +{ + bytesSec ret(_dkLen); + if (PKCS5_PBKDF2_HMAC<SHA256>().DeriveKey( + ret.writable().data(), + _dkLen, + 0, + reinterpret_cast<byte const*>(_pass.data()), + _pass.size(), + _salt.data(), + _salt.size(), + _iterations + ) != _iterations) + BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed.")); + return ret; +} + +void KeyPair::populateFromSecret(Secret const& _sec) +{ + m_secret = _sec; + if (Secp256k1PP::get()->verifySecret(m_secret, m_public)) + m_address = toAddress(m_public); +} + +KeyPair KeyPair::create() +{ + for (int i = 0; i < 100; ++i) + { + KeyPair ret(Secret::random()); + if (ret.address()) + return ret; + } + return KeyPair(); +} + +KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password) +{ + return KeyPair(Secret(sha3(aesDecrypt(_seed, _password)))); +} + +h256 crypto::kdf(Secret const& _priv, h256 const& _hash) +{ + // H(H(r||k)^h) + h256 s; + sha3mac(Secret::random().ref(), _priv.ref(), s.ref()); + s ^= _hash; + sha3(s.ref(), s.ref()); + + if (!s || !_hash || !_priv) + BOOST_THROW_EXCEPTION(InvalidState()); + return s; +} + +Secret Nonce::next() +{ + Guard l(x_value); + if (!m_value) + { + m_value = Secret::random(); + if (!m_value) + BOOST_THROW_EXCEPTION(InvalidState()); + } + m_value = sha3Secure(m_value.ref()); + return sha3(~m_value); +} diff --git a/src/ringdht/eth/libdevcrypto/Common.h b/src/ringdht/eth/libdevcrypto/Common.h new file mode 100644 index 0000000000000000000000000000000000000000..64a6e4c8a58dab58b096018d393ab7251580ec7e --- /dev/null +++ b/src/ringdht/eth/libdevcrypto/Common.h @@ -0,0 +1,222 @@ +/* + 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 Alex Leverington <nessence@gmail.com> + * @author Gav Wood <i@gavwood.com> + * @date 2014 + * + * Ethereum-specific data structures & algorithms. + */ + +#pragma once + +#include <mutex> +#include "libdevcore/Common.h" +#include "libdevcore/FixedHash.h" +#include "libdevcore/Exceptions.h" + +namespace dev +{ + +using Secret = SecureFixedHash<32>; + +/// A public key: 64 bytes. +/// @NOTE This is not endian-specific; it's just a bunch of bytes. +using Public = h512; + +/// A signature: 65 bytes: r: [0, 32), s: [32, 64), v: 64. +/// @NOTE This is not endian-specific; it's just a bunch of bytes. +using Signature = h520; + +struct SignatureStruct +{ + SignatureStruct() = default; + SignatureStruct(Signature const& _s) { *(h520*)this = _s; } + SignatureStruct(h256 const& _r, h256 const& _s, byte _v): r(_r), s(_s), v(_v) {} + operator Signature() const { return *(h520 const*)this; } + + /// @returns true if r,s,v values are valid, otherwise false + bool isValid() const noexcept; + + /// @returns the public part of the key that signed @a _hash to give this sig. + Public recover(h256 const& _hash) const; + + h256 r; + h256 s; + byte v = 0; +}; + +/// An Ethereum address: 20 bytes. +/// @NOTE This is not endian-specific; it's just a bunch of bytes. +using Address = h160; + +/// The zero address. +extern Address ZeroAddress; + +/// A vector of Ethereum addresses. +using Addresses = h160s; + +/// A hash set of Ethereum addresses. +using AddressHash = std::unordered_set<h160>; + +/// A vector of secrets. +using Secrets = std::vector<Secret>; + +/// Convert a secret key into the public key equivalent. +Public toPublic(Secret const& _secret); + +/// Convert a public key to address. +Address toAddress(Public const& _public); + +/// Convert a secret key into address of public key equivalent. +/// @returns 0 if it's not a valid secret key. +Address toAddress(Secret const& _secret); + +// Convert transaction from and nonce to address. +Address toAddress(Address const& _from, u256 const& _nonce); + +/// Encrypts plain text using Public key. +void encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher); + +/// Decrypts cipher using Secret key. +bool decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); + +/// Symmetric encryption. +void encryptSym(Secret const& _k, bytesConstRef _plain, bytes& o_cipher); + +/// Symmetric decryption. +bool decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); + +/// Encrypt payload using ECIES standard with AES128-CTR. +void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher); + +/// Encrypt payload using ECIES standard with AES128-CTR. +/// @a _sharedMacData is shared authenticated data. +void encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytesConstRef _plain, bytes& o_cipher); + +/// Decrypt payload using ECIES standard with AES128-CTR. +bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); + +/// Decrypt payload using ECIES standard with AES128-CTR. +/// @a _sharedMacData is shared authenticated data. +bool decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytesConstRef _cipher, bytes& o_plaintext); + +/// Encrypts payload with random IV/ctr using AES128-CTR. +std::pair<bytes, h128> encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain); + +/// Encrypts payload with specified IV/ctr using AES128-CTR. +bytes encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain); + +/// Decrypts payload with specified IV/ctr using AES128-CTR. +bytesSec decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher); + +/// Encrypts payload with specified IV/ctr using AES128-CTR. +inline bytes encryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } +inline bytes encryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } + +/// Decrypts payload with specified IV/ctr using AES128-CTR. +inline bytesSec decryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } +inline bytesSec decryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } + +/// Recovers Public key from signed message hash. +Public recover(Signature const& _sig, h256 const& _hash); + +/// Returns siganture of message hash. +Signature sign(Secret const& _k, h256 const& _hash); + +/// Verify signature. +bool verify(Public const& _k, Signature const& _s, h256 const& _hash); + +/// Derive key via PBKDF2. +bytesSec pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32); + +/// Simple class that represents a "key pair". +/// All of the data of the class can be regenerated from the secret key (m_secret) alone. +/// Actually stores a tuplet of secret, public and address (the right 160-bits of the public). +class KeyPair +{ +public: + /// Null constructor. + KeyPair() {} + + /// Normal constructor - populates object from the given secret key. + KeyPair(Secret const& _k) { populateFromSecret(_k); } + + /// Create a new, randomly generated object. + static KeyPair create(); + + /// Create from an encrypted seed. + static KeyPair fromEncryptedSeed(bytesConstRef _seed, std::string const& _password); + + /// Retrieve the secret key. + Secret const& secret() const { return m_secret; } + /// Retrieve the secret key. + Secret const& sec() const { return m_secret; } + + /// Retrieve the public key. + Public const& pub() const { return m_public; } + + /// Retrieve the associated address of the public key. + Address const& address() const { return m_address; } + + bool operator==(KeyPair const& _c) const { return m_public == _c.m_public; } + bool operator!=(KeyPair const& _c) const { return m_public != _c.m_public; } + +private: + void populateFromSecret(Secret const& _k); + + Secret m_secret; + Public m_public; + Address m_address; +}; + +namespace crypto +{ + +DEV_SIMPLE_EXCEPTION(InvalidState); + +/// Key derivation +h256 kdf(Secret const& _priv, h256 const& _hash); + +/** + * @brief Generator for non-repeating nonce material. + * The Nonce class should only be used when a non-repeating nonce + * is required and, in its current form, not recommended for signatures. + * This is primarily because the key-material for signatures is + * encrypted on disk whereas the seed for Nonce is not. + * Thus, Nonce's primary intended use at this time is for networking + * where the key is also stored in plaintext. + */ +class Nonce +{ +public: + /// Returns the next nonce (might be read from a file). + static Secret get() { static Nonce s; return s.next(); } + +private: + Nonce() = default; + + /// @returns the next nonce. + Secret next(); + + std::mutex x_value; + Secret m_value; +}; + +} + +} diff --git a/src/ringdht/eth/libdevcrypto/CryptoPP.cpp b/src/ringdht/eth/libdevcrypto/CryptoPP.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d4bb771658e37bdc17b0c9ba1e3b460e6fa403d4 --- /dev/null +++ b/src/ringdht/eth/libdevcrypto/CryptoPP.cpp @@ -0,0 +1,372 @@ +/* + 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 CryptoPP.cpp + * @author Alex Leverington <nessence@gmail.com> + * @date 2014 + */ + +#include <libdevcore/Guards.h> +#include "ECDHE.h" +/* + * At 5.6.3 the ECIES implementation has been deprecated and a warning has + * been added. A new implementation will be added in 6.0. Until then and for + * -Werror to not fail the build we have to have this warning ignore pragma here + * and until the end of the file. + * Refer here for more information: + * https://www.cryptopp.com/wiki/Elliptic_Curve_Integrated_Encryption_Scheme#5.6.3_and_6.0_Changes + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#include "CryptoPP.h" + +using namespace std; +using namespace dev; +using namespace dev::crypto; +using namespace CryptoPP; + +static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes."); +static_assert(dev::Public::size == 64, "Public key must be 64 bytes."); +static_assert(dev::Signature::size == 65, "Signature must be 65 bytes."); + +Secp256k1PP* Secp256k1PP::s_this = nullptr; + +bytes Secp256k1PP::eciesKDF(Secret const& _z, bytes _s1, unsigned kdByteLen) +{ + auto reps = ((kdByteLen + 7) * 8) / (CryptoPP::SHA256::BLOCKSIZE * 8); + // SEC/ISO/Shoup specify counter size SHOULD be equivalent + // to size of hash output, however, it also notes that + // the 4 bytes is okay. NIST specifies 4 bytes. + bytes ctr({0, 0, 0, 1}); + bytes k; + CryptoPP::SHA256 ctx; + for (unsigned i = 0; i <= reps; i++) + { + ctx.Update(ctr.data(), ctr.size()); + ctx.Update(_z.data(), Secret::size); + ctx.Update(_s1.data(), _s1.size()); + // append hash to k + bytes digest(32); + ctx.Final(digest.data()); + ctx.Restart(); + + k.reserve(k.size() + h256::size); + move(digest.begin(), digest.end(), back_inserter(k)); + + if (++ctr[3] || ++ctr[2] || ++ctr[1] || ++ctr[0]) + continue; + } + + k.resize(kdByteLen); + return k; +} + +void Secp256k1PP::encryptECIES(Public const& _k, bytes& io_cipher) +{ + encryptECIES(_k, bytesConstRef(), io_cipher); +} + +void Secp256k1PP::encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytes& io_cipher) +{ + // interop w/go ecies implementation + auto r = KeyPair::create(); + Secret z; + ecdh::agree(r.sec(), _k, z); + auto key = eciesKDF(z, bytes(), 32); + bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); + bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16); + CryptoPP::SHA256 ctx; + ctx.Update(mKeyMaterial.data(), mKeyMaterial.size()); + bytes mKey(32); + ctx.Final(mKey.data()); + + bytes cipherText = encryptSymNoAuth(SecureFixedHash<16>(eKey), h128(), bytesConstRef(&io_cipher)); + if (cipherText.empty()) + return; + + bytes msg(1 + Public::size + h128::size + cipherText.size() + 32); + msg[0] = 0x04; + r.pub().ref().copyTo(bytesRef(&msg).cropped(1, Public::size)); + bytesRef msgCipherRef = bytesRef(&msg).cropped(1 + Public::size + h128::size, cipherText.size()); + bytesConstRef(&cipherText).copyTo(msgCipherRef); + + // tag message + CryptoPP::HMAC<SHA256> hmacctx(mKey.data(), mKey.size()); + bytesConstRef cipherWithIV = bytesRef(&msg).cropped(1 + Public::size, h128::size + cipherText.size()); + hmacctx.Update(cipherWithIV.data(), cipherWithIV.size()); + hmacctx.Update(_sharedMacData.data(), _sharedMacData.size()); + hmacctx.Final(msg.data() + 1 + Public::size + cipherWithIV.size()); + + io_cipher.resize(msg.size()); + io_cipher.swap(msg); +} + +bool Secp256k1PP::decryptECIES(Secret const& _k, bytes& io_text) +{ + return decryptECIES(_k, bytesConstRef(), io_text); +} + +bool Secp256k1PP::decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytes& io_text) +{ + + // interop w/go ecies implementation + + // io_cipher[0] must be 2, 3, or 4, else invalidpublickey + if (io_text.empty() || io_text[0] < 2 || io_text[0] > 4) + // invalid message: publickey + return false; + + if (io_text.size() < (1 + Public::size + h128::size + 1 + h256::size)) + // invalid message: length + return false; + + Secret z; + ecdh::agree(_k, *(Public*)(io_text.data() + 1), z); + auto key = eciesKDF(z, bytes(), 64); + bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); + bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16); + bytes mKey(32); + CryptoPP::SHA256 ctx; + ctx.Update(mKeyMaterial.data(), mKeyMaterial.size()); + ctx.Final(mKey.data()); + + bytes plain; + size_t cipherLen = io_text.size() - 1 - Public::size - h128::size - h256::size; + bytesConstRef cipherWithIV(io_text.data() + 1 + Public::size, h128::size + cipherLen); + bytesConstRef cipherIV = cipherWithIV.cropped(0, h128::size); + bytesConstRef cipherNoIV = cipherWithIV.cropped(h128::size, cipherLen); + bytesConstRef msgMac(cipherNoIV.data() + cipherLen, h256::size); + h128 iv(cipherIV.toBytes()); + + // verify tag + CryptoPP::HMAC<SHA256> hmacctx(mKey.data(), mKey.size()); + hmacctx.Update(cipherWithIV.data(), cipherWithIV.size()); + hmacctx.Update(_sharedMacData.data(), _sharedMacData.size()); + h256 mac; + hmacctx.Final(mac.data()); + for (unsigned i = 0; i < h256::size; i++) + if (mac[i] != msgMac[i]) + return false; + + plain = decryptSymNoAuth(SecureFixedHash<16>(eKey), iv, cipherNoIV).makeInsecure(); + io_text.resize(plain.size()); + io_text.swap(plain); + + return true; +} + +void Secp256k1PP::encrypt(Public const& _k, bytes& io_cipher) +{ + ECIES<ECP>::Encryptor e; + initializeDLScheme(_k, e); + + size_t plen = io_cipher.size(); + bytes ciphertext; + ciphertext.resize(e.CiphertextLength(plen)); + + { + Guard l(x_rng); + e.Encrypt(m_rng, io_cipher.data(), plen, ciphertext.data()); + } + + memset(io_cipher.data(), 0, io_cipher.size()); + io_cipher = std::move(ciphertext); +} + +void Secp256k1PP::decrypt(Secret const& _k, bytes& io_text) +{ + CryptoPP::ECIES<CryptoPP::ECP>::Decryptor d; + initializeDLScheme(_k, d); + + if (!io_text.size()) + { + io_text.resize(1); + io_text[0] = 0; + } + + size_t clen = io_text.size(); + bytes plain; + plain.resize(d.MaxPlaintextLength(io_text.size())); + + DecodingResult r; + { + Guard l(x_rng); + r = d.Decrypt(m_rng, io_text.data(), clen, plain.data()); + } + + if (!r.isValidCoding) + { + io_text.clear(); + return; + } + + io_text.resize(r.messageLength); + io_text = std::move(plain); +} + +Signature Secp256k1PP::sign(Secret const& _k, bytesConstRef _message) +{ + return sign(_k, sha3(_message)); +} + +Signature Secp256k1PP::sign(Secret const& _key, h256 const& _hash) +{ + // assumption made by signing alogrithm + assert(m_q == m_qs); + + Signature sig; + + Integer k(kdf(_key, _hash).data(), 32); + if (k == 0) + BOOST_THROW_EXCEPTION(InvalidState()); + k = 1 + (k % (m_qs - 1)); + + ECP::Point rp; + Integer r; + { + Guard l(x_params); + rp = m_params.ExponentiateBase(k); + r = m_params.ConvertElementToInteger(rp); + } + sig[64] = 0; +// sig[64] = (r >= m_q) ? 2 : 0; + + Integer kInv = k.InverseMod(m_q); + Integer z(_hash.asBytes().data(), 32); + Integer s = (kInv * (Integer(_key.data(), 32) * r + z)) % m_q; + if (r == 0 || s == 0) + BOOST_THROW_EXCEPTION(InvalidState()); + +// if (s > m_qs) +// { +// s = m_q - s; +// if (sig[64]) +// sig[64] ^= 1; +// } + + sig[64] |= rp.y.IsOdd() ? 1 : 0; + r.Encode(sig.data(), 32); + s.Encode(sig.data() + 32, 32); + return sig; +} + +bool Secp256k1PP::verify(Signature const& _signature, bytesConstRef _message) +{ + return !!recover(_signature, _message); +} + +bool Secp256k1PP::verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed) +{ + // todo: verify w/o recovery (if faster) + return _p == (_hashed ? recover(_sig, _message) : recover(_sig, sha3(_message).ref())); +} + +Public Secp256k1PP::recover(Signature _signature, bytesConstRef _message) +{ + Public recovered; + + Integer r(_signature.data(), 32); + Integer s(_signature.data()+32, 32); + // cryptopp encodes sign of y as 0x02/0x03 instead of 0/1 or 27/28 + byte encodedpoint[33]; + encodedpoint[0] = _signature[64] | 2; + memcpy(&encodedpoint[1], _signature.data(), 32); + + ECP::Element x; + { + m_curve.DecodePoint(x, encodedpoint, 33); + if (!m_curve.VerifyPoint(x)) + return recovered; + } + +// if (_signature[64] & 2) +// { +// r += m_q; +// Guard l(x_params); +// if (r >= m_params.GetMaxExponent()) +// return recovered; +// } + + Integer z(_message.data(), 32); + Integer rn = r.InverseMod(m_q); + Integer u1 = m_q - (rn.Times(z)).Modulo(m_q); + Integer u2 = (rn.Times(s)).Modulo(m_q); + + ECP::Point p; + byte recoveredbytes[65]; + { + // todo: make generator member + p = m_curve.CascadeMultiply(u2, x, u1, m_params.GetSubgroupGenerator()); + if (p.identity) + return Public(); + m_curve.EncodePoint(recoveredbytes, p, false); + } + memcpy(recovered.data(), &recoveredbytes[1], 64); + return recovered; +} + +bool Secp256k1PP::verifySecret(Secret const& _s, Public& _p) +{ + DL_PrivateKey_EC<ECP> k; + k.Initialize(m_params, secretToExponent(_s)); + if (!k.Validate(m_rng, 3)) + return false; + + DL_PublicKey_EC<CryptoPP::ECP> pub; + k.MakePublicKey(pub); + if (!k.Validate(m_rng, 3)) + return false; + + exportPublicKey(pub, _p); + return true; +} + +void Secp256k1PP::agree(Secret const& _s, Public const& _r, Secret& o_s) +{ + // TODO: mutex ASN1::secp256k1() singleton + // Creating Domain is non-const for m_oid and m_oid is not thread-safe + ECDH<ECP>::Domain d(ASN1::secp256k1()); + assert(d.AgreedValueLength() == sizeof(o_s)); + byte remote[65] = {0x04}; + memcpy(&remote[1], _r.data(), 64); + d.Agree(o_s.writable().data(), _s.data(), remote); +} + +void Secp256k1PP::exportPublicKey(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> const& _k, Public& o_p) +{ + bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true)); + + { + Guard l(x_params); + m_params.GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false); + assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true)); + } + + memcpy(o_p.data(), &prefixedKey[1], Public::size); +} + +void Secp256k1PP::exponentToPublic(Integer const& _e, Public& o_p) +{ + CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> pk; + + { + Guard l(x_params); + pk.Initialize(m_params, m_params.ExponentiateBase(_e)); + } + + exportPublicKey(pk, o_p); +} +#pragma GCC diagnostic pop diff --git a/src/ringdht/eth/libdevcrypto/CryptoPP.h b/src/ringdht/eth/libdevcrypto/CryptoPP.h new file mode 100644 index 0000000000000000000000000000000000000000..329edfaf70813fc0c80e4ce044eb2de6916e18eb --- /dev/null +++ b/src/ringdht/eth/libdevcrypto/CryptoPP.h @@ -0,0 +1,154 @@ +/* + 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 CryptoPP.h + * @author Alex Leverington <nessence@gmail.com> + * @date 2014 + * + * CryptoPP headers and primitive helper methods + */ + +#pragma once + +#include <mutex> +// need to leave this one disabled for link-time. blame cryptopp. +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma warning(push) +#pragma warning(disable:4100 4244) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" +#pragma GCC diagnostic ignored "-Wextra" +#include <cryptopp/sha.h> +//#include <cryptopp/sha3.h> +#include <cryptopp/ripemd.h> +#include <cryptopp/aes.h> +#include <cryptopp/pwdbased.h> +#include <cryptopp/modes.h> +#include <cryptopp/filters.h> +#include <cryptopp/eccrypto.h> +#include <cryptopp/ecp.h> +#include <cryptopp/files.h> +#include <cryptopp/osrng.h> +#include <cryptopp/oids.h> +#include <cryptopp/dsa.h> +#pragma warning(pop) +#pragma GCC diagnostic pop +#include "libdevcore/SHA3.h" +#include "Common.h" + +namespace dev +{ +namespace crypto +{ + +using namespace CryptoPP; + +inline ECP::Point publicToPoint(Public const& _p) { Integer x(_p.data(), 32); Integer y(_p.data() + 32, 32); return ECP::Point(x,y); } + +inline Integer secretToExponent(Secret const& _s) { return std::move(Integer(_s.data(), Secret::size)); } + +/// Amount of bytes added when encrypting with encryptECIES. +static const unsigned c_eciesOverhead = 113; + +/** + * CryptoPP secp256k1 algorithms. + * @todo Collect ECIES methods into class. + */ +class Secp256k1PP +{ +public: + static Secp256k1PP* get() { if (!s_this) s_this = new Secp256k1PP; return s_this; } + + void toPublic(Secret const& _s, Public& o_public) { exponentToPublic(Integer(_s.data(), sizeof(_s)), o_public); } + + /// Encrypts text (replace input). (ECIES w/XOR-SHA1) + void encrypt(Public const& _k, bytes& io_cipher); + + /// Decrypts text (replace input). (ECIES w/XOR-SHA1) + void decrypt(Secret const& _k, bytes& io_text); + + /// Encrypts text (replace input). (ECIES w/AES128-CTR-SHA256) + void encryptECIES(Public const& _k, bytes& io_cipher); + + /// Encrypts text (replace input). (ECIES w/AES128-CTR-SHA256) + void encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytes& io_cipher); + + /// Decrypts text (replace input). (ECIES w/AES128-CTR-SHA256) + bool decryptECIES(Secret const& _k, bytes& io_text); + + /// Decrypts text (replace input). (ECIES w/AES128-CTR-SHA256) + bool decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytes& io_text); + + /// Key derivation function used by encryptECIES and decryptECIES. + bytes eciesKDF(Secret const& _z, bytes _s1, unsigned kdBitLen = 256); + + /// @returns siganture of message. + Signature sign(Secret const& _k, bytesConstRef _message); + + /// @returns compact siganture of provided hash. + Signature sign(Secret const& _k, h256 const& _hash); + + /// Verify compact signature (public key is extracted from signature). + bool verify(Signature const& _signature, bytesConstRef _message); + + /// Verify signature. + bool verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed = false); + + /// Recovers public key from compact signature. Uses libsecp256k1. + Public recover(Signature _signature, bytesConstRef _message); + + /// Verifies _s is a valid secret key and returns corresponding public key in o_p. + bool verifySecret(Secret const& _s, Public& o_p); + + void agree(Secret const& _s, Public const& _r, Secret& o_s); + +protected: + void exportPrivateKey(DL_PrivateKey_EC<ECP> const& _k, Secret& o_s) { _k.GetPrivateExponent().Encode(o_s.writable().data(), Secret::size); } + + void exportPublicKey(DL_PublicKey_EC<ECP> const& _k, Public& o_p); + + void exponentToPublic(Integer const& _e, Public& o_p); + + template <class T> void initializeDLScheme(Secret const& _s, T& io_operator) { std::lock_guard<std::mutex> l(x_params); io_operator.AccessKey().Initialize(m_params, secretToExponent(_s)); } + + template <class T> void initializeDLScheme(Public const& _p, T& io_operator) { std::lock_guard<std::mutex> l(x_params); io_operator.AccessKey().Initialize(m_params, publicToPoint(_p)); } + +private: + Secp256k1PP(): m_oid(ASN1::secp256k1()), m_params(m_oid), m_curve(m_params.GetCurve()), m_q(m_params.GetGroupOrder()), m_qs(m_params.GetSubgroupOrder()) {} + + OID m_oid; + + std::mutex x_rng; + AutoSeededRandomPool m_rng; + + std::mutex x_params; + DL_GroupParameters_EC<ECP> m_params; + + std::mutex x_curve; + DL_GroupParameters_EC<ECP>::EllipticCurve m_curve; + + Integer m_q; + Integer m_qs; + + static Secp256k1PP* s_this; +}; + +} +} + diff --git a/src/ringdht/eth/libdevcrypto/ECDHE.cpp b/src/ringdht/eth/libdevcrypto/ECDHE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf7139a48d2aa8f00538195da45450f788fc1022 --- /dev/null +++ b/src/ringdht/eth/libdevcrypto/ECDHE.cpp @@ -0,0 +1,44 @@ +/* + 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 ECDHE.cpp + * @author Alex Leverington <nessence@gmail.com> + * @date 2014 + */ + +#include "ECDHE.h" +#include <libdevcore/SHA3.h> +#include "CryptoPP.h" + +using namespace std; +using namespace dev; +using namespace dev::crypto; + +void dev::crypto::ecdh::agree(Secret const& _s, Public const& _r, Secret& o_s) +{ + Secp256k1PP::get()->agree(_s, _r, o_s); +} + +void ECDHE::agree(Public const& _remote, Secret& o_sharedSecret) const +{ + if (m_remoteEphemeral) + // agreement can only occur once + BOOST_THROW_EXCEPTION(InvalidState()); + + m_remoteEphemeral = _remote; + Secp256k1PP::get()->agree(m_ephemeral.sec(), m_remoteEphemeral, o_sharedSecret); +} + diff --git a/src/ringdht/eth/libdevcrypto/ECDHE.h b/src/ringdht/eth/libdevcrypto/ECDHE.h new file mode 100644 index 0000000000000000000000000000000000000000..3658caf3d7f08a46d3dbfd46335ff4897db18810 --- /dev/null +++ b/src/ringdht/eth/libdevcrypto/ECDHE.h @@ -0,0 +1,81 @@ +/* + 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 ECDHE.h + * @author Alex Leverington <nessence@gmail.com> + * @date 2014 + * + * Elliptic curve Diffie-Hellman ephemeral key exchange + */ + +#pragma once + +#include "AES.h" + +namespace dev +{ +namespace crypto +{ + +/// Public key of remote and corresponding shared secret. +using AliasSession = std::pair<Public,h256>; + +/** + * @brief An addressable EC key pair. + */ +class Alias +{ +public: + Alias(Secret const& _s): m_secret(_s) {}; + + AliasSession session(Address _a) { return m_sessions.count(_a) ? m_sessions.find(_a)->second : AliasSession(); } + +private: + std::map<Address,AliasSession> m_sessions; + Secret m_secret; +}; + +namespace ecdh +{ +void agree(Secret const& _s, Public const& _r, Secret& o_s); +} + +/** + * @brief Derive DH shared secret from EC keypairs. + * As ephemeral keys are single-use, agreement is limited to a single occurence. + */ +class ECDHE +{ +public: + /// Constructor (pass public key for ingress exchange). + ECDHE(): m_ephemeral(KeyPair::create()) {}; + + /// Public key sent to remote. + Public pubkey() { return m_ephemeral.pub(); } + + Secret seckey() { return m_ephemeral.sec(); } + + /// Input public key for dh agreement, output generated shared secret. + void agree(Public const& _remoteEphemeral, Secret& o_sharedSecret) const; + +protected: + KeyPair m_ephemeral; ///< Ephemeral keypair; generated. + mutable Public m_remoteEphemeral; ///< Public key of remote; parameter. Set once when agree is called, otherwise immutable. +}; + +} +} + diff --git a/src/ringdht/eth/libdevcrypto/Exceptions.h b/src/ringdht/eth/libdevcrypto/Exceptions.h new file mode 100644 index 0000000000000000000000000000000000000000..858374bda8adfd98240c21fbd29aefc19e1be3b7 --- /dev/null +++ b/src/ringdht/eth/libdevcrypto/Exceptions.h @@ -0,0 +1,35 @@ +/* + 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 Christian <c@ethdev.com> + * @date 2016 + */ + +#pragma once + +#include <libdevcore/Exceptions.h> + +namespace dev +{ +namespace crypto +{ + +/// Rare malfunction of cryptographic functions. +DEV_SIMPLE_EXCEPTION(CryptoException); + +} +} diff --git a/src/ringdht/eth/libdevcrypto/Makefile.am b/src/ringdht/eth/libdevcrypto/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..b94f7ce16c42c311b4bf497372183a8960552332 --- /dev/null +++ b/src/ringdht/eth/libdevcrypto/Makefile.am @@ -0,0 +1,11 @@ +include $(top_srcdir)/globals.mak + +AM_CPPFLAGS += -I../ +noinst_LTLIBRARIES = libdevcrypto.la +libdevcrypto_la_CPPFLAGS = @CPPFLAGS@ -I$(top_srcdir)/src -I$(top_srcdir)/src/ringdht/eth -DBOOST_SYSTEM_NO_DEPRECATED +libdevcrypto_la_CXXFLAGS = @CXXFLAGS@ + +libdevcrypto_la_SOURCES = AES.cpp \ + ECDHE.cpp \ + Common.cpp \ + CryptoPP.cpp