diff --git a/src/crypto/zarcanum.cpp b/src/crypto/zarcanum.cpp index 9056fda5..43f1620d 100644 --- a/src/crypto/zarcanum.cpp +++ b/src/crypto/zarcanum.cpp @@ -46,7 +46,7 @@ namespace crypto if (!(cond)) { LOG_PRINT_RED("zarcanum_generate_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \ if (p_err) { *p_err = err_code; } return false; } - bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector& ring, const point_t& pseudo_out_amount_commitment, + bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector& ring, const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki, 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 */) @@ -144,6 +144,7 @@ namespace crypto // layer 3 secret (with respect to G) // secret_q + point_t pseudo_out_amount_commitment = a * crypto::c_point_H + pseudo_out_blinding_mask * crypto::c_point_G; result.pseudo_out_amount_commitment = (crypto::c_scalar_1div8 * pseudo_out_amount_commitment).to_public_key(); TRY_ENTRY() diff --git a/src/crypto/zarcanum.h b/src/crypto/zarcanum.h index b8471bc3..86a85fce 100644 --- a/src/crypto/zarcanum.h +++ b/src/crypto/zarcanum.h @@ -44,7 +44,7 @@ namespace crypto CLSAG_GGXG_signature clsag_ggxg; }; - bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector& ring, const point_t& pseudo_out_amount_commitment, + bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector& ring, const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki, 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); diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 1b7b4534..f9e0116b 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -2114,37 +2114,13 @@ namespace currency } 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); - - //input_index++; - //in_context_index++; } - /* - for(const tx_source_entry& source_entry : 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, "prepare_prefix_hash_for_sign failed"); - std::stringstream ss_ring_s; - if (source_entry.is_zarcanum()) - { - // 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, input_index, source_entry, in_contexts[in_context_index], sender_account_keys, blinding_masks_sum, flags, local_blinding_masks_sum, tx); - CHECK_AND_ASSERT_MES(r, false, "generate_ZC_sigs failed"); - } - else - { - // NLSAG - r = generate_NLSAG_sig(tx_hash_for_signature, tx_prefix_hash, input_index, source_entry, sender_account_keys, in_contexts[in_context_index], txkey, flags, tx, &ss_ring_s); - CHECK_AND_ASSERT_MES(r, false, "generate_NLSAG_sig failed"); - } + //size_t prefix_size = get_object_blobsize(static_cast(tx)); + //size_t full_blob_size = t_serializable_object_to_blob(tx).size(); + //size_t estimated_blob_size = get_object_blobsize(tx); + //CHECK_AND_ASSERT_MES(full_blob_size == estimated_blob_size, false, "!"); - 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); - - input_index++; - in_context_index++; - } - */ return true; } diff --git a/src/currency_core/pos_mining.h b/src/currency_core/pos_mining.h index 15c43314..988eaf57 100644 --- a/src/currency_core/pos_mining.h +++ b/src/currency_core/pos_mining.h @@ -9,18 +9,17 @@ namespace currency struct pos_mining_context { - wide_difficulty_type basic_diff; + // Zarcanum notation: + wide_difficulty_type basic_diff; // D stake_kernel sk; + crypto::scalar_t last_pow_block_id_hashed; // f' + crypto::scalar_t secret_q; // q + boost::multiprecision::uint256_t z_l_div_z_D; // z * floor( l / (z * D) ) (max possible value (assuming z=2^64) : z * 2^252 / (z * 1) ~= 2^252) + crypto::hash kernel_hash; // h + crypto::scalar_t stake_out_blinding_mask; // f + uint64_t stake_amount; // a - crypto::scalar_t last_pow_block_id_hashed; // Zarcanum notation: f' - crypto::scalar_t secret_q; // Zarcanum notation: q - boost::multiprecision::uint256_t z_l_div_z_D; // Zarcanum notation: z * floor( l / (z * D) ) (max possible value (assuming z=2^64) : z * 2^252 / (z * 1) ~= 2^252) - crypto::hash kernel_hash; // Zarcanum notation: h - crypto::scalar_t stake_out_blinding_mask; // Zarcanum notation: f - - uint64_t stake_amount; - - bool zarcanum; + bool zarcanum; // false for pre-HF4 classic PoS with explicit amounts void init(const wide_difficulty_type& pos_diff, const stake_modifier_type& sm, bool is_zarcanum); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 69038ce1..63b844dc 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3799,21 +3799,17 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, currency::bl } #endif - crypto::scalar_t pseudo_out_blinding_mask = blinding_masks_sum; - //process_type_in_variant_container(b.miner_tx.vout, [&](tx_out_zarcanum& o){ pseudo_out_blinding_mask += o. }); - crypto::point_t pseudo_out_amount_commitment = td.m_amount * crypto::c_point_H + pseudo_out_blinding_mask * crypto::c_point_G; - - crypto::hash tx_hash_for_sig = get_transaction_hash(b.miner_tx); - crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); r = crypto::generate_key_derivation(source_tx_pub_key, m_account.get_keys().view_secret_key, derivation); WLT_CHECK_AND_ASSERT_MES(r, false, "generate_key_derivation failed, tid: " << pe.wallet_index << ", pe.tx_id: " << pe.tx_id); crypto::secret_key secret_x = AUTO_VAL_INIT(secret_x); crypto::derive_secret_key(derivation, pe.tx_out_index, m_account.get_keys().spend_secret_key, secret_x); + crypto::hash tx_hash_for_sig = get_transaction_hash(b.miner_tx); // TODO @#@# consider adding more input data to this hash + uint8_t err = 0; - r = crypto::zarcanum_generate_proof(tx_hash_for_sig, cxt.kernel_hash, ring, pseudo_out_amount_commitment, cxt.last_pow_block_id_hashed, - pe.keyimage, secret_x, cxt.secret_q, secret_index, pseudo_out_blinding_mask, td.m_amount, *td.m_opt_blinding_mask, + r = crypto::zarcanum_generate_proof(tx_hash_for_sig, cxt.kernel_hash, ring, cxt.last_pow_block_id_hashed, pe.keyimage, + secret_x, cxt.secret_q, secret_index, blinding_masks_sum, td.m_amount, *td.m_opt_blinding_mask, static_cast(sig), &err); WLT_CHECK_AND_ASSERT_MES(r, false, "zarcanum_generate_proof failed, err: " << (int)err); diff --git a/tests/core_tests/pos_block_builder.cpp b/tests/core_tests/pos_block_builder.cpp index 2a3161d8..23d91b0b 100644 --- a/tests/core_tests/pos_block_builder.cpp +++ b/tests/core_tests/pos_block_builder.cpp @@ -14,6 +14,7 @@ void pos_block_builder::clear() *this = pos_block_builder{}; } + void pos_block_builder::step1_init_header(const hard_forks_descriptor& hardforks, size_t block_height, crypto::hash& prev_block_hash) { CHECK_AND_ASSERT_THROW_MES(m_step == 0, "pos_block_builder: incorrect step sequence"); @@ -26,9 +27,12 @@ void pos_block_builder::step1_init_header(const hard_forks_descriptor& hardforks m_height = block_height; + m_context.zarcanum = hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, m_height); + m_step = 1; } + void pos_block_builder::step2_set_txs(const std::vector& txs) { CHECK_AND_ASSERT_THROW_MES(m_step == 1, "pos_block_builder: incorrect step sequence"); @@ -50,6 +54,7 @@ void pos_block_builder::step2_set_txs(const std::vector& m_step = 2; } + void pos_block_builder::step3_build_stake_kernel( uint64_t stake_output_amount, size_t stake_output_gindex, @@ -61,44 +66,81 @@ void pos_block_builder::step3_build_stake_kernel( uint64_t timestamp_window, uint64_t timestamp_step) { - CHECK_AND_ASSERT_THROW_MES(m_step == 2, "pos_block_builder: incorrect step sequence"); - m_pos_stake_amount = stake_output_amount; - m_pos_stake_output_gindex = stake_output_gindex; + step3a(difficulty, last_pow_block_hash, last_pos_block_kernel_hash); - m_stake_kernel.kimage = stake_output_key_image; - m_stake_kernel.block_timestamp = 0; - m_stake_kernel.stake_modifier.last_pow_id = last_pow_block_hash; - m_stake_kernel.stake_modifier.last_pos_kernel_id = last_pos_block_kernel_hash; + crypto::public_key stake_source_tx_pub_key {}; + uint64_t stake_out_in_tx_index = UINT64_MAX; + crypto::scalar_t stake_out_blinding_mask {}; + crypto::secret_key view_secret {}; + + step3b(stake_output_amount, stake_output_key_image, stake_source_tx_pub_key, stake_out_in_tx_index, stake_out_blinding_mask, view_secret, stake_output_gindex, + timestamp_lower_bound, timestamp_window, timestamp_step); +} + + +void pos_block_builder::step3a( + currency::wide_difficulty_type difficulty, + const crypto::hash& last_pow_block_hash, + const crypto::hash& last_pos_block_kernel_hash + ) +{ + CHECK_AND_ASSERT_THROW_MES(m_step == 2, "pos_block_builder: incorrect step sequence"); + + stake_modifier_type sm{}; + sm.last_pow_id = last_pow_block_hash; + sm.last_pos_kernel_id = last_pos_block_kernel_hash; if (last_pos_block_kernel_hash == null_hash) { - bool r = string_tools::parse_tpod_from_hex_string(POS_STARTER_KERNEL_HASH, m_stake_kernel.stake_modifier.last_pos_kernel_id); + bool r = string_tools::parse_tpod_from_hex_string(POS_STARTER_KERNEL_HASH, sm.last_pos_kernel_id); CHECK_AND_ASSERT_THROW_MES(r, "Failed to parse POS_STARTER_KERNEL_HASH"); } - wide_difficulty_type stake_difficulty = difficulty / stake_output_amount; + m_context.init(difficulty, sm, m_context.zarcanum); + m_step = 31; +} + + +void pos_block_builder::step3b( + uint64_t stake_output_amount, + const crypto::key_image& stake_output_key_image, + const crypto::public_key& stake_source_tx_pub_key, // zarcanum only + uint64_t stake_out_in_tx_index, // zarcanum only + const crypto::scalar_t& stake_out_blinding_mask, // zarcanum only + const crypto::secret_key& view_secret, // zarcanum only + size_t stake_output_gindex, + uint64_t timestamp_lower_bound, + uint64_t timestamp_window, + uint64_t timestamp_step) +{ + CHECK_AND_ASSERT_THROW_MES(m_step == 31, "pos_block_builder: incorrect step sequence"); + + m_pos_stake_output_gindex = stake_output_gindex; + + m_context.prepare_entry(stake_output_amount, stake_output_key_image, stake_source_tx_pub_key, stake_out_in_tx_index, stake_out_blinding_mask, view_secret); + // align timestamp_lower_bound up to timestamp_step boundary if needed if (timestamp_lower_bound % timestamp_step != 0) timestamp_lower_bound = timestamp_lower_bound - (timestamp_lower_bound % timestamp_step) + timestamp_step; bool sk_found = false; for (uint64_t ts = timestamp_lower_bound; !sk_found && ts < timestamp_lower_bound + timestamp_window; ts += timestamp_step) { - m_stake_kernel.block_timestamp = ts; - crypto::hash sk_hash = crypto::cn_fast_hash(&m_stake_kernel, sizeof(m_stake_kernel)); - if (check_hash(sk_hash, stake_difficulty)) - { + if (m_context.do_iteration(ts)) sk_found = true; - } } if (!sk_found) ASSERT_MES_AND_THROW("Could't build stake kernel"); // update block header with found timestamp - m_block.timestamp = m_stake_kernel.block_timestamp; + m_block.timestamp = m_context.sk.block_timestamp; m_step = 3; } + + + + void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, const account_public_address &reward_and_stake_receiver_address, @@ -110,6 +152,7 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, step4_generate_coinbase_tx(median_size, already_generated_coins, reward_and_stake_receiver_address, reward_and_stake_receiver_address, extra_nonce, max_outs, alias, tx_one_time_key); } + void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, const account_public_address &reward_receiver_address, @@ -123,7 +166,7 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, // generate miner tx using incorrect current_block_size only for size estimation size_t estimated_block_size = m_txs_total_size; - bool r = construct_homemade_pos_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, m_pos_stake_amount, m_stake_kernel.kimage, + bool r = construct_homemade_pos_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, m_context.stake_amount, m_context.sk.kimage, m_pos_stake_output_gindex, reward_receiver_address, stakeholder_address, m_block.miner_tx, extra_nonce, max_outs, tx_one_time_key); CHECK_AND_ASSERT_THROW_MES(r, "construct_homemade_pos_miner_tx failed"); @@ -131,7 +174,7 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, size_t cumulative_size = 0; for (size_t try_count = 0; try_count != 10; ++try_count) { - r = construct_homemade_pos_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, m_pos_stake_amount, m_stake_kernel.kimage, + r = construct_homemade_pos_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, m_context.stake_amount, m_context.sk.kimage, m_pos_stake_output_gindex, reward_receiver_address, stakeholder_address, m_block.miner_tx, extra_nonce, max_outs, tx_one_time_key); CHECK_AND_ASSERT_THROW_MES(r, "construct_homemade_pos_miner_tx failed"); @@ -152,6 +195,7 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, m_step = 4; } + void pos_block_builder::step5_sign(const crypto::public_key& stake_tx_pub_key, size_t stake_tx_out_index, const crypto::public_key& stake_tx_out_pub_key, const currency::account_base& stakeholder_account) { CHECK_AND_ASSERT_THROW_MES(m_step == 4, "pos_block_builder: incorrect step sequence"); @@ -166,11 +210,12 @@ void pos_block_builder::step5_sign(const crypto::public_key& stake_tx_pub_key, s // sign block actually in coinbase transaction crypto::hash block_hash = currency::get_block_hash(m_block); std::vector keys_ptrs(1, &stake_tx_out_pub_key); - crypto::generate_ring_signature(block_hash, m_stake_kernel.kimage, keys_ptrs, derived_secret_ephemeral_key, 0, &boost::get(m_block.miner_tx.signatures[0]).s[0]); + crypto::generate_ring_signature(block_hash, m_context.sk.kimage, keys_ptrs, derived_secret_ephemeral_key, 0, &boost::get(m_block.miner_tx.signatures[0]).s[0]); m_step = 5; } + bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, size_t current_block_size, uint64_t fee, @@ -271,6 +316,7 @@ bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const bo return true; } + bool mine_next_pos_block_in_playtime_sign_cb(currency::core& c, const currency::block& prev_block, const currency::block& coinstake_scr_block, const currency::account_base& acc, std::function before_sign_cb, currency::block& output) { diff --git a/tests/core_tests/pos_block_builder.h b/tests/core_tests/pos_block_builder.h index 5c28acdf..a8f56514 100644 --- a/tests/core_tests/pos_block_builder.h +++ b/tests/core_tests/pos_block_builder.h @@ -27,6 +27,26 @@ struct pos_block_builder uint64_t timestamp_lower_bound, uint64_t timestamp_window = POS_SCAN_WINDOW, uint64_t timestamp_step = POS_SCAN_STEP); + + + void pos_block_builder::step3a( + currency::wide_difficulty_type difficulty, + const crypto::hash& last_pow_block_hash, + const crypto::hash& last_pos_block_kernel_hash + ); + + void pos_block_builder::step3b( + uint64_t stake_output_amount, + const crypto::key_image& stake_output_key_image, + const crypto::public_key& stake_source_tx_pub_key, + uint64_t stake_out_in_tx_index, + const crypto::scalar_t& stake_out_blinding_mask, + const crypto::secret_key& view_secret, + size_t stake_output_gindex, + uint64_t timestamp_lower_bound, + uint64_t timestamp_window, + uint64_t timestamp_step); + void step4_generate_coinbase_tx(size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, @@ -51,12 +71,12 @@ struct pos_block_builder size_t m_step = 0; size_t m_txs_total_size = 0; uint64_t m_total_fee = 0; - currency::stake_kernel m_stake_kernel {}; + //currency::stake_kernel m_stake_kernel {}; size_t m_height = 0; size_t m_pos_stake_output_gindex = 0; - uint64_t m_pos_stake_amount = 0; + //uint64_t m_pos_stake_amount = 0; - bool m_zarcanum = false; + currency::pos_mining_context m_context {}; }; bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins,