forked from lthn/blockchain
crypto: L2S protocol introduced (WIP)
This commit is contained in:
parent
cb18279d57
commit
add0f39302
2 changed files with 188 additions and 39 deletions
112
tests/functional_tests/L2S.h
Normal file
112
tests/functional_tests/L2S.h
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
// Copyright (c) 2020 Zano Project (https://zano.org/)
|
||||
// Copyright (c) 2020 Locksmith (acmxddk@gmail.com)
|
||||
// Copyright (c) 2020 sowle (crypto.sowle@gmail.com)
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// This file contains the implementation of L2S membership proof protocol
|
||||
// and a linkable ring signature scheme based on it.
|
||||
//
|
||||
|
||||
point_t ml2s_rsum_impl(size_t n, size_t N, std::vector<point_t>::const_iterator X_array_bg_it, const std::vector<scalar_t>& c1_array,
|
||||
const std::vector<scalar_t>& c3_array, const scalar_t& cn)
|
||||
{
|
||||
if (n == 1)
|
||||
return *X_array_bg_it + cn * *(X_array_bg_it + 1);
|
||||
|
||||
// n >= 2, N >= 4
|
||||
return ml2s_rsum_impl(n - 1, N / 2, X_array_bg_it, c1_array, c3_array, c1_array[n - 2]) +
|
||||
cn * ml2s_rsum_impl(n - 1, N / 2, X_array_bg_it + N / 2, c1_array, c3_array, c3_array[n - 2]);
|
||||
}
|
||||
|
||||
bool ml2s_rsum(size_t n, const std::vector<point_t>& X_array, const std::vector<scalar_t>& c1_array,
|
||||
const std::vector<scalar_t>& c3_array, point_t& result)
|
||||
{
|
||||
size_t N = (size_t)1 << n;
|
||||
CHECK_AND_ASSERT_MES(n != 0, false, "n == 0");
|
||||
CHECK_AND_ASSERT_MES(N == X_array.size(), false, "|X_array| != N, " << X_array.size() << ", " << N);
|
||||
CHECK_AND_ASSERT_MES(c1_array.size() == n, false, "|c1_array| != n, " << c1_array.size() << ", " << n);
|
||||
CHECK_AND_ASSERT_MES(c3_array.size() == n - 1, false, "|c3_array| != n - 1, " << c3_array.size() << ", " << n - 1);
|
||||
|
||||
result = ml2s_rsum_impl(n, N, X_array.begin(), c1_array, c3_array, c1_array[n - 1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ml2s_signature_element
|
||||
{
|
||||
point_t Z0;
|
||||
point_t T0;
|
||||
scalar_t t0;
|
||||
point_t Z;
|
||||
std::vector<scalar_t> r_array;
|
||||
std::vector<point_t> H_array;
|
||||
point_t T;
|
||||
scalar_t t;
|
||||
};
|
||||
|
||||
struct ml2s_signature
|
||||
{
|
||||
scalar_t z;
|
||||
std::vector<ml2s_signature_element> elements;
|
||||
};
|
||||
|
||||
/* WIP
|
||||
// reference: mL2SLnkSig_Verif()
|
||||
bool ml2s_lnk_sig_verif(const scalar_t& m, const std::vector<point_t>& B_array, const ml2s_signature& signature, uint8_t* p_err = nullptr)
|
||||
{
|
||||
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
|
||||
if (!(cond)) { LOG_PRINT_RED("ml2s_lnk_sig_verif: \"" << #cond << "\" is false at " << LOCATION_SS, LOG_LEVEL_3); if (p_err) *p_err = err_code; return false; }
|
||||
|
||||
auto hash_point_lambda = [&signature](const point_t& point) { return point + signature.z * hash_helper_t::hp(point); };
|
||||
|
||||
size_t L = signature.elements.size();
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(L > 0, 0);
|
||||
size_t n = signature.elements[0].r_array.size();
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(n < 32, 4);
|
||||
size_t N = (size_t)1 << n;
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(B_array.size() == N / 2, 5);
|
||||
|
||||
std::vector<point_t> I_array(L);
|
||||
std::vector<point_t> A_array(L);
|
||||
|
||||
for (size_t i = 0; i < L; ++i)
|
||||
{
|
||||
I_array[i] = (signature.elements[i].Z0 - c_point_G) / signature.z;
|
||||
A_array[i] = signature.elements[i].Z0;
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(signature.elements[i].r_array.size() == n, 1);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(signature.elements[i].H_array.size() == n, 2);
|
||||
}
|
||||
|
||||
scalar_t z_ = hash_helper_t::hs(m, B_array, I_array);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(z_ == signature.z, 3);
|
||||
|
||||
scalar_t e = hash_helper_t::hs(signature.z);
|
||||
|
||||
// ref: mL2SHPoM_Verif()
|
||||
|
||||
// ref: X = mL2SHPoM_GetDecoySet(N, A, hash_point_cb, preimage_set_gen_cb)
|
||||
std::vector<point_t> P_array(B_array.size());
|
||||
for (size_t i = 0; i < B_array.size(); ++i)
|
||||
P_array[i] = hash_point_lambda(B_array[i]);
|
||||
|
||||
point_t Q_shift = hash_helper_t::hs(A_array, P_array) * c_point_G;
|
||||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(P_array.size() * 2 == N, 6);
|
||||
std::vector<point_t> X_array(N);
|
||||
// X_array = { P_array[0], Q_array[0], P_array[1], Q_array[1], etc.
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
X_array[i] = P_array[i / 2];
|
||||
else
|
||||
X_array[i] = hash_point_lambda(Q_shift + B_array[i / 2]);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
|
||||
}
|
||||
|
||||
*/
|
||||
|
|
@ -177,7 +177,6 @@ static const fe scalar_L_fe = { 16110573, 10012311, -6632702, 16062397, 5471207,
|
|||
__declspec(align(32))
|
||||
struct scalar_t
|
||||
{
|
||||
//fe m_fe; // 40 bytes, array 10 * 4, optimized form
|
||||
union
|
||||
{
|
||||
uint64_t m_u64[4];
|
||||
|
|
@ -201,10 +200,8 @@ struct scalar_t
|
|||
{
|
||||
zero();
|
||||
if (v == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<uint64_t&>(m_s) = v;
|
||||
m_u64[0] = v;
|
||||
// do not need to call reduce as 2^64 < L
|
||||
}
|
||||
|
||||
|
|
@ -222,24 +219,32 @@ struct scalar_t
|
|||
{
|
||||
crypto::secret_key result;
|
||||
memcpy(result.data, &m_s, sizeof result.data);
|
||||
//fe_tobytes(reinterpret_cast<unsigned char*>(&result), m_fe);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool from_secret_key(const crypto::secret_key& sk)
|
||||
{
|
||||
// TODO
|
||||
//fe_frombytes(m_fe, reinterpret_cast<const unsigned char*>(&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);
|
||||
}
|
||||
|
||||
static scalar_t random()
|
||||
{
|
||||
unsigned char tmp[64];
|
||||
crypto::generate_random_bytes(64, tmp);
|
||||
sc_reduce(tmp);
|
||||
scalar_t result;
|
||||
memcpy(&result.m_s, tmp, sizeof result.m_s);
|
||||
return result;
|
||||
}
|
||||
|
||||
void make_random()
|
||||
|
|
@ -247,7 +252,7 @@ struct scalar_t
|
|||
unsigned char tmp[64];
|
||||
crypto::generate_random_bytes(64, tmp);
|
||||
sc_reduce(tmp);
|
||||
memcpy(&m_s, tmp, 32);
|
||||
memcpy(&m_s, tmp, sizeof m_s);
|
||||
}
|
||||
|
||||
bool is_zero() const
|
||||
|
|
@ -486,13 +491,26 @@ struct point_g_t : public point_t
|
|||
|
||||
}; // struct point_g_t
|
||||
|
||||
static const point_g_t point_G;
|
||||
static const point_g_t c_point_G;
|
||||
|
||||
static const scalar_t c_scalar_L = { 0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0x0, 0x1000000000000000 };
|
||||
static const scalar_t c_scalar_Lm1 = { 0x5812631a5cf5d3ec, 0x14def9dea2f79cd6, 0x0, 0x1000000000000000 };
|
||||
static const scalar_t c_scalar_P = { 0xffffffffffffffed, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff };
|
||||
static const scalar_t c_scalar_Pm1 = { 0xffffffffffffffec, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff };
|
||||
static const scalar_t c_scalar_256m1 = { 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff };
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include "L2S.h"
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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 };
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -676,31 +694,31 @@ TEST(crypto, scalar_basics)
|
|||
ASSERT_TRUE(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);
|
||||
ASSERT_TRUE(c_scalar_L > 0 && !(c_scalar_L < 0));
|
||||
ASSERT_TRUE(c_scalar_Lm1 > 0 && !(c_scalar_Lm1 < 0));
|
||||
ASSERT_TRUE(c_scalar_Lm1 < c_scalar_L);
|
||||
ASSERT_FALSE(c_scalar_Lm1 > c_scalar_L);
|
||||
ASSERT_TRUE(c_scalar_P > c_scalar_Pm1);
|
||||
ASSERT_FALSE(c_scalar_P < c_scalar_Pm1);
|
||||
|
||||
std::cout << "0 = " << zero << std::endl;
|
||||
std::cout << "1 = " << one << std::endl;
|
||||
std::cout << "L = " << scalar_L << std::endl;
|
||||
std::cout << "L-1 = " << scalar_Lm1 << std::endl;
|
||||
std::cout << "P = " << scalar_P << std::endl;
|
||||
std::cout << "P-1 = " << scalar_Pm1 << std::endl;
|
||||
std::cout << "L = " << c_scalar_L << std::endl;
|
||||
std::cout << "L-1 = " << c_scalar_Lm1 << std::endl;
|
||||
std::cout << "P = " << c_scalar_P << std::endl;
|
||||
std::cout << "P-1 = " << c_scalar_Pm1 << std::endl;
|
||||
std::cout << 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)
|
||||
ASSERT_EQ(scalar_Lm1 * (scalar_Lm1 - 1) * scalar_Lm1, scalar_Lm1 - 1);
|
||||
ASSERT_EQ(scalar_L * scalar_L, 0);
|
||||
ASSERT_EQ(c_scalar_Lm1 + 1, 0);
|
||||
ASSERT_EQ(scalar_t(0) - 1, c_scalar_Lm1);
|
||||
ASSERT_EQ(c_scalar_Lm1 * 2, c_scalar_Lm1 - 1); // (L - 1) * 2 = L + L - 2 = (L - 1) - 1 (mod L)
|
||||
ASSERT_EQ(c_scalar_Lm1 * 100, c_scalar_Lm1 - 99);
|
||||
ASSERT_EQ(c_scalar_Lm1 * c_scalar_Lm1, 1); // (L - 1) * (L - 1) = L*L - 2L + 1 = 1 (mod L)
|
||||
ASSERT_EQ(c_scalar_Lm1 * (c_scalar_Lm1 - 1) * c_scalar_Lm1, c_scalar_Lm1 - 1);
|
||||
ASSERT_EQ(c_scalar_L * c_scalar_L, 0);
|
||||
|
||||
ASSERT_EQ(scalar_t(3) / scalar_Lm1, scalar_t(3) * scalar_Lm1); // because (L - 1) ^ 2 = 1
|
||||
ASSERT_EQ(scalar_t(3) / c_scalar_Lm1, scalar_t(3) * c_scalar_Lm1); // because (L - 1) ^ 2 = 1
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -795,24 +813,24 @@ TEST(crypto, scalar_arithmetic_assignment)
|
|||
TEST(crypto, point_basics)
|
||||
{
|
||||
scalar_t s = 4;
|
||||
point_t E = s * point_G;
|
||||
point_t E = s * c_point_G;
|
||||
point_t X = 4 * E;
|
||||
point_t K = 193847 * point_G;
|
||||
point_t K = 193847 * c_point_G;
|
||||
point_t C = E + K;
|
||||
|
||||
ASSERT_EQ(X, 16 * point_G);
|
||||
ASSERT_EQ(X, 16 * c_point_G);
|
||||
ASSERT_EQ(C - K, E);
|
||||
ASSERT_EQ(C - E, K);
|
||||
ASSERT_EQ(C, (193847 + 4) * point_G);
|
||||
ASSERT_EQ(C, (193847 + 4) * c_point_G);
|
||||
|
||||
ASSERT_EQ(point_G / 1, 1 * point_G);
|
||||
ASSERT_EQ(c_point_G / 1, 1 * c_point_G);
|
||||
ASSERT_EQ(C / 3, E / 3 + K / 3);
|
||||
//ASSERT_EQ(K, 61 * (K / (61)));
|
||||
//ASSERT_EQ(K, 192847 * (K / scalar_t(192847)));
|
||||
ASSERT_EQ(K, 61 * (283 * (192847 * (K / (192847ull * 283 * 61)))));
|
||||
|
||||
ASSERT_EQ(E, point_G + point_G + point_G + point_G);
|
||||
ASSERT_EQ(E - point_G, 3 * point_G);
|
||||
ASSERT_EQ(E, c_point_G + c_point_G + c_point_G + c_point_G);
|
||||
ASSERT_EQ(E - c_point_G, 3 * c_point_G);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -851,6 +869,25 @@ TEST(crypto, scalars)
|
|||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// ML2S tests
|
||||
//
|
||||
|
||||
TEST(ml2s, rsum)
|
||||
{
|
||||
// Ref: Rsum(3, 8, [1, 2, 3, 4, 5, 6, 7, 8], { 1: 1, 2 : 2, 3 : 3 }, { 1: 4, 2 : 5 }) == 659
|
||||
|
||||
point_t A = scalar_t::random() * c_point_G;
|
||||
point_t result;
|
||||
|
||||
bool r = ml2s_rsum(3, std::vector<point_t>{ A, 2 * A, 3 * A, 4 * A, 5 * A, 6 * A, 7 * A, 8 * A },
|
||||
std::vector<scalar_t>{ 1, 2, 3 }, std::vector<scalar_t>{ 4, 5 }, result);
|
||||
ASSERT_TRUE(r);
|
||||
ASSERT_EQ(result, 659 * A);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int crypto_tests()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue