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
This commit is contained in:
parent
60eece9269
commit
fc9f82b6e5
@ -35,8 +35,11 @@ void queue_error_message(const char* psz) {
|
|||||||
void queue_fatal_error(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
|
// Used where throwing immediately would be disastrous, as in a destructor or when constructing the main frame
|
||||||
if (!errorCode)errorCode = 10;
|
if (!errorCode)errorCode = 10;
|
||||||
queue_error_message(psz);
|
queue_error_message(psz); // Message continues to display,
|
||||||
singletonFrame->Close();
|
// 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 :
|
MyException::MyException(const char* sz, int i, const char* func__, const char* FILE__) noexcept :
|
||||||
|
@ -107,7 +107,7 @@ namespace ro {
|
|||||||
template < typename T,
|
template < typename T,
|
||||||
typename std::enable_if<!is_sqlite3_field_type<T>::value, int >::type dummy_arg = 0 >
|
typename std::enable_if<!is_sqlite3_field_type<T>::value, int >::type dummy_arg = 0 >
|
||||||
void bind(int i, const T& j) {
|
void bind(int i, const T& j) {
|
||||||
static_assert(ro::is_serializable<T>::value, "Don't know how to store this type in a database");
|
static_assert(ro::serializable<T>, "Don't know how to store this type in a database");
|
||||||
(*this)->Isqlite3_bind(i, ro::serialize(j));
|
(*this)->Isqlite3_bind(i, ro::serialize(j));
|
||||||
}
|
}
|
||||||
typedef Icompiled_sql::sql_result result;
|
typedef Icompiled_sql::sql_result result;
|
||||||
|
@ -175,6 +175,8 @@ namespace ro {
|
|||||||
apt to unhelpfully and unexpectedly turn it into a wxString,
|
apt to unhelpfully and unexpectedly turn it into a wxString,
|
||||||
|
|
||||||
If you make wxStrings hashable, suprising things become hashable.
|
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.
|
// 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.
|
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
|
Or we might allow arbitrary precision floating point with powers of
|
||||||
a thousand, so that sensible numbers to a human are represented by
|
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
|
secret keys, scalars are actually much larger numbers, modulo
|
||||||
0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ecU
|
0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ecU
|
||||||
@ -359,8 +361,13 @@ namespace ro {
|
|||||||
}
|
}
|
||||||
static constexpr bool value = is_serializable::template test<T,Args...>();
|
static constexpr bool value = is_serializable::template test<T,Args...>();
|
||||||
};
|
};
|
||||||
static_assert(ro::is_serializable<std::span<const char>>::value);
|
|
||||||
static_assert(ro::is_serializable<std::span<const byte>>::value);
|
template<typename... Args>
|
||||||
|
concept serializable = is_serializable<Args...>::value;
|
||||||
|
|
||||||
|
static_assert( !serializable<double>
|
||||||
|
&& serializable<std::span<const byte>, char*, std::span<const char>>,
|
||||||
|
"concepts needed");
|
||||||
|
|
||||||
template<class T> ro::CompileSizedString< (2 * sizeof(T))>bin2hex(const T& pt) {
|
template<class T> ro::CompileSizedString< (2 * sizeof(T))>bin2hex(const T& pt) {
|
||||||
ro::CompileSizedString< (2 * sizeof(T))>sz;
|
ro::CompileSizedString< (2 * sizeof(T))>sz;
|
||||||
@ -392,7 +399,12 @@ namespace ro {
|
|||||||
} //End ro namespace
|
} //End ro namespace
|
||||||
|
|
||||||
namespace ristretto255 {
|
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
|
// a class representing ristretto255 elliptic points
|
||||||
class point;
|
class point;
|
||||||
|
|
||||||
@ -449,64 +461,35 @@ namespace ristretto255 {
|
|||||||
assert(i == 0);
|
assert(i == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<serializable T, typename... Args>
|
||||||
typename std::enable_if<
|
hsh<hashsize>& hashinto(const T& j, Args... args) {
|
||||||
ro::is_serializable<const T>::value,
|
auto sj = ro::serialize(j);
|
||||||
ristretto255::hsh<hashsize>&
|
int i = crypto_generichash_blake2b_update(
|
||||||
>::type operator << (const T& j) {
|
&(this->st),
|
||||||
int i{ 1 };
|
(const unsigned char*)&sj[0],
|
||||||
if constexpr (std::is_same_v<std::remove_cvref_t<T>, std::span<const byte> >) {
|
sj.size()
|
||||||
i = crypto_generichash_blake2b_update(
|
);
|
||||||
&(this->st),
|
if (i) throw HashReuseException();
|
||||||
&j[0],
|
if constexpr (sizeof...(args) > 0) {
|
||||||
j.size()
|
(*this).hashinto(args...);
|
||||||
);
|
|
||||||
}
|
|
||||||
else if constexpr (std::is_same_v<std::remove_cvref_t<T>, const char*>) {
|
|
||||||
i = crypto_generichash_blake2b_update(
|
|
||||||
&(this->st),
|
|
||||||
(const unsigned char*)(j),
|
|
||||||
strlen(j) + 1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
static_assert(is_serializable<const T>::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()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<serializable T> hsh<hashsize>& 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();
|
if (i) throw HashReuseException();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename... Args,
|
|
||||||
typename std::enable_if< is_serializable<const T, Args...>::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<typename T, typename... Args,
|
|
||||||
typename std::enable_if< ro::is_serializable<const T>::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<hsh<256> >::value, "Don't want to partially hash partial hashes");
|
static_assert(!serializable<hsh<256> >, "Don't want to partially hash partial hashes");
|
||||||
|
|
||||||
// This constructs a finalized hash.
|
// This constructs a finalized hash.
|
||||||
// If it has one argument, and that argument is hsh (unfinalized hash) object,
|
// If it has one argument, and that argument is hsh (unfinalized hash) object,
|
||||||
@ -553,9 +536,7 @@ namespace ristretto255 {
|
|||||||
assert(i == 0);
|
assert(i == 0);
|
||||||
if (i) throw HashReuseException();
|
if (i) throw HashReuseException();
|
||||||
}
|
}
|
||||||
template<typename T, typename... Args,
|
template< serializable T, typename... Args>explicit hash(const T& first, Args... args) {
|
||||||
typename std::enable_if< ro::is_serializable<const T, Args...>::value, int >::type dummy_arg = 0
|
|
||||||
>explicit hash(const T& first, Args... args) {
|
|
||||||
hsh<hashsize> in;
|
hsh<hashsize> in;
|
||||||
in << first;
|
in << first;
|
||||||
if constexpr (sizeof...(args) > 0) {
|
if constexpr (sizeof...(args) > 0) {
|
||||||
|
@ -25,11 +25,13 @@ void ascii2test();
|
|||||||
extern const uint8_t* const ascii2six;
|
extern const uint8_t* const ascii2six;
|
||||||
|
|
||||||
namespace testbed {
|
namespace testbed {
|
||||||
using ristretto255::hash, ristretto255::hsh, ristretto255::scalar,
|
using /*ristretto255::hash, ristretto255::hsh, */ristretto255::scalar,
|
||||||
ristretto255::point, ro::serialize, ro::bin2hex, ro::hex2bin,
|
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" };
|
static constexpr char SrcFilename[]{ "src/testbed.cpp" };
|
||||||
|
|
||||||
|
|
||||||
/* experimental code called during unit test
|
/* experimental code called during unit test
|
||||||
Anything here is a residue of forgotten experiments,
|
Anything here is a residue of forgotten experiments,
|
||||||
and can safely be thrown away
|
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.
|
and be reported in the unit test log.
|
||||||
|
|
||||||
If using queumessage, the testbed code will complete while the dialog
|
If using queumessage, the testbed code will complete while the dialog
|
||||||
is waiting, data cannot be returned for use in the testbed code,
|
is waiting, data cannot be returned for use in the testbed code,
|
||||||
and uncaught exceptions will appear in the main UI.
|
and uncaught exceptions in the dialog queued will appear in the main UI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void testbed() {
|
void testbed() {
|
||||||
|
Loading…
Reference in New Issue
Block a user