diff --git a/tests/unit_tests/crypto_tests.cpp b/tests/unit_tests/crypto_tests.cpp new file mode 100644 index 00000000..ccb4e293 --- /dev/null +++ b/tests/unit_tests/crypto_tests.cpp @@ -0,0 +1,262 @@ +// 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" + +/* +Input: +a[0]+256*a[1]+...+256^31*a[31] = a +b[0]+256*b[1]+...+256^31*b[31] = b +Output: +s[0]+256*s[1]+...+256^31*s[31] = (ab) mod l +where l = 2^252 + 27742317777372353535851937790883648493 +*/ + +// TODO: make more efficient multiplication +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" + + +struct scalar_t +{ + //fe m_fe; // 40 bytes, array 10 * 4, optimized form + crypto::ec_scalar m_s; + + scalar_t() + {} + + 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 + } + + operator crypto::secret_key() const + { + crypto::secret_key result; + memcpy(result.data, m_s.data, 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); + memset(m_s.data, 0, sizeof m_s.data); + } + + 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_tobytes(reinterpret_cast(&result), result_f); + return result; + } + + scalar_t operator/(const scalar_t& v) const + { + return operator*(v.reciprocal()); + } + + friend bool operator==(const scalar_t& lhs, const scalar_t& rhs) + { + return memcmp(&lhs, &rhs, sizeof lhs) == 0; + } + +}; + +//__declspec(align(32)) +struct point_t +{ + 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; + static_assert(sizeof result == 32, "size error"); + 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) + { + 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_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 const point_g_t point_G; + +TEST(crypto, 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, scalars) +{ + scalar_t s = 20; + scalar_t d = 5; + scalar_t q = s * d; + scalar_t e = s / d; + scalar_t m = e * d; + + // ASSERT_TRUE(m == s); +}