validate_tx_details_against_tx_generation_context implemented

This commit is contained in:
sowle 2024-06-25 15:46:53 +02:00
parent 5e8cfb9ee3
commit 5ab468be42
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
3 changed files with 109 additions and 10 deletions

View file

@ -398,14 +398,112 @@ namespace currency
CATCH_ENTRY2(std::vector<tx_source_entry::output_entry>{});
}
//---------------------------------------------------------------
bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context)
bool validate_tx_details_against_tx_generation_context(const transaction& tx, const tx_generation_context& tgc)
{
//TODO: Implement this function before mainnet
#ifdef TESTNET
CHECK_AND_ASSERT_MES(tx.version >= TRANSACTION_VERSION_POST_HF4, false, "validate_tx_details_against_tx_generation_context should never be called for pre-HF4 txs");
//
// outputs
// (all outputs are ZC outputs, because we require tx.version to be post-HF4)
size_t tx_outs_count = tx.vout.size();
CHECK_AND_ASSERT_EQ(tgc.asset_ids.size(), tx_outs_count);
CHECK_AND_ASSERT_EQ(tgc.blinded_asset_ids.size(), tx_outs_count);
CHECK_AND_ASSERT_EQ(tgc.amount_commitments.size(), tx_outs_count);
CHECK_AND_ASSERT_EQ(tgc.asset_id_blinding_masks.size(), tx_outs_count);
CHECK_AND_ASSERT_EQ(tgc.amounts.size(), tx_outs_count);
CHECK_AND_ASSERT_EQ(tgc.amount_blinding_masks.size(), tx_outs_count);
crypto::point_t amount_commitments_sum = crypto::c_point_0;
crypto::scalar_t amount_blinding_masks_sum{};
crypto::scalar_t asset_id_blinding_mask_x_amount_sum{};
for(size_t i = 0; i < tx_outs_count; ++i)
{
crypto::point_t calculated_T = tgc.asset_ids[i] + tgc.asset_id_blinding_masks[i] * crypto::c_point_X;
CHECK_AND_ASSERT_MES(calculated_T.is_in_main_subgroup(), false, "calculated_T isn't in the main subgroup");
CHECK_AND_ASSERT_EQ(tgc.blinded_asset_ids[i], calculated_T);
crypto::point_t calculated_A = tgc.amounts[i] * calculated_T + tgc.amount_blinding_masks[i] * crypto::c_point_G;
CHECK_AND_ASSERT_MES(calculated_A.is_in_main_subgroup(), false, "calculated_A isn't in the main subgroup");
CHECK_AND_ASSERT_EQ(tgc.amount_commitments[i], calculated_A);
const tx_out_zarcanum& tx_out_zc = boost::get<tx_out_zarcanum>(tx.vout[i]);
crypto::point_t tx_T = crypto::point_t(tx_out_zc.blinded_asset_id).modify_mul8();
CHECK_AND_ASSERT_EQ(tgc.blinded_asset_ids[i], tx_T);
crypto::point_t tx_A = crypto::point_t(tx_out_zc.amount_commitment).modify_mul8();
CHECK_AND_ASSERT_EQ(tgc.amount_commitments[i], tx_A);
amount_commitments_sum += calculated_A;
amount_blinding_masks_sum += tgc.amount_blinding_masks[i];
asset_id_blinding_mask_x_amount_sum += tgc.asset_id_blinding_masks[i] * tgc.amounts[i];
}
CHECK_AND_ASSERT_EQ(tgc.amount_commitments_sum, amount_commitments_sum);
CHECK_AND_ASSERT_EQ(tgc.amount_blinding_masks_sum, amount_blinding_masks_sum);
CHECK_AND_ASSERT_EQ(tgc.asset_id_blinding_mask_x_amount_sum, asset_id_blinding_mask_x_amount_sum);
//
// inputs
//
size_t tx_inputs_count = tx.vin.size();
size_t tx_zc_inputs_count = count_type_in_variant_container<txin_zc_input>(tx.vin);
size_t tx_bare_inputs_count = count_type_in_variant_container<txin_to_key>(tx.vin);
CHECK_AND_ASSERT_EQ(tx_inputs_count, tx_zc_inputs_count + tx_bare_inputs_count);
CHECK_AND_ASSERT_EQ(tx.signatures.size(), tx.vin.size()); // can do this because we shouldn't face additional signature so far
CHECK_AND_ASSERT_EQ(tgc.pseudo_outs_blinded_asset_ids.size(), tx_zc_inputs_count);
CHECK_AND_ASSERT_EQ(tgc.pseudo_outs_plus_real_out_blinding_masks.size(), tx_zc_inputs_count);
CHECK_AND_ASSERT_EQ(tgc.real_zc_ins_asset_ids.size(), tx_zc_inputs_count);
CHECK_AND_ASSERT_EQ(tgc.zc_input_amounts.size(), tx_zc_inputs_count);
crypto::point_t pseudo_out_amount_commitments_sum = crypto::c_point_0;
for(size_t input_index = 0, zc_input_index = 0; input_index < tx.vin.size(); ++input_index)
{
const txin_v& in_v = tx.vin[input_index];
if (in_v.type() == typeid(txin_zc_input))
{
CHECK_AND_ASSERT_EQ(tx.signatures[input_index].type(), typeid(ZC_sig));
const ZC_sig& sig = boost::get<ZC_sig>(tx.signatures[input_index]);
crypto::point_t sig_pseudo_out_amount_commitment = crypto::point_t(sig.pseudo_out_amount_commitment).modify_mul8();
crypto::point_t sig_pseudo_out_blinded_asset_id = crypto::point_t(sig.pseudo_out_blinded_asset_id).modify_mul8();
crypto::point_t pseudo_out_blinded_asset_id_calculated = tgc.real_zc_ins_asset_ids[zc_input_index] + tgc.pseudo_outs_plus_real_out_blinding_masks[zc_input_index] * crypto::c_point_X; // T^P = H_i + r_pi*X + r'_i*X
CHECK_AND_ASSERT_EQ(sig_pseudo_out_blinded_asset_id, pseudo_out_blinded_asset_id_calculated);
CHECK_AND_ASSERT_EQ(tgc.pseudo_outs_blinded_asset_ids[zc_input_index], pseudo_out_blinded_asset_id_calculated);
CHECK_AND_ASSERT_MES(pseudo_out_blinded_asset_id_calculated.is_in_main_subgroup(), false, "pseudo_out_blinded_asset_id_calculated isn't in the main subgroup");
// cannot be verified:
// tgc.zc_input_amounts[zc_input_index]; // ZC only input amounts
pseudo_out_amount_commitments_sum += sig_pseudo_out_amount_commitment;
++zc_input_index;
}
else if (in_v.type() == typeid(txin_to_key))
{
// do nothing
}
else
{
// should never get here
CHECK_AND_ASSERT_MES(false, false, "internal error, unexpected type: " << in_v.type().name());
}
}
// tx secret and public keys
CHECK_AND_ASSERT_MES(tgc.tx_pub_key_p.is_in_main_subgroup(), false, "tgc.tx_pub_key_p isn't in the main subgroup");
CHECK_AND_ASSERT_EQ(tgc.tx_pub_key_p.to_public_key(), tgc.tx_key.pub);
CHECK_AND_ASSERT_EQ(crypto::scalar_t(tgc.tx_key.sec) * crypto::c_point_G, tgc.tx_pub_key_p);
// no ongoing asset operation
CHECK_AND_ASSERT_EQ(tgc.ao_asset_id, currency::null_pkey);
CHECK_AND_ASSERT_EQ(tgc.ao_asset_id_pt, crypto::c_point_0);
CHECK_AND_ASSERT_EQ(tgc.ao_amount_commitment, crypto::c_point_0);
CHECK_AND_ASSERT_EQ(tgc.ao_amount_blinding_mask, crypto::c_scalar_0);
// cannot be verified:
// tgc.pseudo_out_amount_blinding_masks_sum
// tgc.real_in_asset_id_blinding_mask_x_amount_sum
return true;
#else
return true;
#endif
}
//----------------------------------------------------------------------------------------------------
@ -421,4 +519,4 @@ namespace currency
}
}
}

View file

@ -344,7 +344,8 @@ namespace currency
END_SERIALIZE()
}; // struct tx_generation_context
bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context);
bool validate_tx_details_against_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context);
std::string transform_tx_to_str(const transaction& tx);
transaction transform_str_to_tx(const std::string& tx_str);

View file

@ -6060,8 +6060,8 @@ bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_propo
r = t_unserializable_object_from_blob(ionic_context, decrypted_raw_context);
THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "Failed to unserialize decrypted ionic_context");
r = validate_tx_output_details_againt_tx_generation_context(tx, ionic_context.gen_context);
THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "Failed to validate decrypted ionic_context");
r = validate_tx_details_against_tx_generation_context(tx, ionic_context.gen_context);
THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "validate_tx_details_against_tx_generation_context failed");
std::unordered_map<crypto::public_key, uint64_t> amounts_provided_by_a;