1
0
Fork 0
forked from lthn/blockchain
blockchain/src/crypto/zarcanum.h

189 lines
6.8 KiB
C++

// Copyright (c) 2022-2023 Zano Project
// Copyright (c) 2022-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.
//
// Note: This file originates from tests/functional_tests/crypto_tests.cpp
#pragma once
#include "crypto-sugar.h"
#include "range_proofs.h"
#include "clsag.h"
#include <boost/multiprecision/cpp_int.hpp>
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::uint512_t& rhs);
struct zarcanum_proof
{
scalar_t d = 0;
public_key C; // premultiplied by 1/8
public_key C_prime; // premultiplied by 1/8
public_key E; // premultiplied by 1/8
scalar_t c; // shared Fiat-Shamir challenge for the following three proofs
scalar_t y0; // 1st linear composition proof
scalar_t y1; // ( C + C' = lin(X, H + G) )
scalar_t y2; // 2nd linear composition proof
scalar_t y3; // ( C - C' = lin(X, H - G) )
scalar_t y4; // Schnorr proof (F = lin(X))
bppe_signature E_range_proof;
crypto::public_key pseudo_out_amount_commitment; // premultiplied by 1/8
CLSAG_GGXG_signature clsag_ggxg;
};
bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector<crypto::CLSAG_GGXG_input_ref_t>& ring,
const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki,
const scalar_t& secret_x, const scalar_t& secret_q, uint64_t secret_index, const scalar_t& pseudo_out_blinding_mask, uint64_t stake_amount, const scalar_t& stake_blinding_mask,
zarcanum_proof& result, uint8_t* p_err = nullptr);
bool zarcanum_verify_proof(const hash& m, const hash& kernel_hash, const std::vector<crypto::CLSAG_GGXG_input_ref_t>& ring,
const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki,
const mp::uint128_t& pos_difficulty,
const zarcanum_proof& sig, uint8_t* p_err = nullptr) noexcept;
// TODO @#@#: make sure it is used, implement, then move it to an appropriate place
struct linear_composition_proof
{
scalar_t c;
scalar_t y0;
scalar_t y1;
};
enum generator_tag { gt_void = 0, gt_G = 1, gt_H = 2, gt_H2 = 3, gt_X = 4, gt_U = 5 };
template<generator_tag gen0 = gt_H, generator_tag gen1 = gt_G>
bool generate_linear_composition_proof(const hash& m, const public_key& A, const scalar_t& secret_a, const scalar_t& secret_b, linear_composition_proof& result, uint8_t* p_err = nullptr)
{
// consider embedding generators' tags into random entropy to distinguish proofs made with different generators during verification
return false;
}
template<generator_tag gen0 = gt_H, generator_tag gen1 = gt_G>
bool verify_linear_composition_proof(const hash& m, const public_key& A, const linear_composition_proof& sig, uint8_t* p_err = nullptr)
{
return false;
}
struct generic_schnorr_sig
{
scalar_t c;
scalar_t y;
};
template<generator_tag gen>
inline bool generate_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result);
template<>
inline bool generate_schnorr_sig<gt_G>(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result)
{
#ifndef NDEBUG
if (A != secret_a * c_point_G)
return false;
#endif
scalar_t r = scalar_t::random();
point_t R = r * c_point_G;
hash_helper_t::hs_t hsc(3);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_point(R);
result.c = hsc.calc_hash();
result.y.assign_mulsub(result.c, secret_a, r); // y = r - c * secret_a
return true;
}
template<>
inline bool generate_schnorr_sig<gt_X>(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result)
{
#ifndef NDEBUG
if (A != secret_a * c_point_X)
return false;
#endif
scalar_t r = scalar_t::random();
point_t R = r * c_point_X;
hash_helper_t::hs_t hsc(3);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_point(R);
result.c = hsc.calc_hash();
result.y.assign_mulsub(result.c, secret_a, r); // y = r - c * secret_a
return true;
}
template<generator_tag gen>
inline bool verify_schnorr_sig(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept;
template<>
inline bool verify_schnorr_sig<gt_G>(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept
{
try
{
if (!sig.c.is_reduced() || !sig.y.is_reduced())
return false;
hash_helper_t::hs_t hsc(3);
hsc.add_hash(m);
hsc.add_pub_key(A);
hsc.add_point(point_t(A).mul_plus_G(sig.c, sig.y)); // sig.y * G + sig.c * A
return sig.c == hsc.calc_hash();
}
catch(...)
{
return false;
}
}
template<>
inline bool verify_schnorr_sig<gt_X>(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept
{
try
{
if (!sig.c.is_reduced() || !sig.y.is_reduced())
return false;
hash_helper_t::hs_t hsc(3);
hsc.add_hash(m);
hsc.add_pub_key(A);
hsc.add_point(sig.y * c_point_X + sig.c * point_t(A));
return sig.c == hsc.calc_hash();
}
catch(...)
{
return false;
}
}
// TODO: improve this proof using random weightning factor
struct vector_UG_aggregation_proof
{
std::vector<public_key> amount_commitments_for_rp_aggregation; // E' = e * U + y' * G, premultiplied by 1/8
scalar_vec_t y0s;
scalar_vec_t y1s;
scalar_t c; // common challenge
};
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,
const std::vector<crypto::point_t>& amount_commitments,
const std::vector<crypto::point_t>& amount_commitments_for_rp_aggregation,
const std::vector<crypto::point_t>& blinded_asset_ids,
vector_UG_aggregation_proof& result, uint8_t* p_err = nullptr);
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;
} // namespace crypto