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))
|
__declspec(align(32))
|
||||||
struct scalar_t
|
struct scalar_t
|
||||||
{
|
{
|
||||||
//fe m_fe; // 40 bytes, array 10 * 4, optimized form
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
uint64_t m_u64[4];
|
uint64_t m_u64[4];
|
||||||
|
|
@ -201,10 +200,8 @@ struct scalar_t
|
||||||
{
|
{
|
||||||
zero();
|
zero();
|
||||||
if (v == 0)
|
if (v == 0)
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
m_u64[0] = v;
|
||||||
reinterpret_cast<uint64_t&>(m_s) = v;
|
|
||||||
// do not need to call reduce as 2^64 < L
|
// do not need to call reduce as 2^64 < L
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,24 +219,32 @@ struct scalar_t
|
||||||
{
|
{
|
||||||
crypto::secret_key result;
|
crypto::secret_key result;
|
||||||
memcpy(result.data, &m_s, sizeof result.data);
|
memcpy(result.data, &m_s, sizeof result.data);
|
||||||
//fe_tobytes(reinterpret_cast<unsigned char*>(&result), m_fe);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool from_secret_key(const crypto::secret_key& sk)
|
bool from_secret_key(const crypto::secret_key& sk)
|
||||||
{
|
{
|
||||||
|
// TODO
|
||||||
//fe_frombytes(m_fe, reinterpret_cast<const unsigned char*>(&sk));
|
//fe_frombytes(m_fe, reinterpret_cast<const unsigned char*>(&sk));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void zero()
|
void zero()
|
||||||
{
|
{
|
||||||
//fe_0(m_fe);
|
|
||||||
m_u64[0] = 0;
|
m_u64[0] = 0;
|
||||||
m_u64[1] = 0;
|
m_u64[1] = 0;
|
||||||
m_u64[2] = 0;
|
m_u64[2] = 0;
|
||||||
m_u64[3] = 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()
|
void make_random()
|
||||||
|
|
@ -247,7 +252,7 @@ struct scalar_t
|
||||||
unsigned char tmp[64];
|
unsigned char tmp[64];
|
||||||
crypto::generate_random_bytes(64, tmp);
|
crypto::generate_random_bytes(64, tmp);
|
||||||
sc_reduce(tmp);
|
sc_reduce(tmp);
|
||||||
memcpy(&m_s, tmp, 32);
|
memcpy(&m_s, tmp, sizeof m_s);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_zero() const
|
bool is_zero() const
|
||||||
|
|
@ -486,13 +491,26 @@ struct point_g_t : public point_t
|
||||||
|
|
||||||
}; // struct point_g_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(z < z + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_TRUE(scalar_L > 0 && !(scalar_L < 0));
|
ASSERT_TRUE(c_scalar_L > 0 && !(c_scalar_L < 0));
|
||||||
ASSERT_TRUE(scalar_Lm1 > 0 && !(scalar_Lm1 < 0));
|
ASSERT_TRUE(c_scalar_Lm1 > 0 && !(c_scalar_Lm1 < 0));
|
||||||
ASSERT_TRUE(scalar_Lm1 < scalar_L);
|
ASSERT_TRUE(c_scalar_Lm1 < c_scalar_L);
|
||||||
ASSERT_FALSE(scalar_Lm1 > scalar_L);
|
ASSERT_FALSE(c_scalar_Lm1 > c_scalar_L);
|
||||||
ASSERT_TRUE(scalar_P > scalar_Pm1);
|
ASSERT_TRUE(c_scalar_P > c_scalar_Pm1);
|
||||||
ASSERT_FALSE(scalar_P < scalar_Pm1);
|
ASSERT_FALSE(c_scalar_P < c_scalar_Pm1);
|
||||||
|
|
||||||
std::cout << "0 = " << zero << std::endl;
|
std::cout << "0 = " << zero << std::endl;
|
||||||
std::cout << "1 = " << one << std::endl;
|
std::cout << "1 = " << one << std::endl;
|
||||||
std::cout << "L = " << scalar_L << std::endl;
|
std::cout << "L = " << c_scalar_L << std::endl;
|
||||||
std::cout << "L-1 = " << scalar_Lm1 << std::endl;
|
std::cout << "L-1 = " << c_scalar_Lm1 << std::endl;
|
||||||
std::cout << "P = " << scalar_P << std::endl;
|
std::cout << "P = " << c_scalar_P << std::endl;
|
||||||
std::cout << "P-1 = " << scalar_Pm1 << std::endl;
|
std::cout << "P-1 = " << c_scalar_Pm1 << std::endl;
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
// check rolling over L for scalars arithmetics
|
// check rolling over L for scalars arithmetics
|
||||||
ASSERT_EQ(scalar_Lm1 + 1, 0);
|
ASSERT_EQ(c_scalar_Lm1 + 1, 0);
|
||||||
ASSERT_EQ(scalar_t(0) - 1, scalar_Lm1);
|
ASSERT_EQ(scalar_t(0) - 1, c_scalar_Lm1);
|
||||||
ASSERT_EQ(scalar_Lm1 * 2, scalar_Lm1 - 1); // (L - 1) * 2 = L + L - 2 = (L - 1) - 1 (mod L)
|
ASSERT_EQ(c_scalar_Lm1 * 2, c_scalar_Lm1 - 1); // (L - 1) * 2 = L + L - 2 = (L - 1) - 1 (mod L)
|
||||||
ASSERT_EQ(scalar_Lm1 * 100, scalar_Lm1 - 99);
|
ASSERT_EQ(c_scalar_Lm1 * 100, c_scalar_Lm1 - 99);
|
||||||
ASSERT_EQ(scalar_Lm1 * scalar_Lm1, 1); // (L - 1) * (L - 1) = L*L - 2L + 1 = 1 (mod L)
|
ASSERT_EQ(c_scalar_Lm1 * c_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(c_scalar_Lm1 * (c_scalar_Lm1 - 1) * c_scalar_Lm1, c_scalar_Lm1 - 1);
|
||||||
ASSERT_EQ(scalar_L * scalar_L, 0);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -795,24 +813,24 @@ TEST(crypto, scalar_arithmetic_assignment)
|
||||||
TEST(crypto, point_basics)
|
TEST(crypto, point_basics)
|
||||||
{
|
{
|
||||||
scalar_t s = 4;
|
scalar_t s = 4;
|
||||||
point_t E = s * point_G;
|
point_t E = s * c_point_G;
|
||||||
point_t X = 4 * E;
|
point_t X = 4 * E;
|
||||||
point_t K = 193847 * point_G;
|
point_t K = 193847 * c_point_G;
|
||||||
point_t C = E + K;
|
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 - K, E);
|
||||||
ASSERT_EQ(C - E, K);
|
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(C / 3, E / 3 + K / 3);
|
||||||
//ASSERT_EQ(K, 61 * (K / (61)));
|
//ASSERT_EQ(K, 61 * (K / (61)));
|
||||||
//ASSERT_EQ(K, 192847 * (K / scalar_t(192847)));
|
//ASSERT_EQ(K, 192847 * (K / scalar_t(192847)));
|
||||||
ASSERT_EQ(K, 61 * (283 * (192847 * (K / (192847ull * 283 * 61)))));
|
ASSERT_EQ(K, 61 * (283 * (192847 * (K / (192847ull * 283 * 61)))));
|
||||||
|
|
||||||
ASSERT_EQ(E, point_G + point_G + point_G + point_G);
|
ASSERT_EQ(E, c_point_G + c_point_G + c_point_G + c_point_G);
|
||||||
ASSERT_EQ(E - point_G, 3 * point_G);
|
ASSERT_EQ(E - c_point_G, 3 * c_point_G);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -851,6 +869,25 @@ TEST(crypto, scalars)
|
||||||
return true;
|
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()
|
int crypto_tests()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue