From af9c53794eb9249a49f03d55402e57ac0c2a8709 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 13 Sep 2022 22:08:46 +0200 Subject: [PATCH] 1) zarcanum math moved to separate file; 2) fixed an error in rhs calculation; 3) 2^64 constant + test --- src/crypto/crypto-sugar.cpp | 1 + src/crypto/crypto-sugar.h | 1 + src/crypto/zarcanum.cpp | 33 +++++++++++++++++++++++++ src/crypto/zarcanum.h | 25 +++++++++++++++++++ src/wallet/wallet2.cpp | 17 +++++++------ src/wallet/wallet2.h | 2 +- tests/functional_tests/crypto_tests.cpp | 3 +++ 7 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 src/crypto/zarcanum.cpp create mode 100644 src/crypto/zarcanum.h diff --git a/src/crypto/crypto-sugar.cpp b/src/crypto/crypto-sugar.cpp index bead23df..36ccfeae 100644 --- a/src/crypto/crypto-sugar.cpp +++ b/src/crypto/crypto-sugar.cpp @@ -13,6 +13,7 @@ namespace crypto const point_g_t c_point_G; const scalar_t c_scalar_1 = { 1 }; + const scalar_t c_scalar_2p64 = { 0, 1, 0, 0 }; const scalar_t c_scalar_L = { 0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0x0, 0x1000000000000000 }; const scalar_t c_scalar_Lm1 = { 0x5812631a5cf5d3ec, 0x14def9dea2f79cd6, 0x0, 0x1000000000000000 }; const scalar_t c_scalar_P = { 0xffffffffffffffed, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff }; diff --git a/src/crypto/crypto-sugar.h b/src/crypto/crypto-sugar.h index 59503eff..280a8f79 100644 --- a/src/crypto/crypto-sugar.h +++ b/src/crypto/crypto-sugar.h @@ -456,6 +456,7 @@ namespace crypto // extern const scalar_t c_scalar_1; + extern const scalar_t c_scalar_2p64; extern const scalar_t c_scalar_L; extern const scalar_t c_scalar_Lm1; extern const scalar_t c_scalar_P; diff --git a/src/crypto/zarcanum.cpp b/src/crypto/zarcanum.cpp new file mode 100644 index 00000000..f000139f --- /dev/null +++ b/src/crypto/zarcanum.cpp @@ -0,0 +1,33 @@ +// Copyright (c) 2022 Zano Project +// Copyright (c) 2022 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. +// +// Note: This file originates from tests/functional_tests/crypto_tests.cpp +#include "zarcanum.h" +namespace crypto +{ + const scalar_t c_zarcanum_z_coeff_s = c_scalar_2p64; + const mp::uint256_t c_zarcanum_z_coeff_mp = c_zarcanum_z_coeff_s.as_boost_mp_type(); + + mp::uint256_t zarcanum_precalculate_l_div_z_D(const mp::uint128_t& pos_difficulty) + { + return c_scalar_L.as_boost_mp_type() / (c_zarcanum_z_coeff_mp * pos_difficulty); // == floor( l / (z * D) ) + } + + mp::uint256_t zarcanum_precalculate_z_l_div_z_D(const mp::uint128_t& pos_difficulty) + { + return c_zarcanum_z_coeff_mp * (c_scalar_L.as_boost_mp_type() / (c_zarcanum_z_coeff_mp * pos_difficulty)); // == z * floor( l / (z * D) ) + } + + bool zarcanum_check_main_pos_inequality(const hash& kernel_hash, const scalar_t& blinding_mask, const scalar_t& secret_q, + const scalar_t& last_pow_block_id_hashed, const mp::uint256_t& z_l_div_z_D, uint64_t stake_amount, mp::uint256_t& lhs, mp::uint256_t& rhs) + { + scalar_t lhs_s = scalar_t(kernel_hash) * (blinding_mask + secret_q + last_pow_block_id_hashed); // == h * (f + q + f') mod l + lhs = lhs_s.as_boost_mp_type(); + rhs = z_l_div_z_D * stake_amount; // == floor( l / (z * D) ) * z * a + + return lhs < rhs; // h * (f + q + f') mod l < floor( l / (z * D) ) * z * a + } + +} // namespace crypto diff --git a/src/crypto/zarcanum.h b/src/crypto/zarcanum.h new file mode 100644 index 00000000..daaa1b4e --- /dev/null +++ b/src/crypto/zarcanum.h @@ -0,0 +1,25 @@ +// Copyright (c) 2022 Zano Project +// Copyright (c) 2022 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. +// +// Note: This file originates from tests/functional_tests/crypto_tests.cpp +#pragma once +#include "crypto-sugar.h" +#include + +namespace crypto +{ + namespace mp = boost::multiprecision; + + extern const mp::uint256_t c_zarcanum_z_coeff_mp; + extern const scalar_t c_zarcanum_z_coeff_s; + + mp::uint256_t zarcanum_precalculate_l_div_z_D(const mp::uint128_t& pos_difficulty); + mp::uint256_t zarcanum_precalculate_z_l_div_z_D(const mp::uint128_t& pos_difficulty); + + bool zarcanum_check_main_pos_inequality(const hash& kernel_hash, const scalar_t& blinding_mask, const scalar_t& secret_q, + const scalar_t& last_pow_block_id_hashed, const mp::uint256_t& z_l_div_z_D_, uint64_t stake_amount, mp::uint256_t& lhs, mp::uint256_t& rhs); + + +} // namespace crypto diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index aef50521..a3d7409d 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -38,6 +38,7 @@ using namespace epee; #include "storages/levin_abstract_invoke2.h" #include "common/variant_helper.h" #include "currency_core/crypto_config.h" +#include "crypto/zarcanum.h" using namespace currency; @@ -3636,7 +3637,7 @@ bool wallet2::fill_mining_context(mining_context& ctx) // Zarcanum (PoS with hidden amounts) ctx.zarcanum = true; ctx.last_pow_block_id_hashed = crypto::hash_helper_t::hs(CRYPTO_HDS_ZARCANUM_LAST_POW_HASH, ctx.sk.stake_modifier.last_pow_id); - ctx.l_div_z_D = crypto::c_scalar_L.as_boost_mp_type() / (ctx.basic_diff); + ctx.z_l_div_z_D = crypto::zarcanum_precalculate_z_l_div_z_D(ctx.basic_diff); } ctx.last_block_hash = pos_details_resp.last_block_hash; @@ -3718,12 +3719,13 @@ bool wallet2::do_pos_mining_iteration(mining_context& context, size_t transfer_i if (context.zarcanum && td.is_zc()) { - PROFILE_FUNC("check_zarcanum"); - crypto::scalar_t lhs_s = crypto::scalar_t(kernel_hash) * (*td.m_opt_blinding_mask + context.secret_q + context.last_pow_block_id_hashed); // == h * (f + q + f') mod l - boost::multiprecision::uint256_t lhs = lhs_s.as_boost_mp_type(); - boost::multiprecision::uint256_t rhs = context.l_div_z_D * stake_amount; // == floor( l / (z * D) ) * a - - if (lhs < rhs) + crypto::mp::uint256_t lhs, rhs; + { + PROFILE_FUNC("check_zarcanum"); + found = crypto::zarcanum_check_main_pos_inequality(kernel_hash, *td.m_opt_blinding_mask, context.secret_q, context.last_pow_block_id_hashed, context.z_l_div_z_D, stake_amount, lhs, rhs); + ++context.iterations_processed; + } + if (found) { found = true; LOG_PRINT_GREEN("Found Zarcanum kernel: amount: " << currency::print_money_brief(stake_amount) << ", gindex: " << td.m_global_output_index << ENDL @@ -3736,7 +3738,6 @@ bool wallet2::do_pos_mining_iteration(mining_context& context, size_t transfer_i , LOG_LEVEL_0); } - ++context.iterations_processed; } else { diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 2f43f0eb..621e7aa9 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -463,7 +463,7 @@ namespace tools crypto::scalar_t last_pow_block_id_hashed; // Zarcanum notation: f' crypto::scalar_t secret_q; // Zarcanum notation: q - boost::multiprecision::uint256_t l_div_z_D; // Zarcanum notation: floor( l / (z * D) ) (max possible value: 2^252 / (2^64 * 1) ~= 2^188, or 2^252 / (1 * 1) = 2^252) + boost::multiprecision::uint256_t z_l_div_z_D; // Zarcanum notation: z * floor( l / (z * D) ) (max possible value: 2^64 * 2^252 / (2^64 * 1) ~= 2^252, or 2^252 / (1 * 1) = 2^252) currency::wide_difficulty_type basic_diff; currency::stake_kernel sk; diff --git a/tests/functional_tests/crypto_tests.cpp b/tests/functional_tests/crypto_tests.cpp index 2a08499c..0b7c5a71 100644 --- a/tests/functional_tests/crypto_tests.cpp +++ b/tests/functional_tests/crypto_tests.cpp @@ -863,6 +863,9 @@ TEST(crypto, scalar_basics) mp::uint256_t mp_p_mod_l = c_scalar_P.as_boost_mp_type() % c_scalar_L.as_boost_mp_type(); ASSERT_EQ(p, scalar_t(mp_p_mod_l)); + ASSERT_EQ(c_scalar_2p64 - c_scalar_1, scalar_t(UINT64_MAX)); + ASSERT_EQ(c_scalar_2p64, scalar_t(UINT64_MAX) + c_scalar_1); + return true; }