forked from lthn/blockchain
crypto: 4-CLSAG 2-gen implemented, 2-CLSAG slightly improved; + basic test for 4-CLSAG GGXG
This commit is contained in:
parent
bc88d0d642
commit
ae64a8cbd3
4 changed files with 468 additions and 8 deletions
|
|
@ -14,9 +14,12 @@ namespace crypto
|
|||
#define DBG_VAL_PRINT(x) (void(0)) // std::cout << #x ": " << x << std::endl
|
||||
#define DBG_PRINT(x) (void(0)) // std::cout << x << std::endl
|
||||
|
||||
static std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return o << pod_to_hex(v); }
|
||||
|
||||
bool generate_CLSAG_GG(const hash& m, const std::vector<CLSAG_GG_input_ref_t>& ring, const point_t& pseudo_out_amount_commitment, const key_image& ki,
|
||||
const scalar_t& secret_x, const scalar_t& secret_f, uint64_t secret_index, CLSAG_GG_signature& sig)
|
||||
{
|
||||
DBG_PRINT("generate_CLSAG_GG");
|
||||
size_t ring_size = ring.size();
|
||||
CRYPTO_CHECK_AND_THROW_MES(ring_size > 0, "ring size is zero");
|
||||
CRYPTO_CHECK_AND_THROW_MES(secret_index < ring_size, "secret_index is out of range");
|
||||
|
|
@ -38,7 +41,7 @@ namespace crypto
|
|||
hsc.add_pub_key(ring[i].stealth_address);
|
||||
hsc.add_pub_key(ring[i].amount_commitment);
|
||||
}
|
||||
hsc.add_point(pseudo_out_amount_commitment);
|
||||
hsc.add_point(c_scalar_1div8 * pseudo_out_amount_commitment);
|
||||
hsc.add_key_image(ki);
|
||||
hash input_hash = hsc.calc_hash_no_reduce();
|
||||
|
||||
|
|
@ -105,6 +108,7 @@ namespace crypto
|
|||
bool verify_CLSAG_GG(const hash& m, const std::vector<CLSAG_GG_input_ref_t>& ring, const crypto::public_key& pseudo_out_amount_commitment, const key_image& ki,
|
||||
const CLSAG_GG_signature& sig)
|
||||
{
|
||||
DBG_PRINT("verify_CLSAG_GG");
|
||||
size_t ring_size = ring.size();
|
||||
CRYPTO_CHECK_AND_THROW_MES(ring_size > 0, "ring size is zero");
|
||||
CRYPTO_CHECK_AND_THROW_MES(ring_size == sig.r.size(), "ring size != r size");
|
||||
|
|
@ -123,7 +127,7 @@ namespace crypto
|
|||
hsc.add_pub_key(ring[i].stealth_address);
|
||||
hsc.add_pub_key(ring[i].amount_commitment);
|
||||
}
|
||||
hsc.add_point(pseudo_out_amount_commitment_pt);
|
||||
hsc.add_pub_key(pseudo_out_amount_commitment);
|
||||
hsc.add_key_image(ki);
|
||||
hash input_hash = hsc.calc_hash_no_reduce();
|
||||
|
||||
|
|
@ -164,4 +168,290 @@ namespace crypto
|
|||
return c_prev == sig.c;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
|
||||
|
||||
bool generate_CLSAG_GGXG(const hash& m, const std::vector<CLSAG_GGXG_input_ref_t>& ring, const point_t& pseudo_out_amount_commitment, const point_t& extended_amount_commitment, const key_image& ki,
|
||||
const scalar_t& secret_0_xp, const scalar_t& secret_1_f, const scalar_t& secret_2_x, const scalar_t& secret_3_q, uint64_t secret_index, CLSAG_GGXG_signature& sig)
|
||||
{
|
||||
DBG_PRINT("== generate_CLSAG_GGXG ==");
|
||||
size_t ring_size = ring.size();
|
||||
CRYPTO_CHECK_AND_THROW_MES(ring_size > 0, "ring size is zero");
|
||||
CRYPTO_CHECK_AND_THROW_MES(secret_index < ring_size, "secret_index is out of range");
|
||||
|
||||
// calculate key images
|
||||
point_t ki_base = hash_helper_t::hp(ring[secret_index].stealth_address);
|
||||
point_t key_image = secret_0_xp * ki_base;
|
||||
CRYPTO_CHECK_AND_THROW_MES(key_image == point_t(ki), "key image 0 mismatch");
|
||||
|
||||
point_t K1_div8 = (c_scalar_1div8 * secret_1_f) * ki_base;
|
||||
K1_div8.to_public_key(sig.K1);
|
||||
point_t K1 = K1_div8;
|
||||
K1.modify_mul8();
|
||||
|
||||
point_t K2_div8 = (c_scalar_1div8 * secret_2_x) * ki_base;
|
||||
K2_div8.to_public_key(sig.K2);
|
||||
point_t K2 = K2_div8;
|
||||
K2.modify_mul8();
|
||||
|
||||
point_t K3_div8 = (c_scalar_1div8 * secret_3_q) * ki_base;
|
||||
K3_div8.to_public_key(sig.K3);
|
||||
point_t K3 = K3_div8;
|
||||
K3.modify_mul8();
|
||||
|
||||
// calculate aggregation coefficients
|
||||
hash_helper_t::hs_t hsc(4 + 3 * ring_size);
|
||||
hsc.add_scalar(m);
|
||||
for(size_t i = 0; i < ring_size; ++i)
|
||||
{
|
||||
hsc.add_pub_key(ring[i].stealth_address);
|
||||
hsc.add_pub_key(ring[i].amount_commitment);
|
||||
hsc.add_pub_key(ring[i].concealing_point);
|
||||
}
|
||||
hsc.add_point(c_scalar_1div8 * pseudo_out_amount_commitment);
|
||||
hsc.add_point(c_scalar_1div8 * extended_amount_commitment);
|
||||
hsc.add_key_image(ki);
|
||||
hash input_hash = hsc.calc_hash_no_reduce();
|
||||
DBG_VAL_PRINT(input_hash);
|
||||
|
||||
hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_0);
|
||||
hsc.add_hash(input_hash);
|
||||
scalar_t agg_coeff_0 = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(agg_coeff_0);
|
||||
|
||||
hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_1);
|
||||
hsc.add_hash(input_hash);
|
||||
scalar_t agg_coeff_1 = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(agg_coeff_1);
|
||||
|
||||
// may we get rid of it?
|
||||
hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_2);
|
||||
hsc.add_hash(input_hash);
|
||||
scalar_t agg_coeff_2 = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(agg_coeff_2);
|
||||
|
||||
hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_3);
|
||||
hsc.add_hash(input_hash);
|
||||
scalar_t agg_coeff_3 = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(agg_coeff_3);
|
||||
|
||||
// prepare A_i, Q_i
|
||||
std::vector<point_t> A_i, Q_i;
|
||||
A_i.reserve(ring_size), Q_i.reserve(ring_size);
|
||||
for(size_t i = 0; i < ring_size; ++i)
|
||||
{
|
||||
A_i.emplace_back(ring[i].amount_commitment);
|
||||
A_i.back().modify_mul8();
|
||||
Q_i.emplace_back(ring[i].concealing_point);
|
||||
Q_i.back().modify_mul8();
|
||||
DBG_PRINT("A_i[" << i << "] = " << A_i[i] << " Q_i[" << i << "] = " << Q_i[i]);
|
||||
}
|
||||
|
||||
// calculate aggregate pub keys (layers 0, 1, 3; G components)
|
||||
std::vector<point_t> W_pub_keys_g;
|
||||
W_pub_keys_g.reserve(ring_size);
|
||||
for(size_t i = 0; i < ring_size; ++i)
|
||||
{
|
||||
W_pub_keys_g.emplace_back(
|
||||
agg_coeff_0 * point_t(ring[i].stealth_address) +
|
||||
agg_coeff_1 * (A_i[i] - pseudo_out_amount_commitment) +
|
||||
agg_coeff_3 * Q_i[i]
|
||||
);
|
||||
DBG_VAL_PRINT(W_pub_keys_g[i]);
|
||||
}
|
||||
|
||||
// calculate aggregate pub keys (layer 2; X component)
|
||||
std::vector<point_t> W_pub_keys_x;
|
||||
W_pub_keys_x.reserve(ring_size);
|
||||
for(size_t i = 0; i < ring_size; ++i)
|
||||
{
|
||||
W_pub_keys_x.emplace_back(
|
||||
agg_coeff_2 * (extended_amount_commitment - A_i[i] - Q_i[i])
|
||||
);
|
||||
DBG_VAL_PRINT(W_pub_keys_x[i]);
|
||||
}
|
||||
|
||||
// aggregate secret key (layers 0, 1, 3; G component)
|
||||
scalar_t w_sec_key_g = agg_coeff_0 * secret_0_xp + agg_coeff_1 * secret_1_f + agg_coeff_3 * secret_3_q;
|
||||
DBG_VAL_PRINT(w_sec_key_g * c_point_G);
|
||||
|
||||
// aggregate secret key (layer 2; X component)
|
||||
scalar_t w_sec_key_x = agg_coeff_2 * secret_2_x;
|
||||
DBG_VAL_PRINT(w_sec_key_x * c_point_X);
|
||||
|
||||
// calculate aggregate key image (layers 0, 1, 3; G component)
|
||||
point_t W_key_image_g = agg_coeff_0 * key_image + agg_coeff_1 * K1 + /*agg_coeff_2 * K2 +*/ agg_coeff_3 * K3;
|
||||
DBG_VAL_PRINT(W_key_image_g);
|
||||
|
||||
// calculate aggregate key image (layer 2; X component)
|
||||
point_t W_key_image_x = agg_coeff_2 * K2;
|
||||
DBG_VAL_PRINT(W_key_image_x);
|
||||
|
||||
// initial commitment
|
||||
scalar_t alpha_g = scalar_t::random(); // randomness for layers 0,1,3
|
||||
scalar_t alpha_x = scalar_t::random(); // randomness for layer 2
|
||||
hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_CHALLENGE);
|
||||
hsc.add_hash(input_hash);
|
||||
hsc.add_point(alpha_g * c_point_G); DBG_VAL_PRINT(alpha_g * c_point_G);
|
||||
hsc.add_point(alpha_g * ki_base); DBG_VAL_PRINT(alpha_g * ki_base);
|
||||
hsc.add_point(alpha_x * c_point_X); DBG_VAL_PRINT(alpha_x * c_point_X);
|
||||
hsc.add_point(alpha_x * ki_base); DBG_VAL_PRINT(alpha_x * ki_base);
|
||||
scalar_t c_prev = hsc.calc_hash(); // c_{secret_index + 1}
|
||||
|
||||
sig.r_g.clear();
|
||||
sig.r_x.clear();
|
||||
sig.r_g.reserve(ring_size);
|
||||
sig.r_x.reserve(ring_size);
|
||||
for(size_t i = 0; i < ring_size; ++i)
|
||||
{
|
||||
sig.r_g.emplace_back(scalar_t::random());
|
||||
sig.r_x.emplace_back(scalar_t::random());
|
||||
}
|
||||
|
||||
for(size_t j = 0, i = (secret_index + 1) % ring_size; j < ring_size - 1; ++j, i = (i + 1) % ring_size)
|
||||
{
|
||||
DBG_PRINT("c[" << i << "] = " << c_prev);
|
||||
if (i == 0)
|
||||
sig.c = c_prev; // c_0
|
||||
hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_CHALLENGE);
|
||||
hsc.add_hash(input_hash);
|
||||
hsc.add_point(sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i]);
|
||||
hsc.add_point(sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g);
|
||||
hsc.add_point(sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i]);
|
||||
hsc.add_point(sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x);
|
||||
c_prev = hsc.calc_hash(); // c_{i + 1}
|
||||
}
|
||||
DBG_PRINT("c[" << secret_index << "] = " << c_prev);
|
||||
|
||||
if (secret_index == 0)
|
||||
sig.c = c_prev;
|
||||
|
||||
sig.r_g[secret_index] = alpha_g - c_prev * w_sec_key_g;
|
||||
sig.r_x[secret_index] = alpha_x - c_prev * w_sec_key_x;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool verify_CLSAG_GGXG(const hash& m, const std::vector<CLSAG_GGXG_input_ref_t>& ring, const public_key& pseudo_out_amount_commitment, const public_key& extended_amount_commitment, const key_image& ki,
|
||||
const CLSAG_GGXG_signature& sig)
|
||||
{
|
||||
DBG_PRINT("== verify_CLSAG_GGXG ==");
|
||||
size_t ring_size = ring.size();
|
||||
CRYPTO_CHECK_AND_THROW_MES(ring_size > 0, "ring size is zero");
|
||||
CRYPTO_CHECK_AND_THROW_MES(ring_size == sig.r_g.size(), "ring size != r_g size");
|
||||
CRYPTO_CHECK_AND_THROW_MES(ring_size == sig.r_x.size(), "ring size != r_x size");
|
||||
|
||||
point_t key_image(ki);
|
||||
CRYPTO_CHECK_AND_THROW_MES(key_image.is_in_main_subgroup(), "key image 0 does not belong to the main subgroup");
|
||||
|
||||
point_t pseudo_out_amount_commitment_pt(pseudo_out_amount_commitment);
|
||||
pseudo_out_amount_commitment_pt.modify_mul8();
|
||||
|
||||
point_t extended_amount_commitment_pt(extended_amount_commitment);
|
||||
extended_amount_commitment_pt.modify_mul8();
|
||||
|
||||
// calculate aggregation coefficients
|
||||
hash_helper_t::hs_t hsc(4 + 3 * ring_size);
|
||||
hsc.add_scalar(m);
|
||||
for(size_t i = 0; i < ring_size; ++i)
|
||||
{
|
||||
hsc.add_pub_key(ring[i].stealth_address);
|
||||
hsc.add_pub_key(ring[i].amount_commitment);
|
||||
hsc.add_pub_key(ring[i].concealing_point);
|
||||
}
|
||||
hsc.add_pub_key(pseudo_out_amount_commitment);
|
||||
hsc.add_pub_key(extended_amount_commitment);
|
||||
hsc.add_key_image(ki);
|
||||
hash input_hash = hsc.calc_hash_no_reduce();
|
||||
DBG_VAL_PRINT(input_hash);
|
||||
|
||||
hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_0);
|
||||
hsc.add_hash(input_hash);
|
||||
scalar_t agg_coeff_0 = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(agg_coeff_0);
|
||||
|
||||
hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_1);
|
||||
hsc.add_hash(input_hash);
|
||||
scalar_t agg_coeff_1 = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(agg_coeff_1);
|
||||
|
||||
// may we get rid of it?
|
||||
hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_2);
|
||||
hsc.add_hash(input_hash);
|
||||
scalar_t agg_coeff_2 = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(agg_coeff_2);
|
||||
|
||||
hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_3);
|
||||
hsc.add_hash(input_hash);
|
||||
scalar_t agg_coeff_3 = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(agg_coeff_3);
|
||||
|
||||
// prepare A_i, Q_i
|
||||
std::vector<point_t> A_i, Q_i;
|
||||
A_i.reserve(ring_size), Q_i.reserve(ring_size);
|
||||
for(size_t i = 0; i < ring_size; ++i)
|
||||
{
|
||||
A_i.emplace_back(ring[i].amount_commitment);
|
||||
A_i.back().modify_mul8();
|
||||
Q_i.emplace_back(ring[i].concealing_point);
|
||||
Q_i.back().modify_mul8();
|
||||
DBG_PRINT("A_i[" << i << "] = " << A_i[i] << " Q_i[" << i << "] = " << Q_i[i]);
|
||||
}
|
||||
|
||||
// calculate aggregate pub keys (layers 0, 1, 3; G components)
|
||||
std::vector<point_t> W_pub_keys_g;
|
||||
W_pub_keys_g.reserve(ring_size);
|
||||
for(size_t i = 0; i < ring_size; ++i)
|
||||
{
|
||||
W_pub_keys_g.emplace_back(
|
||||
agg_coeff_0 * point_t(ring[i].stealth_address) +
|
||||
agg_coeff_1 * (A_i[i] - pseudo_out_amount_commitment_pt) +
|
||||
agg_coeff_3 * Q_i[i]
|
||||
);
|
||||
DBG_VAL_PRINT(W_pub_keys_g[i]);
|
||||
}
|
||||
|
||||
// calculate aggregate pub keys (layer 2; X component)
|
||||
std::vector<point_t> W_pub_keys_x;
|
||||
W_pub_keys_x.reserve(ring_size);
|
||||
for(size_t i = 0; i < ring_size; ++i)
|
||||
{
|
||||
W_pub_keys_x.emplace_back(
|
||||
agg_coeff_2 * (extended_amount_commitment_pt - A_i[i] - Q_i[i])
|
||||
);
|
||||
DBG_VAL_PRINT(W_pub_keys_x[i]);
|
||||
}
|
||||
|
||||
// calculate aggregate key image (layers 0, 1, 3; G components)
|
||||
point_t W_key_image_g =
|
||||
agg_coeff_0 * key_image +
|
||||
agg_coeff_1 * point_t(sig.K1).modify_mul8() +
|
||||
agg_coeff_3 * point_t(sig.K3).modify_mul8();
|
||||
DBG_VAL_PRINT(W_key_image_g);
|
||||
|
||||
// calculate aggregate key image (layer 2; X component)
|
||||
point_t W_key_image_x =
|
||||
agg_coeff_2 * point_t(sig.K2).modify_mul8();
|
||||
DBG_VAL_PRINT(W_key_image_x);
|
||||
|
||||
|
||||
scalar_t c_prev = sig.c;
|
||||
DBG_PRINT("c[0] = " << c_prev);
|
||||
for(size_t i = 0; i < ring_size; ++i)
|
||||
{
|
||||
hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_CHALLENGE);
|
||||
hsc.add_hash(input_hash);
|
||||
hsc.add_point(sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i]);
|
||||
hsc.add_point(sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g);
|
||||
hsc.add_point(sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i]);
|
||||
hsc.add_point(sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x);
|
||||
c_prev = hsc.calc_hash(); // c_{i + 1}
|
||||
DBG_PRINT("c[" << i + 1 << "] = " << c_prev);
|
||||
}
|
||||
|
||||
return c_prev == sig.c;
|
||||
}
|
||||
|
||||
} // namespace crypto
|
||||
|
|
|
|||
|
|
@ -44,5 +44,37 @@ namespace crypto
|
|||
bool verify_CLSAG_GG(const hash& m, const std::vector<CLSAG_GG_input_ref_t>& ring, const public_key& pseudo_out_amount_commitment, const key_image& ki,
|
||||
const CLSAG_GG_signature& sig);
|
||||
|
||||
|
||||
//
|
||||
// 4-CLSAG
|
||||
//
|
||||
|
||||
|
||||
// 4-CLSAG signature (with respect to the group element G, G, X, G -- that's why 'GGXG')
|
||||
struct CLSAG_GGXG_signature
|
||||
{
|
||||
scalar_t c;
|
||||
scalar_vec_t r_g; // for G-components (layers 0, 1, 3), size = size of the ring
|
||||
scalar_vec_t r_x; // for X-component (layer 2), size = size of the ring
|
||||
public_key K1; // auxiliary key image for layer 1 (G)
|
||||
public_key K2; // auxiliary key image for layer 2 (X)
|
||||
public_key K3; // auxiliary key image for layer 3 (G)
|
||||
};
|
||||
|
||||
struct CLSAG_GGXG_input_ref_t : public CLSAG_GG_input_ref_t
|
||||
{
|
||||
CLSAG_GGXG_input_ref_t(const public_key& stealth_address, const public_key& amount_commitment, const public_key& concealing_point)
|
||||
: CLSAG_GG_input_ref_t(stealth_address, amount_commitment)
|
||||
, concealing_point(concealing_point)
|
||||
{}
|
||||
|
||||
const public_key& concealing_point; // Q, premultiplied by 1/8
|
||||
};
|
||||
|
||||
bool generate_CLSAG_GGXG(const hash& m, const std::vector<CLSAG_GGXG_input_ref_t>& ring, const point_t& pseudo_out_amount_commitment, const point_t& extended_amount_commitment, const key_image& ki,
|
||||
const scalar_t& secret_0_xp, const scalar_t& secret_1_f, const scalar_t& secret_2_x, const scalar_t& secret_3_q, uint64_t secret_index, CLSAG_GGXG_signature& sig);
|
||||
|
||||
bool verify_CLSAG_GGXG(const hash& m, const std::vector<CLSAG_GGXG_input_ref_t>& ring, const public_key& pseudo_out_amount_commitment, const public_key& extended_amount_commitment, const key_image& ki,
|
||||
const CLSAG_GGXG_signature& sig);
|
||||
|
||||
} // namespace crypto
|
||||
|
|
|
|||
|
|
@ -13,3 +13,11 @@
|
|||
#define CRYPTO_HDS_CLSAG_GG_LAYER_0 "ZANO_HDS_CLSAG_GG_LAYER_ZERO___"
|
||||
#define CRYPTO_HDS_CLSAG_GG_LAYER_1 "ZANO_HDS_CLSAG_GG_LAYER_ONE____"
|
||||
#define CRYPTO_HDS_CLSAG_GG_CHALLENGE "ZANO_HDS_CLSAG_GG_CHALLENGE____"
|
||||
|
||||
#define CRYPTO_HDS_CLSAG_GGXG_LAYER_0 "ZANO_HDS_CLSAG_GGXG_LAYER_ZERO_"
|
||||
#define CRYPTO_HDS_CLSAG_GGXG_LAYER_1 "ZANO_HDS_CLSAG_GGXG_LAYER_ONE__"
|
||||
#define CRYPTO_HDS_CLSAG_GGXG_LAYER_2 "ZANO_HDS_CLSAG_GGXG_LAYER_TWO__"
|
||||
#define CRYPTO_HDS_CLSAG_GGXG_LAYER_3 "ZANO_HDS_CLSAG_GGXG_LAYER_THREE"
|
||||
#define CRYPTO_HDS_CLSAG_GGXG_CHALLENGE "ZANO_HDS_CLSAG_GGXG_CHALLENGE__"
|
||||
|
||||
#define CRYPTO_HDS_ZARCANUM_LAST_POW_HASH "ZANO_HDS_ZARCANUM_LAST_POW_HASH"
|
||||
|
|
|
|||
|
|
@ -159,12 +159,6 @@ TEST(clsag, bad_pub_keys)
|
|||
cc.ki = (point_t(cc.ki) + tor).to_key_image(); // ki is not in main subgroup
|
||||
ASSERT_FALSE(cc.verify());
|
||||
|
||||
// torsion component in pseudo_output_commitment should not affect protocol
|
||||
cc = cc_orig;
|
||||
cc.pseudo_output_commitment = (point_t(cc.pseudo_output_commitment) + tor).to_public_key();
|
||||
ASSERT_TRUE(cc.generate());
|
||||
ASSERT_TRUE(cc.verify());
|
||||
|
||||
// torsion component in amount_commitments[i] should not affect protocol
|
||||
cc = cc_orig;
|
||||
for(size_t i = 0; i < cc.ring.size(); ++i)
|
||||
|
|
@ -188,6 +182,12 @@ TEST(clsag, bad_pub_keys)
|
|||
ASSERT_TRUE(cc.generate());
|
||||
cc.stealth_addresses[cc.secret_index] = (point_t(cc.stealth_addresses[cc.secret_index]) + tor).to_public_key();
|
||||
ASSERT_FALSE(cc.verify());
|
||||
|
||||
// torsion component in pseudo_output_commitment must break the protocol
|
||||
cc = cc_orig;
|
||||
cc.pseudo_output_commitment = (point_t(cc.pseudo_output_commitment) + tor).to_public_key();
|
||||
ASSERT_TRUE(cc.generate());
|
||||
ASSERT_FALSE(cc.verify());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -245,6 +245,118 @@ TEST(clsag, sig_difference)
|
|||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// CLSAG GGXG
|
||||
//
|
||||
|
||||
struct clsag_ggxg_sig_check_t
|
||||
{
|
||||
crypto::hash prefix_hash;
|
||||
crypto::key_image ki;
|
||||
std::vector<public_key> stealth_addresses;
|
||||
std::vector<public_key> amount_commitments; // div 8
|
||||
std::vector<public_key> concealing_points; // div 8
|
||||
std::vector<CLSAG_GGXG_input_ref_t> ring;
|
||||
crypto::public_key pseudo_output_commitment; // div 8
|
||||
crypto::public_key extended_amount_commitment; // div 8
|
||||
scalar_t secret_xp;
|
||||
scalar_t secret_f; // = f - f' = amount_blinding_mask - pseudo_commitment_blinding_mask
|
||||
scalar_t secret_x;
|
||||
scalar_t secret_q;
|
||||
size_t secret_index;
|
||||
CLSAG_GGXG_signature sig;
|
||||
|
||||
clsag_ggxg_sig_check_t()
|
||||
{}
|
||||
|
||||
void rebuild_ring()
|
||||
{
|
||||
ring.clear();
|
||||
ring.reserve(stealth_addresses.size());
|
||||
for(size_t i = 0; i < stealth_addresses.size(); ++i)
|
||||
ring.emplace_back(stealth_addresses[i], amount_commitments[i], concealing_points[i]);
|
||||
}
|
||||
|
||||
clsag_ggxg_sig_check_t& operator=(const clsag_ggxg_sig_check_t& rhs)
|
||||
{
|
||||
prefix_hash = rhs.prefix_hash;
|
||||
ki = rhs.ki;
|
||||
stealth_addresses = rhs.stealth_addresses;
|
||||
amount_commitments = rhs.amount_commitments;
|
||||
concealing_points = rhs.concealing_points;
|
||||
rebuild_ring();
|
||||
pseudo_output_commitment = rhs.pseudo_output_commitment;
|
||||
extended_amount_commitment = rhs.extended_amount_commitment;
|
||||
secret_xp = rhs.secret_xp;
|
||||
secret_f = rhs.secret_f;
|
||||
secret_x = rhs.secret_x;
|
||||
secret_q = rhs.secret_q;
|
||||
secret_index = rhs.secret_index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void prepare_random_data(size_t ring_size)
|
||||
{
|
||||
stealth_addresses.clear();
|
||||
amount_commitments.clear();
|
||||
concealing_points.clear();
|
||||
ring.clear();
|
||||
|
||||
crypto::generate_random_bytes(sizeof prefix_hash, &prefix_hash);
|
||||
|
||||
stealth_addresses.reserve(ring_size);
|
||||
amount_commitments.reserve(ring_size);
|
||||
concealing_points.reserve(ring_size);
|
||||
for(size_t i = 0; i < ring_size; ++i)
|
||||
{
|
||||
stealth_addresses.push_back(hash_helper_t::hp(scalar_t::random()).to_public_key());
|
||||
amount_commitments.push_back(hash_helper_t::hp(scalar_t::random()).to_public_key()); // div 8
|
||||
concealing_points.push_back(hash_helper_t::hp(scalar_t::random()).to_public_key()); // div 8
|
||||
ring.emplace_back(stealth_addresses.back(), amount_commitments.back(), concealing_points.back());
|
||||
}
|
||||
|
||||
secret_xp = scalar_t::random();
|
||||
secret_f = scalar_t::random();
|
||||
secret_x = scalar_t::random();
|
||||
secret_q = scalar_t::random();
|
||||
secret_index = random_in_range(0, ring_size - 1);
|
||||
|
||||
stealth_addresses[secret_index] = (secret_xp * c_point_G).to_public_key();
|
||||
concealing_points[secret_index] = (c_scalar_1div8 * secret_q * c_point_G).to_public_key();
|
||||
ki = (secret_xp * hash_helper_t::hp(stealth_addresses[secret_index])).to_key_image();
|
||||
|
||||
pseudo_output_commitment = (point_t(amount_commitments[secret_index]) - c_scalar_1div8 * secret_f * c_point_G).to_public_key();
|
||||
extended_amount_commitment = (c_scalar_1div8 * secret_x * c_point_X + point_t(amount_commitments[secret_index]) + point_t(concealing_points[secret_index])).to_public_key();
|
||||
}
|
||||
|
||||
bool generate()
|
||||
{
|
||||
try
|
||||
{
|
||||
return generate_CLSAG_GGXG(prefix_hash, ring, point_t(pseudo_output_commitment).modify_mul8(), point_t(extended_amount_commitment).modify_mul8(), ki,
|
||||
secret_xp, secret_f, secret_x, secret_q, secret_index, sig);
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
LOG_PRINT_RED(ENDL << "EXCEPTION: " << e.what(), LOG_LEVEL_0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool verify()
|
||||
{
|
||||
try
|
||||
{
|
||||
return verify_CLSAG_GGXG(prefix_hash, ring, pseudo_output_commitment, extended_amount_commitment, ki, sig);
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
LOG_PRINT_RED(ENDL << "EXCEPTION: " << e.what(), LOG_LEVEL_0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST(clsag_ggxg, basics)
|
||||
{
|
||||
|
|
@ -253,5 +365,23 @@ TEST(clsag_ggxg, basics)
|
|||
LOG_PRINT_L0("X = " << X.to_hex_comma_separated_uint64_str());
|
||||
ASSERT_EQ(X, c_point_X);
|
||||
|
||||
clsag_ggxg_sig_check_t cc;
|
||||
|
||||
cc.prepare_random_data(1);
|
||||
ASSERT_TRUE(cc.generate());
|
||||
ASSERT_TRUE(cc.verify());
|
||||
|
||||
cc.prepare_random_data(2);
|
||||
ASSERT_TRUE(cc.generate());
|
||||
ASSERT_TRUE(cc.verify());
|
||||
|
||||
cc.prepare_random_data(8);
|
||||
ASSERT_TRUE(cc.generate());
|
||||
ASSERT_TRUE(cc.verify());
|
||||
|
||||
cc.prepare_random_data(123);
|
||||
ASSERT_TRUE(cc.generate());
|
||||
ASSERT_TRUE(cc.verify());
|
||||
|
||||
return true;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue