#ifndef FORTUNA_FORTUNA_CPP #define FORTUNA_FORTUNA_CPP #include "fortuna.h" #include "seed_file_management.h" #include "util.h" #include #include #include #include #include #include namespace fortuna { static constexpr const unsigned int min_pool_size{64}; auto now{std::chrono::steady_clock::now()}; Fortuna::Fortuna() { try { initialize_prng(); } catch (CryptoPP::Exception& e) { fmt::print(stderr, "{}\n", e.what()); } th_gen = std::thread(&Fortuna::generator_service, this, std::make_shared()); th_accu = std::thread(&Fortuna::accumulator_service, this); th_sfm = std::thread(&Fortuna::seed_file_manager_service, this); } Fortuna::~Fortuna() noexcept { if (th_gen.joinable()) { th_gen.join(); } if (th_gen.joinable()) { th_accu.join(); } if (th_sfm.joinable()) { th_sfm.join(); } } auto Fortuna::random_data(unsigned int n_bytes) -> void { const auto start{std::chrono::system_clock::now()}; fmt::print("random_data starting - {}\n", start); auto elapsed{std::chrono::duration_cast( std::chrono::steady_clock::now().time_since_epoch() - now.time_since_epoch())}; fmt::print("[i] fortuna: last_reseed: {} ago\n", elapsed); now = std::chrono::steady_clock::now(); std::string s; // synchronise reads and writes to the between // {generator,accumulator,fortuna} service threads -> in member functions const int pools_to_use{ffsll(static_cast(get_reseed_ctr()))}; fmt::print("[*] fortuna: current p0 length: {}\n", R.pools[0].get_s_length()); if (R.pools[0].get_s_length() >= min_pool_size && elapsed > R.Gen.reseed_interval) { for (int i = 0; i < static_cast(pools_to_use); ++i) { if (R.reseed_ctr % static_cast(pow(2, i)) == 0) { try { s.append(fortuna::Util::do_sha(R.pools[i].get_s())); R.pools[i].clear_pool(); } catch (std::exception& e) { fmt::print("{}\n", e.what()); } } } incr_reseed_ctr(); R.Gen.reseed(s); R.last_reseed = std::chrono::steady_clock::now(); s.clear(); } fmt::print("[i] fortuna: reseed ctr {}\n", R.reseed_ctr); if (R.reseed_ctr == 0) { fmt::print("[!] ERROR: reseed ctr is 0, PRNG not seeded!\n"); throw std::runtime_error("illegal state, PRNG not seeded"); } else { std::string n{R.Gen.generate_random_data(n_bytes)}; fmt::print("got you {} proper bytes from generate_random_data -> {}\n", n_bytes, n); n.clear(); } const auto end{std::chrono::system_clock::now()}; std::chrono::duration diff = end - start; fmt::print("random_data done - {}\n", end); fmt::print("getting random data took {:.{}f}s\n", diff.count(), 12); } // random_data auto Fortuna::generator_service( std::shared_ptr Gen) -> void { int i{0}; std::chrono::milliseconds sleep_time{1000}; std::chrono::system_clock::time_point time_point; std::unique_lock p_ul(print_mtx); fmt::print("[i] fortuna: starting generator service\n"); p_ul.unlock(); while (true) { p_ul.lock(); fmt::print("[*] g: sleeping [{}]\n", i); p_ul.unlock(); ++i; time_point = fortuna::Util::current_time(); p_ul.lock(); fmt::print("[*] g: @{}\n", time_point); p_ul.unlock(); std::this_thread::sleep_until(time_point + std::chrono::milliseconds(sleep_time)); } } auto Fortuna::accumulator_service() -> void { std::chrono::seconds sleep_time{10}; std::chrono::system_clock::time_point time_point; std::unique_lock p_ul(print_mtx); fmt::print("[i] fortuna: starting accumulator service\n"); p_ul.unlock(); while (true) { time_point = fortuna::Util::current_time(); p_ul.lock(); fmt::print("[*] accu: @{}\n", time_point); p_ul.unlock(); std::this_thread::sleep_until(time_point + std::chrono::seconds(sleep_time)); } } auto Fortuna::seed_file_manager_service() -> void { static constexpr const std::chrono::seconds checkup_interval{10}; std::unique_lock p_ul(print_mtx); fmt::print("[i] fortuna: starting seed file manager service\n"); fmt::print("[*] sfm: checkup interval {}\n", checkup_interval); p_ul.unlock(); auto right_now{fortuna::Util::current_time()}; std::unique_lock mtx_l(mtx); std::unique_lock a_ul(accu_mtx); SeedFileManager sfm(this->accumulator); a_ul.unlock(); mtx_l.unlock(); while (true) { right_now = fortuna::Util::current_time(); p_ul.lock(); fmt::print("[*] sfm: checkup time @{}\n", right_now); if (!sfm.is_job_running()) { fmt::print("[*] sfm: job not running, starting\n"); try { sfm.do_stuff(); } catch (std::exception& e) { fmt::print(stderr, "[!] sfm: exception caught: {}\n", e.what()); } } else { fmt::print("[*] sfm: job running\n"); } p_ul.unlock(); std::this_thread::sleep_until(right_now + std::chrono::seconds(checkup_interval)); } } } // namespace fortuna #endif // FORTUNA_FORTUNA_CPP