diff --git a/src/crypto/crypto-ops.c b/src/crypto/crypto-ops.c index 5cc3b572..8bc86a2f 100644 --- a/src/crypto/crypto-ops.c +++ b/src/crypto/crypto-ops.c @@ -12,14 +12,14 @@ DISABLE_VS_WARNINGS(4146 4244) /* Predeclarations */ -static void fe_mul(fe, const fe, const fe); -static void fe_sq(fe, const fe); -static void fe_tobytes(unsigned char *, const fe); +void fe_mul(fe, const fe, const fe); +void fe_sq(fe, const fe); +void fe_tobytes(unsigned char *, const fe); static void ge_madd(ge_p1p1 *, const ge_p3 *, const ge_precomp *); static void ge_msub(ge_p1p1 *, const ge_p3 *, const ge_precomp *); static void ge_p2_0(ge_p2 *); static void ge_p3_dbl(ge_p1p1 *, const ge_p3 *); -static void ge_sub(ge_p1p1 *, const ge_p3 *, const ge_cached *); +void ge_sub(ge_p1p1 *, const ge_p3 *, const ge_cached *); static void fe_divpowm1(fe, const fe, const fe); /* Common functions */ @@ -48,7 +48,7 @@ static uint64_t load_4(const unsigned char *in) h = 0 */ -static void fe_0(fe h) { +void fe_0(fe h) { h[0] = 0; h[1] = 0; h[2] = 0; @@ -232,7 +232,7 @@ static void fe_copy(fe h, const fe f) { /* From fe_invert.c */ -static void fe_invert(fe out, const fe z) { +void fe_invert(fe out, const fe z) { fe t0; fe t1; fe t2; @@ -351,7 +351,7 @@ Can get away with 11 carries, but then data flow is much deeper. With tighter constraints on inputs can squeeze carries into int32. */ -static void fe_mul(fe h, const fe f, const fe g) { +void fe_mul(fe h, const fe f, const fe g) { int32_t f0 = f[0]; int32_t f1 = f[1]; int32_t f2 = f[2]; @@ -631,7 +631,7 @@ Postconditions: See fe_mul.c for discussion of implementation strategy. */ -static void fe_sq(fe h, const fe f) { +void fe_sq(fe h, const fe f) { int32_t f0 = f[0]; int32_t f1 = f[1]; int32_t f2 = f[2]; @@ -1005,7 +1005,7 @@ Proof: so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q. */ -static void fe_tobytes(unsigned char *s, const fe h) { +void fe_tobytes(unsigned char *s, const fe h) { int32_t h0 = h[0]; int32_t h1 = h[1]; int32_t h2 = h[2]; @@ -1398,7 +1398,7 @@ void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) { /* From ge_p3_0.c */ -static void ge_p3_0(ge_p3 *h) { +void ge_p3_0(ge_p3 *h) { fe_0(h->X); fe_1(h->Y); fe_1(h->Z); @@ -1565,7 +1565,7 @@ void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) { r = p - q */ -static void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { +void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { fe t0; fe_add(r->X, p->Y, p->X); fe_sub(r->Y, p->Y, p->X); @@ -2963,3 +2963,53 @@ int sc_isnonzero(const unsigned char *s) { s[18] | s[19] | s[20] | s[21] | s[22] | s[23] | s[24] | s[25] | s[26] | s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1; } + +// see implmentation of ge_frombytes_vartime above +void fe_frombytes(fe h, const unsigned char *s) +{ + /* From fe_frombytes.c */ + + int64_t h0 = load_4(s); + int64_t h1 = load_3(s + 4) << 6; + int64_t h2 = load_3(s + 7) << 5; + int64_t h3 = load_3(s + 10) << 3; + int64_t h4 = load_3(s + 13) << 2; + int64_t h5 = load_4(s + 16); + int64_t h6 = load_3(s + 20) << 7; + int64_t h7 = load_3(s + 23) << 5; + int64_t h8 = load_3(s + 26) << 4; + int64_t h9 = (load_3(s + 29) & 8388607) << 2; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + carry9 = (h9 + (int64_t)(1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + carry1 = (h1 + (int64_t)(1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry3 = (h3 + (int64_t)(1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry5 = (h5 + (int64_t)(1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + carry7 = (h7 + (int64_t)(1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry0 = (h0 + (int64_t)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry2 = (h2 + (int64_t)(1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry4 = (h4 + (int64_t)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry6 = (h6 + (int64_t)(1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + carry8 = (h8 + (int64_t)(1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} diff --git a/src/crypto/crypto-ops.h b/src/crypto/crypto-ops.h index c29c100d..138db1d2 100644 --- a/src/crypto/crypto-ops.h +++ b/src/crypto/crypto-ops.h @@ -104,13 +104,17 @@ void ge_scalarmult(ge_p2 *, const unsigned char *, const ge_p3 *); void ge_scalarmult_p3(ge_p3 *, const unsigned char *, const ge_p3 *); void ge_double_scalarmult_precomp_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *, const ge_dsmp); void ge_mul8(ge_p1p1 *, const ge_p2 *); +void ge_fromfe_frombytes_vartime(ge_p2 *, const unsigned char *); +void ge_p3_0(ge_p3 *h); +void ge_sub(ge_p1p1 *, const ge_p3 *, const ge_cached *); + extern const fe fe_ma2; extern const fe fe_ma; extern const fe fe_fffb1; extern const fe fe_fffb2; extern const fe fe_fffb3; extern const fe fe_fffb4; -void ge_fromfe_frombytes_vartime(ge_p2 *, const unsigned char *); + void sc_0(unsigned char *); void sc_reduce32(unsigned char *); void sc_add(unsigned char *, const unsigned char *, const unsigned char *); @@ -118,3 +122,9 @@ void sc_sub(unsigned char *, const unsigned char *, const unsigned char *); void sc_mulsub(unsigned char *, const unsigned char *, const unsigned char *, const unsigned char *); int sc_check(const unsigned char *); int sc_isnonzero(const unsigned char *); /* Doesn't normalize */ + +void fe_sq(fe h, const fe f); +void fe_mul(fe, const fe, const fe); +void fe_frombytes(fe h, const unsigned char *s); +void fe_invert(fe out, const fe z); +void fe_tobytes(unsigned char *s, const fe h); diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index f6a3aebf..64df2444 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -288,7 +288,7 @@ namespace crypto { uint8_t* const m_p_data; size_t m_data_used; bool m_ready; - }; + }; // class stream_cn_hash } // namespace crypto diff --git a/src/currency_core/account.cpp b/src/currency_core/account.cpp index 85c5ba7f..4f8e9320 100644 --- a/src/currency_core/account.cpp +++ b/src/currency_core/account.cpp @@ -226,6 +226,11 @@ namespace currency return true; } //----------------------------------------------------------------- + bool account_base::is_seed_tracking(const std::string& seed_phrase) + { + return seed_phrase.find(':') != std::string::npos; + } + //----------------------------------------------------------------- bool account_base::is_seed_password_protected(const std::string& seed_phrase, bool& is_password_protected) { //cut the last timestamp word from restore_dats diff --git a/src/currency_core/account.h b/src/currency_core/account.h index ba723670..305b02e3 100644 --- a/src/currency_core/account.h +++ b/src/currency_core/account.h @@ -79,6 +79,7 @@ namespace currency static std::string vector_of_chars_to_string(const std::vector& v) { return std::string(v.begin(), v.end()); } static std::vector string_to_vector_of_chars(const std::string& v) { return std::vector(v.begin(), v.end()); } static bool is_seed_password_protected(const std::string& seed_phrase, bool& is_password_protected); + static bool is_seed_tracking(const std::string& seed_phrase); BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(m_keys) diff --git a/src/wallet/wallet_helpers.h b/src/wallet/wallet_helpers.h index 12355011..8e37d856 100644 --- a/src/wallet/wallet_helpers.h +++ b/src/wallet/wallet_helpers.h @@ -27,27 +27,39 @@ namespace tools inline std::string get_seed_phrase_info(const std::string& seed_phrase, const std::string& seed_password, view::seed_phrase_info& result) { //cut the last timestamp word from restore_dats - try{ - result.syntax_correct = currency::account_base::is_seed_password_protected(seed_phrase, result.require_password); + try + { + //restore_from_tracking_seed + bool is_tracking = currency::account_base::is_seed_tracking(seed_phrase); + if (is_tracking) + { + currency::account_base acc; + result.require_password = false; + result.hash_sum_matched = false; + result.syntax_correct = acc.restore_from_tracking_seed(seed_phrase); + } + else + { + result.syntax_correct = currency::account_base::is_seed_password_protected(seed_phrase, result.require_password); + if (result.syntax_correct && result.require_password) + { + if (seed_password.size()) + { + currency::account_base acc; + result.hash_sum_matched = acc.restore_from_seed_phrase(seed_phrase, seed_password); + } + else + { + result.hash_sum_matched = false; + } + } + } + return API_RETURN_CODE_OK; } catch (...) { result.syntax_correct = false; return API_RETURN_CODE_OK; } - - if (result.syntax_correct && result.require_password) - { - if (seed_password.size()) - { - currency::account_base acc; - result.hash_sum_matched = acc.restore_from_seed_phrase(seed_phrase, seed_password); - } - else - { - result.hash_sum_matched = false; - } - } - return API_RETURN_CODE_OK; } } \ No newline at end of file diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index ec07c3b2..eb101997 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -1060,16 +1060,22 @@ std::string wallets_manager::is_pos_allowed() } std::string wallets_manager::is_valid_brain_restore_data(const std::string& seed_phrase, const std::string& seed_password) { + currency::account_base acc; - if (acc.restore_from_seed_phrase(seed_phrase, seed_password)) - return API_RETURN_CODE_TRUE; - - currency::account_public_address addr; - crypto::secret_key view_sec_key; - uint64_t ts; - if (currency::parse_tracking_seed(seed_phrase, addr, view_sec_key, ts)) - return API_RETURN_CODE_TRUE; + if (!currency::account_base::is_seed_tracking(seed_phrase)) + { + if (acc.restore_from_seed_phrase(seed_phrase, seed_password)) + return API_RETURN_CODE_TRUE; + } + else + { + currency::account_public_address addr = AUTO_VAL_INIT(addr); + crypto::secret_key view_sec_key = AUTO_VAL_INIT(view_sec_key); + uint64_t ts = 0; + if (currency::parse_tracking_seed(seed_phrase, addr, view_sec_key, ts)) + return API_RETURN_CODE_TRUE; + } return API_RETURN_CODE_FALSE; } #ifndef MOBILE_WALLET_BUILD @@ -1115,8 +1121,8 @@ std::string wallets_manager::restore_wallet(const std::wstring& path, const std: currency::account_base acc; try { - bool auditable_watch_only = seed_phrase.find(':') != std::string::npos; - w->restore(path, password, seed_phrase, auditable_watch_only, seed_password); + bool is_tracking = currency::account_base::is_seed_tracking(seed_phrase); + w->restore(path, password, seed_phrase, is_tracking, seed_password); //owr.seed = w->get_account().get_seed_phrase(); } catch (const tools::error::file_exists&) diff --git a/tests/unit_tests/crypto_tests.cpp b/tests/unit_tests/crypto_tests.cpp new file mode 100644 index 00000000..366a1145 --- /dev/null +++ b/tests/unit_tests/crypto_tests.cpp @@ -0,0 +1,803 @@ +// Copyright (c) 2020 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#define USE_INSECURE_RANDOM_RPNG_ROUTINES // turns on random manupulation for tests +#include "gtest/gtest.h" +#include "crypto/crypto.h" + +extern "C" { +#include "crypto/crypto-ops.h" +void fe_reduce(fe u, const fe h) +{ + /* From fe_frombytes.c */ + + // loading changed + + int64_t h0 = h[0]; + int64_t h1 = h[1]; + int64_t h2 = h[2]; + int64_t h3 = h[3]; + int64_t h4 = h[4]; + int64_t h5 = h[5]; + int64_t h6 = h[6]; + int64_t h7 = h[7]; + int64_t h8 = h[8]; + int64_t h9 = h[9]; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + carry9 = (h9 + (int64_t)(1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + carry1 = (h1 + (int64_t)(1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry3 = (h3 + (int64_t)(1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry5 = (h5 + (int64_t)(1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + carry7 = (h7 + (int64_t)(1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry0 = (h0 + (int64_t)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry2 = (h2 + (int64_t)(1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry4 = (h4 + (int64_t)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry6 = (h6 + (int64_t)(1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + carry8 = (h8 + (int64_t)(1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + u[0] = h0; + u[1] = h1; + u[2] = h2; + u[3] = h3; + u[4] = h4; + u[5] = h5; + u[6] = h6; + u[7] = h7; + u[8] = h8; + u[9] = h9; + + /* End fe_frombytes.c */ + +} + + +void sc_mul(unsigned char *s, const unsigned char *a, const unsigned char *b) +{ + unsigned char c[32]; + unsigned char neg_a[32]; + sc_0(c); + sc_sub(neg_a, c, a); + // s = c - ab + sc_mulsub(s, neg_a, b, c); +} + +} // extern "C" + + +unsigned char Lm2[32] = { 0xeb, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10 }; + +// out = z ^ s (mod l) +void sc_exp(unsigned char* out, const unsigned char* z, const unsigned char* s) +{ + sc_0(out); + out[0] = 1; + if (sc_isnonzero(s) == 0) + { + return; + } + + // calc position of the most significant bit of s + size_t msb_s = 0; + for (size_t i = 31; i != SIZE_MAX; --i) + { + if (s[i] != 0) + { + msb_s = 8 * i; + uint8_t t = s[i] >> 1; + while (t) + { + t >>= 1; + ++msb_s; + } + break; + } + } + + //memcpy(out, z, sizeof(crypto::ec_scalar)); + + for (size_t i = msb_s; i != SIZE_MAX; --i) + { + sc_mul(out, out, out); + std::cout << "sc_mul(out, out, out);" << std::endl; + uint8_t bit = (s[i / 8] >> (i % 8)) & 1; + if (bit) + { + sc_mul(out, out, z); + std::cout << "sc_mul(out, out, z);" << std::endl; + } + } +} + +void sc_invert(unsigned char* out, const unsigned char* z) +{ + memcpy(out, z, sizeof(crypto::ec_scalar)); + for(size_t i = 0; i < 128; ++i) + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, out); + sc_mul(out, out, z); + sc_mul(out, out, out); + sc_mul(out, out, z); +} + + + + +template +std::string pod_to_hex_big_endian(const pod_t &h) +{ + constexpr char hexmap[] = "0123456789abcdef"; + const char* data = reinterpret_cast(&h); + size_t len = sizeof h; + + std::string s(len * 2, ' '); + for (size_t i = 0; i < len; ++i) { + s[2 * i] = hexmap[(data[len - 1 - i] & 0xF0) >> 4]; + s[2 * i + 1] = hexmap[(data[len - 1 - i] & 0x0F)]; + } + + return s; +} + + +int fe_cmp(const fe a, const fe b) +{ + for (size_t i = 9; i != SIZE_MAX; --i) + { + if (reinterpret_cast(a[i]) < reinterpret_cast(b[i])) return -1; + if (reinterpret_cast(a[i]) > reinterpret_cast(b[i])) return 1; + } + return 0; +} + +static const fe scalar_L_fe = { 16110573, 10012311, -6632702, 16062397, 5471207, 0, 0, 0, 0, 4194304 }; + + +__declspec(align(32)) +struct scalar_t +{ + //fe m_fe; // 40 bytes, array 10 * 4, optimized form + union + { + uint64_t m_u64[4]; + unsigned char m_s[32]; + }; + // DONE! consider 1) change to aligned array of unsigned chars + // consider 2) add 32 byte after to speed up sc_reduce by decreasing num of copy operations + + scalar_t() + {} + + scalar_t(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) + { + m_u64[0] = a0; + m_u64[1] = a1; + m_u64[2] = a2; + m_u64[3] = a3; + } + + scalar_t(int64_t v) + { + zero(); + if (v == 0) + { + return; + } + //unsigned char bytes[32] = {0}; + reinterpret_cast(m_s) = v; + //fe_frombytes(m_fe, bytes); + // do not need to call reduce as 2^64 < L + } + + unsigned char* data() + { + return &m_s[0]; + } + + const unsigned char* data() const + { + return &m_s[0]; + } + + operator crypto::secret_key() const + { + crypto::secret_key result; + memcpy(result.data, &m_s, sizeof result.data); + //fe_tobytes(reinterpret_cast(&result), m_fe); + return result; + } + + bool from_secret_key(const crypto::secret_key& sk) + { + //fe_frombytes(m_fe, reinterpret_cast(&sk)); + return false; + } + + void zero() + { + //fe_0(m_fe); + m_u64[0] = 0; + m_u64[1] = 0; + m_u64[2] = 0; + m_u64[3] = 0; + //memset(&m_s, 0, sizeof m_s); + } + + void make_random() + { + unsigned char tmp[64]; + crypto::generate_random_bytes(64, tmp); + sc_reduce(tmp); + memcpy(&m_s, tmp, 32); + } + + bool is_zero() const + { + return sc_isnonzero(&m_s[0]) == 0; + } + + scalar_t operator+(const scalar_t& v) const + { + scalar_t result; + sc_add(reinterpret_cast(&result), reinterpret_cast(&m_s), reinterpret_cast(&v)); + return result; + } + + scalar_t operator-(const scalar_t& v) const + { + scalar_t result; + sc_sub(reinterpret_cast(&result), reinterpret_cast(&m_s), reinterpret_cast(&v)); + return result; + } + + scalar_t operator*(const scalar_t& v) const + { + scalar_t result; + sc_mul(reinterpret_cast(&result), reinterpret_cast(&m_s), reinterpret_cast(&v)); + return result; + } + + scalar_t reciprocal() const + { + /*unsigned char bytes[32] = {2}; + fe t; + fe_frombytes(t, (unsigned char*)&bytes); + fe r; + fe_invert(r, t); + fe m; + fe_mul(m, r, t); + + + fe r2; + my_fe_invert(r2, t); + fe m2; + fe_mul(m2, r2, t); + + scalar_t result; + fe v_f; + fe result_f; + fe_frombytes(v_f, reinterpret_cast(&m_s)); + my_fe_invert(result_f, v_f); + fe_tobytes(reinterpret_cast(&result), result_f); + //sc_reduce(reinterpret_cast(&result)); + fe result_check; + fe_frombytes(result_check, reinterpret_cast(&result)); + fe v_check; + fe_invert(v_check, result_check); + //sc_reduce(reinterpret_cast(&result)); + return result;*/ + + scalar_t result; + fe v_f; + fe result_f; + fe_frombytes(v_f, reinterpret_cast(&m_s)); + fe_invert(result_f, v_f); + + /*fe x2; + fe_mul(x2, result_f, v_f); + + fe_reduce(result_f, result_f); + if (fe_cmp(result_f, scalar_L_fe) > 0) + { + // result_f > L + fe_sub(result_f, result_f, scalar_L_fe); + if (fe_cmp(result_f, scalar_L_fe) >= 0) + return false; // fail + }*/ + unsigned char tmp[64] = { 0 }; + fe_tobytes(reinterpret_cast(&tmp), result_f); + sc_reduce(tmp); + memcpy(&result, &tmp, sizeof result); + return result; + } + + scalar_t operator/(const scalar_t& v) const + { + return operator*(v.reciprocal()); + } + + bool operator==(const scalar_t& rhs) const + { + return + m_u64[0] == rhs.m_u64[0] && + m_u64[1] == rhs.m_u64[1] && + m_u64[2] == rhs.m_u64[2] && + m_u64[3] == rhs.m_u64[3]; + } + + bool operator<(const scalar_t& rhs) const + { + if (m_u64[3] < rhs.m_u64[3]) return true; + if (m_u64[3] > rhs.m_u64[3]) return false; + if (m_u64[2] < rhs.m_u64[2]) return true; + if (m_u64[2] > rhs.m_u64[2]) return false; + if (m_u64[1] < rhs.m_u64[1]) return true; + if (m_u64[1] > rhs.m_u64[1]) return false; + if (m_u64[0] < rhs.m_u64[0]) return true; + if (m_u64[0] > rhs.m_u64[0]) return false; + return false; + } + + bool operator>(const scalar_t& rhs) const + { + if (m_u64[3] < rhs.m_u64[3]) return false; + if (m_u64[3] > rhs.m_u64[3]) return true; + if (m_u64[2] < rhs.m_u64[2]) return false; + if (m_u64[2] > rhs.m_u64[2]) return true; + if (m_u64[1] < rhs.m_u64[1]) return false; + if (m_u64[1] > rhs.m_u64[1]) return true; + if (m_u64[0] < rhs.m_u64[0]) return false; + if (m_u64[0] > rhs.m_u64[0]) return true; + return false; + } + + friend std::ostream& operator<<(std::ostream& ss, const scalar_t &v) + { + return ss << "0x" << pod_to_hex_big_endian(v); + } + +}; // struct scalar_t + +//__declspec(align(32)) +struct point_t +{ + // A point(x, y) is represented in extended homogeneous coordinates (X, Y, Z, T) + // with x = X / Z, y = Y / Z, x * y = T / Z. + ge_p3 m_p3; + + point_t() + { + } + + void zero() + { + ge_p3_0(&m_p3); + } + + bool from_public_key(const crypto::public_key& pk) + { + return ge_frombytes_vartime(&m_p3, reinterpret_cast(&pk)) == 0; + } + + operator crypto::public_key() + { + crypto::public_key result; + ge_p3_tobytes((unsigned char*)&result, &m_p3); + return result; + } + + point_t operator+(const point_t& rhs) + { + point_t result; + ge_cached rhs_c; + ge_p1p1 t; + ge_p3_to_cached(&rhs_c, &rhs.m_p3); + ge_add(&t, &m_p3, &rhs_c); + ge_p1p1_to_p3(&result.m_p3, &t); + return result; + } + + point_t operator-(const point_t& rhs) + { + point_t result; + ge_cached rhs_c; + ge_p1p1 t; + ge_p3_to_cached(&rhs_c, &rhs.m_p3); + ge_sub(&t, &m_p3, &rhs_c); + ge_p1p1_to_p3(&result.m_p3, &t); + return result; + } + + friend point_t operator*(const scalar_t& lhs, const point_t& rhs) + { + point_t result; + ge_scalarmult_p3(&result.m_p3, reinterpret_cast(&lhs), &rhs.m_p3); + return result; + } + + friend bool operator==(const point_t& lhs, const point_t& rhs) + { + // convert to xy form, then compare components (because (z, y, z, t) representation is not unique) + fe lrecip, lx, ly; + fe rrecip, rx, ry; + + fe_invert(lrecip, lhs.m_p3.Z); + fe_invert(rrecip, rhs.m_p3.Z); + + fe_mul(lx, lhs.m_p3.X, lrecip); + fe_mul(rx, rhs.m_p3.X, rrecip); + if (memcmp(&lx, &rx, sizeof lx) != 0) + return false; + + fe_mul(ly, lhs.m_p3.Y, lrecip); + fe_mul(ry, rhs.m_p3.Y, rrecip); + if (memcmp(&ly, &ry, sizeof ly) != 0) + return false; + + return true; + }; +}; // struct point_t + +struct point_g_t : public point_t +{ + point_g_t() + { + + } + + friend point_t operator*(const scalar_t& lhs, const point_g_t&) + { + point_t result; + ge_scalarmult_base(&result.m_p3, reinterpret_cast(&lhs)); + return result; + } + + /*friend point_t operator*(const int64_t lhs, const point_g_t& rhs) + { + return operator*(scalar_t) + }*/ + + static_assert(sizeof(crypto::public_key) == 32, "size error"); + +}; // struct point_g_t + +static const point_g_t point_G; + +static const scalar_t scalar_L = { 0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0x0, 0x1000000000000000 }; +static const scalar_t scalar_Lm1 = { 0x5812631a5cf5d3ec, 0x14def9dea2f79cd6, 0x0, 0x1000000000000000 }; +static const scalar_t scalar_P = { 0xffffffffffffffed, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff }; +static const scalar_t scalar_Pm1 = { 0xffffffffffffffec, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff }; +static const scalar_t scalar_256m1 = { 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff }; + + +/* temporary disable in order not to break the compilation +TEST(crypto, scalar_basics) +{ + scalar_t zero = 0; + ASSERT_TRUE(zero.is_zero()); + scalar_t one = 1; + ASSERT_FALSE(one.is_zero()); + ASSERT_TRUE(one > zero); + scalar_t z = 0; + for (size_t j = 0; j < 1000; ++j) + { + z.make_random(); + ASSERT_FALSE(z.is_zero()); + ASSERT_GT(z, z - 1); + ASSERT_LT(z, z + 1); + } + + ASSERT_TRUE(scalar_L > 0 && !(scalar_L < 0)); + ASSERT_TRUE(scalar_Lm1 > 0 && !(scalar_Lm1 < 0)); + ASSERT_TRUE(scalar_Lm1 < scalar_L); + ASSERT_FALSE(scalar_Lm1 > scalar_L); + ASSERT_TRUE(scalar_P > scalar_Pm1); + ASSERT_FALSE(scalar_P < scalar_Pm1); + + std::cout << "0 = " << zero << std::endl; + std::cout << "1 = " << one << std::endl; + std::cout << "L = " << scalar_L << std::endl; + std::cout << "Lm1 = " << scalar_Lm1 << std::endl; + std::cout << "P = " << scalar_P << std::endl; + std::cout << "Pm1 = " << scalar_Pm1 << std::endl; + + // check rolling over L for scalars arithmetics + ASSERT_EQ(scalar_Lm1 + 1, 0); + ASSERT_EQ(scalar_t(0) - 1, scalar_Lm1); + ASSERT_EQ(scalar_Lm1 * 2, scalar_Lm1 - 1); // (L - 1) * 2 = L + L - 2 = (L - 1) - 1 (mod L) + ASSERT_EQ(scalar_Lm1 * 100, scalar_Lm1 - 99); + ASSERT_EQ(scalar_Lm1 * scalar_Lm1, 1); // (L - 1) * (L - 1) = L*L - 2L + 1 = 1 (mod L) + + std::cout << std::endl; + + + + fe L_fe; + fe_frombytes(L_fe, &scalar_L.m_s[0]); + + fe Pm1_fe; + fe_frombytes(Pm1_fe, &scalar_Pm1.m_s[0]); + + fe r; + fe f_1 = { 1 }; + fe_add(r, Pm1_fe, f_1); + + + + while(true) + { + static int ti = 2; + static int pi = 3; + scalar_t t = ti; + scalar_t p = pi; + scalar_t r = 0; + //sc_exp(r.data(), t.data(), Lm2); + + sc_invert(r.data(), t.data()); + + std::cout << ti << " ^ L-2" << " = " << r << std::endl; + + r = r * 6; + std::cout << r << std::endl; + } + + + + scalar_t a = 2; + a = a / 2; + std::cout << "2 / 2 = " << a << std::endl; + a = scalar_Lm1 / 2; + std::cout << "L-1 / 2 = " << a << std::endl; + a = a * 2; + std::cout << "L-1 / 2 * 2 = " << a << std::endl; + +} + +TEST(crypto, point_basics) +{ + scalar_t s = 4; + point_t E = s * point_G; + point_t X = 4 * E; + point_t K = 193847 * point_G; + point_t C = E + K; + + ASSERT_TRUE(X == 16 * point_G); + ASSERT_TRUE(C - K == E); + ASSERT_TRUE(C - E == K); + ASSERT_TRUE(C == 193851 * point_G); +} + +TEST(crypto, scalar_reciprocal) +{ + int64_t test_nums[] = {1, 2, 10}; + + for (size_t i = 0; i < sizeof test_nums / sizeof test_nums[0]; ++i) + { + scalar_t s = test_nums[i]; + scalar_t z = s - s; + ASSERT_TRUE(z.is_zero()); + } + + scalar_t s = 20; + scalar_t d = 5; + scalar_t e = s / d; + scalar_t m = e * d; + + ASSERT_TRUE(m == s); +} + + +TEST(crypto, scalars) +{ + scalar_t s = 20; + scalar_t d = 5; + scalar_t e = s / d; + scalar_t m = e * d; + + ASSERT_TRUE(m == s); +} + +*/ \ No newline at end of file