From ddcfa36a90e672ceaef9a28d2ce013a9cba93c3a Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 8 Feb 2024 17:32:41 +0100 Subject: [PATCH] crypto: general_double_schnorr_sig implemented --- src/common/crypto_serialization.h | 21 +++++- src/crypto/zarcanum.h | 108 +++++++++++++++++++++++++++++- 2 files changed, 124 insertions(+), 5 deletions(-) diff --git a/src/common/crypto_serialization.h b/src/common/crypto_serialization.h index 0b8bd62e..dd988a68 100644 --- a/src/common/crypto_serialization.h +++ b/src/common/crypto_serialization.h @@ -104,15 +104,15 @@ namespace crypto FIELD((std::vector&)(r_x)) FIELD(K1) FIELD(K2) - END_SERIALIZE() + END_SERIALIZE() - BEGIN_BOOST_SERIALIZATION() + BEGIN_BOOST_SERIALIZATION() BOOST_SERIALIZE(c) BOOST_SERIALIZE((std::vector&)(r_g)) BOOST_SERIALIZE((std::vector&)(r_x)) BOOST_SERIALIZE(K1) BOOST_SERIALIZE(K2) - END_BOOST_SERIALIZATION() + END_BOOST_SERIALIZATION() }; struct CLSAG_GGXXG_signature_serialized : public CLSAG_GGXXG_signature @@ -183,6 +183,21 @@ namespace crypto END_BOOST_SERIALIZATION() }; + struct generic_double_schnorr_sig_s : public generic_double_schnorr_sig + { + BEGIN_SERIALIZE_OBJECT() + FIELD(c) + FIELD(y0) + FIELD(y1) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(c) + BOOST_SERIALIZE(y0) + BOOST_SERIALIZE(y1) + END_BOOST_SERIALIZATION() + }; + struct BGE_proof_s : public BGE_proof { BEGIN_SERIALIZE_OBJECT() diff --git a/src/crypto/zarcanum.h b/src/crypto/zarcanum.h index b73cabf1..e78e5261 100644 --- a/src/crypto/zarcanum.h +++ b/src/crypto/zarcanum.h @@ -1,5 +1,5 @@ -// Copyright (c) 2022-2023 Zano Project -// Copyright (c) 2022-2023 sowle (val@zano.org, crypto.sowle@gmail.com) +// Copyright (c) 2022-2024 Zano Project +// Copyright (c) 2022-2024 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. // @@ -167,6 +167,110 @@ namespace crypto } } + // -------------------------------------------- + + // multi-base Schnorr-like proof (two generators, two secrets, one Fiat-Shamir challenge) + struct generic_double_schnorr_sig + { + scalar_t c; + scalar_t y0; + scalar_t y1; + }; + + template + inline bool generate_double_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, const point_t& B, const scalar_t& secret_b, generic_double_schnorr_sig& result); + + template<> + inline bool generate_double_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, const point_t& B, const scalar_t& secret_b, generic_double_schnorr_sig& result) + { +#ifndef NDEBUG + if (A != secret_a * c_point_G || B != secret_b * c_point_G) + return false; +#endif + scalar_t r0 = scalar_t::random(); + scalar_t r1 = scalar_t::random(); + point_t R0 = r0 * c_point_G; + point_t R1 = r1 * c_point_G; + hash_helper_t::hs_t hsc(5); + hsc.add_hash(m); + hsc.add_point(A); + hsc.add_point(B); + hsc.add_point(R0); + hsc.add_point(R1); + result.c = hsc.calc_hash(); + result.y0.assign_mulsub(result.c, secret_a, r0); // y0 = r0 - c * secret_a + result.y1.assign_mulsub(result.c, secret_b, r1); // y1 = r1 - c * secret_b + return true; + } + + template<> + inline bool generate_double_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, const point_t& B, const scalar_t& secret_b, generic_double_schnorr_sig& result) + { +#ifndef NDEBUG + if (A != secret_a * c_point_X || B != secret_b * c_point_G) + return false; +#endif + scalar_t r0 = scalar_t::random(); + scalar_t r1 = scalar_t::random(); + point_t R0 = r0 * c_point_X; + point_t R1 = r1 * c_point_G; + hash_helper_t::hs_t hsc(5); + hsc.add_hash(m); + hsc.add_point(A); + hsc.add_point(B); + hsc.add_point(R0); + hsc.add_point(R1); + result.c = hsc.calc_hash(); + result.y0.assign_mulsub(result.c, secret_a, r0); // y0 = r0 - c * secret_a + result.y1.assign_mulsub(result.c, secret_b, r1); // y1 = r1 - c * secret_b + return true; + } + + template + inline bool verify_double_schnorr_sig(const hash& m, const point_t& A, const public_key& B, const generic_double_schnorr_sig& sig) noexcept; + + template<> + inline bool verify_double_schnorr_sig(const hash& m, const point_t& A, const public_key& B, const generic_double_schnorr_sig& sig) noexcept + { + try + { + if (!sig.c.is_reduced() || !sig.y0.is_reduced() || !sig.y1.is_reduced()) + return false; + hash_helper_t::hs_t hsc(5); + hsc.add_hash(m); + hsc.add_point(A); + hsc.add_pub_key(B); + hsc.add_point(A.mul_plus_G(sig.c, sig.y0)); // sig.y0 * G + sig.c * A + hsc.add_point(point_t(B).mul_plus_G(sig.c, sig.y1)); // sig.y1 * G + sig.c * B + return sig.c == hsc.calc_hash(); + } + catch(...) + { + return false; + } + } + + template<> + inline bool verify_double_schnorr_sig(const hash& m, const point_t& A, const public_key& B, const generic_double_schnorr_sig& sig) noexcept + { + try + { + if (!sig.c.is_reduced() || !sig.y0.is_reduced() || !sig.y1.is_reduced()) + return false; + hash_helper_t::hs_t hsc(5); + hsc.add_hash(m); + hsc.add_point(A); + hsc.add_pub_key(B); + hsc.add_point(sig.y0 * c_point_X + sig.c * A); + hsc.add_point(point_t(B).mul_plus_G(sig.c, sig.y1)); // sig.y1 * G + sig.c * B + return sig.c == hsc.calc_hash(); + } + catch(...) + { + return false; + } + } + // TODO: improve this proof using random weightning factor struct vector_UG_aggregation_proof