From 6915213eb122baaf7bf2d8942c5f6ab33ce17f13 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 4 Apr 2023 23:22:11 +0200 Subject: [PATCH] verify_asset_surjection_proof() : first PoC implementation --- src/currency_core/blockchain_storage.cpp | 20 ++++++- src/currency_core/currency_format_utils.cpp | 63 +++++++++++++++++++++ src/currency_core/currency_format_utils.h | 1 + 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 5af4b705..53d37580 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -1354,10 +1354,12 @@ bool blockchain_storage::validate_miner_transaction(const block& b, return false; } - crypto::hash tx_id_for_balance_check = b.miner_tx.version > TRANSACTION_VERSION_PRE_HF4 ? get_transaction_hash(b.miner_tx) : null_hash; - if (!check_tx_balance(b.miner_tx, tx_id_for_balance_check, base_reward + fee)) + uint64_t block_reward = base_reward + fee; + + crypto::hash tx_id_for_post_hf4_era = b.miner_tx.version > TRANSACTION_VERSION_PRE_HF4 ? get_transaction_hash(b.miner_tx) : null_hash; + if (!check_tx_balance(b.miner_tx, tx_id_for_post_hf4_era, block_reward)) { - LOG_ERROR("coinbase transaction balance check failed. Block reward is " << print_money_brief(base_reward + fee) << "(" << print_money(base_reward) << "+" << print_money(fee) + LOG_ERROR("coinbase transaction balance check failed. Block reward is " << print_money_brief(block_reward) << "(" << print_money(base_reward) << "+" << print_money(fee) << ", blocks_size_median = " << blocks_size_median << ", cumulative_block_size = " << cumulative_block_size << ", fee = " << fee @@ -1367,6 +1369,15 @@ bool blockchain_storage::validate_miner_transaction(const block& b, return false; } + if (b.miner_tx.version > TRANSACTION_VERSION_PRE_HF4) + { + if (!verify_asset_surjection_proof(b.miner_tx, tx_id_for_post_hf4_era)) + { + LOG_ERROR("asset surjection proof verification failed for miner tx"); + return false; + } + } + LOG_PRINT_MAGENTA("Mining tx verification ok, blocks_size_median = " << blocks_size_median, LOG_LEVEL_2); return true; } @@ -5914,6 +5925,9 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt CHECK_AND_ASSERT_MES_CUSTOM(check_tx_balance(tx, tx_id), false, cleanup(), "block " << id << ", tx " << tx_id << ": check_tx_balance failed"); + + CHECK_AND_ASSERT_MES_CUSTOM(verify_asset_surjection_proof(tx, tx_id), false, cleanup(), + "block " << id << ", tx " << tx_id << ": verify_asset_surjection_proof failed"); } TIME_MEASURE_START_PD(tx_add_one_tx_time); diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index b8bb19e3..7b3bb029 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -107,6 +107,69 @@ namespace currency return true; } //-------------------------------------------------------------------------------- + bool verify_asset_surjection_proof(const transaction& tx, const crypto::hash& tx_id) + { + bool r = false; + if (tx.version <= TRANSACTION_VERSION_PRE_HF4) + return true; + + size_t outs_count = tx.vout.size(); + + bool has_ZC_inputs = false; + bool has_non_ZC_inputs = false; + for(const auto& in : tx.vin) + { + if (in.type() == typeid(txin_zc_input)) + has_ZC_inputs = true; + else + has_non_ZC_inputs = true; + } + + if (!has_ZC_inputs) + { + // no ZC ins -- just make sure there's only native outputs with explicit asset ids + for(size_t j = 0; j < outs_count; ++j) + { + CHECK_AND_ASSERT_MES(boost::get(tx.vout[j]).blinded_asset_id == native_coin_asset_id_1div8, false, "output #" << j << " has a non explicitly native asset id"); + } + return true; + } + + // tx has ZC inputs + const zc_asset_surjection_proof& sig = get_type_in_variant_container_by_ref(tx.proofs); // order of proofs and uniqueness of zc_asset_surjection_proof should be check before on prevalidation + CHECK_AND_ASSERT_MES(sig.bge_proofs.size() == outs_count, false, "ASP count: " << sig.bge_proofs.size() << ", outputs: " << outs_count << " => missmatch"); + + // make a ring + std::vector pseudo_outs_blinded_asset_ids; + for(const auto& sig : tx.signatures) + { + if (sig.type() == typeid(ZC_sig)) + pseudo_outs_blinded_asset_ids.emplace_back(crypto::point_t(boost::get(sig).pseudo_out_blinded_asset_id).modify_mul8()); + } + if (has_non_ZC_inputs) + pseudo_outs_blinded_asset_ids.emplace_back(currency::native_coin_asset_id_pt); // additional ring member for txs with non-zc inputs + + for(size_t j = 0; j < outs_count; ++j) + { + crypto::point_t blinded_asset_id(boost::get(tx.vout[j]).blinded_asset_id); + blinded_asset_id.modify_mul8(); + + // TODO @#@# remove this redundant conversion to pubkey and back + std::vector ring(pseudo_outs_blinded_asset_ids.size()); + std::vector ring_pointers(pseudo_outs_blinded_asset_ids.size()); + for(size_t i = 0, n = pseudo_outs_blinded_asset_ids.size(); i < n; ++i) + { + ring[i] = ((crypto::c_scalar_1div8 * (pseudo_outs_blinded_asset_ids[i] - blinded_asset_id)).to_public_key()); + ring_pointers[i] = &ring[i]; + } + + uint8_t err = 0; + CHECK_AND_ASSERT_MES(crypto::verify_BGE_proof(tx_id, ring_pointers, sig.bge_proofs[j], &err), false, "verify_BGE_proof failed, err = " << (int)err); + } + + return true; + } + //-------------------------------------------------------------------------------- bool generate_zc_outs_range_proof(const crypto::hash& context_hash, size_t out_index_start, const outputs_generation_context& outs_gen_context, const std::vector& vouts, zc_outs_range_proof& result) { diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 1459a885..9ffbf6f3 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -230,6 +230,7 @@ namespace currency bool verify_multiple_zc_outs_range_proofs(const std::vector& range_proofs); bool generate_asset_surjection_proof(const crypto::hash& context_hash, bool has_non_zc_inputs, outputs_generation_context& ogc, zc_asset_surjection_proof& result); + bool verify_asset_surjection_proof(const transaction& tx, const crypto::hash& tx_id); bool generate_tx_balance_proof(const transaction &tx, const crypto::hash& tx_id, const outputs_generation_context& ogc, uint64_t block_reward_for_miner_tx, zc_balance_proof& proof); bool generate_zc_outs_range_proof(const crypto::hash& context_hash, size_t out_index_start, const outputs_generation_context& outs_gen_context, const std::vector& vouts, zc_outs_range_proof& result);