forked from lthn/blockchain
Zarcanum adaptation for confidential assets (WIP)
This commit is contained in:
parent
4f1d01fc73
commit
b5c1c5477d
8 changed files with 81 additions and 42 deletions
|
|
@ -63,9 +63,9 @@ namespace crypto
|
|||
if (!(cond)) { LOG_PRINT_RED("zarcanum_generate_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \
|
||||
if (p_err) { *p_err = err_code; } return false; }
|
||||
|
||||
bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector<CLSAG_GGXG_input_ref_t>& ring,
|
||||
bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector<CLSAG_GGXXG_input_ref_t>& ring,
|
||||
const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki,
|
||||
const scalar_t& secret_x, const scalar_t& secret_q, uint64_t secret_index, const scalar_t& pseudo_out_blinding_mask, uint64_t stake_amount, const scalar_t& stake_blinding_mask,
|
||||
const scalar_t& secret_x, const scalar_t& secret_q, uint64_t secret_index, const crypto::scalar_t& stake_out_asset_id_blinding_mask, const scalar_t& pseudo_out_blinding_mask, uint64_t stake_amount, const scalar_t& stake_blinding_mask,
|
||||
zarcanum_proof& result, uint8_t* p_err /* = nullptr */)
|
||||
{
|
||||
DBG_PRINT("zarcanum_generate_proof");
|
||||
|
|
@ -139,7 +139,7 @@ namespace crypto
|
|||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bppe_gen<bpp_crypto_trait_Zarcanum>(values, masks, masks2, E_1div8_vec_ptr, result.E_range_proof), 10);
|
||||
|
||||
// = four-layers ring signature data outline =
|
||||
// = five-layers ring signature data outline =
|
||||
// (j in [0, ring_size-1])
|
||||
// layer 0 ring
|
||||
// A[j] ( = ring[j].stealth_address)
|
||||
|
|
@ -153,25 +153,35 @@ namespace crypto
|
|||
// layer 1 secret (with respect to G)
|
||||
// stake_blinding_mask - pseudo_out_blinding_mask
|
||||
//
|
||||
// additional layers for Zarcanum:
|
||||
// additional layer for confidential assets:
|
||||
//
|
||||
// layer 2 ring
|
||||
// C - A[j] - Q[j]
|
||||
// ring[j].blinded_asset_id - pseudo_out_blinded_asset_id
|
||||
// layer 2 secret (with respect to X)
|
||||
// x0
|
||||
// -pseudo_out_asset_id_blinding_mask ( = -r'_i )
|
||||
//
|
||||
// additional layers for Zarcanum:
|
||||
//
|
||||
// layer 3 ring
|
||||
// C - A[j] - Q[j]
|
||||
// layer 3 secret (with respect to X)
|
||||
// x0
|
||||
//
|
||||
// layer 4 ring
|
||||
// Q[j]
|
||||
// layer 3 secret (with respect to G)
|
||||
// layer 4 secret (with respect to G)
|
||||
// secret_q
|
||||
|
||||
point_t pseudo_out_amount_commitment = a * crypto::c_point_H + pseudo_out_blinding_mask * crypto::c_point_G;
|
||||
// such pseudo_out_asset_id_blinding_mask effectively makes pseudo_out_blinded_asset_id == currency::native_coin_asset_id_pt == crypto::point_H
|
||||
scalar_t pseudo_out_asset_id_blinding_mask = -stake_out_asset_id_blinding_mask; // T^p_i = T_i + (-r_i) * X = H_i
|
||||
|
||||
point_t pseudo_out_amount_commitment = a * crypto::c_point_H + pseudo_out_blinding_mask * crypto::c_point_G; // A^p_i = a_i * H_i + f'_i * G
|
||||
result.pseudo_out_amount_commitment = (crypto::c_scalar_1div8 * pseudo_out_amount_commitment).to_public_key();
|
||||
|
||||
TRY_ENTRY()
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(generate_CLSAG_GGXG(m, ring, pseudo_out_amount_commitment, C, stake_ki,
|
||||
secret_x, stake_blinding_mask - pseudo_out_blinding_mask, x0, secret_q, secret_index,
|
||||
result.clsag_ggxg), 20);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(generate_CLSAG_GGXXG(m, ring, pseudo_out_amount_commitment, crypto::c_point_H, C, stake_ki,
|
||||
secret_x, stake_blinding_mask - pseudo_out_blinding_mask, -pseudo_out_asset_id_blinding_mask, x0, secret_q, secret_index,
|
||||
result.clsag_ggxxg), 20);
|
||||
CATCH_ENTRY2(false);
|
||||
|
||||
return true;
|
||||
|
|
@ -179,12 +189,12 @@ namespace crypto
|
|||
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
|
||||
|
||||
|
||||
|
||||
|
||||
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
|
||||
if (!(cond)) { LOG_PRINT_RED("zarcanum_verify_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \
|
||||
if (p_err) { *p_err = err_code; } return false; }
|
||||
|
||||
bool zarcanum_verify_proof(const hash& m, const hash& kernel_hash, const std::vector<CLSAG_GGXG_input_ref_t>& ring,
|
||||
bool zarcanum_verify_proof(const hash& m, const hash& kernel_hash, const std::vector<CLSAG_GGXXG_input_ref_t>& ring,
|
||||
const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki,
|
||||
const mp::uint128_t& pos_difficulty,
|
||||
const zarcanum_proof& sig, uint8_t* p_err /* = nullptr */) noexcept
|
||||
|
|
@ -235,8 +245,10 @@ namespace crypto
|
|||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bppe_verify<bpp_crypto_trait_Zarcanum>(range_proofs), 10);
|
||||
|
||||
static public_key native_coin_asset_id = (crypto::c_scalar_1div8 * crypto::c_point_H).to_public_key(); // consider making it less ugly -- sowle
|
||||
|
||||
// check extended CLSAG-GGXG ring signature
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(verify_CLSAG_GGXG(m, ring, sig.pseudo_out_amount_commitment, sig.C, stake_ki, sig.clsag_ggxg), 1);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(verify_CLSAG_GGXXG(m, ring, sig.pseudo_out_amount_commitment, native_coin_asset_id, sig.C, stake_ki, sig.clsag_ggxxg), 1);
|
||||
}
|
||||
CATCH_ENTRY_CUSTOM2({if (p_err) *p_err = 100;}, false)
|
||||
|
||||
|
|
|
|||
|
|
@ -41,16 +41,16 @@ namespace crypto
|
|||
bppe_signature E_range_proof;
|
||||
|
||||
crypto::public_key pseudo_out_amount_commitment; // premultiplied by 1/8
|
||||
CLSAG_GGXG_signature clsag_ggxg;
|
||||
CLSAG_GGXXG_signature clsag_ggxxg;
|
||||
};
|
||||
|
||||
bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector<crypto::CLSAG_GGXG_input_ref_t>& ring,
|
||||
bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector<crypto::CLSAG_GGXXG_input_ref_t>& ring,
|
||||
const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki,
|
||||
const scalar_t& secret_x, const scalar_t& secret_q, uint64_t secret_index, const scalar_t& pseudo_out_blinding_mask, uint64_t stake_amount, const scalar_t& stake_blinding_mask,
|
||||
const scalar_t& secret_x, const scalar_t& secret_q, uint64_t secret_index, const crypto::scalar_t& stake_out_asset_id_blinding_mask, const scalar_t& pseudo_out_blinding_mask, uint64_t stake_amount, const scalar_t& stake_blinding_mask,
|
||||
zarcanum_proof& result, uint8_t* p_err = nullptr);
|
||||
|
||||
|
||||
bool zarcanum_verify_proof(const hash& m, const hash& kernel_hash, const std::vector<crypto::CLSAG_GGXG_input_ref_t>& ring,
|
||||
bool zarcanum_verify_proof(const hash& m, const hash& kernel_hash, const std::vector<crypto::CLSAG_GGXXG_input_ref_t>& ring,
|
||||
const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki,
|
||||
const mp::uint128_t& pos_difficulty,
|
||||
const zarcanum_proof& sig, uint8_t* p_err = nullptr) noexcept;
|
||||
|
|
|
|||
|
|
@ -376,6 +376,28 @@ namespace currency
|
|||
if (ogc_ptr)
|
||||
*ogc_ptr = outs_gen_context; // TODO @#@# consider refactoring (a lot of copying) -- sowle
|
||||
|
||||
|
||||
if (tx.version > TRANSACTION_VERSION_PRE_HF4 && !pos)
|
||||
{
|
||||
// This is for PoW blocks only, because PoS blocks proofs are handled in wallet2::prepare_and_sign_pos_block() due to the necessity of making Zarcanum proofs first
|
||||
//
|
||||
// tx hash should be sealed by now
|
||||
crypto::hash tx_id = get_transaction_hash(tx);
|
||||
|
||||
//add range proofs
|
||||
currency::zc_outs_range_proof range_proofs = AUTO_VAL_INIT(range_proofs);
|
||||
bool r = generate_zc_outs_range_proof(tx_id, 0, outs_gen_context, tx.vout, range_proofs);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to generate zc_outs_range_proof()");
|
||||
tx.proofs.emplace_back(std::move(range_proofs));
|
||||
|
||||
currency::zc_balance_proof balance_proof{};
|
||||
r = generate_tx_balance_proof(tx, tx_id, outs_gen_context, block_reward, balance_proof);
|
||||
CHECK_AND_ASSERT_MES(r, false, "generate_tx_balance_proof failed");
|
||||
tx.proofs.emplace_back(std::move(balance_proof));
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ namespace currency
|
|||
}
|
||||
|
||||
void pos_mining_context::prepare_entry(uint64_t stake_amount, const crypto::key_image& stake_out_ki, const crypto::public_key& stake_source_tx_pub_key, uint64_t stake_out_in_tx_index,
|
||||
const crypto::scalar_t& stake_out_blinding_mask, const crypto::secret_key& view_secret)
|
||||
const crypto::scalar_t& stake_out_amount_blinding_mask, const crypto::secret_key& view_secret)
|
||||
{
|
||||
this->stake_amount = stake_amount;
|
||||
this->sk.kimage = stake_out_ki;
|
||||
|
|
@ -41,7 +41,7 @@ namespace currency
|
|||
|
||||
// q = Hs(domain_sep, Hs(8 * v * R, i) ) * 8 * v
|
||||
this->secret_q = v * 8 * crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h);
|
||||
this->stake_out_blinding_mask = stake_out_blinding_mask;
|
||||
this->stake_out_amount_blinding_mask = stake_out_amount_blinding_mask;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ namespace currency
|
|||
crypto::mp::uint512_t rhs;
|
||||
{
|
||||
PROFILE_FUNC("check_zarcanum");
|
||||
found = crypto::zarcanum_check_main_pos_inequality(this->kernel_hash, this->stake_out_blinding_mask, this->secret_q, this->last_pow_block_id_hashed, this->z_l_div_z_D, this->stake_amount, lhs, rhs);
|
||||
found = crypto::zarcanum_check_main_pos_inequality(this->kernel_hash, this->stake_out_amount_blinding_mask, this->secret_q, this->last_pow_block_id_hashed, this->z_l_div_z_D, this->stake_amount, lhs, rhs);
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,15 +9,15 @@ namespace currency
|
|||
|
||||
struct pos_mining_context
|
||||
{
|
||||
// Zarcanum notation:
|
||||
wide_difficulty_type basic_diff; // D
|
||||
// Zarcanum notation:
|
||||
wide_difficulty_type basic_diff; // D
|
||||
stake_kernel sk;
|
||||
crypto::scalar_t last_pow_block_id_hashed; // f'
|
||||
crypto::scalar_t secret_q; // q
|
||||
boost::multiprecision::uint256_t z_l_div_z_D; // z * floor( l / (z * D) ) (max possible value (assuming z=2^64) : z * 2^252 / (z * 1) ~= 2^252)
|
||||
crypto::hash kernel_hash; // h
|
||||
crypto::scalar_t stake_out_blinding_mask; // f
|
||||
uint64_t stake_amount; // a
|
||||
crypto::scalar_t last_pow_block_id_hashed; // f'
|
||||
crypto::scalar_t secret_q; // q
|
||||
boost::multiprecision::uint256_t z_l_div_z_D; // z * floor( l / (z * D) ) (max possible value (assuming z=2^64) : z * 2^252 / (z * 1) ~= 2^252)
|
||||
crypto::hash kernel_hash; // h
|
||||
crypto::scalar_t stake_out_amount_blinding_mask; // f
|
||||
uint64_t stake_amount; // a
|
||||
|
||||
bool zarcanum; // false for pre-HF4 classic PoS with explicit amounts
|
||||
|
||||
|
|
|
|||
|
|
@ -3899,7 +3899,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, currency::bl
|
|||
const tx_out_zarcanum& stake_out = boost::get<tx_out_zarcanum>(stake_out_v);
|
||||
|
||||
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response decoys_resp = AUTO_VAL_INIT(decoys_resp);
|
||||
std::vector<crypto::CLSAG_GGXG_input_ref_t> ring;
|
||||
std::vector<crypto::CLSAG_GGXXG_input_ref_t> ring;
|
||||
uint64_t secret_index = 0; // index of the real stake output
|
||||
|
||||
// get decoys outputs and construct miner tx
|
||||
|
|
@ -3952,7 +3952,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, currency::bl
|
|||
if (gindex == td.m_global_output_index)
|
||||
secret_index = i;
|
||||
++i;
|
||||
ring.emplace_back(el.stealth_address, el.amount_commitment, el.concealing_point);
|
||||
ring.emplace_back(el.stealth_address, el.amount_commitment, el.blinded_asset_id, el.concealing_point);
|
||||
stake_input.key_offsets.push_back(el.global_amount_index);
|
||||
}
|
||||
r = absolute_sorted_output_offsets_to_relative_in_place(stake_input.key_offsets);
|
||||
|
|
@ -3961,7 +3961,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, currency::bl
|
|||
else
|
||||
{
|
||||
// no decoys, the ring consist of one element -- the real stake output
|
||||
ring.emplace_back(stake_out.stealth_address, stake_out.amount_commitment, stake_out.concealing_point);
|
||||
ring.emplace_back(stake_out.stealth_address, stake_out.amount_commitment, stake_out.blinded_asset_id, stake_out.concealing_point);
|
||||
stake_input.key_offsets.push_back(td.m_global_output_index);
|
||||
}
|
||||
stake_input.k_image = pe.keyimage;
|
||||
|
|
@ -3969,16 +3969,21 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, currency::bl
|
|||
#ifndef NDEBUG
|
||||
{
|
||||
crypto::point_t source_amount_commitment = crypto::c_scalar_1div8 * td.m_amount * crypto::c_point_H + crypto::c_scalar_1div8 * td.m_zc_info_ptr->amount_blinding_mask * crypto::c_point_G;
|
||||
CHECK_AND_ASSERT_MES(stake_out.amount_commitment == source_amount_commitment.to_public_key(), false, "real output amount commitment check failed");
|
||||
CHECK_AND_ASSERT_MES(ring[secret_index].amount_commitment == stake_out.amount_commitment, false, "ring secret member doesn't match with the stake output");
|
||||
WLT_CHECK_AND_ASSERT_MES(stake_out.amount_commitment == source_amount_commitment.to_public_key(), false, "real output amount commitment check failed");
|
||||
WLT_CHECK_AND_ASSERT_MES(ring[secret_index].amount_commitment == stake_out.amount_commitment, false, "ring secret member doesn't match with the stake output");
|
||||
WLT_CHECK_AND_ASSERT_MES(cxt.stake_amount == td.m_amount, false, "stake_amount missmatch");
|
||||
//WLT_CHECK_AND_ASSERT_MES(source_amount_commitment == cxt.stake_amount * cxt.stake_out_blinded_asset_id + cxt.stake_out_amount_blinding_mask * crypto::c_point_G, false, "source_amount_commitment missmatch");
|
||||
}
|
||||
#endif
|
||||
|
||||
crypto::hash hash_for_zarcanum_sig = get_block_hash(b);
|
||||
|
||||
WLT_CHECK_AND_ASSERT_MES(miner_tx_ogc.pseudo_out_amount_blinding_masks_sum.is_zero(), false, "pseudo_out_amount_blinding_masks_sum is nonzero"); // it should be zero because there's only one input (stake), and thus one pseudo out
|
||||
crypto::scalar_t pseudo_out_amount_blinding_mask = miner_tx_ogc.amount_blinding_masks_sum; // sum of outputs' amount blinding masks
|
||||
|
||||
uint8_t err = 0;
|
||||
r = crypto::zarcanum_generate_proof(hash_for_zarcanum_sig, cxt.kernel_hash, ring, cxt.last_pow_block_id_hashed, cxt.sk.kimage,
|
||||
secret_x, cxt.secret_q, secret_index, -miner_tx_ogc.amount_blinding_masks_sum, cxt.stake_amount, cxt.stake_out_blinding_mask,
|
||||
secret_x, cxt.secret_q, secret_index, td.m_zc_info_ptr->asset_id_blinding_mask, pseudo_out_amount_blinding_mask, cxt.stake_amount, cxt.stake_out_amount_blinding_mask,
|
||||
static_cast<crypto::zarcanum_proof&>(sig), &err);
|
||||
WLT_CHECK_AND_ASSERT_MES(r, false, "zarcanum_generate_proof failed, err: " << (int)err);
|
||||
|
||||
|
|
@ -3991,14 +3996,14 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, currency::bl
|
|||
// proofs for miner_tx
|
||||
currency::zc_outs_range_proof range_proofs = AUTO_VAL_INIT(range_proofs);
|
||||
r = generate_zc_outs_range_proof(miner_tx_id, 0, miner_tx_ogc, b.miner_tx.vout, range_proofs);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to generate zc_outs_range_proof()");
|
||||
WLT_CHECK_AND_ASSERT_MES(r, false, "Failed to generate zc_outs_range_proof()");
|
||||
b.miner_tx.proofs.emplace_back(std::move(range_proofs));
|
||||
|
||||
uint64_t block_reward = COIN;
|
||||
|
||||
currency::zc_balance_proof balance_proof{};
|
||||
r = generate_tx_balance_proof(b.miner_tx, miner_tx_id, miner_tx_ogc, block_reward, balance_proof);
|
||||
CHECK_AND_ASSERT_MES(r, false, "generate_tx_balance_proof failed");
|
||||
WLT_CHECK_AND_ASSERT_MES(r, false, "generate_tx_balance_proof failed");
|
||||
b.miner_tx.proofs.emplace_back(std::move(balance_proof));
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -221,18 +221,18 @@ void pos_block_builder::step5_sign(const currency::tx_source_entry& se, const cu
|
|||
size_t prepared_real_out_index = 0;
|
||||
std::vector<tx_source_entry::output_entry> prepared_outputs = prepare_outputs_entries_for_key_offsets(se.outputs, se.real_output, prepared_real_out_index);
|
||||
|
||||
std::vector<crypto::CLSAG_GGXG_input_ref_t> ring;
|
||||
std::vector<crypto::CLSAG_GGXXG_input_ref_t> ring;
|
||||
for(const auto& el : prepared_outputs)
|
||||
{
|
||||
stake_input.key_offsets.push_back(el.out_reference);
|
||||
ring.emplace_back(el.stealth_address, el.amount_commitment, el.concealing_point);
|
||||
ring.emplace_back(el.stealth_address, el.amount_commitment, el.blinded_asset_id, el.concealing_point);
|
||||
}
|
||||
|
||||
crypto::hash tx_hash_for_sig = get_block_hash(m_block);
|
||||
|
||||
uint8_t err = 0;
|
||||
r = crypto::zarcanum_generate_proof(tx_hash_for_sig, m_context.kernel_hash, ring, m_context.last_pow_block_id_hashed, m_context.sk.kimage,
|
||||
secret_x, m_context.secret_q, prepared_real_out_index, -m_miner_tx_ogc.amount_blinding_masks_sum, m_context.stake_amount, m_context.stake_out_blinding_mask,
|
||||
secret_x, m_context.secret_q, prepared_real_out_index, se.real_out_asset_id_blinding_mask, -m_miner_tx_ogc.amount_blinding_masks_sum, m_context.stake_amount, m_context.stake_out_amount_blinding_mask,
|
||||
static_cast<crypto::zarcanum_proof&>(sig), &err);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "zarcanum_generate_proof failed, err: " << (int)err);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ using namespace currency;
|
|||
//------------------------------------------------------------------------------
|
||||
// helpers
|
||||
|
||||
void invalidate_CLSAG_GGXG_sig(crypto::CLSAG_GGXG_signature& sig)
|
||||
void invalidate_CLSAG_GGXXG_sig(crypto::CLSAG_GGXXG_signature& sig)
|
||||
{
|
||||
sig.c = 7;
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ bool invalidate_zarcanum_sig(size_t n, zarcanum_sig& sig)
|
|||
case 0: break;
|
||||
case 1: invalidate_pub_key(sig.C); break;
|
||||
case 2: sig.c.make_random(); break;
|
||||
case 3: invalidate_CLSAG_GGXG_sig(sig.clsag_ggxg); break;
|
||||
case 3: invalidate_CLSAG_GGXXG_sig(sig.clsag_ggxxg); break;
|
||||
case 4: invalidate_pub_key(sig.C_prime); break;
|
||||
case 5: sig.d.make_random(); break;
|
||||
case 6: invalidate_pub_key(sig.E); break;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue