1
0
Fork 0
forked from lthn/blockchain

the first working implementation of Zarcanum PoS verification + few bugs fixed in proof gen; zarcanum_pos_block_math test should now succeed

This commit is contained in:
sowle 2022-11-18 04:18:41 +01:00
parent 917437b31e
commit 5fba04627b
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
4 changed files with 69 additions and 12 deletions

View file

@ -14,6 +14,10 @@ namespace crypto
const scalar_t c_zarcanum_z_coeff_s = { 0, 1, 0, 0 }; // c_scalar_2p64
const mp::uint256_t c_zarcanum_z_coeff_mp = c_zarcanum_z_coeff_s.as_boost_mp_type<mp::uint256_t>();
#define DBG_VAL_PRINT(x) (void(0)) // std::cout << #x ": " << x << std::endl
#define DBG_PRINT(x) (void(0)) // std::cout << x << std::endl
mp::uint256_t zarcanum_precalculate_l_div_z_D(const mp::uint128_t& pos_difficulty)
{
//LOG_PRINT_GREEN_L0(ENDL << "floor( l / (z * D) ) = " << c_scalar_L.as_boost_mp_type<mp::uint256_t>() / (c_zarcanum_z_coeff_mp * pos_difficulty));
@ -51,6 +55,7 @@ namespace crypto
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,
zarcanum_proof& result, uint8_t* p_err /* = nullptr */)
{
DBG_PRINT("zarcanum_generate_proof");
const scalar_t a = stake_amount;
const scalar_t h = scalar_t(kernel_hash);
const scalar_t f_plus_q = stake_blinding_mask + secret_q;
@ -84,6 +89,9 @@ namespace crypto
point_t F = h * C_prime - dz * C + E + last_pow_block_id_hashed * h * c_point_H;
DBG_VAL_PRINT(h); DBG_VAL_PRINT(last_pow_block_id_hashed); DBG_VAL_PRINT(dz);
DBG_VAL_PRINT(C); DBG_VAL_PRINT(C_prime); DBG_VAL_PRINT(E); DBG_VAL_PRINT(F);
scalar_t r0 = scalar_t::random();
scalar_t r1 = scalar_t::random();
scalar_t r2 = scalar_t::random();
@ -92,9 +100,9 @@ namespace crypto
point_t R_01 = r0 * c_point_X + r1 * c_point_H_plus_G;
point_t R_23 = r2 * c_point_X + r3 * c_point_H_minus_G;
point_t R_4 = r4 * c_point_G;
point_t R_4 = r4 * c_point_X;
hash_helper_t::hs_t hash_calc(3);
hash_helper_t::hs_t hash_calc(7);
hash_calc.add_32_chars(CRYPTO_HDS_ZARCANUM_PROOF_HASH);
hash_calc.add_point(R_01);
hash_calc.add_point(R_23);
@ -165,21 +173,60 @@ namespace crypto
bool zarcanum_verify_proof(const hash& m, const hash& kernel_hash, const std::vector<CLSAG_GGXG_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 */)
{
DBG_PRINT("zarcanum_verify_proof");
bool r = false;
// TODO @#@#
// make sure 0 < d <= l / floor(z * D)
const mp::uint256_t l_div_z_D_mp = crypto::zarcanum_precalculate_l_div_z_D(pos_difficulty);
const scalar_t l_div_z_D(l_div_z_D_mp);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(!sig.d.is_zero() && sig.d < l_div_z_D, 2);
const scalar_t dz = sig.d * c_zarcanum_z_coeff_s;
std::vector<point_t> E_for_range_proof = { point_t(sig.E) };
// calculate h
const scalar_t h = scalar_t(kernel_hash);
// calculate F
point_t C_prime = point_t(sig.C_prime);
C_prime.modify_mul8();
point_t C = point_t(sig.C);
C.modify_mul8();
point_t E = point_t(sig.E);
E.modify_mul8();
point_t F = h * C_prime - dz * C + E + last_pow_block_id_hashed * h * c_point_H;
DBG_VAL_PRINT(h); DBG_VAL_PRINT(last_pow_block_id_hashed); DBG_VAL_PRINT(dz);
DBG_VAL_PRINT(C); DBG_VAL_PRINT(C_prime); DBG_VAL_PRINT(E); DBG_VAL_PRINT(F);
// check three proofs with a shared Fiat-Shamir challenge c
point_t C_plus_C_prime = C + C_prime;
point_t C_minus_C_prime = C - C_prime;
hash_helper_t::hs_t hash_calc(7);
hash_calc.add_32_chars(CRYPTO_HDS_ZARCANUM_PROOF_HASH);
hash_calc.add_point(sig.y0 * c_point_X + sig.y1 * c_point_H_plus_G - sig.c * C_plus_C_prime); // y_0 * X + y1 (H + G) - c (C + C')
hash_calc.add_point(sig.y2 * c_point_X + sig.y3 * c_point_H_minus_G - sig.c * C_minus_C_prime); // y_2 * X + y3 (H - G) - c (C - C')
hash_calc.add_point(sig.y4 * c_point_X - sig.c * F); // y_4 * X - c * F
hash_calc.add_point(C_plus_C_prime);
hash_calc.add_point(C_minus_C_prime);
hash_calc.add_point(F);
scalar_t c_prime = hash_calc.calc_hash();
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.c == c_prime, 3);
// check extended range proof for E
std::vector<point_t> E_for_range_proof = { point_t(sig.E) }; // consider changing to 8*sig.E to avoid additional conversion
std::vector<bppe_sig_commit_ref_t> range_proofs = { bppe_sig_commit_ref_t(sig.E_range_proof, E_for_range_proof) };
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bppe_verify<bpp_crypto_trait_zano<128>>(range_proofs), 10);
// 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);
return true;
}
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
} // namespace crypto

View file

@ -52,6 +52,7 @@ namespace crypto
bool zarcanum_verify_proof(const hash& m, const hash& kernel_hash, const std::vector<crypto::CLSAG_GGXG_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);
} // namespace crypto

View file

@ -5428,7 +5428,8 @@ bool blockchain_storage::validate_pos_block(const block& b,
// build kernel and calculate hash
stake_kernel sk = AUTO_VAL_INIT(sk);
stake_modifier_type sm = AUTO_VAL_INIT(sm);
bool r = build_stake_modifier(sm, alt_chain, split_height);
uint64_t last_pow_block_height = 0;
bool r = build_stake_modifier(sm, alt_chain, split_height, nullptr, &last_pow_block_height);
CHECK_AND_ASSERT_MES(r, false, "failed to build_stake_modifier");
r = build_kernel(stake_key_image, sk, sm, b.timestamp);
CHECK_AND_ASSERT_MES(r, false, "failed to build kernel_stake");
@ -5451,6 +5452,9 @@ bool blockchain_storage::validate_pos_block(const block& b,
r = get_output_keys_for_input_with_checks(b.miner_tx, stake_input, dummy_output_keys, max_related_block_height, dummy_source_max_unlock_time_for_pos_coinbase_dummy, scan_contex);
CHECK_AND_ASSERT_MES(r, false, "get_output_keys_for_input_with_checks failed for stake input");
CHECK_AND_ASSERT_MES(scan_contex.zc_outs.size() == stake_input.key_offsets.size(), false, "incorrect number of referenced outputs found: " << scan_contex.zc_outs.size() << ", while " << stake_input.key_offsets.size() << " is expected.");
// make sure that all referring inputs are either older then, or the same age as, the most resent PoW block.
CHECK_AND_ASSERT_MES(max_related_block_height <= last_pow_block_height, false, "stake input refs' max related block height is " << max_related_block_height << " while last PoW block height is " << last_pow_block_height);
// build a ring of references
vector<crypto::CLSAG_GGXG_input_ref_t> ring;
ring.reserve(scan_contex.zc_outs.size());
@ -5460,10 +5464,8 @@ bool blockchain_storage::validate_pos_block(const block& b,
crypto::scalar_t last_pow_block_id_hashed = crypto::hash_helper_t::hs(CRYPTO_HDS_ZARCANUM_LAST_POW_HASH, sm.last_pow_id);
uint8_t err = 0;
r = crypto::zarcanum_verify_proof(id, kernel_hash, ring, last_pow_block_id_hashed, stake_input.k_image, sig, &err);
r = crypto::zarcanum_verify_proof(id, kernel_hash, ring, last_pow_block_id_hashed, stake_input.k_image, basic_diff, sig, &err);
CHECK_AND_ASSERT_MES(r, false, "zarcanum_verify_proof failed with code " << (int)err);
final_diff = basic_diff; // just for logs
return true;
}
else
@ -6097,10 +6099,12 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
int64_t ts_diff = actual_ts - m_core_runtime_config.get_core_time();
powpos_str_entry << "PoS:\t" << proof_hash << ", stake amount: ";
if (pos_coinstake_amount != UINT64_MAX)
{
powpos_str_entry << print_money_brief(pos_coinstake_amount);
powpos_str_entry << ", final_difficulty: " << this_coin_diff;
}
else
powpos_str_entry << "hidden";
powpos_str_entry << ", final_difficulty: " << this_coin_diff;
timestamp_str_entry << ", actual ts: " << actual_ts << " (diff: " << std::showpos << ts_diff << "s) block ts: " << std::noshowpos << bei.bl.timestamp << " (shift: " << std::showpos << static_cast<int64_t>(bei.bl.timestamp) - actual_ts << ")";
}
else
@ -6451,7 +6455,9 @@ bool blockchain_storage::build_kernel(const block& bl, stake_kernel& kernel, uin
return build_kernel(txin.k_image, kernel, stake_modifier, bl.timestamp);
}
//------------------------------------------------------------------
bool blockchain_storage::build_stake_modifier(stake_modifier_type& sm, const alt_chain_type& alt_chain, uint64_t split_height, crypto::hash *p_last_block_hash /* = nullptr */) const
bool blockchain_storage::build_stake_modifier(stake_modifier_type& sm, const alt_chain_type& alt_chain, uint64_t split_height,
crypto::hash* p_last_block_hash /* = nullptr */,
uint64_t* p_last_pow_block_height /* = nullptr */ ) const
{
CRITICAL_REGION_LOCAL(m_read_lock);
sm = stake_modifier_type();
@ -6473,6 +6479,9 @@ bool blockchain_storage::build_stake_modifier(stake_modifier_type& sm, const alt
if (p_last_block_hash != nullptr)
*p_last_block_hash = get_block_hash(m_db_blocks.back()->bl);
if (p_last_pow_block_height != nullptr)
*p_last_pow_block_height = pbei_last_pow->height;
return true;
}
//------------------------------------------------------------------

View file

@ -346,7 +346,7 @@ namespace currency
stake_kernel& kernel,
const stake_modifier_type& stake_modifier,
uint64_t timestamp) const;
bool build_stake_modifier(stake_modifier_type& sm, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0, crypto::hash *p_last_block_hash = nullptr) const;
bool build_stake_modifier(stake_modifier_type& sm, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0, crypto::hash* p_last_block_hash = nullptr, uint64_t* p_last_pow_block_height = nullptr) const;
bool validate_pos_coinbase_outs_unlock_time(const transaction& miner_tx, uint64_t staked_amount, uint64_t source_max_unlock_time)const;
bool validate_pos_block(const block& b, const crypto::hash& id, bool for_altchain)const;
@ -660,7 +660,7 @@ namespace currency
//bool resync_spent_tx_flags();
bool prune_ring_signatures_and_attachments_if_need();
bool prune_ring_signatures_and_attachments(uint64_t height, uint64_t& transactions_pruned, uint64_t& signatures_pruned, uint64_t& attachments_pruned);
// bool build_stake_modifier_for_alt(const alt_chain_type& alt_chain, stake_modifier_type& sm);
template<class visitor_t>
bool enum_blockchain(visitor_t& v, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0) const;
bool update_spent_tx_flags_for_input(uint64_t amount, const txout_ref_v& o, bool spent);