3-CLSAG GGX implementation + tests

This commit is contained in:
sowle 2023-02-27 18:00:53 +01:00
parent 7bdb410b5d
commit b1ccf8644b
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
4 changed files with 469 additions and 10 deletions

View file

@ -1,5 +1,5 @@
// Copyright (c) 2022 Zano Project
// Copyright (c) 2022 sowle (val@zano.org, crypto.sowle@gmail.com)
// Copyright (c) 2022-2023 Zano Project
// Copyright (c) 2022-2023 sowle (val@zano.org, 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.
//
@ -13,8 +13,13 @@ DISABLE_GCC_AND_CLANG_WARNING(unused-function)
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
#if 0
# define DBG_VAL_PRINT(x) std::cout << #x ": " << x << std::endl
# define DBG_PRINT(x) std::cout << x << std::endl
#else
# define DBG_VAL_PRINT(x) (void(0))
# define DBG_PRINT(x) (void(0))
#endif
static std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return o << pod_to_hex(v); }
static std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) { return o << pod_to_hex(v); }
@ -178,13 +183,311 @@ namespace crypto
bool generate_CLSAG_GGX(const hash& m, const std::vector<CLSAG_GGX_input_ref_t>& ring, const point_t& pseudo_out_amount_commitment, const point_t& pseudo_out_asset_id, const key_image& ki,
const scalar_t& secret_0_xp, const scalar_t& secret_1_f, const scalar_t& secret_2_t, uint64_t secret_index, CLSAG_GGX_signature& sig)
{
return false;
DBG_PRINT("== generate_CLSAG_GGX ==");
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;
#ifndef NDEBUG
CRYPTO_CHECK_AND_THROW_MES(key_image == point_t(ki), "key image 0 mismatch");
CRYPTO_CHECK_AND_THROW_MES((secret_0_xp * c_point_G).to_public_key() == ring[secret_index].stealth_address, "secret_0_xp mismatch");
CRYPTO_CHECK_AND_THROW_MES( secret_1_f * c_point_G == 8 * point_t(ring[secret_index].amount_commitment) - pseudo_out_amount_commitment, "secret_1_f mismatch");
CRYPTO_CHECK_AND_THROW_MES( secret_2_t * c_point_X == 8 * point_t(ring[secret_index].blinded_asset_id) - pseudo_out_asset_id, "secret_2_t mismatch");
//CRYPTO_CHECK_AND_THROW_MES( secret_3_q * c_point_G == 8 * point_t(ring[secret_index].concealing_point), "");
//CRYPTO_CHECK_AND_THROW_MES( secret_4_x * c_point_X == extended_amount_commitment - 8 * point_t(ring[secret_index].amount_commitment) - 8 * point_t(ring[secret_index].concealing_point), "");
#endif
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_t) * 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();
//point_t K4_div8 = (c_scalar_1div8 * secret_4_x) * ki_base;
//K4_div8.to_public_key(sig.K4);
//point_t K4 = K4_div8;
//K4.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].blinded_asset_id);
DBG_PRINT("ring[" << i << "]: sa:" << ring[i].stealth_address << ", ac:" << ring[i].amount_commitment << ", baid:" << ring[i].blinded_asset_id);
}
hsc.add_point(c_scalar_1div8 * pseudo_out_amount_commitment);
hsc.add_point(c_scalar_1div8 * pseudo_out_asset_id);
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_GGX_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_GGX_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_GGX_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_GGX_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].blinded_asset_id);
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; 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)
);
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 * (Q_i[i] - pseudo_out_asset_id)
);
DBG_VAL_PRINT(W_pub_keys_x[i]);
}
// aggregate secret key (layers 0, 1; 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_t;
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_3 * K3 */;
DBG_VAL_PRINT(key_image);
DBG_VAL_PRINT(K1);
//DBG_VAL_PRINT(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(K2);
DBG_VAL_PRINT(W_key_image_x);
#ifndef NDEBUG
CRYPTO_CHECK_AND_THROW_MES(w_sec_key_g * c_point_G == W_pub_keys_g[secret_index], "aggregated secret G and pub key mismatch");
CRYPTO_CHECK_AND_THROW_MES(w_sec_key_g * hash_helper_t::hp(ring[secret_index].stealth_address) == W_key_image_g, "aggregated secret G and key image mismatch");
CRYPTO_CHECK_AND_THROW_MES(w_sec_key_x * c_point_X == W_pub_keys_x[secret_index], "aggregated secret X and pub key mismatch");
CRYPTO_CHECK_AND_THROW_MES(w_sec_key_x * hash_helper_t::hp(ring[secret_index].stealth_address) == W_key_image_x, "aggregated secret X and key image mismatch");
#endif
// initial commitment
scalar_t alpha_g = scalar_t::random(); // randomness for layers 0,1
scalar_t alpha_x = scalar_t::random(); // randomness for layer 2
hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGX_CHALLENGE);
hsc.add_hash(input_hash);
hsc.add_point(alpha_g * c_point_G);
hsc.add_point(alpha_g * ki_base);
hsc.add_point(alpha_x * c_point_X);
hsc.add_point(alpha_x * ki_base);
//DBG_PRINT("c[" << secret_index << "] = Hs(ih, " << alpha_g * c_point_G << ", " << alpha_g * ki_base << ", " << alpha_x * c_point_X << ", " << 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_GGX_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_GGX(const hash& m, const std::vector<CLSAG_GGX_input_ref_t>& ring, const public_key& pseudo_out_amount_commitment,
const public_key& pseudo_out_blinded_asset_id, const key_image& ki, const CLSAG_GGX_signature& sig)
{
return false;
DBG_PRINT("== verify_CLSAG_GGX ==");
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 pseudo_out_blinded_asset_id_pt(pseudo_out_blinded_asset_id);
pseudo_out_blinded_asset_id_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].blinded_asset_id);
DBG_PRINT("ring[" << i << "]: sa:" << ring[i].stealth_address << ", ac:" << ring[i].amount_commitment << ", baid:" << ring[i].blinded_asset_id);
}
hsc.add_pub_key(pseudo_out_amount_commitment);
hsc.add_pub_key(pseudo_out_blinded_asset_id);
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_GGX_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_GGX_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_GGX_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_GGX_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].blinded_asset_id);
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; 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)
);
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 * (Q_i[i] - pseudo_out_blinded_asset_id_pt)
);
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(point_t(sig.K1).modify_mul8());
//DBG_VAL_PRINT(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(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_GGX_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);
//DBG_PRINT("c[" << i + 1 << "] = Hs(ih, " << sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i] << ", " << sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g << ", " << sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i] << ", " << sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x << ")");
}
return c_prev == sig.c;
}
@ -208,7 +511,7 @@ namespace crypto
CRYPTO_CHECK_AND_THROW_MES((secret_0_xp * c_point_G).to_public_key() == ring[secret_index].stealth_address, "secret_0_xp mismatch");
CRYPTO_CHECK_AND_THROW_MES(secret_1_f * c_point_G == 8 * point_t(ring[secret_index].amount_commitment) - pseudo_out_amount_commitment, "secret_1_f mismatch");
CRYPTO_CHECK_AND_THROW_MES(secret_3_q * c_point_G == 8 * point_t(ring[secret_index].concealing_point), "secret_3_q mismatch");
CRYPTO_CHECK_AND_THROW_MES(secret_2_x * c_point_X == extended_amount_commitment - 8 * point_t(ring[secret_index].amount_commitment) - 8 * point_t(ring[secret_index].concealing_point), "secret_3_q mismatch");
CRYPTO_CHECK_AND_THROW_MES(secret_2_x * c_point_X == extended_amount_commitment - 8 * point_t(ring[secret_index].amount_commitment) - 8 * point_t(ring[secret_index].concealing_point), "secret_2_x mismatch");
#endif
point_t K1_div8 = (c_scalar_1div8 * secret_1_f) * ki_base;

View file

@ -1,5 +1,5 @@
// Copyright (c) 2022 Zano Project
// Copyright (c) 2022 sowle (val@zano.org, crypto.sowle@gmail.com)
// Copyright (c) 2022-2023 Zano Project
// Copyright (c) 2022-2023 sowle (val@zano.org, 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.
//
@ -48,6 +48,14 @@ namespace crypto
const CLSAG_GG_signature& sig);
//
// Disclaimer: extensions to the CLSAG implemented below are non-standard and are in proof-of-concept state.
// They shouldn't be used in production code until formal security proofs are done and (ideally) the code is peer-reviewed.
// -- sowle
//
//
// 3-CLSAG
//

View file

@ -16,6 +16,11 @@
#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_GGX_LAYER_0 "ZANO_HDS_CLSAG_GGX_LAYER_ZERO__"
#define CRYPTO_HDS_CLSAG_GGX_LAYER_1 "ZANO_HDS_CLSAG_GGX_LAYER_ONE___"
#define CRYPTO_HDS_CLSAG_GGX_LAYER_2 "ZANO_HDS_CLSAG_GGX_LAYER_TWO___"
#define CRYPTO_HDS_CLSAG_GGX_CHALLENGE "ZANO_HDS_CLSAG_GGX_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__"

View file

@ -245,6 +245,149 @@ TEST(clsag, sig_difference)
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//
// CLSAG GGX
//
struct clsag_ggx_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> blinded_asset_ids; // div 8
std::vector<CLSAG_GGX_input_ref_t> ring;
crypto::public_key pseudo_output_commitment; // div 8
crypto::public_key pseudo_out_asset_id; // div 8
scalar_t secret_0_xp; // xp * G = P
scalar_t secret_1_f; // = f - f' = amount_blinding_mask - pseudo_commitment_blinding_mask
scalar_t secret_2_t; // = -r' = -pseudo_asset_id_blinding_mask
size_t secret_index;
CLSAG_GGX_signature sig;
clsag_ggx_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], blinded_asset_ids[i]);
}
clsag_ggx_sig_check_t& operator=(const clsag_ggx_sig_check_t& rhs)
{
prefix_hash = rhs.prefix_hash;
ki = rhs.ki;
stealth_addresses = rhs.stealth_addresses;
amount_commitments = rhs.amount_commitments;
blinded_asset_ids = rhs.blinded_asset_ids;
rebuild_ring();
pseudo_output_commitment = rhs.pseudo_output_commitment;
pseudo_out_asset_id = rhs.pseudo_out_asset_id;
pseudo_out_asset_id = rhs.pseudo_out_asset_id;
secret_1_f = rhs.secret_1_f;
secret_2_t = rhs.secret_2_t;
secret_index = rhs.secret_index;
return *this;
}
void prepare_random_data(size_t ring_size)
{
stealth_addresses.clear();
amount_commitments.clear();
blinded_asset_ids.clear();
ring.clear();
crypto::generate_random_bytes(sizeof prefix_hash, &prefix_hash);
stealth_addresses.reserve(ring_size);
amount_commitments.reserve(ring_size);
blinded_asset_ids.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
blinded_asset_ids.push_back(hash_helper_t::hp(scalar_t::random()).to_public_key()); // div 8
ring.emplace_back(stealth_addresses.back(), amount_commitments.back(), blinded_asset_ids.back());
}
secret_0_xp = scalar_t::random();
secret_1_f = scalar_t::random();
secret_2_t = scalar_t::random();
secret_index = random_in_range(0, ring_size - 1);
stealth_addresses[secret_index] = (secret_0_xp * c_point_G).to_public_key();
ki = (secret_0_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_1_f * c_point_G).to_public_key();
pseudo_out_asset_id = (point_t(blinded_asset_ids[secret_index]) - c_scalar_1div8 * secret_2_t * c_point_X).to_public_key();
}
bool generate()
{
try
{
return generate_CLSAG_GGX(prefix_hash, ring, point_t(pseudo_output_commitment).modify_mul8(), point_t(pseudo_out_asset_id).modify_mul8(), ki,
secret_0_xp, secret_1_f, secret_2_t, 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_GGX(prefix_hash, ring, pseudo_output_commitment, pseudo_out_asset_id, ki, sig);
}
catch(std::exception& e)
{
LOG_PRINT_RED(ENDL << "EXCEPTION: " << e.what(), LOG_LEVEL_0);
return false;
}
}
};
TEST(clsag_ggx, basics)
{
std::string X_hash_str("X_generator");
point_t X = hash_helper_t::hp(X_hash_str.c_str(), X_hash_str.size());
LOG_PRINT_L0("X = " << X.to_hex_comma_separated_uint64_str());
ASSERT_EQ(X, c_point_X);
clsag_ggx_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;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//
// CLSAG GGXG
//
@ -301,7 +444,7 @@ struct clsag_ggxg_sig_check_t
amount_commitments.clear();
concealing_points.clear();
ring.clear();
crypto::generate_random_bytes(sizeof prefix_hash, &prefix_hash);
stealth_addresses.reserve(ring_size);