From b8a208d3a5a8dd5fa6accbb0913df2512f846b87 Mon Sep 17 00:00:00 2001 From: heck Date: Tue, 12 Oct 2021 21:01:02 +0200 Subject: [PATCH] std_utils - Templatize bin2hex() / hex2bin() FIX: The random generators, they were totally broken. (exhausting the entropy pool) --- src/std_utils.cc | 63 ++++++++++++++--------------------------------- src/std_utils.hh | 8 ++++-- src/std_utils.hxx | 43 ++++++++++++++++++++++++++++++++ test/test_rand.cc | 47 +++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 46 deletions(-) create mode 100644 test/test_rand.cc diff --git a/src/std_utils.cc b/src/std_utils.cc index 4c03ae4..50004f9 100644 --- a/src/std_utils.cc +++ b/src/std_utils.cc @@ -342,64 +342,39 @@ namespace pEp { std::this_thread::sleep_for(timespan); } + int fastrand(int max) + { + static int g_seed = static_cast( + std::chrono::system_clock::now().time_since_epoch().count()); + g_seed = (214013 * g_seed + 2531011); + return ((g_seed >> 16) & 0x7FFF) % max + 1; + } + unsigned char random_char(unsigned char min, unsigned char max) { - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution dis(static_cast(min), static_cast(max)); - return static_cast(dis(gen)); + static unsigned seed1 = std::chrono::system_clock::now().time_since_epoch().count(); + static std::mt19937 gen{ seed1 }; + static std::uniform_int_distribution dis(min, max); + return dis(gen); } std::string random_string(unsigned char min, unsigned char max, int len) { std::stringstream ret; for (int i = 0; i < len; i++) { - ret << random_char(97, 122); + ret << random_char(min, max); } return ret.str(); } - std::string bin2hex(const std::vector &bin) + std::string random_string_fast(unsigned char min, unsigned char max, int len) { - std::string ret{}; - std::stringstream ss{}; - for (const auto &i : bin) { - ss << std::hex << std::setfill('0') << std::setw(2) << (int)i; - } - ret = ss.str(); - return ret; - } - - std::vector hex2bin(const std::string &hex_str) - { - std::vector ret{}; - if ((hex_str.size() % 2) != 0) { - throw std::runtime_error("hex2bin: Invalid hex string: must be even length"); - } - for (int i = 0; i < hex_str.size(); i += 2) { - std::ostringstream val_hex{}; - val_hex << hex_str.at(i); - val_hex << hex_str.at(i + 1); - - int val_int; - std::istringstream conv_ss{ val_hex.str() }; - conv_ss >> std::hex >> val_int; - if (conv_ss.fail()) { - throw std::runtime_error("hex2bin: invalid hex string" + hex_str); - } - ret.push_back((unsigned char)val_int); + int range = std::max(max - min, 1); + std::stringstream ret; + for (int i = 0; i < len; i++) { + ret << (fastrand(range) + min); } - return ret; - - // alternative way - // std::string extract; - // for (std::string::const_iterator pos = hex_str.begin(); pos < hex_str.end(); pos += 2) { - // extract.assign(pos, pos + 2); - // ret.push_back(std::stoi(extract, nullptr, 16)); - // } - // return ret; + return ret.str(); } - - } // namespace Utils } // namespace pEp diff --git a/src/std_utils.hh b/src/std_utils.hh index 63f83a8..dafb5f7 100644 --- a/src/std_utils.hh +++ b/src/std_utils.hh @@ -93,12 +93,16 @@ namespace pEp { void sleep_millis(int milis); // Random + int fastrand(int max); unsigned char random_char(unsigned char min, unsigned char max); std::string random_string(unsigned char min, unsigned char max, int len); + std::string random_string_fast(unsigned char min, unsigned char max, int len); // conversion - std::vector hex2bin(const std::string &hex_str); - std::string bin2hex(const std::vector& bin); + template + std::string bin2hex(const T &bin); + template + T hex2bin(const std::string &hex_str); } // namespace Utils } // namespace pEp diff --git a/src/std_utils.hxx b/src/std_utils.hxx index f7183de..3e733fe 100644 --- a/src/std_utils.hxx +++ b/src/std_utils.hxx @@ -48,6 +48,49 @@ namespace pEp { } } + template + std::string bin2hex(const T &bin) + { + std::string ret{}; + std::stringstream ss{}; + for (const auto &i : bin) { + ss << std::hex << std::setfill('0') << std::setw(2) << (int)i; + } + ret = ss.str(); + return ret; + } + + template + T hex2bin(const std::string &hex_str) + { + T ret{}; + if ((hex_str.size() % 2) != 0) { + throw std::runtime_error("hex2bin: Invalid hex string: must be even length"); + } + for (int i = 0; i < hex_str.size(); i += 2) { + std::ostringstream val_hex{}; + val_hex << hex_str.at(i); + val_hex << hex_str.at(i + 1); + + int val_int; + std::istringstream conv_ss{ val_hex.str() }; + conv_ss >> std::hex >> val_int; + if (conv_ss.fail()) { + throw std::runtime_error("hex2bin: invalid hex string" + hex_str); + } + ret.push_back(static_cast(val_int)); + } + return ret; + + // alternative way + // std::string extract; + // for (std::string::const_iterator pos = hex_str.begin(); pos < hex_str.end(); pos += 2) { + // extract.assign(pos, pos + 2); + // ret.push_back(std::stoi(extract, nullptr, 16)); + // } + // return ret; + } + } // namespace Utils } // namespace pEp #endif // LIBPEPADAPTER_STD_UTILS_HXX diff --git a/test/test_rand.cc b/test/test_rand.cc new file mode 100644 index 0000000..f4b33a8 --- /dev/null +++ b/test/test_rand.cc @@ -0,0 +1,47 @@ +#include "../src/std_utils.hh" +#include "pEp/pEpLog.hh" +#include +#include +#include + +using namespace pEp; + +int main() +{ + pEp::Adapter::pEpLog::set_enabled(true); + + pEpLog("Random functions benchmark"); + int nr_mb = 10; + int nr_bytes = 1024 * 1024 * nr_mb; + pEpLog("generating " + std::to_string(nr_mb) + "MB's of random"); + + { + pEpLog("Utils::random_char()"); + auto time_start = std::chrono::steady_clock::now(); + for (int i = 0; i < nr_bytes; i++) { + Utils::random_char(0, 255); + } + auto time_end = std::chrono::steady_clock::now(); + double duration_ms = (double)std::chrono::duration_cast( + time_end - time_start) + .count() / + 1000; + pEpLog("Time [ms/mbyte]:" + std::to_string(duration_ms / double(nr_mb))); + } + std::cout << "" << std::endl; + { + pEpLog("Utils::Fastrand()"); + auto time_start = std::chrono::steady_clock::now(); + for (int i = 0; i < nr_bytes; i++) { + Utils::fastrand(255); + } + auto time_end = std::chrono::steady_clock::now(); + double duration_ms = (double)std::chrono::duration_cast( + time_end - time_start) + .count() / + 1000; + + pEpLog("Time [ms/mbyte]:" + std::to_string(duration_ms / double(nr_mb))); + } + return 0; +}