1
0
Fork 0
forked from lthn/blockchain

Merge branch 'cryptoassets' into decoy_selection

This commit is contained in:
cryptozoidberg 2024-01-20 16:39:50 +01:00
commit 95e8954c38
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
17 changed files with 727 additions and 110 deletions

View file

@ -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
View 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
View 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: Horners 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

View file

@ -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;

View file

@ -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;

View file

@ -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"

View file

@ -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()
<< ")"
<< "))");

View file

@ -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;

View file

@ -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
{

View file

@ -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;
}
//-----------------------------------------------------------------------

View file

@ -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 "]"

View file

@ -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);

View file

@ -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"

View 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;
}
*/

View 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;
};

View file

@ -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
//

View file

@ -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) {