forked from lthn/blockchain
hidden amounts in wallet: construct_tx deep refactoring(first version, likely with bugs)
This commit is contained in:
parent
9fb947b544
commit
915bdd1efb
1 changed files with 109 additions and 113 deletions
|
|
@ -1319,6 +1319,99 @@ namespace currency
|
||||||
keypair in_ephemeral;
|
keypair in_ephemeral;
|
||||||
//std::vector<keypair> participants_derived_keys;
|
//std::vector<keypair> participants_derived_keys;
|
||||||
};
|
};
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
bool generate_zarcanum_signature(const crypto::hash& prefix_hash, const std::vector<const tx_source_entry*>& sources, const txin_zarcanum_inputs& zins, zarcanum_sig& result)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
bool generate_zc_sig(const std::vector<const tx_source_entry*>& sources, transaction& tx, const crypto::hash& tx_prefix_hash, const account_keys& sender_account_keys)
|
||||||
|
{
|
||||||
|
//TODO: sender_account_keys is not used?
|
||||||
|
tx.signatures.push_back(zarcanum_sig());
|
||||||
|
CHECK_AND_ASSERT_THROW_MES(tx.vin.back().type() == typeid(txin_zarcanum_inputs), "Unexpected input type in generate_zc_sig");
|
||||||
|
crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, tx.vin.size() - 1, tx_prefix_hash);
|
||||||
|
CHECK_AND_ASSERT_MES(tx_hash_for_signature != null_hash, false, "failed to prepare_prefix_hash_for_sign");
|
||||||
|
|
||||||
|
return generate_zarcanum_signature(tx_hash_for_signature, sources, boost::get<txin_zarcanum_inputs>(tx.vin.back()), boost::get<zarcanum_sig>(tx.signatures.back()));
|
||||||
|
}
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
bool generate_NLSAG_sig(const std::vector<const tx_source_entry*>& sources, size_t input_starter_index, transaction& tx, const crypto::hash& tx_prefix_hash, const account_keys& sender_account_keys, const std::vector<input_generation_context_data>& in_contexts, const keypair& txkey, std::stringstream& ss_ring_s)
|
||||||
|
{
|
||||||
|
bool watch_only_mode = sender_account_keys.spend_secret_key == null_skey;
|
||||||
|
size_t input_index = input_starter_index;
|
||||||
|
size_t in_context_index = 0;
|
||||||
|
BOOST_FOREACH(const tx_source_entry* src_entr_ptr, sources)
|
||||||
|
{
|
||||||
|
const tx_source_entry& src_entr = *src_entr_ptr;
|
||||||
|
crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, input_index, tx_prefix_hash);
|
||||||
|
CHECK_AND_ASSERT_MES(tx_hash_for_signature != null_hash, false, "failed to prepare_prefix_hash_for_sign");
|
||||||
|
|
||||||
|
tx.signatures.push_back(NLSAG_sig());
|
||||||
|
std::vector<crypto::signature>& sigs = boost::get<NLSAG_sig>(tx.signatures.back()).s;
|
||||||
|
|
||||||
|
if (src_entr.is_multisig())
|
||||||
|
{
|
||||||
|
// txin_multisig -- don't sign anything here (see also sign_multisig_input_in_tx())
|
||||||
|
sigs.resize(src_entr.ms_keys_count, null_sig); // just reserve keys.size() null signatures (NOTE: not minimum_sigs!)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// regular txin_to_key or htlc
|
||||||
|
ss_ring_s << "input #" << input_index << ", pub_keys:" << ENDL;
|
||||||
|
std::vector<const crypto::public_key*> keys_ptrs;
|
||||||
|
BOOST_FOREACH(const tx_source_entry::output_entry& o, src_entr.outputs)
|
||||||
|
{
|
||||||
|
keys_ptrs.push_back(&o.second);
|
||||||
|
ss_ring_s << o.second << ENDL;
|
||||||
|
}
|
||||||
|
sigs.resize(src_entr.outputs.size());
|
||||||
|
|
||||||
|
if (!watch_only_mode)
|
||||||
|
crypto::generate_ring_signature(tx_hash_for_signature, get_to_key_input_from_txin_v(tx.vin[input_index]).k_image, keys_ptrs, in_contexts[in_context_index].in_ephemeral.sec, src_entr.real_output, sigs.data());
|
||||||
|
|
||||||
|
ss_ring_s << "signatures:" << ENDL;
|
||||||
|
std::for_each(sigs.begin(), sigs.end(), [&ss_ring_s](const crypto::signature& s) { ss_ring_s << s << ENDL; });
|
||||||
|
ss_ring_s << "prefix_hash: " << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[in_context_index].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output << ENDL;
|
||||||
|
}
|
||||||
|
if (src_entr.separately_signed_tx_complete)
|
||||||
|
{
|
||||||
|
// if separately signed tx is complete, put one more signature to the last bunch using tx secret key, which confirms that transaction has been generated by authorized subject
|
||||||
|
CHECK_AND_ASSERT_MES(input_index == tx.vin.size() - 1, false, "separately_signed_tx_complete flag is set for source entry #" << input_index << ", allowed only for the last one");
|
||||||
|
CHECK_AND_ASSERT_MES(get_tx_flags(tx) & TX_FLAG_SIGNATURE_MODE_SEPARATE, false, "sorce entry separately_signed_tx_complete flag is set for tx with no TX_FLAG_SIGNATURE_MODE_SEPARATE flag");
|
||||||
|
CHECK_AND_ASSERT_MES(tx_hash_for_signature == tx_prefix_hash, false, "internal error: hash_for_sign for the last input of separately signed complete tx expected to be the same as tx prefix hash");
|
||||||
|
sigs.resize(sigs.size() + 1);
|
||||||
|
crypto::generate_signature(tx_prefix_hash, txkey.pub, txkey.sec, sigs.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
input_index++;
|
||||||
|
in_context_index++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
bool generate_zarcanum_outs_range_proof(size_t out_index_start, size_t outs_count, const crypto::scalar_vec_t& amounts, const crypto::scalar_vec_t& blinding_masks,
|
||||||
|
const std::vector<tx_out_v>& vouts, zarcanum_outs_range_proof& result)
|
||||||
|
{
|
||||||
|
//TODO: review for Andre
|
||||||
|
CHECK_AND_ASSERT_MES(amounts.size() == outs_count, false, "");
|
||||||
|
CHECK_AND_ASSERT_MES(blinding_masks.size() == outs_count, false, "");
|
||||||
|
CHECK_AND_ASSERT_MES(out_index_start + outs_count == vouts.size(), false, "");
|
||||||
|
|
||||||
|
std::vector<const crypto::public_key*> commitments_1div8;
|
||||||
|
for (size_t out_index = out_index_start, i = 0; i < outs_count; ++out_index, ++i)
|
||||||
|
{
|
||||||
|
const tx_out_zarcanum& toz = boost::get<tx_out_zarcanum>(vouts[out_index]); // may throw an exception, only zarcanum outputs are exprected
|
||||||
|
const crypto::public_key* p = &toz.amount_commitment;
|
||||||
|
commitments_1div8.push_back(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t err = 0;
|
||||||
|
bool r = crypto::bpp_gen<>(amounts, blinding_masks, commitments_1div8, result.bpp, &err);
|
||||||
|
CHECK_AND_ASSERT_MES(r, false, "bpp_gen failed with error " << err);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool construct_tx(const account_keys& sender_account_keys, const finalize_tx_param& ftp, finalized_tx& result)
|
bool construct_tx(const account_keys& sender_account_keys, const finalize_tx_param& ftp, finalized_tx& result)
|
||||||
{
|
{
|
||||||
|
|
@ -1403,20 +1496,9 @@ namespace currency
|
||||||
}
|
}
|
||||||
|
|
||||||
// //first: separate zarcanum inputs and regular one
|
// //first: separate zarcanum inputs and regular one
|
||||||
// const std::vector<tx_source_entry&> zc_sources;
|
std::vector<const tx_source_entry*> zc_sources;
|
||||||
// const std::vector<tx_source_entry&> NLSAG_sources;
|
std::vector<const tx_source_entry*> NLSAG_sources;
|
||||||
//
|
|
||||||
// BOOST_FOREACH(const tx_source_entry& src_entr, sources)
|
|
||||||
// {
|
|
||||||
// if (src_entr.is_zarcanum())
|
|
||||||
// {
|
|
||||||
// zc_sources.push_back(src_entr);
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// NLSAG_sources.push_back(src_entr);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<input_generation_context_data> in_contexts;
|
std::vector<input_generation_context_data> in_contexts;
|
||||||
|
|
@ -1427,7 +1509,7 @@ namespace currency
|
||||||
size_t input_starter_index = tx.vin.size();
|
size_t input_starter_index = tx.vin.size();
|
||||||
uint64_t summary_inputs_money = 0;
|
uint64_t summary_inputs_money = 0;
|
||||||
//fill inputs NLSAG and Zarcanum
|
//fill inputs NLSAG and Zarcanum
|
||||||
for (const tx_source_entry& src_entr : NLSAG_sources)
|
for (const tx_source_entry& src_entr : sources)
|
||||||
{
|
{
|
||||||
in_contexts.push_back(input_generation_context_data());
|
in_contexts.push_back(input_generation_context_data());
|
||||||
if(src_entr.is_multisig())
|
if(src_entr.is_multisig())
|
||||||
|
|
@ -1534,15 +1616,18 @@ namespace currency
|
||||||
input_to_key.key_offsets = absolute_output_offsets_to_relative(input_to_key.key_offsets);
|
input_to_key.key_offsets = absolute_output_offsets_to_relative(input_to_key.key_offsets);
|
||||||
|
|
||||||
//TODO: Might need some refactoring since this scheme is not the clearest one(did it this way for now to keep less changes to not broke anything)
|
//TODO: Might need some refactoring since this scheme is not the clearest one(did it this way for now to keep less changes to not broke anything)
|
||||||
|
//potentially this approach might help to support htlc and multisig without making to complicated code
|
||||||
if (src_entr.is_zarcanum())
|
if (src_entr.is_zarcanum())
|
||||||
{
|
{
|
||||||
zarcanum_input zc_in = AUTO_VAL_INIT(zc_in);
|
zarcanum_input zc_in = AUTO_VAL_INIT(zc_in);
|
||||||
zc_in.k_image = img;
|
zc_in.k_image = img;
|
||||||
zc_in.key_offsets = input_to_key.key_offsets;
|
zc_in.key_offsets = input_to_key.key_offsets;
|
||||||
ins_zc.elements.push_back(zc_in);
|
ins_zc.elements.push_back(zc_in);
|
||||||
|
zc_sources.push_back(&src_entr);
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
tx.vin.push_back(in_v);
|
tx.vin.push_back(in_v);
|
||||||
|
NLSAG_sources.push_back(&src_entr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1563,7 +1648,7 @@ namespace currency
|
||||||
size_t output_index = tx.vout.size(); // in case of append mode we need to start output indexing from the last one + 1
|
size_t output_index = tx.vout.size(); // in case of append mode we need to start output indexing from the last one + 1
|
||||||
uint64_t range_proof_start_index = output_index;
|
uint64_t range_proof_start_index = output_index;
|
||||||
std::set<uint16_t> deriv_cache;
|
std::set<uint16_t> deriv_cache;
|
||||||
crypto::scalar_vec_t blinding_masks(destinations.size()); // vector of secret blinging masks for each output. For range proof generation
|
crypto::scalar_vec_t blinding_masks(destinations.size()); // vector of secret binging masks for each output. For range proof generation
|
||||||
crypto::scalar_vec_t amounts(destinations.size()); // vector of amounts, converted to scalars. For rnage proof generation
|
crypto::scalar_vec_t amounts(destinations.size()); // vector of amounts, converted to scalars. For rnage proof generation
|
||||||
for(const tx_destination_entry& dst_entr : shuffled_dsts)
|
for(const tx_destination_entry& dst_entr : shuffled_dsts)
|
||||||
{
|
{
|
||||||
|
|
@ -1586,7 +1671,6 @@ namespace currency
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//process offers and put there offers derived keys
|
//process offers and put there offers derived keys
|
||||||
uint64_t att_count = 0;
|
uint64_t att_count = 0;
|
||||||
for (auto& o : tx.attachment)
|
for (auto& o : tx.attachment)
|
||||||
|
|
@ -1641,86 +1725,25 @@ namespace currency
|
||||||
get_transaction_prefix_hash(tx, tx_prefix_hash);
|
get_transaction_prefix_hash(tx, tx_prefix_hash);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::stringstream ss_ring_s;
|
std::stringstream ss_ring_s;
|
||||||
if (tx.version <= TRANSACTION_VERSION_PRE_HF4)
|
if (NLSAG_sources.size())
|
||||||
{
|
{
|
||||||
bool r = generate_NLSAG_sig(ftp, input_starter_index, tx, tx_prefix_hash, sender_account_keys, in_contexts, txkey, ss_ring_s);
|
bool r = generate_NLSAG_sig(NLSAG_sources, input_starter_index, tx, tx_prefix_hash, sender_account_keys, in_contexts, txkey, ss_ring_s);
|
||||||
CHECK_AND_ASSERT_MES(r, false, "Failed to generate_NLSAG_sig()");
|
CHECK_AND_ASSERT_MES(r, false, "Failed to generate_NLSAG_sig()");
|
||||||
}else
|
|
||||||
{
|
|
||||||
bool r = generate_hybrid_sig();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (zc_sources.size())
|
||||||
|
{
|
||||||
|
generate_zc_sig(zc_sources, tx, tx_prefix_hash, sender_account_keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
LOG_PRINT2("construct_tx.log", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL << ss_ring_s.str(), LOG_LEVEL_3);
|
LOG_PRINT2("construct_tx.log", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL << ss_ring_s.str(), LOG_LEVEL_3);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool generate_hybrid_sig(const finalize_tx_param& ftp, size_t input_starter_index, transaction& tx, const crypto::hash& tx_prefix_hash, const account_keys& sender_account_keys, const std::vector<input_generation_context_data>& in_contexts, const keypair& txkey, std::stringstream& ss_ring_s)
|
|
||||||
{
|
|
||||||
const std::vector<tx_source_entry>& sources = ftp.sources;
|
|
||||||
bool watch_only_mode = sender_account_keys.spend_secret_key == null_skey;
|
|
||||||
size_t input_index = input_starter_index;
|
|
||||||
size_t in_context_index = 0;
|
|
||||||
|
|
||||||
|
|
||||||
bool r = generate_zarcanum_signature(tx_prefix_hash, zc_sources, const txin_zarcanum_inputs& zins, zarcanum_sig& result)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool generate_NLSAG_sig(const finalize_tx_param& ftp, size_t input_starter_index, transaction& tx, const crypto::hash& tx_prefix_hash, const account_keys& sender_account_keys, const std::vector<input_generation_context_data>& in_contexts, const keypair& txkey, std::stringstream& ss_ring_s)
|
|
||||||
{
|
|
||||||
const std::vector<tx_source_entry>& sources = ftp.sources;
|
|
||||||
bool watch_only_mode = sender_account_keys.spend_secret_key == null_skey;
|
|
||||||
size_t input_index = input_starter_index;
|
|
||||||
size_t in_context_index = 0;
|
|
||||||
BOOST_FOREACH(const tx_source_entry& src_entr, sources)
|
|
||||||
{
|
|
||||||
crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, input_index, tx_prefix_hash);
|
|
||||||
CHECK_AND_ASSERT_MES(tx_hash_for_signature != null_hash, false, "failed to prepare_prefix_hash_for_sign");
|
|
||||||
|
|
||||||
tx.signatures.push_back(NLSAG_sig());
|
|
||||||
std::vector<crypto::signature>& sigs = boost::get<NLSAG_sig>(tx.signatures.back()).s;
|
|
||||||
|
|
||||||
if (src_entr.is_multisig())
|
|
||||||
{
|
|
||||||
// txin_multisig -- don't sign anything here (see also sign_multisig_input_in_tx())
|
|
||||||
sigs.resize(src_entr.ms_keys_count, null_sig); // just reserve keys.size() null signatures (NOTE: not minimum_sigs!)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// regular txin_to_key or htlc
|
|
||||||
ss_ring_s << "input #" << input_index << ", pub_keys:" << ENDL;
|
|
||||||
std::vector<const crypto::public_key*> keys_ptrs;
|
|
||||||
BOOST_FOREACH(const tx_source_entry::output_entry& o, src_entr.outputs)
|
|
||||||
{
|
|
||||||
keys_ptrs.push_back(&o.second);
|
|
||||||
ss_ring_s << o.second << ENDL;
|
|
||||||
}
|
|
||||||
sigs.resize(src_entr.outputs.size());
|
|
||||||
|
|
||||||
if (!watch_only_mode)
|
|
||||||
crypto::generate_ring_signature(tx_hash_for_signature, get_to_key_input_from_txin_v(tx.vin[input_index]).k_image, keys_ptrs, in_contexts[in_context_index].in_ephemeral.sec, src_entr.real_output, sigs.data());
|
|
||||||
|
|
||||||
ss_ring_s << "signatures:" << ENDL;
|
|
||||||
std::for_each(sigs.begin(), sigs.end(), [&ss_ring_s](const crypto::signature& s) { ss_ring_s << s << ENDL; });
|
|
||||||
ss_ring_s << "prefix_hash: " << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[in_context_index].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output << ENDL;
|
|
||||||
}
|
|
||||||
if (src_entr.separately_signed_tx_complete)
|
|
||||||
{
|
|
||||||
// if separately signed tx is complete, put one more signature to the last bunch using tx secret key, which confirms that transaction has been generated by authorized subject
|
|
||||||
CHECK_AND_ASSERT_MES(input_index == tx.vin.size() - 1, false, "separately_signed_tx_complete flag is set for source entry #" << input_index << ", allowed only for the last one");
|
|
||||||
CHECK_AND_ASSERT_MES(flags & TX_FLAG_SIGNATURE_MODE_SEPARATE, false, "sorce entry separately_signed_tx_complete flag is set for tx with no TX_FLAG_SIGNATURE_MODE_SEPARATE flag");
|
|
||||||
CHECK_AND_ASSERT_MES(tx_hash_for_signature == tx_prefix_hash, false, "internal error: hash_for_sign for the last input of separately signed complete tx expected to be the same as tx prefix hash");
|
|
||||||
sigs.resize(sigs.size() + 1);
|
|
||||||
crypto::generate_signature(tx_prefix_hash, txkey.pub, txkey.sec, sigs.back());
|
|
||||||
}
|
|
||||||
|
|
||||||
input_index++;
|
|
||||||
in_context_index++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
uint64_t get_tx_version(uint64_t h, const hard_forks_descriptor& hfd)
|
uint64_t get_tx_version(uint64_t h, const hard_forks_descriptor& hfd)
|
||||||
{
|
{
|
||||||
|
|
@ -3530,29 +3553,7 @@ namespace currency
|
||||||
//@#@ TODO
|
//@#@ TODO
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
//--------------------------------------------------------------------------------
|
|
||||||
bool generate_zarcanum_outs_range_proof(size_t out_index_start, size_t outs_count, const crypto::scalar_vec_t& amounts, const crypto::scalar_vec_t& blinding_masks,
|
|
||||||
const std::vector<tx_out_v>& vouts, zarcanum_outs_range_proof& result)
|
|
||||||
{
|
|
||||||
//TODO: review for Andre
|
|
||||||
CHECK_AND_ASSERT_MES(amounts.size() == outs_count, false, "");
|
|
||||||
CHECK_AND_ASSERT_MES(blinding_masks.size() == outs_count, false, "");
|
|
||||||
CHECK_AND_ASSERT_MES(out_index_start + outs_count == vouts.size(), false, "");
|
|
||||||
|
|
||||||
std::vector<const crypto::public_key*> commitments_1div8;
|
|
||||||
for(size_t out_index = out_index_start, i = 0; i < outs_count; ++out_index, ++i)
|
|
||||||
{
|
|
||||||
const tx_out_zarcanum& toz = boost::get<tx_out_zarcanum>(vouts[out_index]); // may throw an exception, only zarcanum outputs are exprected
|
|
||||||
const crypto::public_key* p = &toz.amount_commitment;
|
|
||||||
commitments_1div8.push_back(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t err = 0;
|
|
||||||
bool r = crypto::bpp_gen<>(amounts, blinding_masks, commitments_1div8, result.bpp, &err);
|
|
||||||
CHECK_AND_ASSERT_MES(r, false, "bpp_gen failed with error " << err);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------
|
||||||
struct zarcanum_outs_range_proof_commit_ref_t
|
struct zarcanum_outs_range_proof_commit_ref_t
|
||||||
{
|
{
|
||||||
|
|
@ -3577,11 +3578,6 @@ namespace currency
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//--------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------
|
||||||
bool generate_zarcanum_signature(const crypto::hash& prefix_hash, const std::vector<tx_source_entry>& sources, const txin_zarcanum_inputs& zins, zarcanum_sig& result)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
boost::multiprecision::uint1024_t get_a_to_b_relative_cumulative_difficulty(const wide_difficulty_type& difficulty_pos_at_split_point,
|
boost::multiprecision::uint1024_t get_a_to_b_relative_cumulative_difficulty(const wide_difficulty_type& difficulty_pos_at_split_point,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue