From fc9f82b6e510ff40b8ac397fe241247ae4cb1361 Mon Sep 17 00:00:00 2001 From: Cheng Date: Sun, 24 Sep 2023 15:21:18 +1000 Subject: [PATCH] Documented a bit of code that I had started to forget. Remade hashing according to the dry principle, eliminating much code repetition. Introduced c++20 "concepts" to radically reduce verbose and incomprehensible template metacode. modified: src/db_accessors.h modified: src/ristretto255.h modified: src/testbed.cpp --- src/ILog.cpp | 7 +++- src/db_accessors.h | 2 +- src/ristretto255.h | 97 +++++++++++++++++++--------------------------- src/testbed.cpp | 10 +++-- 4 files changed, 51 insertions(+), 65 deletions(-) diff --git a/src/ILog.cpp b/src/ILog.cpp index 1fa6f2c..f02728e 100644 --- a/src/ILog.cpp +++ b/src/ILog.cpp @@ -35,8 +35,11 @@ void queue_error_message(const char* psz) { void queue_fatal_error(const char* psz) { // Used where throwing immediately would be disastrous, as in a destructor or when constructing the main frame if (!errorCode)errorCode = 10; - queue_error_message(psz); - singletonFrame->Close(); + queue_error_message(psz); // Message continues to display, + // even after App window that contains the frame has closed + singletonFrame->Close(); // Generates close event, which is handled as usual after this returns + // Main window closes after the close message is handled, but App still running, displaying the message + // put up by queue_error_message. When that message is closed, App finally terminates. } MyException::MyException(const char* sz, int i, const char* func__, const char* FILE__) noexcept : diff --git a/src/db_accessors.h b/src/db_accessors.h index e68d6c0..531176e 100644 --- a/src/db_accessors.h +++ b/src/db_accessors.h @@ -107,7 +107,7 @@ namespace ro { template < typename T, typename std::enable_if::value, int >::type dummy_arg = 0 > void bind(int i, const T& j) { - static_assert(ro::is_serializable::value, "Don't know how to store this type in a database"); + static_assert(ro::serializable, "Don't know how to store this type in a database"); (*this)->Isqlite3_bind(i, ro::serialize(j)); } typedef Icompiled_sql::sql_result result; diff --git a/src/ristretto255.h b/src/ristretto255.h index 67269cf..883902b 100644 --- a/src/ristretto255.h +++ b/src/ristretto255.h @@ -175,6 +175,8 @@ namespace ro { apt to unhelpfully and unexpectedly turn it into a wxString, If you make wxStrings hashable, suprising things become hashable. + However, we do make the strange data structure provided by wxString.ToUTF8() hashable, + so that the wxString will not be implicitly hashable, but will be explicitly hashable. */ // data structure containing a serialized signed integer. @@ -334,7 +336,7 @@ namespace ro { currency is fixed at 2^64-1 which will suffice for a thousand years. Or we might allow arbitrary precision floating point with powers of a thousand, so that sensible numbers to a human are represented by - sensible numbers in the actuall representation. + sensible numbers in the actual representation. secret keys, scalars are actually much larger numbers, modulo 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ecU @@ -359,8 +361,13 @@ namespace ro { } static constexpr bool value = is_serializable::template test(); }; - static_assert(ro::is_serializable>::value); - static_assert(ro::is_serializable>::value); + + template + concept serializable = is_serializable::value; + + static_assert( !serializable + && serializable, char*, std::span>, + "concepts needed"); template ro::CompileSizedString< (2 * sizeof(T))>bin2hex(const T& pt) { ro::CompileSizedString< (2 * sizeof(T))>sz; @@ -392,7 +399,12 @@ namespace ro { } //End ro namespace namespace ristretto255 { - using ro::to_base64_string, ro::is_serializable; + using + ro::to_base64_string, ro::is_serializable, + ro::serialize, ro::bin2hex, ro::hex2bin, + ro::bin2hex, ro::CompileSizedString, + ro::serializable; + ; // a class representing ristretto255 elliptic points class point; @@ -449,64 +461,35 @@ namespace ristretto255 { assert(i == 0); } - template - typename std::enable_if< - ro::is_serializable::value, - ristretto255::hsh& - >::type operator << (const T& j) { - int i{ 1 }; - if constexpr (std::is_same_v, std::span >) { - i = crypto_generichash_blake2b_update( - &(this->st), - &j[0], - j.size() - ); - } - else if constexpr (std::is_same_v, const char*>) { - i = crypto_generichash_blake2b_update( - &(this->st), - (const unsigned char*)(j), - strlen(j) + 1 - ); - } - else { - static_assert(is_serializable::value, "don't know a machine and compiler independent representation of this type"); - auto sj = ro::serialize(j); - i = crypto_generichash_blake2b_update( - &(this->st), - (const unsigned char*)&sj[0], - sj.size() - ); + template + hsh& hashinto(const T& j, Args... args) { + auto sj = ro::serialize(j); + int i = crypto_generichash_blake2b_update( + &(this->st), + (const unsigned char*)&sj[0], + sj.size() + ); + if (i) throw HashReuseException(); + if constexpr (sizeof...(args) > 0) { + (*this).hashinto(args...); } + return *this; + } + + template hsh& operator << (const T& j) { + auto sj = ro::serialize(j); + auto i = crypto_generichash_blake2b_update( + &(this->st), + (const unsigned char*)&sj[0], + sj.size() + ); if (i) throw HashReuseException(); return *this; } - template::value, int >::type dummy_arg = 0 - >explicit hsh(const T first, Args... args) { - int i{ crypto_generichash_blake2b_init( - &st, - nullptr,0, - hashsize / 8) - }; - assert(i == 0); - (*this) << first; - if constexpr (sizeof...(args) > 0) { - (*this).hashinto(args...); - } - } - template::value, int >::type dummy_arg = 0 - > void hashinto(const T first, Args... args) { - *this << first; - if constexpr (sizeof...(args) > 0) { - (*this).hashinto(args...); - } - } }; - static_assert(!ro::is_serializable >::value, "Don't want to partially hash partial hashes"); + static_assert(!serializable >, "Don't want to partially hash partial hashes"); // This constructs a finalized hash. // If it has one argument, and that argument is hsh (unfinalized hash) object, @@ -553,9 +536,7 @@ namespace ristretto255 { assert(i == 0); if (i) throw HashReuseException(); } - template::value, int >::type dummy_arg = 0 - >explicit hash(const T& first, Args... args) { + template< serializable T, typename... Args>explicit hash(const T& first, Args... args) { hsh in; in << first; if constexpr (sizeof...(args) > 0) { diff --git a/src/testbed.cpp b/src/testbed.cpp index 93f47f7..1a44eac 100644 --- a/src/testbed.cpp +++ b/src/testbed.cpp @@ -25,11 +25,13 @@ void ascii2test(); extern const uint8_t* const ascii2six; namespace testbed { - using ristretto255::hash, ristretto255::hsh, ristretto255::scalar, + using /*ristretto255::hash, ristretto255::hsh, */ristretto255::scalar, ristretto255::point, ro::serialize, ro::bin2hex, ro::hex2bin, - ro::bin2hex, ro::fasthash,ro::CompileSizedString ; + ro::bin2hex, ro::fasthash, ro::CompileSizedString, + ro::base58, ro::serializable; static constexpr char SrcFilename[]{ "src/testbed.cpp" }; + /* experimental code called during unit test Anything here is a residue of forgotten experiments, and can safely be thrown away @@ -54,8 +56,8 @@ If using postmessage, execution of the code waits for the dialog to and be reported in the unit test log. If using queumessage, the testbed code will complete while the dialog - is waiting, data cannot be returned for use in the testbed code, - and uncaught exceptions will appear in the main UI. + is waiting, data cannot be returned for use in the testbed code, + and uncaught exceptions in the dialog queued will appear in the main UI. */ void testbed() {