forked from lthn/blockchain
confidential assets: global core refactoring (wip)
This commit is contained in:
parent
47b1338d32
commit
abf99ece5e
5 changed files with 278 additions and 172 deletions
|
|
@ -56,7 +56,9 @@ namespace currency
|
|||
|
||||
const static crypto::hash gdefault_genesis = epee::string_tools::hex_to_pod<crypto::hash>("CC608F59F8080E2FBFE3C8C80EB6E6A953D47CF2D6AEBD345BADA3A1CAB99852");
|
||||
const static crypto::hash ffff_hash = epee::string_tools::hex_to_pod<crypto::hash>("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||
const static crypto::public_key ffff_pkey = epee::string_tools::hex_to_pod<crypto::public_key>("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||
const static crypto::public_key ffff_pkey = epee::string_tools::hex_to_pod<crypto::public_key>("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // TODO @#@# consider getting rid of this
|
||||
|
||||
extern const crypto::public_key native_coin_asset_id;
|
||||
|
||||
const static wide_difficulty_type global_difficulty_pow_starter = DIFFICULTY_POW_STARTER;
|
||||
const static wide_difficulty_type global_difficulty_pos_starter = DIFFICULTY_POS_STARTER;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ using namespace epee;
|
|||
|
||||
namespace currency
|
||||
{
|
||||
const crypto::public_key native_coin_asset_id = crypto::point_t(0x05087c1f5b9b32d6, 0x00547595f445c3b5, 0x764df64578552f2a, 0x8a49a651e0e0da45).to_public_key(); // == crypto::c_point_H, checked in crypto_basics test
|
||||
|
||||
//---------------------------------------------------------------
|
||||
bool add_tx_extra_alias(transaction& tx, const extra_alias_entry& alinfo)
|
||||
|
|
@ -66,27 +67,84 @@ namespace currency
|
|||
pos_entry());
|
||||
}*/
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
bool generate_zc_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, zc_outs_range_proof& result)
|
||||
struct outputs_generation_context
|
||||
{
|
||||
//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, "");
|
||||
outputs_generation_context(size_t outs_count)
|
||||
: asset_ids(outs_count)
|
||||
, blinded_asset_ids(outs_count)
|
||||
, amount_commitments(outs_count)
|
||||
, asset_id_blinding_masks(outs_count)
|
||||
, amounts(outs_count)
|
||||
, amount_blinding_masks(outs_count)
|
||||
{}
|
||||
|
||||
std::vector<const crypto::public_key*> commitments_1div8;
|
||||
for (size_t out_index = out_index_start, i = 0; i < outs_count; ++out_index, ++i)
|
||||
bool check_sizes(size_t outs_count) const
|
||||
{
|
||||
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);
|
||||
return
|
||||
asset_ids.size() == outs_count &&
|
||||
blinded_asset_ids.size() == outs_count &&
|
||||
amount_commitments.size() == outs_count &&
|
||||
asset_id_blinding_masks.size() == outs_count &&
|
||||
amounts.size() == outs_count &&
|
||||
amount_blinding_masks.size() == outs_count;
|
||||
}
|
||||
|
||||
result.outputs_count = outs_count;
|
||||
// per output data
|
||||
std::vector<crypto::point_t> asset_ids;
|
||||
std::vector<crypto::point_t> blinded_asset_ids;
|
||||
std::vector<crypto::point_t> amount_commitments;
|
||||
crypto::scalar_vec_t asset_id_blinding_masks;
|
||||
crypto::scalar_vec_t amounts;
|
||||
crypto::scalar_vec_t amount_blinding_masks;
|
||||
|
||||
// common data
|
||||
crypto::scalar_t asset_id_blinding_masks_sum = 0;
|
||||
crypto::scalar_t local_asset_id_blinding_masks_sum = 0;
|
||||
crypto::scalar_t amount_blinding_masks_sum = 0;
|
||||
crypto::scalar_t local_amount_blinding_masks_sum = 0;
|
||||
};
|
||||
//--------------------------------------------------------------------------------
|
||||
bool generate_asset_surjection_proof(zc_asset_surjection_proof& result)
|
||||
{
|
||||
// TODO: membership proof here
|
||||
return false;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool generate_zc_outs_range_proof(size_t out_index_start, size_t outs_count, const outputs_generation_context& outs_gen_context,
|
||||
const std::vector<tx_out_v>& vouts, zc_outs_range_proof& result)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(outs_gen_context.check_sizes(outs_count), false, "");
|
||||
CHECK_AND_ASSERT_MES(out_index_start + outs_count == vouts.size(), false, "");
|
||||
|
||||
// prepare data for aggregation proof
|
||||
std::vector<crypto::point_t> amount_commitments_for_rp_aggregation; // E' = amount * U + y' * G
|
||||
crypto::scalar_vec_t g_secrets; // amount + y'
|
||||
crypto::scalar_vec_t y_primes; // y'
|
||||
for (size_t out_index = out_index_start, i = 0; i < outs_count; ++out_index, ++i)
|
||||
{
|
||||
crypto::scalar_t y_prime = crypto::scalar_t::random();
|
||||
amount_commitments_for_rp_aggregation.emplace_back(outs_gen_context.amounts[i] * crypto::c_point_U + y_prime * crypto::c_point_G); // E'_j = e_j * U + y'_j * G
|
||||
g_secrets.emplace_back(outs_gen_context.amount_blinding_masks[i] + y_prime);
|
||||
y_primes.emplace_back(std::move(y_prime));
|
||||
}
|
||||
|
||||
// aggregation proof
|
||||
// TODO: @#@# use appropriate hash for context binding
|
||||
uint8_t err = 0;
|
||||
bool r = crypto::bpp_gen<>(amounts, blinding_masks, commitments_1div8, result.bpp, &err);
|
||||
bool r = crypto::generate_vector_UG_aggregation_proof(null_hash, outs_gen_context.amounts, g_secrets,
|
||||
outs_gen_context.amount_commitments,
|
||||
amount_commitments_for_rp_aggregation,
|
||||
outs_gen_context.blinded_asset_ids, result.aggregation_proof, &err);
|
||||
CHECK_AND_ASSERT_MES(r, false, "generate_vector_UG_aggregation_proof failed with error " << (int)err);
|
||||
|
||||
// aggregated range proof
|
||||
std::vector<const crypto::public_key*> commitments_1div8(result.aggregation_proof.amount_commitments_for_rp_aggregation.size());
|
||||
for(size_t i = 0, sz = result.aggregation_proof.amount_commitments_for_rp_aggregation.size(); i < sz; ++i)
|
||||
commitments_1div8[i] = &result.aggregation_proof.amount_commitments_for_rp_aggregation[i];
|
||||
|
||||
err = 0;
|
||||
r = crypto::bpp_gen<>(outs_gen_context.amounts, y_primes, commitments_1div8, result.bpp, &err);
|
||||
CHECK_AND_ASSERT_MES(r, false, "bpp_gen failed with error " << (int)err);
|
||||
|
||||
return true;
|
||||
|
|
@ -104,10 +162,10 @@ namespace currency
|
|||
}
|
||||
//------------------------------------------------------------------
|
||||
// for txs with no zc inputs (and thus no zc signatures) but with zc outputs
|
||||
bool generate_tx_balance_proof(transaction &tx, const crypto::scalar_t& outputs_blinding_masks_sum, uint64_t block_reward_for_miner_tx = 0)
|
||||
bool generate_tx_balance_proof(transaction &tx, const outputs_generation_context& outs_gen_context, uint64_t block_reward_for_miner_tx = 0)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(tx.version > TRANSACTION_VERSION_PRE_HF4, false, "unsupported tx.version: " << tx.version);
|
||||
CHECK_AND_ASSERT_MES(count_type_in_variant_container<ZC_sig>(tx.signatures) == 0, false, "");
|
||||
CHECK_AND_ASSERT_MES(count_type_in_variant_container<ZC_sig>(tx.signatures) == 0, false, "ZC_sig is unexpected");
|
||||
|
||||
uint64_t bare_inputs_sum = block_reward_for_miner_tx;
|
||||
// TODO: condider remove the followin cycle
|
||||
|
|
@ -149,7 +207,7 @@ namespace currency
|
|||
//crypto::scalar_t witness = outputs_blinding_masks_sum;
|
||||
|
||||
// TODO: consider adding more data to message
|
||||
crypto::generate_signature(null_hash, commitment_to_zero.to_public_key(), outputs_blinding_masks_sum.as_secret_key(), balance_proof.s);
|
||||
crypto::generate_signature(null_hash, commitment_to_zero.to_public_key(), outs_gen_context.amount_blinding_masks_sum.as_secret_key(), balance_proof.s);
|
||||
tx.attachment.push_back(balance_proof);
|
||||
|
||||
return true;
|
||||
|
|
@ -289,19 +347,20 @@ namespace currency
|
|||
}
|
||||
|
||||
// fill outputs
|
||||
crypto::scalar_vec_t blinding_masks(destinations.size()); // vector of secret blinging masks for each output. For range proof generation
|
||||
crypto::scalar_vec_t amounts(destinations.size()); // vector of amounts, converted to scalars. For ranage proof generation
|
||||
crypto::scalar_t blinding_masks_sum = 0;
|
||||
outputs_generation_context outs_gen_context(destinations.size()); // auxiliary data for each output
|
||||
uint64_t output_index = 0;
|
||||
for (auto& d : destinations)
|
||||
{
|
||||
std::set<uint16_t> deriv_cache;
|
||||
finalized_tx result = AUTO_VAL_INIT(result);
|
||||
uint8_t tx_outs_attr = 0;
|
||||
r = construct_tx_out(d, txkey.sec, output_index, tx, deriv_cache, account_keys(), blinding_masks[output_index], result, tx_outs_attr);
|
||||
r = construct_tx_out(d, txkey.sec, output_index, tx, deriv_cache, account_keys(),
|
||||
outs_gen_context.asset_id_blinding_masks[output_index], outs_gen_context.amount_blinding_masks[output_index],
|
||||
outs_gen_context.blinded_asset_ids[output_index], outs_gen_context.amount_commitments[output_index], result, tx_outs_attr);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx_out failed, output #" << output_index << ", amount: " << print_money_brief(d.amount));
|
||||
amounts[output_index] = d.amount;
|
||||
blinding_masks_sum += blinding_masks[output_index];
|
||||
outs_gen_context.amounts[output_index] = d.amount;
|
||||
outs_gen_context.asset_id_blinding_masks_sum += outs_gen_context.asset_id_blinding_masks[output_index];
|
||||
outs_gen_context.amount_blinding_masks_sum += outs_gen_context.amount_blinding_masks[output_index];
|
||||
++output_index;
|
||||
}
|
||||
|
||||
|
|
@ -309,13 +368,13 @@ namespace currency
|
|||
{
|
||||
//add range proofs
|
||||
currency::zc_outs_range_proof range_proofs = AUTO_VAL_INIT(range_proofs);
|
||||
bool r = generate_zc_outs_range_proof(0, amounts.size(), amounts, blinding_masks, tx.vout, range_proofs);
|
||||
bool r = generate_zc_outs_range_proof(0, destinations.size(), outs_gen_context, tx.vout, range_proofs);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to generate zc_outs_range_proof()");
|
||||
tx.attachment.push_back(range_proofs);
|
||||
|
||||
if (!pos)
|
||||
{
|
||||
r = generate_tx_balance_proof(tx, blinding_masks_sum, block_reward);
|
||||
r = generate_tx_balance_proof(tx, outs_gen_context, block_reward);
|
||||
CHECK_AND_ASSERT_MES(r, false, "generate_tx_balance_proof failed");
|
||||
}
|
||||
}
|
||||
|
|
@ -330,7 +389,7 @@ namespace currency
|
|||
}
|
||||
|
||||
if (blinding_masks_sum_ptr)
|
||||
*blinding_masks_sum_ptr = blinding_masks_sum;
|
||||
*blinding_masks_sum_ptr = outs_gen_context.amount_blinding_masks_sum; // TODO @#@#
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -339,16 +398,8 @@ namespace currency
|
|||
{
|
||||
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
|
||||
{
|
||||
//@#@ TODO: This is just a temporary code
|
||||
uint64_t assets_emmited = 0;
|
||||
asset_descriptor_operation ado = AUTO_VAL_INIT(ado);
|
||||
if (get_type_in_variant_container(tx.extra, ado) && ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER)
|
||||
{
|
||||
assets_emmited += ado.descriptor.current_supply;
|
||||
}
|
||||
|
||||
size_t zc_inputs_count = 0;
|
||||
uint64_t bare_inputs_sum = additional_inputs_amount_and_fees_for_mining_tx + assets_emmited;
|
||||
uint64_t bare_inputs_sum = additional_inputs_amount_and_fees_for_mining_tx;
|
||||
for(auto& vin : tx.vin)
|
||||
{
|
||||
VARIANT_SWITCH_BEGIN(vin);
|
||||
|
|
@ -363,7 +414,7 @@ namespace currency
|
|||
VARIANT_SWITCH_END();
|
||||
}
|
||||
|
||||
crypto::point_t outs_commitments_sum = crypto::c_point_0;
|
||||
crypto::point_t outs_commitments_sum = crypto::c_point_0; // TODO: consider adding additional commitments / spends / burns here
|
||||
for(auto& vout : tx.vout)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(vout.type() == typeid(tx_out_zarcanum), false, "unexpected type in outs: " << vout.type().name());
|
||||
|
|
@ -378,8 +429,15 @@ namespace currency
|
|||
CHECK_AND_ASSERT_MES(additional_inputs_amount_and_fees_for_mining_tx == 0 || fee == 0, false, "invalid tx: fee = " << print_money_brief(fee) <<
|
||||
", additional inputs + fees = " << print_money_brief(additional_inputs_amount_and_fees_for_mining_tx));
|
||||
|
||||
size_t zc_sigs_count = 0;
|
||||
crypto::point_t sum_of_pseudo_out_amount_commitments = crypto::c_point_0;
|
||||
// take into account newly emitted assets
|
||||
asset_descriptor_operation ado = AUTO_VAL_INIT(ado);
|
||||
if (get_type_in_variant_container(tx.extra, ado) && ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) // @#@ TODO: Support other asset operations
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(ado.asset_id.size() == 1, false, "invalid size of ado.asset_id: " << ado.asset_id.size());
|
||||
sum_of_pseudo_out_amount_commitments += crypto::scalar_t(ado.descriptor.current_supply) * crypto::point_t(ado.asset_id.back()).modify_mul8();
|
||||
}
|
||||
size_t zc_sigs_count = 0;
|
||||
for(auto& sig_v : tx.signatures)
|
||||
{
|
||||
VARIANT_SWITCH_BEGIN(sig_v);
|
||||
|
|
@ -393,27 +451,22 @@ namespace currency
|
|||
}
|
||||
sum_of_pseudo_out_amount_commitments.modify_mul8();
|
||||
|
||||
CHECK_AND_ASSERT_MES(zc_inputs_count == zc_sigs_count, false, "zc inputs count (" << zc_inputs_count << ") and zc sigs count (" << zc_sigs_count << ") missmatch");
|
||||
// (sum(bare inputs' amounts) - fee) * H + sum(pseudo outs commitments for ZC inputs) - sum(outputs' commitments) = 0 OR = lin(G)
|
||||
crypto::point_t commitment_to_zero = (crypto::scalar_t(bare_inputs_sum) - crypto::scalar_t(fee)) * crypto::c_point_H + sum_of_pseudo_out_amount_commitments - outs_commitments_sum;
|
||||
|
||||
CHECK_AND_ASSERT_MES(zc_inputs_count == zc_sigs_count, false, "zc inputs count (" << zc_inputs_count << ") and zc sigs count (" << zc_sigs_count << ") missmatch");
|
||||
if (zc_inputs_count > 0)
|
||||
{
|
||||
// no need for additional Schnorr proof for commitment to zero
|
||||
|
||||
// sum(bare inputs' amounts) * H + sum(pseudo outs commitments for ZC inputs) = sum(outputs' commitments) + fee * H
|
||||
// <=>
|
||||
// (sum(bare inputs' amounts) - fee) * H + sum(pseudo outs commitments for ZC inputs) - sum(outputs' commitments) = 0
|
||||
crypto::point_t Z = (crypto::scalar_t(bare_inputs_sum) - crypto::scalar_t(fee)) * crypto::c_point_H + sum_of_pseudo_out_amount_commitments - outs_commitments_sum;
|
||||
CHECK_AND_ASSERT_MES(Z.is_zero(), false, "balace equation does not hold");
|
||||
// no need for additional proof for commitment to zero
|
||||
CHECK_AND_ASSERT_MES(commitment_to_zero.is_zero(), false, "balace equation does not hold");
|
||||
}
|
||||
else
|
||||
{
|
||||
// no zc inputs -- there should be Schnorr proof for commitment to zero
|
||||
// no zc inputs -- there should be an explicit proof structure (Schnorr proof), proving that:
|
||||
// (sum(bare inputs' amounts) - fee) * H + sum(pseudo outs commitments for ZC inputs) - sum(outputs' commitments) = residual_g * G
|
||||
zc_balance_proof balance_proof = AUTO_VAL_INIT(balance_proof);
|
||||
bool r = get_type_in_variant_container<zc_balance_proof>(tx.attachment, balance_proof);
|
||||
CHECK_AND_ASSERT_MES(r, false, "no zc inputs are present, but at the same time there's no zc_balance_proof in attachment");
|
||||
|
||||
// (fee - sum(bare inputs' amounts)) * H + sum(outputs' commitments) = residual * G
|
||||
crypto::point_t commitment_to_zero = (crypto::scalar_t(fee) - crypto::scalar_t(bare_inputs_sum)) * crypto::c_point_H + outs_commitments_sum;
|
||||
r = crypto::check_signature(null_hash, commitment_to_zero.to_public_key(), balance_proof.s);
|
||||
CHECK_AND_ASSERT_MES(r, false, "zc_balance_proof is invalid");
|
||||
}
|
||||
|
|
@ -809,6 +862,8 @@ namespace currency
|
|||
return derive_public_key_from_target_address(destination_addr, tx_sec_key, index, out_eph_public_key, derivation);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// derived_sec_key = Hs(domain, 8 * src_sec_key * src_pub_key, index)
|
||||
// derived_pub_key = derived_sec_key * G
|
||||
bool derive_key_pair_from_key_pair(const crypto::public_key& src_pub_key, const crypto::secret_key& src_sec_key, crypto::secret_key& derived_sec_key, crypto::public_key& derived_pub_key, const char(&hs_domain)[32], uint64_t index)
|
||||
{
|
||||
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
|
||||
|
|
@ -878,30 +933,25 @@ namespace currency
|
|||
return origin_blob;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, uint8_t tx_outs_attr)
|
||||
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, uint8_t tx_outs_attr /* = CURRENCY_TO_KEY_OUT_RELAXED */)
|
||||
{
|
||||
finalized_tx result = AUTO_VAL_INIT(result);
|
||||
crypto::scalar_t out_blinding_mask = AUTO_VAL_INIT(out_blinding_mask);
|
||||
return construct_tx_out(de, tx_sec_key, output_index, tx, deriv_cache, self, out_blinding_mask, result, tx_outs_attr);
|
||||
crypto::scalar_t asset_blinding_mask{}, amount_blinding_mask{};
|
||||
crypto::point_t blinded_asset_id{}, amount_commitment{};
|
||||
return construct_tx_out(de, tx_sec_key, output_index, tx, deriv_cache, self, asset_blinding_mask, amount_blinding_mask, blinded_asset_id, amount_commitment, result, tx_outs_attr);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache,
|
||||
const account_keys& self, crypto::scalar_t& out_blinding_mask, finalized_tx& result, uint8_t tx_outs_attr)
|
||||
const account_keys& self, crypto::scalar_t& asset_blinding_mask, crypto::scalar_t& amount_blinding_mask, crypto::point_t& blinded_asset_id, crypto::point_t& amount_commitment,
|
||||
finalized_tx& result, uint8_t tx_outs_attr)
|
||||
{
|
||||
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
|
||||
{
|
||||
// create tx_out_zarcanum
|
||||
CHECK_AND_ASSERT_MES(de.addr.size() == 1, false, "zarcanum multisig not implemented yet");
|
||||
CHECK_AND_ASSERT_MES(de.addr.size() == 1, false, "zarcanum multisig not implemented for tx_out_zarcanum yet");
|
||||
// TODO @#@# implement multisig support
|
||||
|
||||
tx_out_zarcanum out = AUTO_VAL_INIT(out);
|
||||
//@#@
|
||||
//TODO: TEMPORARY
|
||||
if (de.asset_id != currency::null_hash)
|
||||
{
|
||||
out.etc_details.push_back(open_asset_id{ de.asset_id });
|
||||
}
|
||||
//@#@
|
||||
|
||||
const account_public_address& apa = de.addr.front();
|
||||
if (apa.spend_public_key == null_pkey && apa.view_public_key == null_pkey)
|
||||
|
|
@ -916,9 +966,14 @@ namespace currency
|
|||
crypto::scalar_t amount_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_MASK, h);
|
||||
out.encrypted_amount = de.amount ^ amount_mask.m_u64[0];
|
||||
|
||||
out_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
|
||||
out.amount_commitment = (crypto::c_scalar_1div8 * de.amount * crypto::c_point_H + crypto::c_scalar_1div8 * out_blinding_mask * crypto::c_point_G).to_public_key(); // A = 1/8 * a * H + 1/8 * f * G
|
||||
asset_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_ASSET_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
|
||||
blinded_asset_id = crypto::point_t(de.asset_id) + asset_blinding_mask * crypto::c_point_X;
|
||||
out.blinded_asset_id = (crypto::c_scalar_1div8 * blinded_asset_id).to_public_key(); // T = 1/8 * (H_asset + s * X)
|
||||
|
||||
amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
|
||||
amount_commitment = de.amount * blinded_asset_id + amount_blinding_mask * crypto::c_point_G;
|
||||
out.amount_commitment = (crypto::c_scalar_1div8 * amount_commitment).to_public_key(); // E = 1/8 * e * T + 1/8 * y * G
|
||||
|
||||
out.mix_attr = tx_outs_attr; // TODO @#@# @CZ check this
|
||||
}
|
||||
else
|
||||
|
|
@ -934,8 +989,13 @@ namespace currency
|
|||
crypto::scalar_t amount_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_MASK, h);
|
||||
out.encrypted_amount = de.amount ^ amount_mask.m_u64[0];
|
||||
|
||||
out_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_BLINDING_MASK, h); // f = Hs(domain_sep, Hs(8 * r * V, i) )
|
||||
out.amount_commitment = (crypto::c_scalar_1div8 * de.amount * crypto::c_point_H + crypto::c_scalar_1div8 * out_blinding_mask * crypto::c_point_G).to_public_key(); // A = 1/8 * a * H + 1/8 * f * G
|
||||
asset_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_ASSET_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
|
||||
blinded_asset_id = crypto::point_t(de.asset_id) + asset_blinding_mask * crypto::c_point_X;
|
||||
out.blinded_asset_id = (crypto::c_scalar_1div8 * blinded_asset_id).to_public_key(); // T = 1/8 * (H_asset + s * X)
|
||||
|
||||
amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
|
||||
amount_commitment = de.amount * blinded_asset_id + amount_blinding_mask * crypto::c_point_G;
|
||||
out.amount_commitment = (crypto::c_scalar_1div8 * amount_commitment).to_public_key(); // E = 1/8 * e * T + 1/8 * y * G
|
||||
|
||||
if (de.addr.front().is_auditable())
|
||||
out.mix_attr = CURRENCY_TO_KEY_OUT_FORCED_NO_MIX; // override mix_attr to 1 for auditable target addresses
|
||||
|
|
@ -956,6 +1016,7 @@ namespace currency
|
|||
{
|
||||
// create tx_out_bare, this section can be removed after HF4
|
||||
CHECK_AND_ASSERT_MES(de.addr.size() == 1 || (de.addr.size() > 1 && de.minimum_sigs <= de.addr.size()), false, "Invalid destination entry: amount: " << de.amount << " minimum_sigs: " << de.minimum_sigs << " addr.size(): " << de.addr.size());
|
||||
CHECK_AND_ASSERT_MES(de.asset_id == currency::null_pkey, false, "assets are not allowed prior to HF4");
|
||||
|
||||
std::vector<crypto::public_key> target_keys;
|
||||
target_keys.reserve(de.addr.size());
|
||||
|
|
@ -1602,7 +1663,7 @@ namespace currency
|
|||
};
|
||||
//--------------------------------------------------------------------------------
|
||||
bool generate_ZC_sig(const crypto::hash& tx_hash_for_signature, size_t input_index, const tx_source_entry& se, const input_generation_context_data& in_context,
|
||||
const account_keys& sender_account_keys, const crypto::scalar_t& blinding_masks_sum, const uint64_t tx_flags, crypto::scalar_t& local_blinding_masks_sum, transaction& tx, bool last_output)
|
||||
const account_keys& sender_account_keys, const uint64_t tx_flags, outputs_generation_context& outs_gen_context, transaction& tx, bool last_output)
|
||||
{
|
||||
bool watch_only_mode = sender_account_keys.spend_secret_key == null_skey;
|
||||
CHECK_AND_ASSERT_MES(se.is_zarcanum(), false, "sources contains a non-zarcanum input");
|
||||
|
|
@ -1620,26 +1681,36 @@ namespace currency
|
|||
{
|
||||
crypto::point_t source_amount_commitment = crypto::c_scalar_1div8 * se.amount * crypto::c_point_H + crypto::c_scalar_1div8 * se.real_out_amount_blinding_mask * crypto::c_point_G;
|
||||
CHECK_AND_ASSERT_MES(in_context.outputs[in_context.real_out_index].amount_commitment == source_amount_commitment.to_public_key(), false, "real output amount commitment check failed");
|
||||
crypto::point_t source_blinded_asset_id = crypto::c_scalar_1div8 * crypto::point_t(se.asset_id) + crypto::c_scalar_1div8 * se.real_out_asset_id_blinding_mask * crypto::c_point_X;
|
||||
CHECK_AND_ASSERT_MES(in_context.outputs[in_context.real_out_index].blinded_asset_id == source_blinded_asset_id.to_public_key(), false, "real output blinded asset id check failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
crypto::scalar_t blinding_mask = 0;
|
||||
crypto::scalar_t amount_blinding_mask = 0;
|
||||
crypto::scalar_t asset_id_blinding_mask = 0;
|
||||
if ((last_output && (tx_flags & TX_FLAG_SIGNATURE_MODE_SEPARATE) == 0) || se.separately_signed_tx_complete)
|
||||
{
|
||||
// either normal tx or the last signature of consolidated tx -- in both cases we need to calculate non-random blinding mask for pseudo output commitment
|
||||
blinding_mask = blinding_masks_sum + local_blinding_masks_sum;
|
||||
amount_blinding_mask = outs_gen_context.amount_blinding_masks_sum + outs_gen_context.local_amount_blinding_masks_sum;
|
||||
asset_id_blinding_mask = outs_gen_context.asset_id_blinding_masks_sum + outs_gen_context.local_asset_id_blinding_masks_sum;
|
||||
// @#@ TODO additional check for the last iteration ?
|
||||
}
|
||||
else
|
||||
{
|
||||
blinding_mask.make_random();
|
||||
local_blinding_masks_sum -= blinding_mask; // pseudo out masks are taken into account with negative sign
|
||||
amount_blinding_mask.make_random();
|
||||
asset_id_blinding_mask.make_random();
|
||||
outs_gen_context.local_amount_blinding_masks_sum -= amount_blinding_mask; // pseudo out masks are taken into account with negative sign
|
||||
outs_gen_context.local_asset_id_blinding_masks_sum -= asset_id_blinding_mask; //
|
||||
}
|
||||
|
||||
crypto::point_t pseudo_out_amount_commitment = se.amount * crypto::c_point_H + blinding_mask * crypto::c_point_G;
|
||||
crypto::point_t pseudo_out_amount_commitment = se.amount * crypto::c_point_H + amount_blinding_mask * crypto::c_point_G;
|
||||
sig.pseudo_out_amount_commitment = (crypto::c_scalar_1div8 * pseudo_out_amount_commitment).to_public_key();
|
||||
|
||||
// = two-layers ring signature data outline =
|
||||
|
||||
crypto::point_t pseudo_out_blinded_asset_id = crypto::point_t(se.asset_id) + asset_id_blinding_mask * crypto::c_point_X;
|
||||
sig.pseudo_out_blinded_asset_id = (crypto::c_scalar_1div8 * pseudo_out_blinded_asset_id).to_public_key();
|
||||
|
||||
// = three-layers ring signature data outline =
|
||||
// (j in [0, ring_size-1])
|
||||
// layer 0 ring
|
||||
// se.outputs[j].stealth_address;
|
||||
|
|
@ -1651,13 +1722,20 @@ namespace currency
|
|||
// layer 1 ring
|
||||
// crypto::point_t(se.outputs[j].amount_commitment) - pseudo_out_amount_commitment;
|
||||
// layer 1 secret (with respect to G)
|
||||
// se.real_out_amount_blinding_mask - blinding_mask;
|
||||
// se.real_out_amount_blinding_mask - amount_blinding_mask;
|
||||
//
|
||||
// layer 2 ring
|
||||
// crypto::point_t(se.outputs[j].blinded_asset_id) - pseudo_out_asset_id;
|
||||
// layer 2 secret (with respect to X)
|
||||
// se.real_out_asset_id_blinding_mask - asset_id_blinding_mask;
|
||||
|
||||
std::vector<crypto::CLSAG_GG_input_ref_t> ring;
|
||||
std::vector<crypto::CLSAG_GGX_input_ref_t> ring;
|
||||
for(size_t j = 0; j < in_context.outputs.size(); ++j)
|
||||
ring.emplace_back(in_context.outputs[j].stealth_address, in_context.outputs[j].amount_commitment);
|
||||
ring.emplace_back(in_context.outputs[j].stealth_address, in_context.outputs[j].amount_commitment, in_context.outputs[j].blinded_asset_id);
|
||||
|
||||
return crypto::generate_CLSAG_GG(tx_hash_for_signature, ring, pseudo_out_amount_commitment, in.k_image, in_context.in_ephemeral.sec, se.real_out_amount_blinding_mask - blinding_mask, in_context.real_out_index, sig.clsags_gg);
|
||||
return crypto::generate_CLSAG_GGX(tx_hash_for_signature, ring, pseudo_out_amount_commitment, pseudo_out_blinded_asset_id, in.k_image, in_context.in_ephemeral.sec,
|
||||
se.real_out_amount_blinding_mask - amount_blinding_mask,
|
||||
se.real_out_asset_id_blinding_mask - asset_id_blinding_mask, in_context.real_out_index, sig.clsags_ggx);
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool generate_NLSAG_sig(const crypto::hash& tx_hash_for_signature, const crypto::hash& tx_prefix_hash, size_t input_index, const tx_source_entry& src_entr,
|
||||
|
|
@ -1714,10 +1792,21 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
crypto::hash get_asset_id_from_descriptor(const asset_descriptor_base& adb)
|
||||
#define CRYPTO_HASH_ASSET_ID_ITERATIONS 1024
|
||||
void calculate_asset_id(const crypto::public_key& asset_owner, crypto::point_t* p_result_point, crypto::public_key* p_result_pub_key)
|
||||
{
|
||||
return get_hash_from_POD_objects(CRYPTO_HDS_ASSET_ID, adb.owner);
|
||||
crypto::hash h = get_hash_from_POD_objects(CRYPTO_HDS_ASSET_ID, asset_owner);
|
||||
|
||||
// this hash function needs to be computationally expensive (s.e. the whitepaper)
|
||||
for(uint64_t i = 0; i < CRYPTO_HASH_ASSET_ID_ITERATIONS; ++i)
|
||||
h = get_hash_from_POD_objects(CRYPTO_HDS_ASSET_ID, h, i);
|
||||
|
||||
crypto::point_t local_point{};
|
||||
if (!p_result_point)
|
||||
p_result_point = &local_point;
|
||||
*p_result_point = crypto::hash_helper_t::hp(&h, sizeof h);
|
||||
if (p_result_pub_key)
|
||||
p_result_point->to_public_key(*p_result_pub_key);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1803,20 +1892,21 @@ namespace currency
|
|||
}
|
||||
|
||||
|
||||
uint64_t summary_inputs_money = 0;
|
||||
uint64_t native_coins_input_sum = 0;
|
||||
|
||||
crypto::hash asset_id_for_destinations = currency::null_hash;
|
||||
crypto::public_key asset_id_for_asset_operation = currency::null_pkey;
|
||||
asset_descriptor_operation* pado = nullptr;
|
||||
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
|
||||
{
|
||||
pado = get_type_in_variant_container<asset_descriptor_operation>(tx.extra);
|
||||
if (pado)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(pado->operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER, false, "unsupported asset operation");
|
||||
crypto::secret_key stub = AUTO_VAL_INIT(stub);
|
||||
bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, one_time_secret_key, stub, pado->descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to derive_public_key_from_tx_and_account_pub_key()");
|
||||
//also assign this asset id to destinations
|
||||
asset_id_for_destinations = get_asset_id_from_descriptor(pado->descriptor);
|
||||
calculate_asset_id(pado->descriptor.owner, nullptr, &asset_id_for_asset_operation);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1843,7 +1933,7 @@ namespace currency
|
|||
if(src_entr.is_multisig())
|
||||
{//multisig input
|
||||
txin_multisig input_multisig = AUTO_VAL_INIT(input_multisig);
|
||||
summary_inputs_money += input_multisig.amount = src_entr.amount;
|
||||
input_multisig.amount = src_entr.amount;
|
||||
input_multisig.multisig_out_id = src_entr.multisig_id;
|
||||
input_multisig.sigs_count = src_entr.ms_sigs_count;
|
||||
tx.vin.push_back(input_multisig);
|
||||
|
|
@ -1858,7 +1948,6 @@ namespace currency
|
|||
LOG_ERROR("htlc in: wrong output src_entr.outputs.size() = " << src_entr.outputs.size());
|
||||
return false;
|
||||
}
|
||||
summary_inputs_money += src_entr.amount;
|
||||
|
||||
//key_derivation recv_derivation;
|
||||
crypto::key_image img;
|
||||
|
|
@ -1889,8 +1978,6 @@ namespace currency
|
|||
CHECK_AND_ASSERT_MES(in_context.real_out_index < in_context.outputs.size(), false,
|
||||
"real_output index (" << in_context.real_out_index << ") greater than or equal to in_context.outputs.size()=" << in_context.outputs.size());
|
||||
|
||||
summary_inputs_money += src_entr.amount;
|
||||
|
||||
//key_derivation recv_derivation;
|
||||
crypto::key_image img;
|
||||
if (!generate_key_image_helper(sender_account_keys, src_entr.real_out_tx_key, src_entr.real_output_in_tx_index, in_context.in_ephemeral, img))
|
||||
|
|
@ -1918,13 +2005,7 @@ namespace currency
|
|||
txin_zc_input zc_in = AUTO_VAL_INIT(zc_in);
|
||||
zc_in.k_image = img;
|
||||
zc_in.key_offsets = std::move(key_offsets);
|
||||
//TEMPORARY
|
||||
if (src_entr.asset_id != currency::null_hash)
|
||||
{
|
||||
zc_in.etc_details.push_back(open_asset_id{ src_entr.asset_id });
|
||||
}
|
||||
tx.vin.push_back(zc_in);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1935,25 +2016,26 @@ namespace currency
|
|||
tx.vin.push_back(input_to_key);
|
||||
}
|
||||
}
|
||||
|
||||
if (src_entr.is_native_coin())
|
||||
native_coins_input_sum += src_entr.amount;
|
||||
}
|
||||
|
||||
uint64_t amount_of_assets = 0;
|
||||
uint64_t amount_of_emitted_asset = 0;
|
||||
std::vector<tx_destination_entry> shuffled_dsts(destinations);
|
||||
if (asset_id_for_destinations != currency::null_hash)
|
||||
if (asset_id_for_asset_operation != currency::null_pkey)
|
||||
{
|
||||
//must be asset publication
|
||||
for (auto& item : shuffled_dsts)
|
||||
{
|
||||
if (item.asset_id == currency::ffff_hash)
|
||||
if (item.asset_id == currency::ffff_pkey)
|
||||
{
|
||||
item.asset_id = asset_id_for_destinations;
|
||||
amount_of_assets += item.amount;
|
||||
item.asset_id = asset_id_for_asset_operation;
|
||||
amount_of_emitted_asset += item.amount;
|
||||
}
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(pado, false, "pado is null ??");
|
||||
pado->descriptor.current_supply = amount_of_assets;
|
||||
//TODO: temporary
|
||||
summary_inputs_money += amount_of_assets;
|
||||
pado->descriptor.current_supply = amount_of_emitted_asset; // TODO: consider setting current_supply beforehand, not setting it hear in ad-hoc manner -- sowle
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1964,35 +2046,37 @@ namespace currency
|
|||
|
||||
// TODO: consider "Shuffle" inputs
|
||||
|
||||
uint64_t summary_outs_money = 0;
|
||||
//fill outputs
|
||||
// construct outputs
|
||||
uint64_t native_coins_output_sum = 0;
|
||||
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 outputs_to_be_constructed = shuffled_dsts.size();
|
||||
outputs_generation_context outs_gen_context(outputs_to_be_constructed); // auxiliary data for each output
|
||||
uint64_t range_proof_start_index = output_index;
|
||||
std::set<uint16_t> deriv_cache;
|
||||
crypto::scalar_vec_t blinding_masks(tx.vout.size() + destinations.size()); // vector of secret blinging masks for each output. For range proof generation
|
||||
crypto::scalar_vec_t amounts(tx.vout.size() + destinations.size()); // vector of amounts, converted to scalars. For ranage proof generation
|
||||
crypto::scalar_t blinding_masks_sum = 0;
|
||||
for(const tx_destination_entry& dst_entr : shuffled_dsts)
|
||||
for(size_t j = 0; j < outputs_to_be_constructed; ++j, ++output_index)
|
||||
{
|
||||
const tx_destination_entry& dst_entr = shuffled_dsts[j];
|
||||
CHECK_AND_ASSERT_MES(dst_entr.amount > 0, false, "Destination with wrong amount: " << dst_entr.amount); // <<-- TODO @#@# consider removing this check
|
||||
r = construct_tx_out(dst_entr, txkey.sec, output_index, tx, deriv_cache, sender_account_keys, blinding_masks[output_index], result, tx_outs_attr);
|
||||
r = construct_tx_out(dst_entr, txkey.sec, output_index, tx, deriv_cache, sender_account_keys,
|
||||
outs_gen_context.asset_id_blinding_masks[j], outs_gen_context.amount_blinding_masks[j],
|
||||
outs_gen_context.blinded_asset_ids[j], outs_gen_context.amount_commitments[j], result, tx_outs_attr);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to construct tx out");
|
||||
amounts[output_index - range_proof_start_index] = dst_entr.amount;
|
||||
summary_outs_money += dst_entr.amount;
|
||||
blinding_masks_sum += blinding_masks[output_index];
|
||||
output_index++;
|
||||
outs_gen_context.amounts[j] = dst_entr.amount;
|
||||
outs_gen_context.asset_id_blinding_masks_sum += outs_gen_context.asset_id_blinding_masks[j];
|
||||
outs_gen_context.amount_blinding_masks_sum += outs_gen_context.amount_blinding_masks[j];
|
||||
if (dst_entr.is_native_coin())
|
||||
native_coins_output_sum += dst_entr.amount;
|
||||
}
|
||||
|
||||
//check money
|
||||
if (!(flags&TX_FLAG_SIGNATURE_MODE_SEPARATE))
|
||||
{
|
||||
if (summary_outs_money > summary_inputs_money)
|
||||
{
|
||||
LOG_ERROR("Transaction inputs money (" << print_money_brief(summary_inputs_money) << ") is less than outputs money (" << print_money_brief(summary_outs_money) << ")");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//if (!(flags&TX_FLAG_SIGNATURE_MODE_SEPARATE))
|
||||
//{
|
||||
// if (summary_outs_money > summary_inputs_money)
|
||||
// {
|
||||
// LOG_ERROR("Transaction inputs money (" << print_money_brief(summary_inputs_money) << ") is less than outputs money (" << print_money_brief(summary_outs_money) << ")");
|
||||
// return false;
|
||||
// }
|
||||
//}
|
||||
|
||||
//process offers and put there offers derived keys
|
||||
uint64_t att_count = 0;
|
||||
|
|
@ -2026,19 +2110,25 @@ namespace currency
|
|||
|
||||
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
|
||||
{
|
||||
// asset surjeciton proof
|
||||
currency::zc_asset_surjection_proof asp{};
|
||||
bool r = generate_asset_surjection_proof(asp);
|
||||
CHECK_AND_ASSERT_MES(r, false, "generete_asset_surjection_proof failed");
|
||||
tx.attachment.push_back(asp);
|
||||
|
||||
// add range proofs
|
||||
currency::zc_outs_range_proof range_proofs = AUTO_VAL_INIT(range_proofs);
|
||||
bool r = generate_zc_outs_range_proof(range_proof_start_index, amounts.size(), amounts, blinding_masks, tx.vout, range_proofs);
|
||||
r = generate_zc_outs_range_proof(range_proof_start_index, outputs_to_be_constructed, outs_gen_context, tx.vout, range_proofs);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to generate zc_outs_range_proof()");
|
||||
tx.attachment.push_back(range_proofs);
|
||||
|
||||
// add explicit fee info
|
||||
r = add_tx_fee_amount_to_extra(tx, summary_inputs_money - summary_outs_money);
|
||||
r = add_tx_fee_amount_to_extra(tx, native_coins_input_sum - native_coins_output_sum);
|
||||
CHECK_AND_ASSERT_MES(r, false, "add_tx_fee_amount_to_extra failed");
|
||||
|
||||
if (!has_zc_inputs)
|
||||
{
|
||||
r = generate_tx_balance_proof(tx, blinding_masks_sum, amount_of_assets);
|
||||
r = generate_tx_balance_proof(tx, outs_gen_context);
|
||||
CHECK_AND_ASSERT_MES(r, false, "generate_tx_balance_proof failed");
|
||||
}
|
||||
}
|
||||
|
|
@ -2071,7 +2161,6 @@ namespace currency
|
|||
get_transaction_prefix_hash(tx, tx_prefix_hash);
|
||||
//size_t input_index = input_starter_index;
|
||||
//size_t in_context_index = 0;
|
||||
crypto::scalar_t local_blinding_masks_sum = 0; // ZC only
|
||||
r = false;
|
||||
for (size_t i_ = 0; i_ != sources.size(); i_++)
|
||||
{
|
||||
|
|
@ -2086,8 +2175,7 @@ namespace currency
|
|||
{
|
||||
// ZC
|
||||
// blinding_masks_sum is supposed to be sum(mask of all tx output) - sum(masks of all pseudo out commitments)
|
||||
r = generate_ZC_sig(tx_hash_for_signature, i_ + input_starter_index, source_entry, in_contexts[i_mapped], sender_account_keys, blinding_masks_sum, flags,
|
||||
local_blinding_masks_sum, tx, i_ + 1 == sources.size());
|
||||
r = generate_ZC_sig(tx_hash_for_signature, i_ + input_starter_index, source_entry, in_contexts[i_mapped], sender_account_keys, flags, outs_gen_context, tx, i_ + 1 == sources.size());
|
||||
CHECK_AND_ASSERT_MES(r, false, "generate_ZC_sigs failed");
|
||||
}
|
||||
else
|
||||
|
|
@ -2490,7 +2578,8 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
|
||||
bool is_out_to_acc(const account_public_address& addr, const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, size_t output_index, uint64_t& decoded_amount, crypto::scalar_t& blinding_mask)
|
||||
bool is_out_to_acc(const account_public_address& addr, const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, size_t output_index, uint64_t& decoded_amount,
|
||||
crypto::scalar_t& amount_blinding_mask, crypto::scalar_t& asset_id_blinding_mask)
|
||||
{
|
||||
crypto::scalar_t h; // = crypto::hash_helper_t::hs(reinterpret_cast<const crypto::public_key&>(derivation), output_index); // h = Hs(8 * r * V, i)
|
||||
crypto::derivation_to_scalar(derivation, output_index, h.as_secret_key()); // h = Hs(8 * r * V, i)
|
||||
|
|
@ -2506,13 +2595,18 @@ namespace currency
|
|||
crypto::scalar_t amount_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_MASK, h);
|
||||
decoded_amount = zo.encrypted_amount ^ amount_mask.m_u64[0];
|
||||
|
||||
blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_BLINDING_MASK, h); // f = Hs(domain_sep, h)
|
||||
amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_BLINDING_MASK, h); // f = Hs(domain_sep, h)
|
||||
|
||||
crypto::point_t A_prime;
|
||||
A_prime.assign_mul_plus_G(decoded_amount, crypto::c_point_H, blinding_mask); // A' * 8 =? a * H + f * G
|
||||
crypto::point_t blinded_asset_id = crypto::point_t(zo.blinded_asset_id).modify_mul8();
|
||||
crypto::point_t A_prime = decoded_amount * blinded_asset_id + amount_blinding_mask * crypto::c_point_G; // A' * 8 =? a * T + f * G
|
||||
if (A_prime != crypto::point_t(zo.amount_commitment).modify_mul8())
|
||||
return false;
|
||||
|
||||
asset_id_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_ASSET_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
|
||||
|
||||
// crypto::point_t asset_id = blinded_asset_id - asset_id_blinding_mask * crypto::c_point_X; // H = T - s * X
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2631,15 +2725,11 @@ namespace currency
|
|||
}
|
||||
VARIANT_CASE_CONST(tx_out_zarcanum, zo)
|
||||
uint64_t amount = 0;
|
||||
crypto::scalar_t blinding_mask = 0;
|
||||
if (is_out_to_acc(acc.account_address, zo, derivation, output_index, amount, blinding_mask))
|
||||
crypto::scalar_t amount_blinding_mask = 0, asset_id_blinding_mask = 0;
|
||||
if (is_out_to_acc(acc.account_address, zo, derivation, output_index, amount, amount_blinding_mask, asset_id_blinding_mask))
|
||||
{
|
||||
outs.emplace_back(output_index, amount, blinding_mask);
|
||||
open_asset_id v = AUTO_VAL_INIT(v);
|
||||
if (get_type_in_variant_container(zo.etc_details, v))
|
||||
{
|
||||
outs.back().asset_id = v.asset_id;
|
||||
}
|
||||
crypto::point_t asset_id_pt = crypto::point_t(zo.blinded_asset_id) - asset_id_blinding_mask * crypto::c_point_X;
|
||||
outs.emplace_back(output_index, amount, amount_blinding_mask, asset_id_blinding_mask, asset_id_pt.to_public_key());
|
||||
money_transfered += amount;
|
||||
}
|
||||
VARIANT_SWITCH_END();
|
||||
|
|
@ -3379,7 +3469,8 @@ namespace currency
|
|||
bool operator()(const zc_outs_range_proof& rp)
|
||||
{
|
||||
tv.type = "zc_outs_range_proof";
|
||||
tv.short_view = "outputs_count = " + std::to_string(rp.outputs_count);
|
||||
// TODO @#@#
|
||||
//tv.short_view = "outputs_count = " + std::to_string(rp.outputs_count);
|
||||
return true;
|
||||
}
|
||||
bool operator()(const zc_balance_proof& bp)
|
||||
|
|
|
|||
|
|
@ -205,16 +205,19 @@ namespace currency
|
|||
: index(index)
|
||||
, amount(amount)
|
||||
{}
|
||||
wallet_out_info(size_t index, uint64_t amount, const crypto::scalar_t& blinding_mask)
|
||||
wallet_out_info(size_t index, uint64_t amount, const crypto::scalar_t& amount_blinding_mask, const crypto::scalar_t& asset_id_blinding_mask, const crypto::public_key& asset_id)
|
||||
: index(index)
|
||||
, amount(amount)
|
||||
, blinding_mask(blinding_mask)
|
||||
, amount_blinding_mask(amount_blinding_mask)
|
||||
, asset_id_blinding_mask(asset_id_blinding_mask)
|
||||
, asset_id(asset_id)
|
||||
{}
|
||||
|
||||
size_t index = SIZE_MAX;
|
||||
uint64_t amount = 0;
|
||||
crypto::scalar_t blinding_mask = 0;
|
||||
crypto::hash asset_id = currency::null_hash;
|
||||
size_t index = SIZE_MAX;
|
||||
uint64_t amount = 0;
|
||||
crypto::scalar_t amount_blinding_mask = 0;
|
||||
crypto::scalar_t asset_id_blinding_mask = 0;
|
||||
crypto::public_key asset_id = currency::native_coin_asset_id; // use point_t instead as this is for internal use only?
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -249,8 +252,9 @@ namespace currency
|
|||
const keypair* tx_one_time_key_to_use = nullptr);
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_string_uint64_hash(const std::string& str);
|
||||
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, crypto::scalar_t& out_blinding_mask, finalized_tx& result, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
|
||||
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, crypto::scalar_t& asset_blinding_mask, crypto::scalar_t& amount_blinding_mask, crypto::point_t& blinded_asset_id, crypto::point_t& amount_commitment, finalized_tx& result, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
|
||||
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
|
||||
|
||||
bool validate_alias_name(const std::string& al);
|
||||
bool validate_password(const std::string& password);
|
||||
void get_attachment_extra_info_details(const std::vector<attachment_v>& attachment, extra_attachment_info& eai);
|
||||
|
|
@ -293,7 +297,8 @@ namespace currency
|
|||
|
||||
uint64_t get_tx_version(uint64_t tx_expected_block_height, const hard_forks_descriptor& hfd); // returns tx version based on the height of the block where the transaction is expected to be
|
||||
bool construct_tx(const account_keys& sender_account_keys, const finalize_tx_param& param, finalized_tx& result);
|
||||
crypto::hash get_asset_id_from_descriptor(const asset_descriptor_base& adb);
|
||||
void calculate_asset_id(const crypto::public_key& asset_owner, crypto::point_t* p_result_point, crypto::public_key* p_result_pub_key);
|
||||
|
||||
|
||||
|
||||
bool sign_multisig_input_in_tx(currency::transaction& tx, size_t ms_input_index, const currency::account_keys& keys, const currency::transaction& source_tx, bool *p_is_input_fully_signed = nullptr);
|
||||
|
|
@ -311,7 +316,7 @@ namespace currency
|
|||
crypto::hash get_multisig_out_id(const transaction& tx, size_t n);
|
||||
bool is_out_to_acc(const account_public_address& addr, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index);
|
||||
bool is_out_to_acc(const account_public_address& addr, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index);
|
||||
bool is_out_to_acc(const account_public_address& addr, const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, size_t output_index, uint64_t& decoded_amount, crypto::scalar_t& blinding_mask);
|
||||
bool is_out_to_acc(const account_public_address& addr, const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, size_t output_index, uint64_t& decoded_amount, crypto::scalar_t& amount_blinding_mask, crypto::scalar_t& asset_id_blinding_mask);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<wallet_out_info>& outs, uint64_t& money_transfered, crypto::key_derivation& derivation);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<wallet_out_info>& outs, uint64_t& money_transfered, crypto::key_derivation& derivation, std::list<htlc_info>& htlc_info_list);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<wallet_out_info>& outs, uint64_t& money_transfered, crypto::key_derivation& derivation);
|
||||
|
|
|
|||
|
|
@ -22,13 +22,14 @@ namespace currency
|
|||
output_entry(const output_entry &) = default;
|
||||
output_entry(const txout_ref_v& out_reference, const crypto::public_key& stealth_address)
|
||||
: out_reference(out_reference), stealth_address(stealth_address), concealing_point(null_pkey), amount_commitment(null_pkey) {}
|
||||
output_entry(const txout_ref_v& out_reference, const crypto::public_key& stealth_address, const crypto::public_key& concealing_point, const crypto::public_key& amount_commitment)
|
||||
: out_reference(out_reference), stealth_address(stealth_address), concealing_point(concealing_point), amount_commitment(amount_commitment) {}
|
||||
output_entry(const txout_ref_v& out_reference, const crypto::public_key& stealth_address, const crypto::public_key& concealing_point, const crypto::public_key& amount_commitment, const crypto::public_key& blinded_asset_id)
|
||||
: out_reference(out_reference), stealth_address(stealth_address), concealing_point(concealing_point), amount_commitment(amount_commitment), blinded_asset_id(blinded_asset_id) {}
|
||||
|
||||
txout_ref_v out_reference; // either global output index or ref_by_id
|
||||
crypto::public_key stealth_address; // a.k.a output's one-time public key
|
||||
crypto::public_key concealing_point; // only for zarcaum outputs
|
||||
crypto::public_key amount_commitment; // only for zarcaum outputs
|
||||
crypto::public_key concealing_point; // only for ZC outputs
|
||||
crypto::public_key amount_commitment; // only for ZC outputs
|
||||
crypto::public_key blinded_asset_id; // only for ZC outputs
|
||||
|
||||
bool operator==(const output_entry& rhs) const { return out_reference == rhs.out_reference; } // used in prepare_outputs_entries_for_key_offsets, it's okay to do partially comparison
|
||||
|
||||
|
|
@ -37,6 +38,7 @@ namespace currency
|
|||
FIELD(stealth_address)
|
||||
FIELD(concealing_point)
|
||||
FIELD(amount_commitment)
|
||||
FIELD(blinded_asset_id)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
|
@ -45,7 +47,8 @@ namespace currency
|
|||
std::vector<output_entry> outputs;
|
||||
uint64_t real_output = 0; //index in outputs vector of real output_entry
|
||||
crypto::public_key real_out_tx_key = currency::null_pkey; //real output's transaction's public key
|
||||
crypto::scalar_t real_out_amount_blinding_mask; //blinding mask of real out's amount committment (only for zarcanum inputs, otherwise must be 0)
|
||||
crypto::scalar_t real_out_amount_blinding_mask = 0; //blinding mask of real out's amount committment (only for ZC inputs, otherwise must be 0)
|
||||
crypto::scalar_t real_out_asset_id_blinding_mask = 0; //blinding mask of real out's asset_od (only for ZC inputs, otherwise must be 0)
|
||||
size_t real_output_in_tx_index = 0; //index in transaction outputs vector
|
||||
uint64_t amount = 0; //money
|
||||
uint64_t transfer_index = 0; //index in m_transfers
|
||||
|
|
@ -54,16 +57,18 @@ namespace currency
|
|||
size_t ms_keys_count = 0; //if txin_multisig: must be equal to size of output's keys container
|
||||
bool separately_signed_tx_complete = false; //for separately signed tx only: denotes the last source entry in complete tx to explicitly mark the final step of tx creation
|
||||
std::string htlc_origin; //for htlc, specify origin
|
||||
crypto::hash asset_id = currency::null_hash; //asset id
|
||||
crypto::public_key asset_id = currency::native_coin_asset_id; //asset id (not blinded, not premultiplied by 1/8) TODO @#@# consider changing to crypto::point_t
|
||||
|
||||
bool is_multisig() const { return ms_sigs_count > 0; }
|
||||
bool is_zarcanum() const { return !real_out_amount_blinding_mask.is_zero(); }
|
||||
bool is_multisig() const { return ms_sigs_count > 0; }
|
||||
bool is_zarcanum() const { return !real_out_amount_blinding_mask.is_zero(); }
|
||||
bool is_native_coin() const { return asset_id == currency::native_coin_asset_id; }
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(outputs)
|
||||
FIELD(real_output)
|
||||
FIELD(real_out_tx_key)
|
||||
FIELD(real_out_amount_blinding_mask)
|
||||
FIELD(real_out_asset_id_blinding_mask)
|
||||
FIELD(real_output_in_tx_index)
|
||||
FIELD(amount)
|
||||
FIELD(transfer_index)
|
||||
|
|
@ -91,21 +96,23 @@ namespace currency
|
|||
|
||||
struct tx_destination_entry
|
||||
{
|
||||
uint64_t amount = 0; //money
|
||||
std::list<account_public_address> addr; //destination address, in case of 1 address - txout_to_key, in case of more - txout_multisig
|
||||
size_t minimum_sigs = 0; //if txout_multisig: minimum signatures that are required to spend this output (minimum_sigs <= addr.size()) IF txout_to_key - not used
|
||||
uint64_t amount_to_provide = 0; //amount money that provided by initial creator of tx, used with partially created transactions
|
||||
uint64_t amount = 0; // money
|
||||
std::list<account_public_address> addr; // destination address, in case of 1 address - txout_to_key, in case of more - txout_multisig
|
||||
size_t minimum_sigs = 0; // if txout_multisig: minimum signatures that are required to spend this output (minimum_sigs <= addr.size()) IF txout_to_key - not used
|
||||
uint64_t amount_to_provide = 0; // amount money that provided by initial creator of tx, used with partially created transactions
|
||||
uint64_t unlock_time = 0;
|
||||
destination_option_htlc_out htlc_options; //htlc options
|
||||
crypto::hash asset_id = currency::null_hash;
|
||||
destination_option_htlc_out htlc_options; // htlc options
|
||||
crypto::public_key asset_id = currency::native_coin_asset_id;
|
||||
|
||||
|
||||
tx_destination_entry() = default;
|
||||
tx_destination_entry(uint64_t a, const account_public_address& ad) : amount(a), addr(1, ad) {}
|
||||
tx_destination_entry(uint64_t a, const account_public_address& ad, const crypto::hash& aid) : amount(a), addr(1, ad), asset_id(aid) {}
|
||||
tx_destination_entry(uint64_t a, const account_public_address& ad, const crypto::public_key& aid) : amount(a), addr(1, ad), asset_id(aid) {}
|
||||
tx_destination_entry(uint64_t a, const account_public_address& ad, uint64_t ut) : amount(a), addr(1, ad), unlock_time(ut) {}
|
||||
tx_destination_entry(uint64_t a, const std::list<account_public_address>& addr) : amount(a), addr(addr), minimum_sigs(addr.size()){}
|
||||
tx_destination_entry(uint64_t a, const std::list<account_public_address>& addr, const crypto::hash& aid) : amount(a), addr(addr), minimum_sigs(addr.size()), asset_id(aid) {}
|
||||
tx_destination_entry(uint64_t a, const std::list<account_public_address>& addr, const crypto::public_key& aid) : amount(a), addr(addr), minimum_sigs(addr.size()), asset_id(aid) {}
|
||||
|
||||
bool is_native_coin() const { return asset_id == currency::native_coin_asset_id; }
|
||||
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ namespace currency
|
|||
|
||||
struct asset_id_kv
|
||||
{
|
||||
crypto::hash asset_id;
|
||||
crypto::public_key asset_id;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(asset_id)
|
||||
|
|
@ -359,16 +359,17 @@ namespace currency
|
|||
struct out_entry
|
||||
{
|
||||
out_entry() = default;
|
||||
out_entry(uint64_t global_amount_index, const crypto::public_key& stealth_address, const crypto::public_key& amount_commitment, const crypto::public_key& concealing_point)
|
||||
: global_amount_index(global_amount_index), stealth_address(stealth_address), amount_commitment(amount_commitment), concealing_point(concealing_point)
|
||||
{}
|
||||
out_entry(uint64_t global_amount_index, const crypto::public_key& stealth_address)
|
||||
: global_amount_index(global_amount_index), stealth_address(stealth_address), amount_commitment{}, concealing_point{}
|
||||
: global_amount_index(global_amount_index), stealth_address(stealth_address), concealing_point{}, amount_commitment{}, blinded_asset_id{}
|
||||
{}
|
||||
out_entry(uint64_t global_amount_index, const crypto::public_key& stealth_address, const crypto::public_key& amount_commitment, const crypto::public_key& concealing_point, const crypto::public_key& blinded_asset_id)
|
||||
: global_amount_index(global_amount_index), stealth_address(stealth_address), concealing_point(concealing_point), amount_commitment(amount_commitment), blinded_asset_id(blinded_asset_id)
|
||||
{}
|
||||
uint64_t global_amount_index;
|
||||
crypto::public_key stealth_address;
|
||||
crypto::public_key concealing_point;
|
||||
crypto::public_key amount_commitment;
|
||||
crypto::public_key concealing_point; // premultiplied by 1/8
|
||||
crypto::public_key amount_commitment; // premultiplied by 1/8
|
||||
crypto::public_key blinded_asset_id; // premultiplied by 1/8
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue