forked from lthn/blockchain
Merge branch 'cryptoassets' into decoy_selection
This commit is contained in:
commit
95e8954c38
17 changed files with 727 additions and 110 deletions
|
|
@ -517,6 +517,24 @@ namespace crypto
|
|||
m_u64[bit_index >> 6] &= ~(1ull << (bit_index & 63));
|
||||
}
|
||||
|
||||
// the result is guaranteed to be within [ 0; 2 ^ bits_count )
|
||||
uint64_t get_bits(uint8_t bit_index_first, uint8_t bits_count) const
|
||||
{
|
||||
if (bits_count == 0 || bits_count > 64)
|
||||
return 0;
|
||||
uint8_t bits_count_m_1 = bits_count - 1;
|
||||
unsigned int bit_index_last = bit_index_first + bits_count_m_1;
|
||||
if (bit_index_last > 255)
|
||||
bit_index_last = 255;
|
||||
|
||||
uint64_t result = m_u64[bit_index_first >> 6] >> (bit_index_first & 63);
|
||||
if (bits_count_m_1 > (bit_index_last & 63))
|
||||
result |= m_u64[bit_index_last >> 6] << (bits_count_m_1 - (bit_index_last & 63));
|
||||
|
||||
uint64_t result_mask = ((1ull << bits_count_m_1) - 1) << 1 | 1; // (just because 1ull << 64 in undefined behaviour, not a 0 as one would expect)
|
||||
return result & result_mask;
|
||||
}
|
||||
|
||||
// does not reduce
|
||||
static scalar_t power_of_2(uint8_t exponent)
|
||||
{
|
||||
|
|
@ -746,6 +764,24 @@ namespace crypto
|
|||
return *this;
|
||||
}
|
||||
|
||||
point_t modify_mul_pow_2(size_t power)
|
||||
{
|
||||
if (power > 0)
|
||||
{
|
||||
ge_p1p1 p1;
|
||||
ge_p2 p2;
|
||||
ge_p3_to_p2(&p2, &m_p3);
|
||||
for (size_t i = 1; i < power; ++i)
|
||||
{
|
||||
ge_p2_dbl(&p1, &p2);
|
||||
ge_p1p1_to_p2(&p2, &p1);
|
||||
}
|
||||
ge_p2_dbl(&p1, &p2);
|
||||
ge_p1p1_to_p3(&m_p3, &p1);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// returns a * this + G
|
||||
point_t mul_plus_G(const scalar_t& a) const
|
||||
{
|
||||
|
|
|
|||
25
src/crypto/msm.cpp
Normal file
25
src/crypto/msm.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) 2023-2023 Zano Project
|
||||
// Copyright (c) 2023-2023 sowle (val@zano.org, crypto.sowle@gmail.com)
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
//
|
||||
#include "epee/include/misc_log_ex.h"
|
||||
//#include "zarcanum.h"
|
||||
#include "msm.h"
|
||||
//#include "../currency_core/crypto_config.h" // TODO: move it to the crypto
|
||||
//#include "../common/crypto_stream_operators.h" // TODO: move it to the crypto
|
||||
|
||||
#if 0
|
||||
# define DBG_VAL_PRINT(x) std::cout << std::setw(30) << std::left << #x ": " << x << std::endl
|
||||
# define DBG_PRINT(x) std::cout << x << std::endl
|
||||
#else
|
||||
# define DBG_VAL_PRINT(x) (void(0))
|
||||
# define DBG_PRINT(x) (void(0))
|
||||
#endif
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
|
||||
|
||||
|
||||
} // namespace crypto
|
||||
173
src/crypto/msm.h
Normal file
173
src/crypto/msm.h
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
// Copyright (c) 2023-2023 Zano Project (https://zano.org/)
|
||||
// Copyright (c) 2023-2023 sowle (val@zano.org, crypto.sowle@gmail.com)
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#pragma once
|
||||
|
||||
// This file contains Multi-Scalar Multiplication routines
|
||||
|
||||
#include "epee/include/misc_log_ex.h"
|
||||
#include "crypto-sugar.h"
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
|
||||
template<typename CT>
|
||||
bool msm_and_check_zero_naive(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(g_scalars.size() <= CT::c_bpp_mn_max, false, "g_scalars oversized");
|
||||
CHECK_AND_ASSERT_MES(h_scalars.size() <= CT::c_bpp_mn_max, false, "h_scalars oversized");
|
||||
|
||||
point_t result = summand;
|
||||
|
||||
for (size_t i = 0; i < g_scalars.size(); ++i)
|
||||
result += g_scalars[i] * CT::get_generator(false, i);
|
||||
|
||||
for (size_t i = 0; i < h_scalars.size(); ++i)
|
||||
result += h_scalars[i] * CT::get_generator(true, i);
|
||||
|
||||
if (!result.is_zero())
|
||||
{
|
||||
LOG_PRINT_L0("msm result is non zero: " << result);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// https://eprint.iacr.org/2022/999.pdf
|
||||
// "Pippenger algorithm [1], and its variant that is widely used in the ZK space is called the bucket method"
|
||||
template<typename CT>
|
||||
bool msm_and_check_zero_pippenger_v3(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand, uint8_t c)
|
||||
{
|
||||
// TODO: with c = 8 and with direct access got much worse result than with c = 7 and get_bits() for N = 128..256, consider checking again for bigger datasets (N>256)
|
||||
// TODO: consider preparing a cached generators' points
|
||||
|
||||
CHECK_AND_ASSERT_MES(g_scalars.size() <= CT::c_bpp_mn_max, false, "g_scalars oversized");
|
||||
CHECK_AND_ASSERT_MES(h_scalars.size() <= CT::c_bpp_mn_max, false, "h_scalars oversized");
|
||||
CHECK_AND_ASSERT_MES(c < 10, false, "c is too big");
|
||||
|
||||
size_t C = 1ull << c;
|
||||
|
||||
// k_max * c + (c-1) >= max_bit_idx
|
||||
//
|
||||
// max_bit_idx - (c - 1) max_bit_idx - (c - 1) + (c - 1) max_bit_idx
|
||||
// k_max = ceil ( --------------------- ) = floor ( ------------------------------ ) = floor ( ----------- )
|
||||
// c c c
|
||||
const size_t b = 253; // the maximum number of bits in x https://eprint.iacr.org/2022/999.pdf TODO: we may also scan for maximum bit used in all the scalars if all the scalars are small
|
||||
const size_t max_bit_idx = b - 1;
|
||||
const size_t k_max = max_bit_idx / c;
|
||||
const size_t K = k_max + 1;
|
||||
|
||||
std::vector<point_t> buckets(C * K);
|
||||
std::vector<bool> buckets_inited(C * K);
|
||||
std::vector<point_t> Sk(K);
|
||||
std::vector<bool> Sk_inited(K);
|
||||
std::vector<point_t> Gk(K);
|
||||
std::vector<bool> Gk_inited(K);
|
||||
|
||||
// first loop, calculate partial bucket sums
|
||||
for (size_t n = 0; n < g_scalars.size(); ++n)
|
||||
{
|
||||
for (size_t k = 0; k < K; ++k)
|
||||
{
|
||||
uint64_t l = g_scalars[n].get_bits((uint8_t)(k * c), c); // l in [0; 2^c-1]
|
||||
if (l != 0)
|
||||
{
|
||||
size_t bucket_id = l * K + k;
|
||||
if (buckets_inited[bucket_id])
|
||||
buckets[bucket_id] += CT::get_generator(false, n);
|
||||
else
|
||||
{
|
||||
buckets[bucket_id] = CT::get_generator(false, n);
|
||||
buckets_inited[bucket_id] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// still the first loop (continued)
|
||||
for (size_t n = 0; n < h_scalars.size(); ++n)
|
||||
{
|
||||
for (size_t k = 0; k < K; ++k)
|
||||
{
|
||||
uint64_t l = h_scalars[n].get_bits((uint8_t)(k * c), c); // l in [0; 2^c-1]
|
||||
if (l != 0)
|
||||
{
|
||||
size_t bucket_id = l * K + k;
|
||||
if (buckets_inited[bucket_id])
|
||||
buckets[bucket_id] += CT::get_generator(true, n);
|
||||
else
|
||||
{
|
||||
buckets[bucket_id] = CT::get_generator(true, n);
|
||||
buckets_inited[bucket_id] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the second loop
|
||||
for (size_t l = C - 1; l > 0; --l)
|
||||
{
|
||||
for (size_t k = 0; k < K; ++k)
|
||||
{
|
||||
size_t bucket_id = l * K + k;
|
||||
if (buckets_inited[bucket_id])
|
||||
{
|
||||
if (Sk_inited[k])
|
||||
Sk[k] += buckets[bucket_id];
|
||||
else
|
||||
{
|
||||
Sk[k] = buckets[bucket_id];
|
||||
Sk_inited[k] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Sk_inited[k])
|
||||
{
|
||||
if (Gk_inited[k])
|
||||
Gk[k] += Sk[k];
|
||||
else
|
||||
{
|
||||
Gk[k] = Sk[k];
|
||||
Gk_inited[k] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the third loop: Horner’s rule
|
||||
point_t result = Gk_inited[K - 1] ? Gk[K - 1] : c_point_0;
|
||||
for (size_t k = K - 2; k != SIZE_MAX; --k)
|
||||
{
|
||||
result.modify_mul_pow_2(c);
|
||||
if (Gk_inited[k])
|
||||
result += Gk[k];
|
||||
}
|
||||
|
||||
result += summand;
|
||||
|
||||
if (!result.is_zero())
|
||||
{
|
||||
LOG_PRINT_L0("multiexp result is non zero: " << result);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Just switcher
|
||||
|
||||
template<typename CT>
|
||||
bool msm_and_check_zero(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand)
|
||||
{
|
||||
//return msm_and_check_zero_naive<CT>(g_scalars, h_scalars, summand);
|
||||
return msm_and_check_zero_pippenger_v3<CT>(g_scalars, h_scalars, summand, 7);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace crypto
|
||||
|
|
@ -716,7 +716,7 @@ namespace crypto
|
|||
|
||||
point_t GH_exponents = c_point_0;
|
||||
CT::calc_pedersen_commitment(G_scalar, H_scalar, GH_exponents);
|
||||
bool result = multiexp_and_check_being_zero<CT>(g_scalars, h_scalars, summand + GH_exponents);
|
||||
bool result = msm_and_check_zero<CT>(g_scalars, h_scalars, summand + GH_exponents);
|
||||
if (result)
|
||||
DBG_PRINT(ENDL << " . . . . bpp_verify() -- SUCCEEDED!!!" << ENDL);
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -734,7 +734,7 @@ namespace crypto
|
|||
|
||||
point_t GH_exponents = c_point_0;
|
||||
CT::calc_pedersen_commitment_2(G_scalar, H_scalar, H2_scalar, GH_exponents);
|
||||
bool result = multiexp_and_check_being_zero<CT>(g_scalars, h_scalars, summand + GH_exponents);
|
||||
bool result = msm_and_check_zero<CT>(g_scalars, h_scalars, summand + GH_exponents);
|
||||
if (result)
|
||||
DBG_PRINT(ENDL << " . . . . bppe_verify() -- SUCCEEDED!!!" << ENDL);
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ namespace crypto
|
|||
////////////////////////////////////////
|
||||
struct bpp_ct_generators_HGX
|
||||
{
|
||||
// NOTE! This notation follows the original BP+ whitepaper, see mapping to Zano's generators below
|
||||
// NOTE! This notation follows the original BP+ whitepaper, see mapping to Zano's generators in range_proofs.cpp
|
||||
static const point_t& bpp_G;
|
||||
static const point_t& bpp_H;
|
||||
static const point_t& bpp_H2;
|
||||
|
|
@ -49,7 +49,7 @@ namespace crypto
|
|||
|
||||
struct bpp_ct_generators_UGX
|
||||
{
|
||||
// NOTE! This notation follows the original BP+ whitepaper, see mapping to Zano's generators below
|
||||
// NOTE! This notation follows the original BP+ whitepaper, see mapping to Zano's generators in range_proofs.cpp
|
||||
static const point_t& bpp_G;
|
||||
static const point_t& bpp_H;
|
||||
static const point_t& bpp_H2;
|
||||
|
|
@ -138,32 +138,11 @@ namespace crypto
|
|||
|
||||
typedef bpp_crypto_trait_zano<bpp_ct_generators_HGX, 128, 16> bpp_crypto_trait_Zarcanum;
|
||||
|
||||
|
||||
// efficient multiexponentiation (naive stub implementation atm, TODO)
|
||||
template<typename CT>
|
||||
bool multiexp_and_check_being_zero(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(g_scalars.size() <= CT::c_bpp_mn_max, false, "g_scalars oversized");
|
||||
CHECK_AND_ASSERT_MES(h_scalars.size() <= CT::c_bpp_mn_max, false, "h_scalars oversized");
|
||||
|
||||
point_t result = summand;
|
||||
|
||||
for (size_t i = 0; i < g_scalars.size(); ++i)
|
||||
result += g_scalars[i] * CT::get_generator(false, i);
|
||||
|
||||
for (size_t i = 0; i < h_scalars.size(); ++i)
|
||||
result += h_scalars[i] * CT::get_generator(true, i);
|
||||
|
||||
if (!result.is_zero())
|
||||
{
|
||||
LOG_PRINT_L0("multiexp result is non zero: " << result);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace crypto
|
||||
|
||||
#include "epee/include/profile_tools.h" // <- remove this, sowle
|
||||
|
||||
#include "msm.h"
|
||||
#include "range_proof_bpp.h"
|
||||
#include "range_proof_bppe.h"
|
||||
|
|
|
|||
|
|
@ -1360,13 +1360,10 @@ bool blockchain_storage::validate_miner_transaction(const block& b,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (b.miner_tx.version > TRANSACTION_VERSION_PRE_HF4)
|
||||
if (!verify_asset_surjection_proof(b.miner_tx, tx_id_for_post_hf4_era))
|
||||
{
|
||||
if (!verify_asset_surjection_proof(b.miner_tx, tx_id_for_post_hf4_era))
|
||||
{
|
||||
LOG_ERROR("asset surjection proof verification failed for miner tx");
|
||||
return false;
|
||||
}
|
||||
LOG_ERROR("asset surjection proof verification failed for miner tx");
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_PRINT_MAGENTA("Mining tx verification ok, blocks_size_median = " << blocks_size_median, LOG_LEVEL_2);
|
||||
|
|
@ -4776,7 +4773,7 @@ bool blockchain_storage::print_tx_outputs_lookup(const crypto::hash& tx_id)const
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool check_tx_explicit_asset_id_rules(const transaction& tx, bool all_tx_ins_have_explicit_asset_ids)
|
||||
bool check_tx_explicit_asset_id_rules(const transaction& tx, bool all_tx_ins_have_explicit_native_asset_ids)
|
||||
{
|
||||
if (tx.version <= TRANSACTION_VERSION_PRE_HF4)
|
||||
return true;
|
||||
|
|
@ -4784,13 +4781,13 @@ bool check_tx_explicit_asset_id_rules(const transaction& tx, bool all_tx_ins_hav
|
|||
// ( assuming that post-HF4 txs can only have tx_out_zarcanum outs )
|
||||
|
||||
bool r = false;
|
||||
// if all tx inputs have explicit asset id AND it does not emit a new asset THEN all outputs must have explicit asset id (native coin)
|
||||
if (all_tx_ins_have_explicit_asset_ids && !is_asset_emitting_transaction(tx))
|
||||
// if all tx inputs have explicit native asset id AND it does not emit a new asset THEN all outputs must have explicit asset id (native coin)
|
||||
if (all_tx_ins_have_explicit_native_asset_ids && !is_asset_emitting_transaction(tx))
|
||||
{
|
||||
for(size_t j = 0, k = tx.vout.size(); j < k; ++j)
|
||||
{
|
||||
r = crypto::point_t(boost::get<tx_out_zarcanum>(tx.vout[j]).blinded_asset_id).modify_mul8().to_public_key() == native_coin_asset_id;
|
||||
CHECK_AND_ASSERT_MES(r, false, "output #" << j << " has a non-explicit asset id");
|
||||
CHECK_AND_ASSERT_MES(r, false, "output #" << j << " has a non-explicit asset id in a tx where all inputs have an explicit native asset id");
|
||||
}
|
||||
}
|
||||
else // otherwise all outputs must have hidden asset id (unless they burn money by sending them to null pubkey)
|
||||
|
|
@ -4799,7 +4796,7 @@ bool check_tx_explicit_asset_id_rules(const transaction& tx, bool all_tx_ins_hav
|
|||
{
|
||||
const tx_out_zarcanum& zo = boost::get<tx_out_zarcanum>(tx.vout[j]);
|
||||
r = zo.stealth_address == null_pkey || crypto::point_t(zo.blinded_asset_id).modify_mul8().to_public_key() != native_coin_asset_id;
|
||||
CHECK_AND_ASSERT_MES(r, false, "output #" << j << " has an explicit asset id");
|
||||
CHECK_AND_ASSERT_MES(r, false, "output #" << j << " has an explicit asset id in a tx where not all inputs have an explicit native asset id");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
@ -4845,7 +4842,7 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha
|
|||
{
|
||||
size_t sig_index = 0;
|
||||
max_used_block_height = 0;
|
||||
bool all_tx_ins_have_explicit_asset_ids = true;
|
||||
bool all_tx_ins_have_explicit_native_asset_ids = true;
|
||||
|
||||
auto local_check_key_image = [&](const crypto::key_image& ki) -> bool
|
||||
{
|
||||
|
|
@ -4907,7 +4904,7 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha
|
|||
if (!local_check_key_image(in_zc.k_image))
|
||||
return false;
|
||||
|
||||
if (!check_tx_input(tx, sig_index, in_zc, tx_prefix_hash, max_used_block_height, all_tx_ins_have_explicit_asset_ids))
|
||||
if (!check_tx_input(tx, sig_index, in_zc, tx_prefix_hash, max_used_block_height, all_tx_ins_have_explicit_native_asset_ids))
|
||||
{
|
||||
LOG_ERROR("Failed to validate zc input #" << sig_index << " in tx: " << tx_prefix_hash);
|
||||
return false;
|
||||
|
|
@ -4930,7 +4927,7 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha
|
|||
CHECK_AND_ASSERT_MES(r, false, "Failed to validate attachments in tx " << tx_prefix_hash << ": incorrect extra_attachment_info in tx.extra");
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(check_tx_explicit_asset_id_rules(tx, all_tx_ins_have_explicit_asset_ids), false, "tx does not comply with explicit asset id rules");
|
||||
CHECK_AND_ASSERT_MES(check_tx_explicit_asset_id_rules(tx, all_tx_ins_have_explicit_native_asset_ids), false, "tx does not comply with explicit asset id rules");
|
||||
}
|
||||
TIME_MEASURE_FINISH_PD(tx_check_inputs_attachment_check);
|
||||
return true;
|
||||
|
|
@ -5314,7 +5311,7 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index,
|
|||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_zc_input& zc_in, const crypto::hash& tx_prefix_hash,
|
||||
uint64_t& max_related_block_height, bool& all_tx_ins_have_explicit_asset_ids) const
|
||||
uint64_t& max_related_block_height, bool& all_tx_ins_have_explicit_native_asset_ids) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
|
||||
|
|
@ -5347,8 +5344,8 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index,
|
|||
for(auto& zc_out : scan_contex.zc_outs)
|
||||
{
|
||||
ring.emplace_back(zc_out.stealth_address, zc_out.amount_commitment, zc_out.blinded_asset_id);
|
||||
if (all_tx_ins_have_explicit_asset_ids && crypto::point_t(zc_out.blinded_asset_id).modify_mul8().to_public_key() != native_coin_asset_id)
|
||||
all_tx_ins_have_explicit_asset_ids = false;
|
||||
if (all_tx_ins_have_explicit_native_asset_ids && crypto::point_t(zc_out.blinded_asset_id).modify_mul8().to_public_key() != native_coin_asset_id)
|
||||
all_tx_ins_have_explicit_native_asset_ids = false;
|
||||
}
|
||||
|
||||
// calculate corresponding tx prefix hash
|
||||
|
|
@ -5940,10 +5937,12 @@ bool blockchain_storage::validate_pos_block(const block& b,
|
|||
CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key) || b.miner_tx.vin[1].type() == typeid(txin_zc_input), false, "incorrect input 1 type: " << b.miner_tx.vin[1].type().name());
|
||||
const crypto::key_image& stake_key_image = get_key_image_from_txin_v(b.miner_tx.vin[1]);
|
||||
//check keyimage if it's main chain candidate
|
||||
TIME_MEASURE_START_PD(pos_validate_ki_search);
|
||||
if (!for_altchain)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!have_tx_keyimg_as_spent(stake_key_image), false, "stake key image has been already spent in blockchain: " << stake_key_image);
|
||||
}
|
||||
TIME_MEASURE_FINISH_PD(pos_validate_ki_search);
|
||||
|
||||
if (!is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM))
|
||||
{
|
||||
|
|
@ -5980,6 +5979,7 @@ bool blockchain_storage::validate_pos_block(const block& b,
|
|||
|
||||
if (!for_altchain)
|
||||
{
|
||||
TIME_MEASURE_START_PD(pos_validate_get_out_keys_for_inputs);
|
||||
// do general input check for main chain blocks only
|
||||
// TODO @#@#: txs in alternative PoS blocks (including miner_tx) must be validated by validate_alt_block_txs()
|
||||
const zarcanum_sig& sig = boost::get<zarcanum_sig>(b.miner_tx.signatures[0]);
|
||||
|
|
@ -5993,6 +5993,8 @@ bool blockchain_storage::validate_pos_block(const block& b,
|
|||
// make sure that all referring inputs are either older then, or the same age as, the most resent PoW block.
|
||||
CHECK_AND_ASSERT_MES(max_related_block_height <= last_pow_block_height, false, "stake input refs' max related block height is " << max_related_block_height << " while last PoW block height is " << last_pow_block_height);
|
||||
|
||||
TIME_MEASURE_FINISH_PD(pos_validate_get_out_keys_for_inputs);
|
||||
|
||||
// build a ring of references
|
||||
vector<crypto::CLSAG_GGXXG_input_ref_t> ring;
|
||||
ring.reserve(scan_contex.zc_outs.size());
|
||||
|
|
@ -6002,7 +6004,9 @@ bool blockchain_storage::validate_pos_block(const block& b,
|
|||
crypto::scalar_t last_pow_block_id_hashed = crypto::hash_helper_t::hs(CRYPTO_HDS_ZARCANUM_LAST_POW_HASH, sm.last_pow_id);
|
||||
|
||||
uint8_t err = 0;
|
||||
TIME_MEASURE_START_PD(pos_validate_zvp);
|
||||
r = crypto::zarcanum_verify_proof(id, kernel_hash, ring, last_pow_block_id_hashed, stake_input.k_image, basic_diff, sig, &err);
|
||||
TIME_MEASURE_FINISH_PD(pos_validate_zvp);
|
||||
CHECK_AND_ASSERT_MES(r, false, "zarcanum_verify_proof failed with code " << (int)err);
|
||||
}
|
||||
|
||||
|
|
@ -6457,7 +6461,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
}
|
||||
TIME_MEASURE_FINISH_PD(tx_check_inputs_time);
|
||||
tx_total_inputs_processing_time += tx_check_inputs_time;
|
||||
tx_total_inputs_count++;
|
||||
tx_total_inputs_count += tx.vin.size();
|
||||
burned_coins += get_burned_amount(tx);
|
||||
|
||||
TIME_MEASURE_START_PD(tx_prapare_append);
|
||||
|
|
@ -6508,6 +6512,8 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
|
||||
if (!m_is_in_checkpoint_zone)
|
||||
{
|
||||
// validate_miner_transaction will check balance proof and asset surjection proof
|
||||
// and, as a side effect, it MAY recalculate base_reward, consider redisign, TODO -- sowle
|
||||
TIME_MEASURE_START_PD(validate_miner_transaction_time);
|
||||
if (!validate_miner_transaction(bl, cumulative_block_size, fee_summary, base_reward, already_generated_coins)) // TODO @#@# base_reward will be calculated once again, consider refactoring
|
||||
{
|
||||
|
|
@ -6658,7 +6664,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
TIME_MEASURE_FINISH_PD_MS(block_processing_time_0_ms);
|
||||
|
||||
//print result
|
||||
stringstream powpos_str_entry, timestamp_str_entry;
|
||||
stringstream powpos_str_entry, timestamp_str_entry, pos_validation_str_entry;
|
||||
if (is_pos_bl)
|
||||
{ // PoS
|
||||
int64_t actual_ts = get_block_datetime(bei.bl); // signed int is intentionally used here
|
||||
|
|
@ -6672,6 +6678,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
else
|
||||
powpos_str_entry << "hidden";
|
||||
timestamp_str_entry << ", actual ts: " << actual_ts << " (diff: " << std::showpos << ts_diff << "s) block ts: " << std::noshowpos << bei.bl.timestamp << " (shift: " << std::showpos << static_cast<int64_t>(bei.bl.timestamp) - actual_ts << ")";
|
||||
pos_validation_str_entry << "(" << m_performance_data.pos_validate_ki_search.get_last_val() << "/" << m_performance_data.pos_validate_get_out_keys_for_inputs.get_last_val() << "/" << m_performance_data.pos_validate_zvp.get_last_val() << ")";
|
||||
}
|
||||
else
|
||||
{ // PoW
|
||||
|
|
@ -6692,14 +6699,15 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
<< ", timing: " << block_processing_time_0_ms << "ms"
|
||||
<< "(micrsec:" << block_processing_time_1
|
||||
<< "(" << target_calculating_time_2 << "(" << m_performance_data.target_calculating_enum_blocks.get_last_val() << "/" << m_performance_data.target_calculating_calc.get_last_val() << ")"
|
||||
<< "/" << longhash_calculating_time_3
|
||||
<< "/" << longhash_calculating_time_3 << pos_validation_str_entry.str()
|
||||
<< "/" << insert_time_4
|
||||
<< "/" << all_txs_insert_time_5
|
||||
<< "/" << etc_stuff_6
|
||||
<< "/" << tx_total_inputs_processing_time << " of " << tx_total_inputs_count
|
||||
<< "/(" << m_performance_data.validate_miner_transaction_time.get_last_val() << "|"
|
||||
<< m_performance_data.collect_rangeproofs_data_from_tx_time.get_last_val() << "|"
|
||||
<< m_performance_data.verify_multiple_zc_outs_range_proofs_time.get_last_val()
|
||||
<< m_performance_data.verify_multiple_zc_outs_range_proofs_time.get_last_val() << "~"
|
||||
<< range_proofs_agregated.size()
|
||||
<< ")"
|
||||
<< "))");
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,11 @@ namespace currency
|
|||
epee::math_helper::average<uint64_t, 5> target_calculating_enum_blocks;
|
||||
epee::math_helper::average<uint64_t, 5> target_calculating_calc;
|
||||
|
||||
//longhash_calculating_time_3
|
||||
epee::math_helper::average<uint64_t, 1> pos_validate_ki_search;
|
||||
epee::math_helper::average<uint64_t, 1> pos_validate_get_out_keys_for_inputs;
|
||||
epee::math_helper::average<uint64_t, 1> pos_validate_zvp;
|
||||
|
||||
//tx processing zone
|
||||
epee::math_helper::average<uint64_t, 1> tx_check_inputs_time;
|
||||
epee::math_helper::average<uint64_t, 1> tx_add_one_tx_time;
|
||||
|
|
@ -299,7 +304,7 @@ namespace currency
|
|||
bool check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase)const;
|
||||
bool check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height)const;
|
||||
bool check_tx_input(const transaction& tx, size_t in_index, const txin_htlc& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height)const;
|
||||
bool check_tx_input(const transaction& tx, size_t in_index, const txin_zc_input& zc_in, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, bool& tx_has_explicit_asset_ids_in_all_ins) const;
|
||||
bool check_tx_input(const transaction& tx, size_t in_index, const txin_zc_input& zc_in, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, bool& all_tx_ins_have_explicit_native_asset_ids) const;
|
||||
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height)const;
|
||||
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash) const;
|
||||
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height, crypto::hash& max_used_block_id)const;
|
||||
|
|
|
|||
|
|
@ -315,51 +315,6 @@ namespace currency
|
|||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Zarcanum structures
|
||||
//
|
||||
//#pragma pack(push, 1)
|
||||
/*
|
||||
struct zarcanum_input : public referring_input
|
||||
{
|
||||
zarcanum_input() {}
|
||||
// Boost's Assignable concept
|
||||
zarcanum_input(const zarcanum_input&) = default;
|
||||
zarcanum_input& operator=(const zarcanum_input&)= default;
|
||||
|
||||
crypto::key_image k_image;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(k_image)
|
||||
FIELD(key_offsets) // referring_input
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_BOOST_SERIALIZATION()
|
||||
BOOST_SERIALIZE(k_image)
|
||||
BOOST_SERIALIZE(key_offsets) // referring_input
|
||||
END_BOOST_SERIALIZATION()
|
||||
};
|
||||
|
||||
// txin_zarcanum_inputs contains several zarcanum_input instances and corresponds to one ZC_sig
|
||||
struct txin_zarcanum_inputs
|
||||
{
|
||||
txin_zarcanum_inputs() {}
|
||||
|
||||
// Boost's Assignable concept
|
||||
txin_zarcanum_inputs(const txin_zarcanum_inputs&) = default;
|
||||
txin_zarcanum_inputs& operator=(const txin_zarcanum_inputs&) = default;
|
||||
|
||||
std::vector<zarcanum_input> elements;
|
||||
std::vector<txin_etc_details_v> etc_details;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(elements)
|
||||
FIELD(etc_details)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_BOOST_SERIALIZATION()
|
||||
BOOST_SERIALIZE(elements)
|
||||
BOOST_SERIALIZE(etc_details)
|
||||
END_BOOST_SERIALIZATION()
|
||||
};
|
||||
*/
|
||||
|
||||
struct txin_zc_input : public referring_input
|
||||
{
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ namespace currency
|
|||
secret_index = ring.size() - 1;
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(secret_index != SIZE_MAX, false, "out #" << j << ": can't find a corresponding asset id in inputs");
|
||||
CHECK_AND_ASSERT_MES(secret_index != SIZE_MAX, false, "out #" << j << ": can't find a corresponding asset id in inputs, asset id: " << H);
|
||||
|
||||
result.bge_proofs.emplace_back(crypto::BGE_proof_s{});
|
||||
uint8_t err = 0;
|
||||
|
|
@ -550,16 +550,16 @@ namespace currency
|
|||
if (additional_inputs_amount_and_fees_for_mining_tx == 0)
|
||||
{
|
||||
// normal tx
|
||||
CHECK_AND_ASSERT_MES(bare_inputs_sum >= bare_outputs_sum, false, "tx balance error: sum of inputs (" << print_money_brief(bare_inputs_sum)
|
||||
<< ") is less than or equal to sum of outputs(" << print_money_brief(bare_outputs_sum) << ")");
|
||||
CHECK_AND_ASSERT_MES(bare_inputs_sum >= bare_outputs_sum, false, "tx balance error: the sum of inputs (" << print_money_brief(bare_inputs_sum)
|
||||
<< ") is less than or equal to the sum of outputs (" << print_money_brief(bare_outputs_sum) << ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
// miner tx
|
||||
CHECK_AND_ASSERT_MES(bare_inputs_sum + additional_inputs_amount_and_fees_for_mining_tx == bare_outputs_sum, false,
|
||||
"tx balance error: sum of inputs (" << print_money_brief(bare_inputs_sum) <<
|
||||
"tx balance error: the sum of inputs (" << print_money_brief(bare_inputs_sum) <<
|
||||
") + additional inputs and fees (" << print_money_brief(additional_inputs_amount_and_fees_for_mining_tx) <<
|
||||
") is less than or equal to sum of outputs(" << print_money_brief(bare_outputs_sum) << ")");
|
||||
") is less than or equal to the sum of outputs (" << print_money_brief(bare_outputs_sum) << ")");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -4060,11 +4060,7 @@ namespace currency
|
|||
//-----------------------------------------------------------------------
|
||||
bool is_pos_coinbase(const transaction& tx)
|
||||
{
|
||||
bool pos = false;
|
||||
if (!is_coinbase(tx, pos) || !pos)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return is_pos_miner_tx(tx);
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
bool is_coinbase(const transaction& tx, bool& pos_coinbase)
|
||||
|
|
@ -4072,7 +4068,7 @@ namespace currency
|
|||
if (!is_coinbase(tx))
|
||||
return false;
|
||||
|
||||
pos_coinbase = (tx.vin.size() == 2 && tx.vin[1].type() == typeid(txin_to_key));
|
||||
pos_coinbase = is_pos_coinbase(tx);
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -8,6 +8,6 @@
|
|||
#define PROJECT_REVISION "0"
|
||||
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
|
||||
|
||||
#define PROJECT_VERSION_BUILD_NO 249
|
||||
#define PROJECT_VERSION_BUILD_NO 250
|
||||
#define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO)
|
||||
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]"
|
||||
|
|
|
|||
|
|
@ -1241,6 +1241,9 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(hard_fork_2_incorrect_alias_update<true>);
|
||||
GENERATE_AND_PLAY(hard_fork_2_incorrect_alias_update<false>);
|
||||
|
||||
// HF4
|
||||
// GENERATE_AND_PLAY_HF(hard_fork_4_consolidated_txs, "4"); TODO, doesn't work atm -- sowle
|
||||
|
||||
// atomics
|
||||
GENERATE_AND_PLAY(atomic_simple_test);
|
||||
GENERATE_AND_PLAY(atomic_test_wrong_redeem_wrong_refund);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2024 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -38,9 +38,10 @@
|
|||
#include "hard_fork_1_bad_pos_source.h"
|
||||
#include "hard_fork_1.h"
|
||||
#include "hard_fork_2.h"
|
||||
#include "hard_fork_4.h"
|
||||
#include "atomic_tests.h"
|
||||
#include "isolate_auditable_and_proof.h"
|
||||
#include "zarcanum_test.h"
|
||||
#include "multiassets_test.h"
|
||||
#include "ionic_swap_tests.h"
|
||||
#include "attachment_isolation_encryption_test.h"
|
||||
#include "attachment_isolation_encryption_test.h"
|
||||
|
|
|
|||
223
tests/core_tests/hard_fork_4.cpp
Normal file
223
tests/core_tests/hard_fork_4.cpp
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
// Copyright (c) 2023-2024 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#include "chaingen.h"
|
||||
#include "hard_fork_4.h"
|
||||
#include "random_helper.h"
|
||||
|
||||
using namespace currency;
|
||||
|
||||
namespace currency
|
||||
{
|
||||
bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources,
|
||||
const std::vector<tx_destination_entry>& destinations,
|
||||
const std::vector<extra_v>& extra,
|
||||
const std::vector<attachment_v>& attachments,
|
||||
transaction& tx,
|
||||
uint64_t tx_version,
|
||||
crypto::secret_key& one_time_secret_key,
|
||||
uint64_t unlock_time,
|
||||
uint64_t expiration_time,
|
||||
uint8_t tx_outs_attr,
|
||||
bool shuffle,
|
||||
uint64_t flags,
|
||||
uint64_t explicit_consolidated_tx_fee,
|
||||
tx_generation_context& gen_context)
|
||||
{
|
||||
//extra copy operation, but creating transaction is not sensitive to this
|
||||
finalize_tx_param ftp{};
|
||||
ftp.tx_version = tx_version;
|
||||
ftp.sources = sources;
|
||||
ftp.prepared_destinations = destinations;
|
||||
ftp.extra = extra;
|
||||
ftp.attachments = attachments;
|
||||
ftp.unlock_time = unlock_time;
|
||||
// ftp.crypt_address = crypt_destination_addr;
|
||||
ftp.expiration_time = expiration_time;
|
||||
ftp.tx_outs_attr = tx_outs_attr;
|
||||
ftp.shuffle = shuffle;
|
||||
ftp.flags = flags;
|
||||
ftp.mode_separate_fee = explicit_consolidated_tx_fee;
|
||||
|
||||
finalized_tx ft = AUTO_VAL_INIT(ft);
|
||||
ft.tx = tx;
|
||||
ft.one_time_key = one_time_secret_key;
|
||||
ftp.gen_context = gen_context; // ftp, not ft here, this is UGLY -- sowle
|
||||
bool r = construct_tx(sender_account_keys, ftp, ft);
|
||||
tx = ft.tx;
|
||||
one_time_secret_key = ft.one_time_key;
|
||||
gen_context = ft.ftp.gen_context;
|
||||
return r;
|
||||
}
|
||||
} // namespace currency
|
||||
|
||||
void add_flags_to_all_destination_entries(const uint64_t flags, std::vector<currency::tx_destination_entry>& destinations)
|
||||
{
|
||||
for(auto& de : destinations)
|
||||
de.flags |= flags;
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
|
||||
|
||||
hard_fork_4_consolidated_txs::hard_fork_4_consolidated_txs()
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(hard_fork_4_consolidated_txs, c1);
|
||||
}
|
||||
|
||||
bool hard_fork_4_consolidated_txs::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
bool r = false;
|
||||
|
||||
uint64_t ts = test_core_time::get_time();
|
||||
m_accounts.resize(TOTAL_ACCS_COUNT);
|
||||
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
|
||||
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
|
||||
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(); bob_acc.set_createtime(ts);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
|
||||
DO_CALLBACK(events, "configure_core"); // necessary for the test to be run by GENERATE_AND_PLAY_HF
|
||||
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
m_post_hf4_zarcanum = get_hardforks().get_the_most_recent_hardfork_id_for_height(CURRENCY_MINED_MONEY_UNLOCK_WINDOW) >= ZANO_HARDFORK_04_ZARCANUM;
|
||||
|
||||
uint64_t alice_amount = MK_TEST_COINS(50);
|
||||
MAKE_TX(events, tx_0a, miner_acc, alice_acc, alice_amount, blk_0r);
|
||||
// tx_0b is only needed for decoy outputs with amount = alice_amount (important only for pre-HF4)
|
||||
transaction tx_0b{};
|
||||
construct_tx_with_many_outputs(m_hardforks, events, blk_0r, miner_acc.get_keys(), miner_acc.get_public_address(), alice_amount * 10, 10, TESTS_DEFAULT_FEE, tx_0b);
|
||||
ADD_CUSTOM_EVENT(events, tx_0b);
|
||||
MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, std::list<transaction>({tx_0a, tx_0b}));
|
||||
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
// check Alice's balance
|
||||
std::shared_ptr<tools::wallet2> alice_wlt;
|
||||
r = generator.init_test_wallet(alice_acc, get_block_hash(blk_0), alice_wlt);
|
||||
CHECK_AND_ASSERT_MES(r, false, "init_test_wallet failed");
|
||||
r = generator.refresh_test_wallet(events, alice_wlt.get(), get_block_hash(blk_1r), 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
|
||||
CHECK_AND_ASSERT_MES(r, false, "refresh_test_wallet failed");
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "alice", alice_amount, 0, alice_amount, 0, 0), false, "");
|
||||
|
||||
uint64_t miner_amount = MK_TEST_COINS(60);
|
||||
uint64_t bob_amount = miner_amount + alice_amount - TX_DEFAULT_FEE;
|
||||
|
||||
// Consolidated tx (TX_FLAG_SIGNATURE_MODE_SEPARATE).
|
||||
|
||||
// this data will be transferred between stage 1 and 2
|
||||
transaction tx_1{};
|
||||
crypto::secret_key one_time_secret_key{};
|
||||
tx_generation_context gen_context{};
|
||||
|
||||
// Part 1/2, miner's inputs
|
||||
{
|
||||
std::vector<tx_source_entry> sources;
|
||||
r = fill_tx_sources(sources, events, blk_1r, miner_acc.get_keys(), miner_amount, 10);
|
||||
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed");
|
||||
uint64_t miner_change = get_sources_total_amount(sources) - miner_amount;
|
||||
|
||||
std::vector<tx_destination_entry> destinations;
|
||||
if (miner_change != 0)
|
||||
destinations.push_back(tx_destination_entry(miner_change, miner_acc.get_public_address()));
|
||||
destinations.push_back(tx_destination_entry(bob_amount, bob_acc.get_public_address()));
|
||||
|
||||
add_flags_to_all_destination_entries(tx_destination_entry_flags::tdef_explicit_native_asset_id, destinations);
|
||||
r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_extra, empty_attachment, tx_1, get_tx_version_from_events(events), one_time_secret_key,
|
||||
0, 0, 0, true, TX_FLAG_SIGNATURE_MODE_SEPARATE, TX_DEFAULT_FEE, gen_context);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
|
||||
// partially completed tx_1 shouldn't be accepted
|
||||
//DO_CALLBACK(events, "mark_invalid_tx");
|
||||
ADD_CUSTOM_EVENT(events, tx_1);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_2a, blk_1r, miner_acc, tx_1);
|
||||
}
|
||||
|
||||
|
||||
// Part 2/2, Alice's inputs
|
||||
{
|
||||
std::vector<tx_source_entry> sources;
|
||||
r = fill_tx_sources(sources, events, blk_1r, alice_acc.get_keys(), alice_amount, 10);
|
||||
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed");
|
||||
CHECK_AND_ASSERT_MES(get_sources_total_amount(sources) == alice_amount, false, "no change for Alice is expected");
|
||||
sources.back().separately_signed_tx_complete = true;
|
||||
|
||||
std::vector<tx_destination_entry> destinations;
|
||||
|
||||
r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_extra, empty_attachment, tx_1, get_tx_version_from_events(events), one_time_secret_key,
|
||||
0, 0, 0, true, TX_FLAG_SIGNATURE_MODE_SEPARATE, 0 /* note zero fee here */, gen_context);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
|
||||
ADD_CUSTOM_EVENT(events, tx_1);
|
||||
}
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_acc, tx_1);
|
||||
|
||||
//std::shared_ptr<tools::wallet2> bob_wlt;
|
||||
//r = generator.init_test_wallet(bob_acc, get_block_hash(blk_0), bob_wlt);
|
||||
//CHECK_AND_ASSERT_MES(r, false, "init_test_wallet failed");
|
||||
//r = generator.refresh_test_wallet(events, bob_wlt.get(), get_block_hash(blk_2), 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2);
|
||||
//CHECK_AND_ASSERT_MES(r, false, "refresh_test_wallet failed");
|
||||
//CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", bob_amount, 0, 0, 0, 0), false, "");
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hard_fork_4_consolidated_txs::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
hardfork_4_explicit_native_ids_in_outs::hardfork_4_explicit_native_ids_in_outs()
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(hardfork_4_explicit_native_ids_in_outs, c1);
|
||||
|
||||
m_hardforks.clear();
|
||||
m_hardforks.set_hardfork_height(ZANO_HARDFORK_04_ZARCANUM, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
|
||||
}
|
||||
|
||||
bool hardfork_4_explicit_native_ids_in_outs::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
bool r = false;
|
||||
|
||||
uint64_t ts = test_core_time::get_time();
|
||||
m_accounts.resize(TOTAL_ACCS_COUNT);
|
||||
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
|
||||
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
|
||||
DO_CALLBACK(events, "configure_core"); // necessary to set m_hardforks
|
||||
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_hardfork_inactive", static_cast<size_t>(ZANO_HARDFORK_04_ZARCANUM));
|
||||
|
||||
// tx_0: miner -> Alice
|
||||
// make tx_0 before HF4, so Alice will have only bare outs
|
||||
m_alice_initial_balance = MK_TEST_COINS(1000);
|
||||
MAKE_TX(events, tx_0, miner_acc, alice_acc, m_alice_initial_balance, blk_0r);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0);
|
||||
|
||||
// make sure HF4 has been activated
|
||||
DO_CALLBACK_PARAMS(events, "check_hardfork_active", static_cast<size_t>(ZANO_HARDFORK_04_ZARCANUM));
|
||||
|
||||
// rewind blocks
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
// check Alice's balance and make sure she cannot deploy an asset
|
||||
DO_CALLBACK(events, "c1_alice_cannot_deploy_asset");
|
||||
|
||||
// tx_1: Alice -> Alice (all coins) : this will convert all Alice outputs to ZC outs
|
||||
MAKE_TX(events, tx_1, alice_acc, alice_acc, m_alice_initial_balance - TESTS_DEFAULT_FEE, blk_1r);
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hardfork_4_explicit_native_ids_in_outs::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
26
tests/core_tests/hard_fork_4.h
Normal file
26
tests/core_tests/hard_fork_4.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright (c) 2023-2024 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#pragma once
|
||||
#include "chaingen.h"
|
||||
#include "wallet_tests_basic.h"
|
||||
|
||||
|
||||
struct hard_fork_4_consolidated_txs : public wallet_test
|
||||
{
|
||||
hard_fork_4_consolidated_txs();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
|
||||
mutable bool m_post_hf4_zarcanum = false;
|
||||
};
|
||||
|
||||
|
||||
struct hardfork_4_explicit_native_ids_in_outs : public wallet_test
|
||||
{
|
||||
hardfork_4_explicit_native_ids_in_outs();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
|
||||
mutable uint64_t m_alice_initial_balance = 0;
|
||||
};
|
||||
|
|
@ -1619,6 +1619,7 @@ TEST(crypto, schnorr_sig)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
TEST(crypto, point_negation)
|
||||
{
|
||||
ASSERT_EQ(c_point_0, -c_point_0);
|
||||
|
|
@ -1651,6 +1652,116 @@ TEST(crypto, point_negation)
|
|||
}
|
||||
|
||||
|
||||
TEST(crypto, scalar_get_bits)
|
||||
{
|
||||
scalar_t x = scalar_t::random();
|
||||
for(size_t i = 0; i < 256; ++i)
|
||||
ASSERT_EQ(x.get_bits(i, 0), 0);
|
||||
for(size_t i = 0; i < 256; ++i)
|
||||
ASSERT_EQ(x.get_bits(i, std::min(255ull, i + 65)), 0);
|
||||
|
||||
ASSERT_EQ(x.get_bits(0, 64), x.m_u64[0]);
|
||||
ASSERT_EQ(x.get_bits(64, 64), x.m_u64[1]);
|
||||
ASSERT_EQ(x.get_bits(128, 64), x.m_u64[2]);
|
||||
ASSERT_EQ(x.get_bits(192, 64), x.m_u64[3]);
|
||||
|
||||
uint64_t high_32_bits = x.m_u64[3] >> 32;
|
||||
ASSERT_EQ(x.get_bits(192+32, 32), high_32_bits);
|
||||
|
||||
for(size_t i = 33; i <= 64; ++i)
|
||||
ASSERT_EQ(x.get_bits(192+32, i), high_32_bits);
|
||||
|
||||
for(size_t i = 0; i < 10000; ++i)
|
||||
{
|
||||
scalar_t b = scalar_t::random();
|
||||
scalar_t x = scalar_t::random();
|
||||
size_t bit_index_from = b.m_s[5];
|
||||
size_t bits_count = b.m_s[6] % 65; // [0; 64] are allowed
|
||||
|
||||
uint64_t extracted_bits = 0;
|
||||
for(size_t j = 0; j < bits_count; ++j)
|
||||
{
|
||||
if (bit_index_from + j <= 255 && x.get_bit(bit_index_from + j))
|
||||
extracted_bits |= 1ull << j;
|
||||
}
|
||||
|
||||
if (extracted_bits != x.get_bits(bit_index_from, bits_count))
|
||||
{
|
||||
std::cout << "i: " << i << ", bit_index_from: " << bit_index_from << ", bits_count: " << bits_count << ENDL
|
||||
<< "extracted_bits: " << extracted_bits << ", get_bits(): " << x.get_bits(bit_index_from, bits_count);
|
||||
ASSERT_TRUE(false);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename CT>
|
||||
bool crypto_msm_runner(size_t N, size_t low_bits_to_clear, size_t high_bits_to_clear)
|
||||
{
|
||||
scalar_vec_t g_scalars, h_scalars;
|
||||
g_scalars.resize_and_make_random(N);
|
||||
h_scalars.resize_and_make_random(N);
|
||||
if (N > 4)
|
||||
{
|
||||
g_scalars[0] = c_scalar_Lm1; // always include the max and the min
|
||||
h_scalars[0] = c_scalar_Lm1;
|
||||
g_scalars[1] = 0;
|
||||
h_scalars[1] = 0;
|
||||
}
|
||||
|
||||
point_t sum = c_point_0;
|
||||
for(size_t i = 0; i < N; ++i)
|
||||
{
|
||||
for(size_t bit_index = 0; bit_index < low_bits_to_clear; ++bit_index)
|
||||
{
|
||||
g_scalars[i].clear_bit(bit_index);
|
||||
h_scalars[i].clear_bit(bit_index);
|
||||
}
|
||||
for(size_t bit_index = 256 - high_bits_to_clear; bit_index < 256; ++bit_index)
|
||||
{
|
||||
g_scalars[i].clear_bit(bit_index);
|
||||
h_scalars[i].clear_bit(bit_index);
|
||||
}
|
||||
sum += g_scalars[i] * CT::get_generator(false, i) + h_scalars[i] * CT::get_generator(true, i);
|
||||
}
|
||||
|
||||
//TIME_MEASURE_START(t);
|
||||
bool r = msm_and_check_zero<CT>(g_scalars, h_scalars, -sum);
|
||||
//TIME_MEASURE_FINISH(t);
|
||||
return r;
|
||||
}
|
||||
|
||||
TEST(crypto, msm)
|
||||
{
|
||||
// test the default msm_and_check_zero correctness
|
||||
bool r = false;
|
||||
|
||||
for(size_t N = 1; N <= 128; ++N)
|
||||
{
|
||||
std::cout << "N = " << N << ENDL;
|
||||
r = crypto_msm_runner<bpp_crypto_trait_Zarcanum>(N, 0, 0);
|
||||
ASSERT_TRUE(r);
|
||||
r = crypto_msm_runner<bpp_crypto_trait_ZC_out>(N, 0, 0);
|
||||
ASSERT_TRUE(r);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i <= 128; ++i)
|
||||
{
|
||||
std::cout << "i = " << i << ENDL;
|
||||
r = crypto_msm_runner<bpp_crypto_trait_Zarcanum>(128, i, 0);
|
||||
ASSERT_TRUE(r);
|
||||
r = crypto_msm_runner<bpp_crypto_trait_Zarcanum>(128, 0, i);
|
||||
ASSERT_TRUE(r);
|
||||
r = crypto_msm_runner<bpp_crypto_trait_ZC_out>(256, i, 0);
|
||||
ASSERT_TRUE(r);
|
||||
r = crypto_msm_runner<bpp_crypto_trait_ZC_out>(256, 0, i);
|
||||
ASSERT_TRUE(r);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// test's runner
|
||||
//
|
||||
|
|
|
|||
|
|
@ -3,7 +3,45 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#pragma once
|
||||
|
||||
TEST(crypto, primitives)
|
||||
|
||||
uint64_t get_bits_v1(const scalar_t& s, uint8_t bit_index_first, uint8_t bits_count)
|
||||
{
|
||||
if (bits_count == 0 || bits_count > 64)
|
||||
return 0;
|
||||
unsigned int bit_index_last = bit_index_first + bits_count - 1;
|
||||
if (bit_index_last > 255)
|
||||
bit_index_last = 255;
|
||||
uint64_t result_mask = ((1ull << (bits_count - 1)) - 1) << 1 | 1; // (just because 1ull << 64 in undefined behaviour, not a 0 as one would expect)
|
||||
|
||||
uint64_t result = s.m_u64[bit_index_first >> 6] >> (bit_index_first & 63);
|
||||
if (bits_count > (bit_index_last & 63) + 1)
|
||||
result |= s.m_u64[bit_index_last >> 6] << (bits_count - (bit_index_last & 63) - 1);
|
||||
return result & result_mask;
|
||||
}
|
||||
|
||||
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::ge_precomp v)
|
||||
{
|
||||
o << "{{";
|
||||
|
||||
for(size_t i = 0; i < 9; ++i)
|
||||
o << v.yplusx[i] << ", ";
|
||||
|
||||
o << v.yplusx[9] << "},\n {";
|
||||
|
||||
for(size_t i = 0; i < 9; ++i)
|
||||
o << v.yminusx[i] << ", ";
|
||||
|
||||
o << v.yminusx[9] << "},\n {";
|
||||
|
||||
for(size_t i = 0; i < 9; ++i)
|
||||
o << v.xy2d[i] << ", ";
|
||||
|
||||
o << v.xy2d[9] << "}}\n";
|
||||
return o;
|
||||
}
|
||||
|
||||
TEST(perf, primitives)
|
||||
{
|
||||
struct helper
|
||||
{
|
||||
|
|
@ -46,6 +84,44 @@ TEST(crypto, primitives)
|
|||
|
||||
#define HASH_64_VEC(vec_var_name) hash_64(vec_var_name.data(), vec_var_name.size() * sizeof(vec_var_name[0]))
|
||||
|
||||
LOG_PRINT_L0(ENDL << "hash functions:");
|
||||
|
||||
struct run_cn_fash_hash
|
||||
{
|
||||
static uint64_t run(timer_t& t, size_t rounds, size_t data_size)
|
||||
{
|
||||
std::vector<size_t> rnd_indecies;
|
||||
helper::make_rnd_indicies(rnd_indecies, rounds);
|
||||
|
||||
struct bytes64
|
||||
{
|
||||
unsigned char b[64];
|
||||
};
|
||||
|
||||
std::vector<bytes64> scalars_64(rounds);
|
||||
for (size_t i = 0; i < scalars_64.size(); ++i)
|
||||
crypto::generate_random_bytes(sizeof(bytes64), scalars_64[i].b);
|
||||
|
||||
std::vector<hash> results(rounds);
|
||||
t.start();
|
||||
for (size_t i = 0; i < rounds; ++i)
|
||||
{
|
||||
results[i] = cn_fast_hash(scalars_64[rnd_indecies[i]].b, 64);
|
||||
}
|
||||
t.stop();
|
||||
|
||||
return HASH_64_VEC(results);
|
||||
};
|
||||
};
|
||||
|
||||
run("cn_fast_hash(64 bytes)", 1000, [](timer_t& t, size_t rounds) {
|
||||
return run_cn_fash_hash::run(t, rounds, 64ull);
|
||||
});
|
||||
|
||||
run("cn_fast_hash(2048 bytes)", 1000, [](timer_t& t, size_t rounds) {
|
||||
return run_cn_fash_hash::run(t, rounds, 2048ull);
|
||||
});
|
||||
|
||||
LOG_PRINT_L0(ENDL << "native crypto primitives:");
|
||||
|
||||
run("sc_reduce", 30000, [](timer_t& t, size_t rounds) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue