diff --git a/libethereum/Dagger.cpp b/libethereum/Dagger.cpp new file mode 100644 index 000000000..bb87b4916 --- /dev/null +++ b/libethereum/Dagger.cpp @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include "Common.h" +#include "Dagger.h" +using namespace std; +using namespace std::chrono; +using namespace eth; + +Dagger::Dagger(u256 _hash): m_hash(_hash) +{ +} + +Dagger::~Dagger() +{ +} + +u256 Dagger::search(uint _msTimeout, u256 _diff) +{ + static mt19937_64 s_engine((std::random_device())()); + u256 bound = (u256)((bigint(1) << 256) / _diff); + + auto start = steady_clock::now(); + + while (steady_clock::now() - start < milliseconds(_msTimeout)) + for (uint sp = std::uniform_int_distribution()(s_engine), j = 0; j < 1000; ++j, ++sp) + if (eval(sp) < bound) + return sp; + return 0; +} + +template +inline void update(_T& _sha, u256 const& _value) +{ + std::array buf; + toBigEndian(_value, buf); + _sha.Update(buf.data(), 32); +} + +template +inline u256 get(_T& _sha) +{ + byte buf[32]; + _sha.TruncatedFinal(buf, 32); + return fromBigEndian(bytesConstRef(buf, 32)); +} + +u256 Dagger::node(uint_fast32_t _L, uint_fast32_t _i) const +{ + if (!_L && !_i) + return m_hash; + u256 m = (_L == 9) ? 16 : 3; + CryptoPP::SHA3_256 bsha; + for (uint_fast32_t k = 0; k < m; ++k) + { + CryptoPP::SHA3_256 sha; + update(sha, m_hash); + update(sha, m_xn); + update(sha, (u256)_L); + update(sha, (u256)_i); + update(sha, (u256)k); + uint_fast32_t pk = (uint_fast32_t)get(sha) & ((1 << ((_L - 1) * 3)) - 1); + update(bsha, node(_L - 1, pk)); + } + return get(bsha); +} + +u256 Dagger::eval(u256 _N) +{ + m_xn = _N >> 26; // with xn = floor(n / 2^26) -> assuming this is with xn = floor(N / 2^26) + CryptoPP::SHA3_256 bsha; + for (uint_fast32_t k = 0; k < 4; ++k) + { + //sha256(D || xn || i || k) -> sha256(D || xn || k) - there's no 'i' here! + CryptoPP::SHA3_256 sha; + update(sha, m_hash); + update(sha, m_xn); + update(sha, _N); + update(sha, (u256)k); + uint_fast32_t pk = (uint_fast32_t)get(sha) & 0x1ffffff; // mod 8^8 * 2 [ == mod 2^25 ?! ] [ == & ((1 << 25) - 1) ] [ == & 0x1ffffff ] + update(bsha, node(9, pk)); + } + return get(bsha); +} diff --git a/libethereum/Dagger.h b/libethereum/Dagger.h new file mode 100644 index 000000000..59884ded5 --- /dev/null +++ b/libethereum/Dagger.h @@ -0,0 +1,26 @@ +#pragma once + +#include "Common.h" + +namespace eth +{ + +/// Functions are not re-entrant. If you want to multi-thread, then use different classes for each thread. +class Dagger +{ +public: + Dagger(u256 _hash); + ~Dagger(); + + u256 node(uint_fast32_t _L, uint_fast32_t _i) const; + u256 eval(u256 _N); + u256 search(uint _msTimeout, u256 _diff); + +private: + u256 m_hash; + u256 m_xn; +}; + +} + + diff --git a/test/main.cpp b/test/main.cpp index 551b21abb..2216e8776 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -21,18 +21,28 @@ */ #include +#include #include #include +#include "Dagger.h" #include "RLP.h" #include "Trie.h" #include "State.h" using namespace std; +using namespace std::chrono; using namespace eth; // TODO: utilise the shared testdata. int main() { + // Test dagger + { + Dagger d(1); + auto s = steady_clock::now(); + cout << hex << d.eval(0); + cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl; + } /* // Test transaction. bytes tx = fromUserHex("88005401010101010101010101010101010101010101011f0de0b6b3a76400001ce8d4a5100080181c373130a009ba1f10285d4e659568bfcfec85067855c5a3c150100815dad4ef98fd37cf0593828c89db94bd6c64e210a32ef8956eaa81ea9307194996a3b879441f5d");