1
0
Fork 0
forked from lthn/blockchain

crypto::generic_schnorr_sig + test

This commit is contained in:
sowle 2023-02-28 02:04:50 +01:00
parent 5127c77ebf
commit dd1631461d
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
2 changed files with 139 additions and 3 deletions

View file

@ -64,21 +64,107 @@ namespace crypto
scalar_t y1;
};
enum generator_tag { generator_tag_void = 0, generator_tag_G = 1, generator_tag_H = 2, generator_tag_H2 = 3, generator_tag_X = 4, generator_tag_U = 5 };
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 = generator_tag_H, generator_tag gen1 = generator_tag_G>
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 = generator_tag_H, generator_tag gen1 = generator_tag_G>
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

View file

@ -1460,6 +1460,56 @@ TEST(crypto, sc_set_bit_clear_bit)
}
TEST(crypto, schnorr_sig)
{
public_key invalid_pk = parse_tpod_from_hex_string<public_key>("0000000000000000000000000000000000000000000000000000000000000001");
ASSERT_FALSE(check_key(invalid_pk));
hash m = *(crypto::hash*)(&scalar_t::random());
for(size_t i = 0; i < 1000; ++i)
{
generic_schnorr_sig ss{};
scalar_t a = scalar_t::random();
point_t A_pt = a * c_point_G;
public_key A = A_pt.to_public_key();
ASSERT_FALSE(generate_schnorr_sig<gt_X>(m, A_pt, a, ss));
ASSERT_TRUE(generate_schnorr_sig<gt_G>(m, A_pt, a, ss));
ASSERT_FALSE(verify_schnorr_sig<gt_X>(m, A, ss));
ASSERT_TRUE(verify_schnorr_sig<gt_G>(m, A, ss));
A_pt = a * c_point_X;
A = A_pt.to_public_key();
ASSERT_FALSE(generate_schnorr_sig<gt_G>(m, A_pt, a, ss));
ASSERT_TRUE(generate_schnorr_sig<gt_X>(m, A_pt, a, ss));
ASSERT_FALSE(verify_schnorr_sig<gt_G>(m, A, ss));
ASSERT_TRUE(verify_schnorr_sig<gt_X>(m, A, ss));
ASSERT_FALSE(verify_schnorr_sig<gt_X>(currency::null_hash, A, ss));
ASSERT_FALSE(verify_schnorr_sig<gt_X>(m, invalid_pk, ss));
generic_schnorr_sig bad_ss = ss;
bad_ss.c = c_scalar_Pm1;
ASSERT_FALSE(bad_ss.c.is_reduced());
ASSERT_FALSE(verify_schnorr_sig<gt_X>(m, A, bad_ss));
bad_ss = ss;
bad_ss.y = c_scalar_Pm1;
ASSERT_FALSE(bad_ss.y.is_reduced());
ASSERT_FALSE(verify_schnorr_sig<gt_X>(m, A, bad_ss));
bad_ss = ss;
mp::uint256_t c_mp = bad_ss.c.as_boost_mp_type<mp::uint256_t>();
c_mp += c_scalar_L.as_boost_mp_type<mp::uint256_t>();
memcpy(bad_ss.c.data(), c_mp.backend().limbs(), sizeof(scalar_t));
ASSERT_FALSE(bad_ss.c.is_reduced());
scalar_t tmp(bad_ss.c);
tmp.reduce();
ASSERT_EQ(tmp, ss.c);
ASSERT_FALSE(verify_schnorr_sig<gt_X>(m, A, bad_ss));
}
}
//
// test's runner