2025-09-30 16:48:13 +01:00
// Copyright (c) 2014-2018 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Boolberry developers
// Copyright (c) 2017-2025 Lethean (https://lt.hn)
//
// Licensed under the European Union Public Licence (EUPL) version 1.2.
// You may obtain a copy of the licence at:
//
// https://joinup.ec.europa.eu/software/page/eupl/licence-eupl
//
// The EUPL is a copyleft licence that is compatible with the MIT/X11
// licence used by the original projects; the MIT terms are therefore
// considered “grandfathered” under the EUPL for this code.
//
// SPDX‑ License‑ Identifier: EUPL-1.2
2022-09-13 22:08:46 +02:00
//
2022-10-12 19:17:00 +02:00
# include "epee/include/misc_log_ex.h"
2022-09-13 22:08:46 +02:00
# include "zarcanum.h"
2023-02-27 02:56:12 +01:00
# include "range_proofs.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
2022-10-12 19:17:00 +02:00
2023-03-13 20:05:06 +01:00
#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
2022-09-13 22:08:46 +02:00
namespace crypto
{
2022-10-12 19:17:00 +02:00
const scalar_t c_zarcanum_z_coeff_s = { 0 , 1 , 0 , 0 } ; // c_scalar_2p64
2022-09-13 22:08:46 +02:00
const mp : : uint256_t c_zarcanum_z_coeff_mp = c_zarcanum_z_coeff_s . as_boost_mp_type < mp : : uint256_t > ( ) ;
2023-02-27 02:56:12 +01:00
template < typename T >
inline std : : ostream & operator < < ( std : : ostream & o , const std : : vector < T > & v )
{
for ( size_t i = 0 , n = v . size ( ) ; i < n ; + + i )
o < < ENDL < < " [ " < < std : : setw ( 2 ) < < i < < " ]: " < < v [ i ] ;
return o ;
}
2022-11-18 04:18:41 +01:00
2022-09-13 22:08:46 +02:00
mp : : uint256_t zarcanum_precalculate_l_div_z_D ( const mp : : uint128_t & pos_difficulty )
{
2022-10-12 19:17:00 +02:00
//LOG_PRINT_GREEN_L0(ENDL << "floor( l / (z * D) ) = " << c_scalar_L.as_boost_mp_type<mp::uint256_t>() / (c_zarcanum_z_coeff_mp * pos_difficulty));
2022-09-13 22:08:46 +02:00
return c_scalar_L . as_boost_mp_type < mp : : uint256_t > ( ) / ( 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 )
{
2022-10-12 19:17:00 +02:00
//LOG_PRINT_GREEN_L0(ENDL << "z * floor( l / (z * D) ) = " << c_zarcanum_z_coeff_mp * (c_scalar_L.as_boost_mp_type<mp::uint256_t>() / (c_zarcanum_z_coeff_mp * pos_difficulty)));
2022-09-13 22:08:46 +02:00
return c_zarcanum_z_coeff_mp * ( c_scalar_L . as_boost_mp_type < mp : : uint256_t > ( ) / ( 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 ,
2022-10-05 14:02:32 +02:00
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 : : uint512_t & rhs )
2022-09-13 22:08:46 +02:00
{
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 < mp : : uint256_t > ( ) ;
2022-10-05 14:02:32 +02:00
rhs = static_cast < mp : : uint512_t > ( z_l_div_z_D ) * stake_amount ; // == floor( l / (z * D) ) * z * a
2022-09-13 22:08:46 +02:00
2022-10-12 19:17:00 +02:00
//LOG_PRINT_GREEN_L0(ENDL <<
// "z_l_div_z_D = " << z_l_div_z_D << ENDL <<
// "stake_amount = " << stake_amount << ENDL <<
// "lhs = " << lhs << ENDL <<
// "rhs = " << rhs);
2022-09-13 22:08:46 +02:00
return lhs < rhs ; // h * (f + q + f') mod l < floor( l / (z * D) ) * z * a
}
2022-10-12 19:17:00 +02:00
# define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
2022-11-17 00:38:33 +01:00
if ( ! ( cond ) ) { LOG_PRINT_RED ( " zarcanum_generate_proof: \" " < < # cond < < " \" is false at " < < LOCATION_SS < < ENDL < < " error code = " < < ( int ) err_code , LOG_LEVEL_3 ) ; \
2022-10-12 19:17:00 +02:00
if ( p_err ) { * p_err = err_code ; } return false ; }
2022-10-14 19:26:52 +02:00
2023-03-20 21:25:08 +01:00
bool zarcanum_generate_proof ( const hash & m , const hash & kernel_hash , const std : : vector < CLSAG_GGXXG_input_ref_t > & ring ,
2022-10-16 03:17:18 +02:00
const scalar_t & last_pow_block_id_hashed , const key_image & stake_ki ,
2023-08-08 16:58:49 +02:00
const scalar_t & secret_x , const scalar_t & secret_q , uint64_t secret_index , uint64_t stake_amount ,
const scalar_t & stake_out_asset_id_blinding_mask , const scalar_t & stake_out_amount_blinding_mask , const scalar_t & pseudo_out_amount_blinding_mask ,
2022-10-14 19:26:52 +02:00
zarcanum_proof & result , uint8_t * p_err /* = nullptr */ )
2022-10-12 19:17:00 +02:00
{
2022-11-18 04:18:41 +01:00
DBG_PRINT ( " zarcanum_generate_proof " ) ;
2022-10-12 19:17:00 +02:00
const scalar_t a = stake_amount ;
const scalar_t h = scalar_t ( kernel_hash ) ;
2023-08-08 16:58:49 +02:00
const scalar_t f_plus_q = stake_out_amount_blinding_mask + secret_q ;
2022-10-12 19:17:00 +02:00
const scalar_t f_plus_q_plus_fp = f_plus_q + last_pow_block_id_hashed ;
const scalar_t lhs = h * f_plus_q_plus_fp ; // == h * (f + q + f') mod l
const mp : : uint256_t d_mp = lhs . as_boost_mp_type < mp : : uint256_t > ( ) / ( c_zarcanum_z_coeff_mp * stake_amount ) + 1 ;
result . d = scalar_t ( d_mp ) ;
const scalar_t dz = result . d * c_zarcanum_z_coeff_s ;
const scalar_t ba = dz * a - lhs ; // b_a = dza - h(f + q + f')
const scalar_t bf = dz * f_plus_q - h * a ; // b_f = dz(f + q) - ha
const scalar_t x0 = scalar_t : : random ( ) , x1 = scalar_t : : random ( ) , x2 = scalar_t : : random ( ) ;
const scalar_t bx = x2 - h * x1 + dz * x0 ; // b_x = x'' - hx' + dzx
point_t C = x0 * c_point_X + a * c_point_H + f_plus_q * c_point_G ;
point_t C_prime = x1 * c_point_X + f_plus_q * c_point_H + a * c_point_G ;
point_t E = bx * c_point_X + ba * c_point_H + bf * c_point_G ;
2022-10-14 19:26:52 +02:00
result . C = ( c_scalar_1div8 * C ) . to_public_key ( ) ;
result . C_prime = ( c_scalar_1div8 * C_prime ) . to_public_key ( ) ;
result . E = ( c_scalar_1div8 * E ) . to_public_key ( ) ;
2022-10-12 19:17:00 +02:00
// three proofs with a shared Fiat-Shamir challenge c
// 1) linear composition proof for the fact, that C + C' = lin(X, H + G) = (x + x') X + (a + f + q) (H + G)
// 2) linear composition proof for the fact, that C - C' = lin(X, H - G) = (x - x') X + (a - f - q) (H - G)
// 3) Schnorr proof for the fact, that hC' - dzC + E + f'hH = lin(X) = x'' X
point_t F = h * C_prime - dz * C + E + last_pow_block_id_hashed * h * c_point_H ;
2022-11-18 04:18:41 +01:00
DBG_VAL_PRINT ( h ) ; DBG_VAL_PRINT ( last_pow_block_id_hashed ) ; DBG_VAL_PRINT ( dz ) ;
DBG_VAL_PRINT ( C ) ; DBG_VAL_PRINT ( C_prime ) ; DBG_VAL_PRINT ( E ) ; DBG_VAL_PRINT ( F ) ;
2022-10-12 19:17:00 +02:00
scalar_t r0 = scalar_t : : random ( ) ;
scalar_t r1 = scalar_t : : random ( ) ;
scalar_t r2 = scalar_t : : random ( ) ;
scalar_t r3 = scalar_t : : random ( ) ;
scalar_t r4 = scalar_t : : random ( ) ;
point_t R_01 = r0 * c_point_X + r1 * c_point_H_plus_G ;
point_t R_23 = r2 * c_point_X + r3 * c_point_H_minus_G ;
2022-11-18 04:18:41 +01:00
point_t R_4 = r4 * c_point_X ;
2022-10-12 19:17:00 +02:00
2022-11-18 04:18:41 +01:00
hash_helper_t : : hs_t hash_calc ( 7 ) ;
2022-10-12 19:17:00 +02:00
hash_calc . add_32_chars ( CRYPTO_HDS_ZARCANUM_PROOF_HASH ) ;
hash_calc . add_point ( R_01 ) ;
hash_calc . add_point ( R_23 ) ;
hash_calc . add_point ( R_4 ) ;
hash_calc . add_point ( C + C_prime ) ;
hash_calc . add_point ( C - C_prime ) ;
hash_calc . add_point ( F ) ;
result . c = hash_calc . calc_hash ( ) ;
result . y0 = r0 + result . c * ( x0 + x1 ) ; // y_0 = r_0 + c (x + x')
result . y1 = r1 + result . c * ( a + f_plus_q ) ; // y_1 = r_1 + c (a + f + q)
result . y2 = r2 + result . c * ( x0 - x1 ) ; // y_2 = r_2 + c (x - x')
result . y3 = r3 + result . c * ( a - f_plus_q ) ; // y_3 = r_3 + c (a - f - q)
result . y4 = r4 + result . c * x2 ; // y_4 = r_4 + c x''
// range proof for E
2022-10-14 19:26:52 +02:00
const scalar_vec_t values = { ba } ; // H component
2022-10-12 19:17:00 +02:00
const scalar_vec_t masks = { bf } ; // G component
const scalar_vec_t masks2 = { bx } ; // X component
2022-10-14 19:26:52 +02:00
const std : : vector < const public_key * > E_1div8_vec_ptr = { & result . E } ;
2023-03-13 20:05:06 +01:00
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( bppe_gen < bpp_crypto_trait_Zarcanum > ( values , masks , masks2 , E_1div8_vec_ptr , result . E_range_proof ) , 10 ) ;
2022-10-12 19:17:00 +02:00
2023-03-20 21:25:08 +01:00
// = five-layers ring signature data outline =
2022-10-12 19:17:00 +02:00
// (j in [0, ring_size-1])
// layer 0 ring
2022-10-16 03:17:18 +02:00
// A[j] ( = ring[j].stealth_address)
2022-10-12 19:17:00 +02:00
// layer 0 secret (with respect to G)
2022-10-16 03:17:18 +02:00
// secret_x
2022-10-12 19:17:00 +02:00
// layer 0 linkability
2022-10-16 03:17:18 +02:00
// stake_ki
2022-10-12 19:17:00 +02:00
//
// layer 1 ring
2022-10-16 03:17:18 +02:00
// ring[j].amount_commitment - pseudo_out_amount_commitment
2022-10-12 19:17:00 +02:00
// layer 1 secret (with respect to G)
2023-08-08 16:58:49 +02:00
// stake_out_amount_blinding_mask - pseudo_out_amount_blinding_mask ( = f_i - f'_i )
2022-10-12 19:17:00 +02:00
//
2023-03-20 21:25:08 +01:00
// additional layer for confidential assets:
2022-10-12 19:17:00 +02:00
//
// layer 2 ring
2023-03-20 21:25:08 +01:00
// ring[j].blinded_asset_id - pseudo_out_blinded_asset_id
2022-10-12 19:17:00 +02:00
// layer 2 secret (with respect to X)
2023-03-20 21:25:08 +01:00
// -pseudo_out_asset_id_blinding_mask ( = -r'_i )
//
// additional layers for Zarcanum:
2022-10-12 19:17:00 +02:00
//
// layer 3 ring
2023-03-20 21:25:08 +01:00
// C - A[j] - Q[j]
// layer 3 secret (with respect to X)
2023-08-08 16:58:49 +02:00
// x0 - a * stake_out_asset_id_blinding_mask ( = x - a * r_i )
2023-03-20 21:25:08 +01:00
//
// layer 4 ring
2022-10-12 19:17:00 +02:00
// Q[j]
2023-03-20 21:25:08 +01:00
// layer 4 secret (with respect to G)
2022-10-12 19:17:00 +02:00
// secret_q
2022-10-19 04:42:36 +02:00
2023-08-08 16:58:49 +02:00
// such pseudo_out_asset_id_blinding_mask effectively makes pseudo_out_blinded_asset_id == currency::native_coin_asset_id_pt == point_H
scalar_t pseudo_out_asset_id_blinding_mask = - stake_out_asset_id_blinding_mask ; // T^p_i = T_i + (-r_i) * X = H
2023-03-20 21:25:08 +01:00
2023-08-08 16:58:49 +02:00
point_t stake_out_asset_id = c_point_H + stake_out_asset_id_blinding_mask * c_point_X ; // T_i = H + r_i * X
point_t pseudo_out_amount_commitment = a * stake_out_asset_id + pseudo_out_amount_blinding_mask * c_point_G ; // A^p_i = a_i * T_i + f'_i * G
result . pseudo_out_amount_commitment = ( c_scalar_1div8 * pseudo_out_amount_commitment ) . to_public_key ( ) ;
2022-10-19 04:42:36 +02:00
2022-10-16 03:17:18 +02:00
TRY_ENTRY ( )
2023-08-08 16:58:49 +02:00
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( generate_CLSAG_GGXXG ( m , ring , pseudo_out_amount_commitment , c_point_H , C , stake_ki ,
secret_x , stake_out_amount_blinding_mask - pseudo_out_amount_blinding_mask , - pseudo_out_asset_id_blinding_mask , x0 - a * stake_out_asset_id_blinding_mask , secret_q , secret_index ,
2023-03-20 21:25:08 +01:00
result . clsag_ggxxg ) , 20 ) ;
2022-10-16 03:17:18 +02:00
CATCH_ENTRY2 ( false ) ;
2022-10-12 19:17:00 +02:00
2022-10-16 03:17:18 +02:00
return true ;
2022-10-12 19:17:00 +02:00
}
2022-10-19 04:42:36 +02:00
# undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
2022-10-12 19:17:00 +02:00
2023-03-20 21:25:08 +01:00
2022-10-19 04:42:36 +02:00
# define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
2022-11-17 00:38:33 +01:00
if ( ! ( cond ) ) { LOG_PRINT_RED ( " zarcanum_verify_proof: \" " < < # cond < < " \" is false at " < < LOCATION_SS < < ENDL < < " error code = " < < ( int ) err_code , LOG_LEVEL_3 ) ; \
2022-10-19 04:42:36 +02:00
if ( p_err ) { * p_err = err_code ; } return false ; }
2023-03-20 21:25:08 +01:00
bool zarcanum_verify_proof ( const hash & m , const hash & kernel_hash , const std : : vector < CLSAG_GGXXG_input_ref_t > & ring ,
2022-10-19 04:42:36 +02:00
const scalar_t & last_pow_block_id_hashed , const key_image & stake_ki ,
2022-11-18 04:18:41 +01:00
const mp : : uint128_t & pos_difficulty ,
2023-02-26 21:45:54 +01:00
const zarcanum_proof & sig , uint8_t * p_err /* = nullptr */ ) noexcept
2022-10-12 19:17:00 +02:00
{
2023-02-26 21:45:54 +01:00
TRY_ENTRY ( )
{
DBG_PRINT ( " zarcanum_verify_proof " ) ;
2024-01-28 19:40:34 +01:00
//bool r = false;
2023-02-26 21:45:54 +01:00
2023-05-22 04:27:40 +02:00
//std::cout << "===== zarcanum_verify_proof =====" << ENDL
// << "m: " << m << ENDL
// << "kernel_hash: " << kernel_hash << ENDL
// << "last_pow_block_id_hashed: " << last_pow_block_id_hashed << ENDL
// << "stake_ki: " << stake_ki << ENDL
// << "pos_difficulty: " << pos_difficulty << ENDL;
//size_t ii = 0;
//for(const auto& el : ring)
//{
// std::cout << "[" << ii << "]" << ENDL
// << " amount_commitment: " << el.amount_commitment << ENDL
// << " blinded_asset_id: " << el.blinded_asset_id << ENDL
// << " concealing_point: " << el.concealing_point << ENDL
// << " stealth_address: " << el.stealth_address << ENDL;
//}
2023-02-26 21:45:54 +01:00
// make sure 0 < d <= l / floor(z * D)
2023-08-08 16:58:49 +02:00
const mp : : uint256_t l_div_z_D_mp = zarcanum_precalculate_l_div_z_D ( pos_difficulty ) ;
2023-02-26 21:45:54 +01:00
const scalar_t l_div_z_D ( l_div_z_D_mp ) ;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( ! sig . d . is_zero ( ) & & sig . d < l_div_z_D , 2 ) ;
const scalar_t dz = sig . d * c_zarcanum_z_coeff_s ;
// calculate h
const scalar_t h = scalar_t ( kernel_hash ) ;
// calculate F
point_t C_prime = point_t ( sig . C_prime ) ;
C_prime . modify_mul8 ( ) ;
point_t C = point_t ( sig . C ) ;
C . modify_mul8 ( ) ;
point_t E = point_t ( sig . E ) ;
E . modify_mul8 ( ) ;
point_t F = h * C_prime - dz * C + E + last_pow_block_id_hashed * h * c_point_H ;
DBG_VAL_PRINT ( h ) ; DBG_VAL_PRINT ( last_pow_block_id_hashed ) ; DBG_VAL_PRINT ( dz ) ;
DBG_VAL_PRINT ( C ) ; DBG_VAL_PRINT ( C_prime ) ; DBG_VAL_PRINT ( E ) ; DBG_VAL_PRINT ( F ) ;
// check three proofs with a shared Fiat-Shamir challenge c
point_t C_plus_C_prime = C + C_prime ;
point_t C_minus_C_prime = C - C_prime ;
hash_helper_t : : hs_t hash_calc ( 7 ) ;
hash_calc . add_32_chars ( CRYPTO_HDS_ZARCANUM_PROOF_HASH ) ;
hash_calc . add_point ( sig . y0 * c_point_X + sig . y1 * c_point_H_plus_G - sig . c * C_plus_C_prime ) ; // y_0 * X + y1 (H + G) - c (C + C')
hash_calc . add_point ( sig . y2 * c_point_X + sig . y3 * c_point_H_minus_G - sig . c * C_minus_C_prime ) ; // y_2 * X + y3 (H - G) - c (C - C')
hash_calc . add_point ( sig . y4 * c_point_X - sig . c * F ) ; // y_4 * X - c * F
hash_calc . add_point ( C_plus_C_prime ) ;
hash_calc . add_point ( C_minus_C_prime ) ;
hash_calc . add_point ( F ) ;
scalar_t c_prime = hash_calc . calc_hash ( ) ;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( sig . c = = c_prime , 3 ) ;
// check extended range proof for E
std : : vector < point_t > E_for_range_proof = { point_t ( sig . E ) } ; // consider changing to 8*sig.E to avoid additional conversion
std : : vector < bppe_sig_commit_ref_t > range_proofs = { bppe_sig_commit_ref_t ( sig . E_range_proof , E_for_range_proof ) } ;
2023-03-13 20:05:06 +01:00
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( bppe_verify < bpp_crypto_trait_Zarcanum > ( range_proofs ) , 10 ) ;
2023-02-26 21:45:54 +01:00
2023-08-08 16:58:49 +02:00
static public_key native_coin_asset_id = ( c_scalar_1div8 * c_point_H ) . to_public_key ( ) ; // consider making it less ugly -- sowle
2023-03-20 21:25:08 +01:00
2023-02-26 21:45:54 +01:00
// check extended CLSAG-GGXG ring signature
2023-03-20 21:25:08 +01:00
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( verify_CLSAG_GGXXG ( m , ring , sig . pseudo_out_amount_commitment , native_coin_asset_id , sig . C , stake_ki , sig . clsag_ggxxg ) , 1 ) ;
2023-02-26 21:45:54 +01:00
}
CATCH_ENTRY_CUSTOM2 ( { if ( p_err ) * p_err = 100 ; } , false )
2022-10-19 04:42:36 +02:00
2023-02-26 21:45:54 +01:00
return true ;
}
2022-11-18 04:18:41 +01:00
2023-02-26 21:45:54 +01:00
# undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
2022-11-18 04:18:41 +01:00
2022-10-25 04:16:25 +02:00
2023-02-26 21:45:54 +01:00
# define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if ( ! ( cond ) ) { LOG_PRINT_RED ( " generate_vector_UG_aggregation_proof: \" " < < # cond < < " \" is false at " < < LOCATION_SS < < ENDL < < " error code = " < < ( int ) err_code , LOG_LEVEL_3 ) ; \
if ( p_err ) { * p_err = err_code ; } return false ; }
2022-11-18 04:18:41 +01:00
2023-03-02 22:06:42 +01:00
bool generate_vector_UG_aggregation_proof ( const hash & m , const scalar_vec_t & u_secrets , const scalar_vec_t & g_secrets0 , const scalar_vec_t & g_secrets1 ,
2023-02-26 21:45:54 +01:00
const std : : vector < point_t > & amount_commitments ,
const std : : vector < point_t > & amount_commitments_for_rp_aggregation ,
const std : : vector < point_t > & blinded_asset_ids ,
vector_UG_aggregation_proof & result , uint8_t * p_err /* = nullptr */ )
{
2023-03-02 22:06:42 +01:00
// w - public random weighting factor
2023-02-26 21:45:54 +01:00
// proof of knowing e_j and y'' in zero knowledge in the following eq:
2023-03-02 22:06:42 +01:00
// E_j + w * E'_j = e_j * (T'_j + w * U) + (y_j + w * y'_j) * G
2023-02-26 21:45:54 +01:00
// where:
// e_j -- output's amount
// T'_j -- output's blinded asset tag
// E_j == e_j * T'_j + y_j * G -- output's amount commitments
// E'_j == e_j * U + y'_j * G -- additional commitment to the same amount for range proof aggregation
2023-03-02 22:06:42 +01:00
// amount_commitments[j] + w * amount_commitments_for_rp_aggregation[j]
2023-02-26 21:45:54 +01:00
// ==
2023-03-02 22:06:42 +01:00
// u_secrets[j] * (blinded_asset_ids[j] + w * U) + (g_secrets0[j] + w * g_secrets1[j]) * G
2023-02-26 21:45:54 +01:00
const size_t n = u_secrets . size ( ) ;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( n ! = 0 , 1 ) ;
2023-03-02 22:06:42 +01:00
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( n = = g_secrets0 . size ( ) , 2 ) ;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( n = = g_secrets1 . size ( ) , 3 ) ;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( n = = amount_commitments . size ( ) , 4 ) ;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( n = = amount_commitments_for_rp_aggregation . size ( ) , 5 ) ;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( n = = blinded_asset_ids . size ( ) , 6 ) ;
2023-08-08 16:58:49 +02:00
hash_helper_t : : hs_t hash_calculator ( 1 + 3 * n ) ;
2023-03-02 22:06:42 +01:00
hash_calculator . add_hash ( m ) ;
hash_calculator . add_points_array ( amount_commitments ) ;
hash_calculator . add_points_array ( amount_commitments_for_rp_aggregation ) ;
scalar_t w = hash_calculator . calc_hash ( false ) ; // don't clean the buffer
DBG_VAL_PRINT ( w ) ;
2023-02-26 21:45:54 +01:00
2023-02-27 02:56:12 +01:00
# ifndef NDEBUG
for ( size_t j = 0 ; j < n ; + + j )
2023-08-08 16:58:49 +02:00
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( amount_commitments [ j ] + w * amount_commitments_for_rp_aggregation [ j ] = = u_secrets [ j ] * ( blinded_asset_ids [ j ] + w * c_point_U ) + ( g_secrets0 [ j ] + w * g_secrets1 [ j ] ) * c_point_G , 20 ) ;
2023-02-27 02:56:12 +01:00
# endif
2023-02-26 21:45:54 +01:00
result . amount_commitments_for_rp_aggregation . clear ( ) ;
result . y0s . clear ( ) ;
result . y1s . clear ( ) ;
2023-08-08 16:58:49 +02:00
scalar_vec_t r0 , r1 ;
2023-02-26 21:45:54 +01:00
r0 . resize_and_make_random ( n ) ;
r1 . resize_and_make_random ( n ) ;
2023-08-08 16:58:49 +02:00
std : : vector < point_t > asset_tag_plus_U_vec ( n ) ;
2023-02-26 21:45:54 +01:00
for ( size_t j = 0 ; j < n ; + + j )
2023-08-08 16:58:49 +02:00
asset_tag_plus_U_vec [ j ] = blinded_asset_ids [ j ] + w * c_point_U ;
2023-02-26 21:45:54 +01:00
2023-08-08 16:58:49 +02:00
std : : vector < point_t > R ( n ) ;
2023-02-26 21:45:54 +01:00
for ( size_t j = 0 ; j < n ; + + j )
2023-03-02 22:06:42 +01:00
R [ j ] . assign_mul_plus_G ( r0 [ j ] , asset_tag_plus_U_vec [ j ] , r1 [ j ] ) ; // R[j] = r0[j] * asset_tag_plus_U_vec[j] + r1[j] * G
2023-02-26 21:45:54 +01:00
hash_calculator . add_points_array ( R ) ;
result . c = hash_calculator . calc_hash ( ) ;
2023-02-27 02:56:12 +01:00
DBG_VAL_PRINT ( asset_tag_plus_U_vec ) ; DBG_VAL_PRINT ( m ) ; DBG_VAL_PRINT ( amount_commitments ) ; DBG_VAL_PRINT ( amount_commitments_for_rp_aggregation ) ; DBG_VAL_PRINT ( R ) ;
DBG_VAL_PRINT ( result . c ) ;
2023-02-26 21:45:54 +01:00
for ( size_t j = 0 ; j < n ; + + j )
{
result . y0s . emplace_back ( r0 [ j ] - result . c * u_secrets [ j ] ) ;
2023-03-02 22:06:42 +01:00
result . y1s . emplace_back ( r1 [ j ] - result . c * ( g_secrets0 [ j ] + w * g_secrets1 [ j ] ) ) ;
2023-08-08 16:58:49 +02:00
result . amount_commitments_for_rp_aggregation . emplace_back ( ( c_scalar_1div8 * amount_commitments_for_rp_aggregation [ j ] ) . to_public_key ( ) ) ;
2023-02-26 21:45:54 +01:00
}
return true ;
}
# undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
2022-11-18 04:18:41 +01:00
2022-10-19 04:42:36 +02:00
2023-02-26 21:45:54 +01:00
# define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if ( ! ( cond ) ) { LOG_PRINT_RED ( " verify_vector_UG_aggregation_proof: \" " < < # cond < < " \" is false at " < < LOCATION_SS < < ENDL < < " error code = " < < ( int ) err_code , LOG_LEVEL_3 ) ; \
if ( p_err ) { * p_err = err_code ; } return false ; }
2022-10-19 04:42:36 +02:00
2023-02-26 21:45:54 +01:00
bool verify_vector_UG_aggregation_proof ( const hash & m , const std : : vector < const public_key * > amount_commitments_1div8 , const std : : vector < const public_key * > blinded_asset_ids_1div8 ,
const vector_UG_aggregation_proof & sig , uint8_t * p_err /* = nullptr */ ) noexcept
{
TRY_ENTRY ( )
{
const size_t n = amount_commitments_1div8 . size ( ) ;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( n > 0 , 1 ) ;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( blinded_asset_ids_1div8 . size ( ) = = n , 2 ) ;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( sig . amount_commitments_for_rp_aggregation . size ( ) = = n , 3 ) ;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( sig . y0s . size ( ) = = n , 4 ) ;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( sig . y1s . size ( ) = = n , 5 ) ;
2023-08-08 16:58:49 +02:00
hash_helper_t : : hs_t hash_calculator ( 1 + 3 * n ) ;
2023-02-26 21:45:54 +01:00
hash_calculator . add_hash ( m ) ;
2023-02-27 02:56:12 +01:00
DBG_VAL_PRINT ( m ) ;
2023-02-26 21:45:54 +01:00
std : : vector < point_t > amount_commitments_pt ;
for ( size_t j = 0 ; j < n ; + + j )
{
2023-08-08 16:58:49 +02:00
point_t A = point_t ( * amount_commitments_1div8 [ j ] ) . modify_mul8 ( ) ;
2023-02-26 21:45:54 +01:00
hash_calculator . add_point ( A ) ;
amount_commitments_pt . emplace_back ( A ) ;
2023-02-27 02:56:12 +01:00
DBG_VAL_PRINT ( A ) ;
2023-02-26 21:45:54 +01:00
}
2023-02-27 02:56:12 +01:00
std : : vector < point_t > amount_commitments_for_rp_aggregation_pt ;
for ( size_t j = 0 ; j < n ; + + j )
{
2023-08-08 16:58:49 +02:00
point_t Arpa = point_t ( sig . amount_commitments_for_rp_aggregation [ j ] ) . modify_mul8 ( ) ;
2023-02-27 02:56:12 +01:00
hash_calculator . add_point ( Arpa ) ; // TODO @#@ performance: consider adding premultiplied by 1/8 points to the hash
amount_commitments_for_rp_aggregation_pt . emplace_back ( Arpa ) ;
DBG_VAL_PRINT ( Arpa ) ;
}
2023-02-26 21:45:54 +01:00
2023-03-02 22:06:42 +01:00
scalar_t w = hash_calculator . calc_hash ( false ) ; // don't clear the buffer
DBG_VAL_PRINT ( w ) ;
2023-08-08 16:58:49 +02:00
std : : vector < point_t > asset_tag_plus_U_vec ( n ) ;
2023-03-02 22:06:42 +01:00
for ( size_t j = 0 ; j < n ; + + j )
2023-08-08 16:58:49 +02:00
asset_tag_plus_U_vec [ j ] = point_t ( * blinded_asset_ids_1div8 [ j ] ) . modify_mul8 ( ) + w * c_point_U ;
2023-03-02 22:06:42 +01:00
DBG_VAL_PRINT ( asset_tag_plus_U_vec ) ;
2023-02-26 21:45:54 +01:00
for ( size_t j = 0 ; j < n ; + + j )
2023-02-27 02:56:12 +01:00
{
2023-08-08 16:58:49 +02:00
hash_calculator . add_pub_key ( point_t (
2023-02-27 02:56:12 +01:00
sig . y0s [ j ] * asset_tag_plus_U_vec [ j ] +
2023-08-08 16:58:49 +02:00
sig . y1s [ j ] * c_point_G +
2023-03-02 22:06:42 +01:00
sig . c * ( amount_commitments_pt [ j ] + w * amount_commitments_for_rp_aggregation_pt [ j ] )
2023-02-27 02:56:12 +01:00
) . to_public_key ( ) ) ;
DBG_VAL_PRINT ( hash_calculator . m_elements . back ( ) . pk ) ;
}
2023-02-26 21:45:54 +01:00
2023-08-08 16:58:49 +02:00
scalar_t c = hash_calculator . calc_hash ( ) ;
2023-02-27 02:56:12 +01:00
DBG_VAL_PRINT ( c ) ; DBG_VAL_PRINT ( sig . c ) ;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE ( sig . c = = c , 0 ) ;
2023-02-26 21:45:54 +01:00
}
CATCH_ENTRY_CUSTOM2 ( { if ( p_err ) * p_err = 100 ; } , false )
2022-10-19 04:42:36 +02:00
return true ;
2022-10-12 19:17:00 +02:00
}
2023-02-26 21:45:54 +01:00
# undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
2022-11-18 04:18:41 +01:00
2022-10-12 19:17:00 +02:00
2022-09-13 22:08:46 +02:00
} // namespace crypto