diff --git a/app.cpp b/app.cpp index b6bae26..befcee3 100644 --- a/app.cpp +++ b/app.cpp @@ -1,13 +1,12 @@ #include "stdafx.h" -thread_local thread_local__* thl{ nullptr }; wxIMPLEMENT_APP(App); App::App() { assert (singletonApp == nullptr); singletonApp = this; - if (thl == nullptr)thl = new thread_local__(); + } App::~App() diff --git a/frame.cpp b/frame.cpp index aa0785e..7b63c41 100644 --- a/frame.cpp +++ b/frame.cpp @@ -116,22 +116,26 @@ try { SetIcon(wxICON(AAArho)); //Does not appear to do anything. Maybe it does something in Unix. //wxICON is a namestring on windows, and a symbol on Unix Bind(wxEVT_CLOSE_WINDOW, &Frame::OnClose, this); + Bind(wxEVT_CLOSE_WINDOW, &Frame::OnClose, this); wxMenu* menuFile = new wxMenu; - menuFile->Append(wxID_NEW, _T("&New wallet..."), _T("New wallet file From new secret")); - menuFile->Bind(wxEVT_MENU, &Frame::OnSaveNew, this, wxID_NEW); - menuFile->Append(wxID_REFRESH, _T("Existing secret..."), _T("New Wallet File From the secret of an old wallet")); - menuFile->Bind(wxEVT_MENU, &Frame::RecreateWalletFromExistingSecret, this, wxID_REFRESH); - menuFile->Append(wxID_OPEN, _T("&Open existing wallet file..."), _T("")); - menuFile->Bind(wxEVT_MENU, &Frame::OnFileOpen, this, wxID_OPEN); - menuFile->Append(wxID_DELETE, _T("&Delete Wallet File"), _T("Delete ") + m_LastUsedSqlite.GetFullPath()); - menuFile->Bind(wxEVT_MENU, &Frame::OnDelete, this, wxID_DELETE); - menuFile->AppendSeparator(); - menuFile->Append(myID_DELETECONFIG, _T("&Reset defaults"), _T("Delete config file")); - menuFile->Bind(wxEVT_MENU, &Frame::OnDeleteConfiguration, this, myID_DELETECONFIG); - menuFile->AppendSeparator(); - menuFile->Append(wxID_EXIT); - menuFile->Bind(wxEVT_MENU, &Frame::OnExit, this, wxID_EXIT); + menuFile->Append(wxID_NEW, menu_strings[0].tail[0][0], menu_strings[0].tail[0][1]); + menuFile->Bind(wxEVT_MENU, &Frame::OnSaveNew, this, wxID_NEW); + + menuFile->Append(wxID_REFRESH, menu_strings[0].tail[1][0], menu_strings[0].tail[1][1]); + menuFile->Bind(wxEVT_MENU, &Frame::RecreateWalletFromExistingSecret, this, wxID_REFRESH); + + menuFile->Append(wxID_OPEN, menu_strings[0].tail[2][0], menu_strings[0].tail[2][1]); + menuFile->Bind(wxEVT_MENU, &Frame::OnFileOpen, this, wxID_OPEN); + + menuFile->Append(wxID_DELETE, menu_strings[0].tail[3][0], menu_strings[0].tail[3][1] + m_LastUsedSqlite.GetFullPath()); + menuFile->Bind(wxEVT_MENU, &Frame::OnDelete, this, wxID_DELETE); + + menuFile->AppendSeparator(); + + menuFile->Append(myID_DELETECONFIG, menu_strings[0].tail[4][0], menu_strings[0].tail[4][1] + m_LastUsedSqlite.GetFullPath()); + menuFile->Bind(wxEVT_MENU, &Frame::OnDeleteConfiguration, this, myID_DELETECONFIG); + wxMenu* menuHelp = new wxMenu; menuHelp->Append(wxID_ABOUT); menuHelp->Bind(wxEVT_MENU, &Frame::OnAbout, this, wxID_ABOUT); @@ -142,8 +146,9 @@ try { menuHelp->Bind(wxEVT_MENU, &Frame::OnDeleteLastSubwindow, this, myID_DELETE_LAST_SUBWINDOW); // menu_OnFirstUse.Append(menuHelp, this, _T("New wallet"), _T("add new wallet")); wxMenuBar* menuBar = new wxMenuBar; - menuBar->Append(menuFile, "&File"); - menuBar->Append(menuHelp, "&Help"); + menuBar->Append(menuFile, menu_strings[0].head); + menuBar->Append(new wxMenu, menu_strings[1].head); + menuBar->Append(menuHelp, menu_strings[2].head); SetMenuBar(menuBar); CreateStatusBar(); // child controls diff --git a/frame.h b/frame.h index 5059f29..6a173d7 100644 --- a/frame.h +++ b/frame.h @@ -1,8 +1,8 @@ #pragma once template -// This class exists to record the information -// needed to unbind a menu action and delete the corresponding item from the menu. -// when the handler is destroyed. +// This class exists to record the needed to unbind a drop down menu action and delete +// the corresponding item from the drop down menu when the handler is destroyed. +// (Because the handler is a method of an object that is about to be destroyed.) // Also avoids the need for manually creating a new windowid to link each additional bind // to each menu item, thus avoids the likelihood of mismatching binds and menu entries. class MenuLink { diff --git a/introspection_of_standard_C_types.h b/introspection_of_standard_C_types.h index 47d9ba7..5532c4e 100644 --- a/introspection_of_standard_C_types.h +++ b/introspection_of_standard_C_types.h @@ -64,16 +64,47 @@ namespace ro { template inline constexpr bool is_same = std::is_same_v, std::remove_cvref_t>; + // A compile time test to see if spaceship operator already exists + template struct has_spaceship { + template + static constexpr + decltype( + std::declval< + std::remove_cvref_t + >() + <=> + std::declval< + std::remove_cvref_t + >(), + bool() + )test() { + return true; + } + template + static constexpr bool + test(int = 0) { + return false; + } + static constexpr bool value =has_spaceship::template test(); + }; + + template + inline constexpr bool has_spaceship_v = has_spaceship::value; } -/*spaceship operator for any pair of types that take an index - * + + + +/*spaceship operator for any pair of types that + * do not already have a spaceship operator + * can be arguments for std::span + * and whose members have the spaceship operator * noexistent values of the shorter array are considered zero if of * arithmetic type, otherwise, considered greater than zero */ template -decltype(std::declval()[0] <=> std::declval()[0]) operator <=> ( +std::enable_if_t, decltype(std::span(declval())[0] <=> std::span(declval())[0]) >operator <=>( const T& lh, const U& rh - ) { + ){ typedef decltype(lh[0] <=> rh[0]) spaceship_return_type; auto slh{ std::span(lh) }; auto srh{ std::span(rh) }; diff --git a/localization.cpp b/localization.cpp index 3f173c8..d27c84b 100644 --- a/localization.cpp +++ b/localization.cpp @@ -50,7 +50,7 @@ // code is intentionally written to break on such locales. // No intent to support local date formats. -// All dates and times shall be YYYY-MM-DDtHH-mm-ss (international format) +// All dates and times shall be YYYY-MM-DD_HH:mm:ss (international format) // Local date formats are always ambiguous. Date localization is dangerous // in a program intended to support promises and contracts. @@ -69,6 +69,23 @@ However my experience is that all the terribly clever solutions for and break every time they issue a new skew of the operating system. I don't trust them, and are not interested in learning about them.*/ + + //Menu strings + +static const char * file_menu_strings[][2]{ + {"&New wallet...", "New wallet file From new secret"}, + {"Existing secret...","New Wallet File From the secret of an old wallet"}, + {"&Open existing wallet file...",""}, + {"&Delete Wallet File","Delete"}, + {"&Reset defaults","Delete config file"}}; + +const menu_string menu_strings_[]{ + {"&File", file_menu_strings}, + {"&Edit", nullptr}, + {"&Help", nullptr} }; + +const menu_string* menu_strings{ menu_strings_ }; + // Strings for the startup display, load existing wallet or create new // wallet. const char sz_NewWallet[] {R"|(New Wallet)|"}; diff --git a/localization.h b/localization.h index b634f44..0445c05 100644 --- a/localization.h +++ b/localization.h @@ -16,6 +16,14 @@ // file in several languages, it will matter again. Since network is utf8 // the whole program has to be utf, even if localization not an issue. +//Menu strings +struct menu_string { + const char* head; + const char*(* tail)[2]; +}; +extern const menu_string* menu_strings; + + // Strings for the startup display, load existing wallet or create new // wallet. // String array for the english passphrase diff --git a/mpir_and_base58.cpp b/mpir_and_base58.cpp index 93d1e08..1f7ce61 100644 --- a/mpir_and_base58.cpp +++ b/mpir_and_base58.cpp @@ -29,8 +29,8 @@ namespace ro { //template <> class base58 : public CompileSizedString<44> {}; static_assert(sizeof(base58) == 46, "base58 point strings unexpected size"); - static constexpr char index2cryptoBase58[]{ "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" }; - static constexpr char index2MpirBase58[]{ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv" }; + static constexpr char index2cryptoBase58[] { "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" }; + static constexpr char index2MpirBase58[] { "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv" }; void map_base_from_mpir58(char* p) { static const charmap map(index2MpirBase58, index2cryptoBase58); @@ -65,3 +65,28 @@ namespace ro { else assert(*terminal_null == '\0'); } } + + +namespace mpir { + mpz ristretto25519_curve_order("1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed", 16); +} + +/* +thread_local std::unique_ptr thl2{ std::make_unique() }; //Destructor is not called +std::unique_ptr thl2{ std::make_unique() }; //Destructor is called +looks like cannot use smart pointers with thread_local +The destructor will not be called on thread_local variables +The machinery of classes just does not work with thread local variables. +A thread local variable can only be defined outside of the stack, +its destructor will probably not be called, and there are whimsical, +arbitrary, and incomprehensible restrictions on its constructor +*/ + +// The class thread_locall__, which holds all my thread_local global values +// has to be explicitly constructed in code with new +// and explicitly with delete destructed at program +// termination +// Because the compiler will not generate code +// for construction and destruction of thread_local +// values. +thread_local thread_local__* thl{ nullptr }; diff --git a/mpir_and_base58.h b/mpir_and_base58.h index a996f68..f18a230 100644 --- a/mpir_and_base58.h +++ b/mpir_and_base58.h @@ -23,8 +23,6 @@ namespace mpir { extern mpz ristretto25519_curve_order; } - - // This global thread local object is explicitly constructed // on the heap in the code on need once the thread starts running // and destroyed when the thread exits. @@ -44,7 +42,9 @@ public: // These are used all over the place as temporaries. mpir::mpz q, r, n; }; -extern thread_local thread_local__*thl; //Constructor in app.obj. + +extern thread_local thread_local__* thl; +//extern thread_local thread_local__* thl; //Constructor in app.obj. // Destructor does not seem to get called, hence using a pointer // and destroying explicitly, rather than an std::unique_ptr // needs testing to figure out what is going on diff --git a/ristretto255.cpp b/ristretto255.cpp index b311e1f..dd4edf9 100644 --- a/ristretto255.cpp +++ b/ristretto255.cpp @@ -27,7 +27,7 @@ namespace ristretto255 { bool scalar::constant_time_required{ true }; bool point::constant_time_required{ true }; - scalar::scalar(int i) { + constexpr scalar::scalar(int i) { if (i >= 0) { auto k{ unsigned int(i) }; for (auto& j : blob) { j = k; k = k >> 8; } @@ -56,6 +56,37 @@ namespace ristretto255 { point point::ptBase({ 0xe2, 0xf2, 0xae, 0x0a, 0x6a, 0xbc, 0x4e, 0x71, 0xa8, 0x84, 0xa9, 0x61, 0xc5, 0x00, 0x51, 0x5f, 0x58, 0xe3, 0x0b, 0x6a, 0xa5, 0x82, 0xdd, 0x8d, 0xb6, 0xa6, 0x59, 0x45, 0xe0, 0x8d, 0x2d, 0x76}); + static constexpr scalar curveOrder({ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, + 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 }); + const scalar& scalar::scOrder{ curveOrder }; + + std::strong_ordering scalar::operator<=>(const scalar& sclr) const& noexcept { + static_assert(std::endian::native == std::endian::little); +// Instead of a static assert, we really should have an if constexpr() +// that defines reverse iterators for little endian order +// and defines forward iterators for big endian order. +// but we will fix that when the time comes. +// as it depends on how the libsodium library will implement +// scalars on big endian order. + std::strong_ordering retval{ std::strong_ordering::equal }; + constexpr auto bg = sizeof(scalar::blob); + typedef const std::arrayas_uint64_t; + auto lh{ reinterpret_cast(this->blob)}; + auto rh{ reinterpret_cast(sclr.blob) }; + static_assert(sizeof(as_uint64_t) == sizeof(sclr.blob)); + auto p{ lh.end() }; + auto q{ rh.end() }; + do + { + auto vp{ *--p }; + auto vq{ *--q }; + retval = vp <=> vq; + } + while (std::is_eq(retval) && + bool(p > lh.begin())); + return retval; + } signed_text::signed_text( const scalar &k, // Signer's secret key @@ -126,6 +157,3 @@ template<> CompileSizedString < (sizeof(scalar) * 8 + 5) / 6> return sz; } -namespace mpir { - mpz ristretto25519_curve_order("1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed", 16); -} diff --git a/ristretto255.h b/ristretto255.h index e9cb218..56898b5 100644 --- a/ristretto255.h +++ b/ristretto255.h @@ -509,7 +509,12 @@ namespace ristretto255 { // The program should by running in the UTF8 locale, attempts to set that // locale on startup. and tests for success in the unit test. template class hash { - static_assert(hashsize > 63 && hashsize % 64 == 0 && crypto_generichash_BYTES_MIN * 8 <= hashsize && hashsize <= crypto_generichash_BYTES_MAX * 8, "Bad hash size."); + static_assert( + hashsize > 63 && hashsize % 64 == 0 + && crypto_generichash_BYTES_MIN * 8 <= hashsize + && hashsize <= crypto_generichash_BYTES_MAX * 8, + "Bad hash size." + ); friend point; friend scalar; friend hsh; @@ -561,18 +566,29 @@ namespace ristretto255 { // which are conveniently of prime order. class point { - // We will be reading points from the database, as blobs, reading them from the network as blobs, and reading them from human entered text as slash6 encoded blobs. Therefore, invalid point initialization data is all too possible. + // We will be reading points from the database, as blobs, + // reading them from the network as blobs, + // and reading them from human entered text as base52 encoded blobs. + // Therefore, invalid point initialization data is all too possible. public: static constexpr unsigned int type_indentifier = 1; std::array blob; - static_assert(std::is_trivially_copyable>(), "does not support memcpy init"); - static_assert(sizeof(blob) == 32, "watch for size and alignment bugs. Everyone should standarize on 256 bit public keys except for special needs"); + static_assert( + std::is_trivially_copyable>(), + "does not support memcpy init" + ); + static_assert(sizeof(blob) == 32, + "watch for size and alignment bugs. " + "Everyone should standarize on 256 bit public keys except for special needs" + ); static point ptZero; static point ptBase; explicit point() = default; - // After loading a point as a blog from the network, from the database, or from user data typed as text, have to check for validity. + // After loading a point as a blog from the network, from the database, + // or from user data typed as text, have to check for validity. bool valid(void) const { return 0 != crypto_core_ristretto255_is_valid_point(&blob[0]); } - explicit point(std::array&& in) : blob{ std::forward>(in) } { }; + explicit constexpr point(std::array&& in) : + blob{ std::forward>(in) } { }; static_assert(crypto_core_ristretto255_BYTES == 32, "256 bit points expected"); ~point() = default; point(point&&) = default; // Move constructor @@ -582,10 +598,6 @@ namespace ristretto255 { bool operator==(const point& pt) const& { return ConstantTimeEqualityTest(*this, pt); } - bool operator!=(const point& pt) const &{ - return !ConstantTimeEqualityTest(*this, pt); - } - point operator+(const point &pt) const& { point me; auto i{ crypto_core_ristretto255_add(&me.blob[0], &blob[0], &pt.blob[0]) }; @@ -607,7 +619,9 @@ namespace ristretto255 { point operator*(int) const& noexcept; explicit point(const hash<512>& x) noexcept { - static_assert(crypto_core_ristretto255_HASHBYTES * 8 == 512, "we need 512 bit randoms to ensure our points and scalars are uniformly distributed"); + static_assert(crypto_core_ristretto255_HASHBYTES * 8 == 512, + "we need 512 bit randoms to ensure our points and scalars are uniformly distributed" + ); // There should be scalar from hash, not point from hash int i{ crypto_core_ristretto255_from_hash(&blob[0], &(x.blob)[0]) }; @@ -628,11 +642,6 @@ namespace ristretto255 { }; - - // a class representing ristretto255 scalars - // very large integers modulo the order of the - // ristretto255 elliptic curve, which is - // conveniently of prime order. class scalar { friend point; @@ -644,18 +653,27 @@ namespace ristretto255 { ~scalar() = default; explicit constexpr scalar(std::array&& in) : blob{ in } {}; explicit constexpr scalar(std::array* in) :blob(*in) {}; - - explicit scalar(int); + explicit constexpr scalar(int); scalar(scalar&&) = default; // Move constructor scalar(const scalar&) = default; // Copy constructor scalar& operator=(scalar&&) = default; // Move assignment. scalar& operator=(const scalar&) = default; // Copy assignment. +/* Don't need constant time equality test bool operator==(const scalar& sc) const& { return ConstantTimeEqualityTest(*this, sc); - } - bool operator!=(const scalar& sc) const& { - return !ConstantTimeEqualityTest(*this, sc); - } + }*/ + std::strong_ordering operator <=>(const scalar& sc) const& noexcept; + // strangely, contrary to documentation, compiler generates operator> + // but fails to generate operator== + bool operator==(const scalar& sc) const& = default; + /* { + return (*this <=> sc) == 0; + }*/ + + + //bool operator!=(const scalar& sc) const& { +// return !ConstantTimeEqualityTest(*this, sc); +// } scalar operator+(const scalar sclr) const& { scalar me; crypto_core_ristretto255_scalar_add(&me.blob[0], &blob[0], &sclr.blob[0]); @@ -719,17 +737,24 @@ namespace ristretto255 { } bool valid(void) const& { - return _sodium_sc25519_is_canonical(&blob[0]) != 0 || - sodium_is_zero(&blob[0], crypto_core_ed25519_SCALARBYTES); + int x = sodium_is_zero(&blob[0], crypto_core_ed25519_SCALARBYTES); + return x==0 && *thisconst& ac) { auto p = blob.rbegin(); diff --git a/rotime.h b/rotime.h index b337bc9..40fb2b8 100644 --- a/rotime.h +++ b/rotime.h @@ -3,7 +3,8 @@ namespace ro { // need to define my own time types: typedef time_t time_t; // is always time in seconds past the epoch modulo 2 ^ 64 // equivalent to regular old time_t - // except in environments where time_t is seconds past the epoch modulo 2 ^ 32 + // except in environments where time_t is seconds past the epoch + // modulo 2 ^ 32 ro::time_t time(); // equivalent to regular old time(nullptr); // except in environments where time_t is seconds past the epoch modulo 2 ^ 32 @@ -21,24 +22,26 @@ namespace ro { typedef std::chrono::duration > msec; - // duration past startup time modulo 2^32 Rolls over every forty eight days, making durations longer than twenty four days of unclear sign + // duration past startup time modulo 2^32 Rolls over every forty eight days, making + // durations longer than twenty four days of unclear sign msec msec_since_epoch(void); - // Obliterates chrono's elegant but pain in the ass distinction between time points and durations. - // Which type distinction in practice gets in the way off all sorts of things that just need to be done. - // In truth, it is a distinction that only matters, and is indeed only meaningful, with respect to shared global consensus time, universal coordinated time - // It is not meaningful for steady time or high precision time, which means that all sorts of stuff gets assigned to the wrong type, a duration when you need it to be a time point, or a time point when you need it to be a duration. - // A time point is just a duration relative to some globally agreed consensus time point, and if you don't have such a consensus, forget it. And when you are measuring millisecond times, you do not have such a consensus - // millisecond clocks are not expected to be synchronized between systems, nor to measure milliseconds exactly nor to be exactly the same time unit between systems, but they are expected to advance similarly on both systems for the life of any connection, making the distinction between time points and durations problematic. - // We expect to compare the change in time on one system, with the change in time on another system, in which case the time point class gets in the way. - - -/* - std::array msec::operator() const { - std::array x; - return x; - - }*/ - - - + // Obliterates chrono's elegant but pain in the ass distinction between time points and + // durations. Which type distinction in practice gets in the way off all sorts of things + // that just need to be done. + // In truth, it is a distinction that only matters, and is indeed only meaningful, with + // respect to shared global consensus time, universal coordinated time. It is not + // meaningful for steady time or high precision time, which means that all sorts of stuff + // gets assigned to the wrong type, a duration when you need it to be a time point, or a + // time point when you need it to be a duration. + // + // A time point is just a duration relative to some globally agreed consensus time point, + // and if you don't have such a consensus, forget it. And when you are measuring + // millisecond times, you do not have such a consensus. + // + // millisecond clocks are not expected to be synchronized between systems, nor to + // measure milliseconds exactly nor to be exactly the same time unit between systems, + // but they are expected to advance similarly on both systems for the life of any + // connection, making the distinction between time points and durations problematic. + // We expect to compare the change in time on one system, with the change in time + // on another system, in which case the time point class gets in the way. } diff --git a/slash6.cpp b/slash6.cpp index 86702d4..06fb72b 100644 --- a/slash6.cpp +++ b/slash6.cpp @@ -12,17 +12,29 @@ #include "slash6.h" // This base64 uses the following characters as the numerals 0 to 63: // Table to convert six bit to ascii -static constexpr uint8_t index2base64[]{ "0123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz!$*+-_" }; +static constexpr uint8_t index2base64[]{ + "0123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz!$*+-_" + }; -// Unlike regular baseINV, and incompatible with it. Intended to encode stuff small enough that it might be human typed and human transmitted, therefore maps 'o' and 'O' to '0', 'I' and 'l' to '1' +// Unlike regular baseINV, and incompatible with it. Intended to encode stuff small enough +// that it might be human typed and human transmitted, therefore maps 'o' and 'O' to '0', 'I' and +// 'l' to '1' // uses six url safe additional characters !$*+-_ to bring it up to six bits static_assert(index2base64[63] == '_', "surprise numeral at 63"); // Being intended for small bits of data, assumes no whitespace within an entity -// Encode and decode are called with a bit buffer, consisting of an unsigned byte pointer, a starting bit position relative to the pointer, and a bit count. We assume that there is room enough in the object pointed to to accommodate the bytes referenced by Bit Position+BitCount. We don't change bits outside the range. -// The bit buffer does not need to be aligned, nor does it need to be a multiple of six bits, eight bits, or twenty four bits. -// If the input bit buffer to be encoded to base sixty four is not a multiple of six bits, the last base sixty four numeral output will represent the bit buffer padded with trailing zeroes. -// If there is no room in the output span for all the base sixty four digits, the encode routine will return a number of bits less than the size of the input bit buffer, less than the bitcount it was given. +// Encode and decode are called with a bit buffer, consisting of an unsigned byte pointer, a +// starting bit position relative to the pointer, and a bit count. We assume that there is room +// enough in the object pointed to to accommodate the bytes referenced by +// Bit Position+BitCount. We don't change bits outside the range. +// The bit buffer does not need to be aligned, nor does it need to be a multiple of six bits, +// eight bits, or twenty four bits. +// If the input bit buffer to be encoded to base sixty four is not a multiple of six bits, the +// last base sixty four numeral output will represent the bit buffer padded with trailing zeroes. +// If there is no room in the output span for all the base sixty four digits, the encode routine +// will return a number of bits less than the size of the input bit buffer, less than the bitcount +// it was given. + // Table to convert ascii to six bit. static constexpr std::array ascii2six_ar{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //control characters @@ -43,17 +55,33 @@ static constexpr std::array ascii2six_ar{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff // utf8 multibyte characters, all stops. }; -// Table to convert ascii to six bit as a good old fashioned non owning naked pointer to const, whose storage is owned by a const static which exists until the program terminates. +// Table to convert ascii to six bit as a good old fashioned non owning naked pointer to const, +// whose storage is owned by a const static which exists until the program terminates. static const uint8_t *ascii2six{ &ascii2six_ar[0] }; -// Compile time execution is C++ is a pain, because expressions are apt to unpredictably lose their constexpr character for reasons that are far from clear. -// You really have to write compile time code in templates as a language, which is the totally obscure and hard to use language apt to generate remarkably voluminous error messages will little obvious connection to the actual problem, and surprising result that are very difficult to predict in advance or understand at all. -//In general, the better solution is to have a routine that is called once and only once at the beginning of the program, which initializes a bunch of static const values, if that solution is adequate, or to have a preproces routine written in python which generates the required C files and header files. +// Compile time execution is C++ is a pain, because expressions are apt to unpredictably lose +// their constexpr character for reasons that are far from clear. +// You really have to write compile time code in templates as a language, which is the totally +// obscure and hard to use language apt to generate remarkably voluminous error messages +// will little obvious connection to the actual problem, and surprising result that are ver +// difficult to predict in advance or understand at all. +// In general, the better solution is to have a routine that is called once and only once at the +// beginning of the program, which initializes a bunch of static const values, if that solution is +// adequate, or to have a preproces routine written in python which generates the required C +// files and header files. // After this experiment in compile time code, I swear off it. -// Decode does not have an input span of encoded characters, but a char *, because it assumes the string is always terminated by an invalid character, such as the trailing null at the end of string or a space, or any character that is not one of our base sixty four numerals -// If the there are not enough input base sixty four numerals, it returns a size less than requested. -// if the requested bit buffer is not a multiple of six bits, and the last base 64 numeral had trailing ones that would not fit in the buffer, rather than the expected trailing zeroes, then it returns a size larger than the buffer, as if it changed stuff outside the buffer but does not actually change bits outside the buffer. This is likely an error, because obviously we want to decode something from base sixty four that was originally decoded using the same sized buffer. +// Decode does not have an input span of encoded characters, but a char *, because it assumes +// the string is always terminated by an invalid character, such as the trailing null at the end of +// string or a space, or any character that is not one of our base sixty four numerals +// If the there are not enough input base sixty four numerals, it returns a size less than +// requested. +// if the requested bit buffer is not a multiple of six bits, and the last base 64 numeral had +// trailing ones that would not fit in the buffer, rather than the expected trailing zeroes, then +// it returns a size larger than the buffer, as if it changed stuff outside the buffer but does not +// actually change bits outside the buffer. This is likely an error, because obviously we want +// to decode something from base sixty four that was originally decoded using the same sized +// buffer. static const uint8_t INV{ UCHAR_MAX }; @@ -64,11 +92,13 @@ static_assert(CHAR_BIT + 1 == sizeof(lowBitMask), "expecting eight bits per char // Converts bit a bit buffer into base 64 numerals -// Start does not need to be byte aligned, nor does the length need to be a multiple of eight, six, or twenty four. +// Start does not need to be byte aligned, nor does the length need to be a multiple of eight, +// six, or twenty four. // If insufficient room is provided for the base 64 value, throws exception. void bits2base64(const uint8_t * bitBuffer, unsigned int start, unsigned int length, std::spanbase64Numerals) { assert(length <= 6 * base64Numerals.size() - 6); - // If you hit this assert you probably passed in a negative number, overflowing the string buffer + // If you hit this assert you probably passed in a negative number, overflowing the + // string buffer // which would cause you to write all over memory. // Expects(length <= 6 * base64Numerals.size()-6); if (length > 6 * base64Numerals.size() - 6)throw FatalException(sz_text_buffer_overflow); @@ -84,7 +114,9 @@ void bits2base64(const uint8_t * bitBuffer, unsigned int start, unsigned int len unsigned int bitsInAccumulator{ 8 - start }; assert(bitsInAccumulator < 9); unsigned int count{ length - bitsInAccumulator }; //count is bits lifted out of the buffer. - // We need to keep track of count, because the last byte lifted out of the buffer may well have to be an incomplete byte, so when count gets down to below 8, we have to special case loading the bitAccumulator. + // We need to keep track of count, because the last byte lifted out of the buffer may well + // have to be an incomplete byte, so when count gets down to below 8, we have to + // special case loading the bitAccumulator. char * Outputsz{ &(base64Numerals[0]) }; auto endBaseNumeralBuffer{ Outputsz + length / 6 }; for (; e < endBaseNumeralBuffer; e++) { @@ -98,7 +130,8 @@ void bits2base64(const uint8_t * bitBuffer, unsigned int start, unsigned int len assert(count + bitsInAccumulator + 6 * (unsigned int)(e - Outputsz) == length); } else { - assert(count + bitsInAccumulator >= 6); // Should be enough bits in buffer for all numerals produced by this for loop. + assert(count + bitsInAccumulator >= 6); // Should be enough bits in buffer for + // all numerals produced by this for loop. bitAccumulator = (((bitAccumulator << 8) | (*bitBuffer++)) >> (8 - count)); bitsInAccumulator += count; count = 0; @@ -109,7 +142,9 @@ void bits2base64(const uint8_t * bitBuffer, unsigned int start, unsigned int len *e = index2base64[(bitAccumulator >> (bitsInAccumulator - 6)) & 0x3F]; bitsInAccumulator -= 6; } - // When we drop out of the for loop, we may have more than 0 bits left but less than six, in which case we then have to special case the last numeral by filling the bit accumulator with our zeropadding. + // When we drop out of the for loop, we may have more than 0 bits left but less than six, in + // which case we then have to special case the last numeral by filling the bit accumulato + // with our zeropadding. if (count) { bitAccumulator = (((bitAccumulator << 8) | (*bitBuffer++)) >> (8 - count)); bitsInAccumulator += count; @@ -135,7 +170,8 @@ void bits2base64(const uint8_t * bitBuffer, unsigned int start, unsigned int len // This may produce the runtime error that there are too few numerals to fill the bit buffer. // Stops at the first invalid numeral - such as a space. -// This is intended for quite short bit fields, not for transmitting megabytes of data over lines that are not eight bit safe. +// This is intended for quite short bit fields, not for transmitting megabytes of data over lines +// that are not eight bit safe. // Returns the actual size of the fill. // If the bit buffer is not a multiple of six, the last numerals excess bits need to be zero // If they are not zero will truncate the excess bits and and throw BadDataException. @@ -151,7 +187,11 @@ unsigned int base64_to_bits(uint8_t * bitBuffer, unsigned int start, unsigned in unsigned int numeral; uint8_t overflowBits{ '\0' }; uint8_t * p{ bitBuffer }; - for (const char * e = base64Numerals; ((numeral = ascii2six[static_cast(*e)]), (numeral < INV)); e++) { + for ( + const char * e = base64Numerals; + ((numeral = ascii2six[static_cast(*e)]), (numeral < INV)); + e++ + ){ assert((e - base64Numerals) * 6 + count == length); assert((p-bitBuffer)*8 + bitsInAccumulator == start + (e-base64Numerals)*6 ); bitAccumulator = (bitAccumulator << 6) | numeral; @@ -175,7 +215,9 @@ unsigned int base64_to_bits(uint8_t * bitBuffer, unsigned int start, unsigned in if (count == 0) { assert(bitsInAccumulator < 9); if (bitsInAccumulator) { - *p = (bitAccumulator << (8 - bitsInAccumulator)) | (*p & lowBitMask[bitsInAccumulator]); + *p = + (bitAccumulator << (8 - bitsInAccumulator)) + |(*p & lowBitMask[bitsInAccumulator]); } break; } @@ -190,7 +232,11 @@ unsigned int base64_to_bits(uint8_t * bitBuffer, unsigned int start, unsigned in Throws exception if that is not what it gets. Fills the byte buffer exactly. Returns a uint8_t containing the excess bits of the last numeral in its low order part.*/ -uint8_t base64_to_bytes(uint8_t* byteBuffer, uint_fast32_t byteCount, const char* base64Numerals) { +uint8_t base64_to_bytes( + uint8_t* byteBuffer, + uint_fast32_t byteCount, + const char* base64Numerals +) { auto numeralsCount{ byteCount * 8 / 6 }; auto bitsCount{ numeralsCount * 6 }; auto length{ base64_to_bits(byteBuffer, 0, bitsCount, base64Numerals) }; @@ -220,7 +266,8 @@ uint8_t base64_to_bytes(uint8_t* byteBuffer, uint_fast32_t byteCount, const char // Converts bit a bit buffer into base 2048 BIPS-39 words // Using the array ar_sz_bip_0039_wordlist defined in localization.cpp // The largest word in the array is eight characters, but other languages likely have longer words. -// Start does not need to be byte aligned, nor does the length need to be a multiple of eight or eleven. +// Start does not need to be byte aligned, nor does the length need to be a multiple of eight or +// eleven. void bits2base2048(const uint8_t* bitBuffer, int start, int length, std::spanszBipsWords) { char* Outputsz{ &(szBipsWords[0]) }; if (szBipsWords.size() == 0)throw ; @@ -233,7 +280,9 @@ void bits2base2048(const uint8_t* bitBuffer, int start, int length, std::span0) { @@ -255,11 +304,15 @@ void bits2base2048(const uint8_t* bitBuffer, int start, int length, std::span 0) { - if (Outputsz == end_of_Outputsz)throw FatalException("not enough room for BIPS-0039 passphrase"); + if (Outputsz == end_of_Outputsz){ + throw FatalException("not enough room for BIPS-0039 passphrase"); + } *Outputsz++ = ' '; } } diff --git a/slash6.h b/slash6.h index f9ea648..0c95c1c 100644 --- a/slash6.h +++ b/slash6.h @@ -1,12 +1,27 @@ #pragma once -// Converts a bit buffer, arbitrarily positioned with respect to byte boundaries, into a base sixty four numeral. -// In release mode, returns without doing anything if the output string buffer is too small. -// In debug mode, halts execution with an assert. Should throw, need to put in and unit test. -void bits2base64(const uint8_t * bitBuffer, unsigned int start, unsigned int length, std::spanbase64Numerals); +// Converts a bit buffer, arbitrarily positioned with respect to byte boundaries, into a +// base sixty four numeral. In release mode, returns without doing anything if the output +// string buffer is too small. +// In debug mode, halts execution with an assert. Should throw, need to put in and +// unit test. +void bits2base64( + const uint8_t * bitBuffer, + unsigned int start, + unsigned int length, + std::spanbase64Numerals + ); -// Converts a base64 numeral into a bit buffer. The input string is terminated by the first non base64 character, normally a space or null, or terminated when the bit buffer is full. A correct length base64 numeral does not need a terminating space or null. -// If successful, returns a length equal to the bit buffer length. If the input string is too short, returns a length shorter than the bit buffer. If the bit buffer is not a multiple of six bits, and the last base64 numeral of the bit buffer has trailing binary ones, returns a length greater than the size of the bitbuffer, without writing the trailing binary bits into the bit buffer. -unsigned int base64_to_bits(uint8_t* bitBuffer, unsigned int start, unsigned int length, const char* base64Numerals); +// Converts a base64 numeral into a bit buffer. The input string is terminated by the first +// non base64 character, normally a space or null, or terminated when the bit buffer is full. +// A correct length base64 numeral does not need a terminating space or null. +// If successful, returns a length equal to the bit buffer length. If the input string is too +// short, returns a length shorter than the bit buffer. If the bit buffer is not a multiple of six bits, and the last base64 numeral of the bit buffer has trailing binary ones, returns a length greater than the size of the bitbuffer, without writing the trailing binary bits into the bit buffer. +unsigned int base64_to_bits( + uint8_t* bitBuffer, + unsigned int start, + unsigned int length, + const char* base64Numerals + ); /* Expects pointer to byte buffer and pointer to string. Expects a string of exactly the correct number of numerals, @@ -14,7 +29,11 @@ unsigned int base64_to_bits(uint8_t* bitBuffer, unsigned int start, unsigned int Throws exception if that is not what it gets. Fills the byte buffer exactly. Returns a uint8_t containing the excess bits of the last numeral in its low order part.*/ -uint8_t base64_to_bytes(uint8_t* byteBuffer, uint_fast32_t byteCount, const char* base64Numerals); +uint8_t base64_to_bytes( + uint8_t* byteBuffer, + uint_fast32_t byteCount, + const char* base64Numerals + ); /* Expects reference to a range object over bytes and pointer to string. Expects a string of exactly the correct number of numerals, @@ -28,5 +47,7 @@ std::enable_if_t< sizeof(std::declval()[0]) == 1, uint8_t >base64_to_bytes( T& byteRange, const char* base64Numerals) { - return base64_to_bytes(static_cast(&byteRange[0]), static_cast(std::size(byteRange)), base64Numerals); + return base64_to_bytes( + static_cast(&byteRange[0]), + static_cast(std::size(byteRange)), base64Numerals); } diff --git a/stdafx.h b/stdafx.h index f46a9b6..7ae2498 100644 --- a/stdafx.h +++ b/stdafx.h @@ -82,10 +82,6 @@ std::span& operator^=(std::span&, byte *); #define SODIUM_STATIC #include #include -extern "C" { - int _sodium_sc25519_is_canonical(const unsigned char s[32]); -} //This is a private identifier used by libsodium, which - //outsiders are not supposed to access, but we need it regardless. #pragma comment(lib, "libsodium.lib") inline wxString _wx(const char* sz) { return wxString::FromUTF8Unchecked(sz); } #include "introspection_of_standard_C_types.h" diff --git a/testbed.cpp b/testbed.cpp index 688debe..8b542a9 100644 --- a/testbed.cpp +++ b/testbed.cpp @@ -1,7 +1,7 @@ #include "stdafx.h" //#include - /* Any code here can be deleted at will without impact on the +/* Any code here can be deleted at will without impact on the functioning of the program. This routine gets called during every unit test, and can log its results @@ -9,25 +9,42 @@ This routine gets called during every unit test, and can log its results because useful working code should be moved the appropriate files, and broken code should be thrown away - Anything here is a residue of forgotten experiments, and can safely +Anything here is a residue of forgotten experiments, and can safely be thrown away. If any experiments have value, they will be have been recorded in git. Nothing here is needed. If it was needed, would have been moved. - If it needs to interact with the outside world, should post a message +Namespace testbed is only defined in this cpp file, hence nothing within + this namespace can be accessed from anywhere else. + except the routine testbed + +If it needs to interact with the outside world, should post a message analogously to queue_error_message, which then calls back to a routine in this file.*/ namespace testbed { - using ristretto255::hash, ristretto255::hsh, ristretto255::scalar, ristretto255::point, ro::serialize, ro::bin2hex, ro::hex2bin, ro::bin2hex, ro::fasthash,ro::CompileSizedString ; + using ristretto255::hash, ristretto255::hsh, ristretto255::scalar, + ristretto255::point, ro::serialize, ro::bin2hex, ro::hex2bin, + ro::bin2hex, ro::fasthash,ro::CompileSizedString ; - /* experimental code called during unit test -* Anything here is a residue of forgotten experiments, +/* experimental code called during unit test + Anything here is a residue of forgotten experiments, and can safely be thrown away - This is a playground, where you can do stuff without worrying you might inadvertently break something that matters +This is a playground, where you can do stuff without worrying you might + inadvertently break something that matters - No mechanism for input is available, but you generally do not need it because you hard code the testing data, but, of course, it can post a dialog using postmessage, then immediately return, and the dialog can then call anything. +No mechanism for input is available. You generally do not need it because you + hard code the testing data, and detect errors with asserts, rather than exceptions + but, of course, it can post a dialog using postmessage, then immediately return + and the dialog can then call anything. + +Uncaught exceptions result in unit test failure, but not in an error + message in the main program UI. + +If using a dialog, exceptions within the dialog will result in an error message in the + main program UI, rather than in the unit test result, since the unit test + is over before the dialog runs. */ void testbed() { diff --git a/unit_test.cpp b/unit_test.cpp index bfe1572..d998a82 100644 --- a/unit_test.cpp +++ b/unit_test.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" -using ro::msec, ro::msec_since_epoch, ro::bin2hex, ro::to_base64_string, ristretto255::hash, ristretto255::hsh, ristretto255::scalar, +using ro::msec, ro::msec_since_epoch, ro::bin2hex, ro::to_base64_string, ristretto255::hash, + ristretto255::hsh, ristretto255::scalar, ristretto255::point, ro::base58; class FailureToThrowExpectedException : public MyException { @@ -81,23 +82,63 @@ static bool EndUnitTest() { ILogMessage("Passed Unit Test"); } else { - wxLogMessage(_T("\nFailed Unit Test\nunit test error %d\n%s"), errorCode, _wx(szError.c_str())); + wxLogMessage(_T("\nFailed Unit Test\nunit test error %d\n%s"), + errorCode, _wx(szError.c_str()) + ); } if (singletonApp->m_unit_test && !singletonApp->m_display) { - singletonFrame->Close(); //Shuts down program immediately. When the program is closed, now or later, will return errorCode. + singletonFrame->Close(); //Shuts down program immediately. + // When the program is closed, now or later, will return errorCode. } return true; } static bool curve_order(void) { unit_test_action = &EndUnitTest; next_action = unit_test_action; - ILogMessage("\tChecking mpz arbitrary precision integer conversions to cryptographic values."); + ILogMessage( + "\tChecking mpz arbitrary precision integer conversions to cryptographic values." + ); try { scalar max(-1); - wxLogMessage(_wx("\t\tmax scalar:\t0x%s"), _wx(bin2hex(max))); + wxString curve_order_as_unreduced_scalar{ _wx(bin2hex(scalar::scOrder)) }; ro::CompileSizedString sz; mpz_get_str(sz, 16, mpir::ristretto25519_curve_order); - wxLogMessage(_wx("\t\tcurve order:\t0x%s"), _wx(sz)); + wxString curve_order_as_mpir_bigint{ _wx(sz) }; + if (curve_order_as_unreduced_scalar != curve_order_as_mpir_bigint){ + throw MyException("inconsistent curve order"); + } + scalar sc_zero{ 0 }; + scalar sc_one{ 1 }; + scalar sc1{ scalar::random() }; + scalar sc2{ scalar::random() }; + assert(sc1 != sc2); + assert(sc1sc2); + assert(sc1 < scalar::scOrder); + assert(max < scalar::scOrder); + assert(max > sc_zero); + assert(max + sc_one == scalar(0)); + assert(sc_one + max < scalar::scOrder); + assert(!(sc_one < scalar::scOrder + sc_one)); + assert(sc_one == scalar::scOrder + sc_one); + assert((sc_one + max < scalar::scOrder)); + assert(sc1.valid()); + assert(!scalar::scOrder.valid()); + assert(!scalar(0).valid()); + bool f = true + && sc1 != sc2 + && sc1sc2 + && (sc1 < scalar::scOrder + && max < scalar::scOrder + && max > sc_zero + && max + sc_one == sc_zero + && sc_one + max < scalar::scOrder + && !(sc_one < scalar::scOrder + sc_one) + && sc_one == scalar::scOrder + sc_one + && (sc_one + max < scalar::scOrder) + && sc1.valid()) + && !scalar::scOrder.valid() + && !scalar(0).valid(); + if (!f)throw MyException("scalar range and validation messed up"); } catch (const std::exception& e) { errorCode = 30; @@ -122,7 +163,8 @@ static bool checkDataConversionsProduceExpected(void){ std::arrayar_brownfox{ "the quick brown fox jumped" }; char* p_over{ p_brownfox + 27 }; wxString wx_over{ p_over }; - *--ar_brownfox.end() = ' '; //fixes the trailing nul appended to ar_brownfox, so that it is no longer a null terminated string. + *--ar_brownfox.end() = ' '; //fixes the trailing nul appended to ar_brownfox, so that it is + // no longer a null terminated string. wxString wx_jumped(&ar_brownfox[0], std::size(ar_brownfox)); hsh hsh1; hsh hsh2; @@ -144,30 +186,40 @@ static bool checkDataConversionsProduceExpected(void){ scalar scl_b{ scalar::random() }; point pt_a{ scl_b.timesBase() }; std::string str_pt_a{ &(base58(pt_a))[0] }; - if (pt_a != base58::bin(str_pt_a.c_str()))MyException("Round trip from and two base 58 representation failed"); + if (pt_a != base58::bin(str_pt_a.c_str())){ + MyException("Round trip from and two base 58 representation failed"); + } } { point pt_b; try { - pt_b = base58::bin("galvhAmKLYPjiEUbiDvE54pnKhhdYSxC3G5p9czHPuKaB not base 58 because uses 'l'"); + pt_b = base58::bin( + "galvhAmKLYPjiEUbiDvE54pnKhhdYSxC3G5p9czHPuKaB not base 58 because uses 'l'" + ); throw FailureToThrowExpectedException(); assert(false); } catch (const NotBase58Exception&) {} try { - pt_b = base58::bin("AWyxo34SopBAtWy9qH6RfheK3xUCmu9fgF4ZjHwT9RVrS wrong checksum"); + pt_b = base58::bin( + "AWyxo34SopBAtWy9qH6RfheK3xUCmu9fgF4ZjHwT9RVrS wrong checksum" + ); throw FailureToThrowExpectedException(); assert(false); } catch (const BadStringRepresentationOfCryptoIdException&) {} try { - pt_b = base58::bin("MaevYgZimDjzQWxbnHcNdMqkMVmjWpYEqippTfj9y6U7sM overlong error"); + pt_b = base58::bin( + "MaevYgZimDjzQWxbnHcNdMqkMVmjWpYEqippTfj9y6U7sM overlong error" + ); throw FailureToThrowExpectedException(); assert(false); } catch (const OversizeBase58String&) {} } - hash<512>hash_a{ ar_brownfox, wx_over.ToUTF8(), hash1,base58::bin("AWyxo34SopBAtWy9qH6RfheK3xUCmu9fgF4ZjHwT9RVrP") }; + hash<512>hash_a{ ar_brownfox, wx_over.ToUTF8(), hash1,base58::bin( + "AWyxo34SopBAtWy9qH6RfheK3xUCmu9fgF4ZjHwT9RVrP" + ) }; std::string str_hash_a{ &(base58(hash_a))[0] }; scalar scl_a{ hash_a }; std::string str_sclr_a = &(base58(scl_a))[0]; @@ -176,7 +228,11 @@ static bool checkDataConversionsProduceExpected(void){ std::string str_pt_a = &(base58(pt_a))[0]; assert(base58::bin(str_pt_a.c_str()) == pt_a); hash<256> hash_b{ hash_a,str_hash_a,scl_a,str_sclr_a,pt_a,str_pt_a,33, 66ull }; - if (base58(hash_b).operator std::string() != "i22EVNPsKRjdxYTZrPPu9mx6vnrBjosFix5F4gn2mb2kF")throw MyException("unexpected hash of transformations"); + if (base58(hash_b).operator std::string() != + "i22EVNPsKRjdxYTZrPPu9mx6vnrBjosFix5F4gn2mb2kF" + ){ + throw MyException("unexpected hash of transformations"); + } } catch (const std::exception& e) { errorCode = 27; @@ -259,7 +315,8 @@ static bool TestDelayedErrorDialog(void) { unit_test_action = &Waiting_for_delayed_dummy_error_message; next_action = &CheckForUtfEnvironment; ILogMessage("\t\tthrowing exception"); - throw UnitTestOfException(); //If we throw exception before setting the next unit test, this unit test gets endless recalled. + throw UnitTestOfException(); //If we throw exception before setting the next unit test, + // this unit test gets endless recalled. return true; } @@ -297,10 +354,16 @@ static bool WalletCreationUI(void) { static bool OpenWallet(void) { try { - /* If LastUsed is the empty string, check if default filename exists. If it exists, set Last Used to default file name - If LastUsed is not the empty string, or no longer the empty string, attempt to open indicated file. If open fails, or reading the opened file produces bad results, abort with exception - If LastUsed is still the empty string, attempt to create default filename. If creation fails, abort with exception. If it succeeds, set LastUsed to default filename. - The exception in unit test should simply generate an error message, but if run during initialization, should bring up the more complex UI for constructing or selecting your wallet file.*/ + /* If LastUsed is the empty string, check if default filename exists. If it exists, set + Last Used to default file name + If LastUsed is not the empty string, or no longer the empty string, attempt to open + indicated file. If open fails, or reading the opened file produces bad results, abort with + exception + If LastUsed is still the empty string, attempt to create default filename. If creation fails, + abort with exception. If it succeeds, set LastUsed to default filename. + The exception in unit test should simply generate an error message, but if run during + initialization, should bring up the more complex UI for constructing or selecting your + wallet file.*/ ILogMessage("\tWallet file"); assert(singletonApp->pConfig); singletonApp->pConfig->SetPath(_T("/Wallet")); @@ -336,8 +399,12 @@ static bool OpenWallet(void) { auto pubkey = read_keys.column(0); auto id = read_keys.column(1); auto use = read_keys.column(2); - if (use != 1)throw MyException(R"|(Unknown secret key algorithm index in "Names" table)|"); - if (!read_name(id)) throw MyException(R"|(No entry corresponding to public key in "Names" table)|"); + if (use != 1){ + throw MyException(R"|(Unknown secret key algorithm index in "Names" table)|"); + } + if (!read_name(id)){ + throw MyException(R"|(No entry corresponding to public key in "Names" table)|"); + } const char* name = read_name.name(); if(MasterSecret(name).timesBase()!=*pubkey)throw MyException(R"|(Public key of name fails to correspond)|"); wxLogMessage(_T("\t\t\"%s\" has expected public key 0x%s"), name, (wxString)(bin2hex(*pubkey))); @@ -714,9 +781,9 @@ static bool TestShareSecretGenerationSpeed(void) { || !(true && !point::ptZero && false == !point::ptBase - && !scalar(0) - && false == !scalar(1) - && false == !scalar::random() + && scalar(0).valid()==false + && scalar(1).valid() + && scalar::random().valid() && !ristretto_test_vector[0x00] && point::ptBase * 6 == ristretto_test_vector[0x06] && scalar(7) * point::ptBase == ristretto_test_vector[0x07] @@ -735,7 +802,8 @@ static bool TestShareSecretGenerationSpeed(void) { && scalar(3) == scalar(2) + scalar(1) && scalar(3) == scalar(4) + scalar(-1) && scalar(0x0103) == scalar(0xFE) + scalar(5) - && !scalar::random() == false + && scalar(0xDEADBEEF) == scalar(0xDEADBDDE) + scalar(0x111) + && scalar(0xBEEFDEADBEEF) == scalar(0xBEEFDEADBDDE) + scalar(0x111) ) ) {