diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 8567ac12b..94f78b1e2 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -254,42 +254,71 @@ h256 crypto::kdf(Secret const& _priv, h256 const& _hash) return s; } -h256 Nonce::get(bool _commit) +mutex Nonce::s_x; + +h256 Nonce::get() { // todo: atomic efface bit, periodic save, kdf, rr, rng // todo: encrypt - static h256 s_seed; - static string s_seedFile(getDataDir() + "/seed"); - static mutex s_x; - Guard l(s_x); - if (!s_seed) + Guard l(Nonce::s_x); + return Nonce::singleton().next(); +} + +// get: Called for the first time: read seed hash from file (or generate) +// before destruction: increment current value and store + +Nonce::~Nonce() +{ + Guard l(Nonce::s_x); + // These might throw. + next(); + commit(); +} + +Nonce& Nonce::singleton() +{ + static Nonce s; + return s; +} + +void Nonce::initialiseIfNeeded() +{ + if (m_value) + return; + + bytes b = contents(seedFile()); + if (b.size() == 32) + memcpy(m_value.data(), b.data(), 32); + else { - static Nonce s_nonce; - bytes b = contents(s_seedFile); - if (b.size() == 32) - memcpy(s_seed.data(), b.data(), 32); - else - { - // todo: replace w/entropy from user and system - std::mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count()); - std::uniform_int_distribution d(0, 255); - for (unsigned i = 0; i < 32; ++i) - s_seed[i] = (byte)d(s_eng); - } - if (!s_seed) - BOOST_THROW_EXCEPTION(InvalidState()); - - // prevent seed reuse if process terminates abnormally - try { writeFile(s_seedFile, bytes()); } catch (FileError const&) {} + // todo: replace w/entropy from user and system + std::mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count()); + std::uniform_int_distribution d(0, 255); + for (unsigned i = 0; i < 32; ++i) + m_value[i] = byte(d(s_eng)); } - h256 prev(s_seed); - sha3(prev.ref(), s_seed.ref()); - if (_commit) - try { writeFile(s_seedFile, s_seed.asBytes()); } catch (FileError const&) {} - return std::move(s_seed); + if (!m_value) + BOOST_THROW_EXCEPTION(InvalidState()); + + // prevent seed reuse if process terminates abnormally + // this might throw + writeFile(seedFile(), bytes()); } -Nonce::~Nonce() +h256 Nonce::next() +{ + initialiseIfNeeded(); + m_value = sha3(m_value); + return m_value; +} + +void Nonce::commit() +{ + // this might throw + writeFile(seedFile(), m_value.asBytes()); +} + +string Nonce::seedFile() { - Nonce::get(true); + return getDataDir() + "/seed"; } diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 7bb51e563..96f525e49 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -24,6 +24,7 @@ #pragma once +#include #include #include #include @@ -180,14 +181,30 @@ struct InvalidState: public dev::Exception {}; h256 kdf(Secret const& _priv, h256 const& _hash); /** - * @brief Generator for nonce material + * @brief Generator for nonce material. */ struct Nonce { - static h256 get(bool _commit = false); + static h256 get(); private: Nonce() {} ~Nonce(); + /// @returns the singleton instance. + static Nonce& singleton(); + /// Reads the last seed from the seed file. + void initialiseIfNeeded(); + /// @returns the next nonce. + h256 next(); + /// Stores the current seed in the seed file. + void commit(); + /// @returns the path of the seed file. + static std::string seedFile(); + + /// Mutex for the singleton object. + /// @note Every access to any private function has to be guarded by this mutex. + static std::mutex s_x; + + h256 m_value; }; } diff --git a/libdevcrypto/Exceptions.h b/libdevcrypto/Exceptions.h index 675213d8b..858374bda 100644 --- a/libdevcrypto/Exceptions.h +++ b/libdevcrypto/Exceptions.h @@ -29,7 +29,7 @@ namespace crypto { /// Rare malfunction of cryptographic functions. -DEV_SIMPLE_EXCEPTION_RLP(CryptoException); +DEV_SIMPLE_EXCEPTION(CryptoException); } }