From 4a1b9f4958b9e533dc5247d37372d302b33fda20 Mon Sep 17 00:00:00 2001 From: Iluvmagick Date: Tue, 16 Jan 2024 18:24:53 +0400 Subject: [PATCH 1/3] Added top bit field grinding variant. --- .github/workflows/pull-request.yml | 1 + .../detail/polynomial/proof_of_work.hpp | 45 +++++++++ .../plonk/placeholder/gates_argument.hpp | 2 + test/CMakeLists.txt | 3 +- test/commitment/proof_of_work.cpp | 98 +++++++++++++++++++ 5 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 test/commitment/proof_of_work.cpp diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index c5eeba552..b8b05fec4 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -26,3 +26,4 @@ jobs: crypto3_zk_systems_plonk_plonk_constraint_test crypto3_zk_commitment_proof_of_knowledge_test crypto3_zk_transcript_transcript_test + crypto3_zk_commitment_proof_of_work_test diff --git a/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp b/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp index b63bc0c4c..c58f61f9c 100644 --- a/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp +++ b/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp @@ -27,6 +27,9 @@ #include +#include + +#include #include #include @@ -83,6 +86,48 @@ namespace nil { return ((result & mask) == 0); } }; + + template + class field_proof_of_work { + public: + using transcript_hash_type = TranscriptHashType; + using transcript_type = transcript::fiat_shamir_heuristic_sequential; + using value_type = typename FieldType::value_type; + using integral_type = typename FieldType::integral_type; + + constexpr static const integral_type mask = integral_type(MASK) << FieldType::modulus_bits - 64; + + static inline boost::property_tree::ptree get_params() { + boost::property_tree::ptree params; + params.put("mask", mask); + return params; + } + + static inline value_type generate(transcript_type &transcript) { + static boost::random::random_device dev; + static nil::crypto3::random::algebraic_engine random_engine(dev); + value_type proof_of_work = random_engine(); + integral_type result; + + while( true ) { + transcript_type tmp_transcript = transcript; + tmp_transcript(proof_of_work); + result = integral_type(tmp_transcript.template challenge().data); + if ((result & mask) == 0) + break; + proof_of_work++; + } + transcript(proof_of_work); + result = integral_type(transcript.template challenge().data); + return proof_of_work; + } + + static inline bool verify(transcript_type &transcript, value_type proof_of_work) { + transcript(proof_of_work); + integral_type result = integral_type(transcript.template challenge().data); + return ((result & mask) == 0); + } + }; } } } diff --git a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/gates_argument.hpp b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/gates_argument.hpp index 74d470f5c..11d080c34 100644 --- a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/gates_argument.hpp +++ b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/gates_argument.hpp @@ -30,11 +30,13 @@ #include #include +#include #include #include #include #include +#include #include diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 137fec07c..b2f0dfdda 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -82,6 +82,7 @@ set(TESTS_NAMES "commitment/r1cs_gg_ppzksnark_mpc" "commitment/type_traits" "commitment/kimchi_pedersen" + "commitment/proof_of_work" "math/expression" @@ -96,7 +97,7 @@ set(TESTS_NAMES "systems/plonk/pickles/oracles" "systems/plonk/pickles/to_field" "systems/plonk/pickles/to_group" - + "systems/plonk/placeholder/placeholder" "systems/plonk/placeholder/performance" diff --git a/test/commitment/proof_of_work.cpp b/test/commitment/proof_of_work.cpp new file mode 100644 index 000000000..706c616f0 --- /dev/null +++ b/test/commitment/proof_of_work.cpp @@ -0,0 +1,98 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Dmitrii Tabalin +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE proof_of_work_test + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +using namespace nil::crypto3::algebra; +using namespace nil::crypto3::zk::commitments; + +BOOST_AUTO_TEST_SUITE(proof_of_knowledge_test_suite) + +BOOST_AUTO_TEST_CASE(pow_poseidon_basic_test) { + using curve_type = curves::pallas; + using field_type = curve_type::base_field_type; + using integral_type = typename field_type::integral_type; + using policy = nil::crypto3::hashes::detail::mina_poseidon_policy; + using poseidon = nil::crypto3::hashes::poseidon; + const std::uint64_t mask = 0x1F; + using pow_type = nil::crypto3::zk::commitments::field_proof_of_work; + + nil::crypto3::zk::transcript::fiat_shamir_heuristic_sequential transcript; + auto old_transcript_1 = transcript, old_transcript_2 = transcript; + + auto result = pow_type::generate(transcript); + BOOST_ASSERT(pow_type::verify(old_transcript_1, result)); + + // manually reimplement verify to ensure that changes in implementation didn't break it + old_transcript_2(result); + auto chal = old_transcript_2.template challenge(); + integral_type int_mask = integral_type(mask) << (field_type::modulus_bits - 64); + BOOST_ASSERT((integral_type(chal.data) & int_mask) == 0); + + using hard_pow_type = nil::crypto3::zk::commitments::field_proof_of_work; + // check that random stuff doesn't pass verify + BOOST_ASSERT(!hard_pow_type::verify(old_transcript_1, result)); +} + +BOOST_AUTO_TEST_CASE(pow_basic_test) { + using keccak = nil::crypto3::hashes::keccak_1600<512>; + const std::uint32_t mask = 0xFFFFF000; + using pow_type = nil::crypto3::zk::commitments::proof_of_work; + + nil::crypto3::zk::transcript::fiat_shamir_heuristic_sequential transcript; + auto old_transcript_1 = transcript, old_transcript_2 = transcript; + + auto result = pow_type::generate(transcript); + BOOST_ASSERT(pow_type::verify(old_transcript_1, result)); + + // manually reimplement verify to ensure that changes in implementation didn't break it + std::array bytes; + bytes[0] = std::uint8_t((result & 0xFF000000) >> 24); + bytes[1] = std::uint8_t((result & 0x00FF0000) >> 16); + bytes[2] = std::uint8_t((result & 0x0000FF00) >> 8); + bytes[3] = std::uint8_t(result & 0x000000FF); + old_transcript_2(bytes); + auto chal = old_transcript_2.template int_challenge(); + BOOST_ASSERT((chal & mask) == 0); + + // check that random stuff doesn't pass verify + using hard_pow_type = nil::crypto3::zk::commitments::proof_of_work; + BOOST_ASSERT(!hard_pow_type::verify(old_transcript_1, result)); +} + +BOOST_AUTO_TEST_SUITE_END() From dd012a07e6ffd0b3e2cbba1f7d4726b6b90d0730 Mon Sep 17 00:00:00 2001 From: Iluvmagick Date: Wed, 17 Jan 2024 00:30:31 +0400 Subject: [PATCH 2/3] Changed the default/testing mask to match intent. --- .../zk/commitments/detail/polynomial/proof_of_work.hpp | 2 +- test/commitment/proof_of_work.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp b/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp index c58f61f9c..be1f8e819 100644 --- a/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp +++ b/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp @@ -87,7 +87,7 @@ namespace nil { } }; - template + template class field_proof_of_work { public: using transcript_hash_type = TranscriptHashType; diff --git a/test/commitment/proof_of_work.cpp b/test/commitment/proof_of_work.cpp index 706c616f0..7f3f768f3 100644 --- a/test/commitment/proof_of_work.cpp +++ b/test/commitment/proof_of_work.cpp @@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(pow_poseidon_basic_test) { using integral_type = typename field_type::integral_type; using policy = nil::crypto3::hashes::detail::mina_poseidon_policy; using poseidon = nil::crypto3::hashes::poseidon; - const std::uint64_t mask = 0x1F; + const std::uint64_t mask = 0xFF00000000000000; using pow_type = nil::crypto3::zk::commitments::field_proof_of_work; nil::crypto3::zk::transcript::fiat_shamir_heuristic_sequential transcript; @@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE(pow_poseidon_basic_test) { integral_type int_mask = integral_type(mask) << (field_type::modulus_bits - 64); BOOST_ASSERT((integral_type(chal.data) & int_mask) == 0); - using hard_pow_type = nil::crypto3::zk::commitments::field_proof_of_work; + using hard_pow_type = nil::crypto3::zk::commitments::field_proof_of_work; // check that random stuff doesn't pass verify BOOST_ASSERT(!hard_pow_type::verify(old_transcript_1, result)); } From 6029e9dc121c982eed359ec5ac5a6e4cfcc1dc4f Mon Sep 17 00:00:00 2001 From: Iluvmagick Date: Wed, 17 Jan 2024 15:50:23 +0400 Subject: [PATCH 3/3] Changed field PoW interface to a more intuitive one. --- .../commitments/detail/polynomial/proof_of_work.hpp | 11 +++++++++-- test/commitment/proof_of_work.cpp | 10 +++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp b/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp index be1f8e819..f7f855f1d 100644 --- a/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp +++ b/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp @@ -87,7 +87,11 @@ namespace nil { } }; - template + // Note that the interface here is slightly different from the one above: + // amount of bits for grinding instead of the mask. + // This was done because the actual mask is applied to the high bits instead of the low bits + // which makes manually setting the mask error-prone. + template class field_proof_of_work { public: using transcript_hash_type = TranscriptHashType; @@ -95,7 +99,10 @@ namespace nil { using value_type = typename FieldType::value_type; using integral_type = typename FieldType::integral_type; - constexpr static const integral_type mask = integral_type(MASK) << FieldType::modulus_bits - 64; + constexpr static const integral_type mask = + (GrindingBits > 0 ? + ((integral_type(2) << GrindingBits - 1) - 1) << (FieldType::modulus_bits - GrindingBits) + : 0); static inline boost::property_tree::ptree get_params() { boost::property_tree::ptree params; diff --git a/test/commitment/proof_of_work.cpp b/test/commitment/proof_of_work.cpp index 7f3f768f3..b514f9698 100644 --- a/test/commitment/proof_of_work.cpp +++ b/test/commitment/proof_of_work.cpp @@ -49,22 +49,22 @@ BOOST_AUTO_TEST_CASE(pow_poseidon_basic_test) { using integral_type = typename field_type::integral_type; using policy = nil::crypto3::hashes::detail::mina_poseidon_policy; using poseidon = nil::crypto3::hashes::poseidon; - const std::uint64_t mask = 0xFF00000000000000; - using pow_type = nil::crypto3::zk::commitments::field_proof_of_work; + using pow_type = nil::crypto3::zk::commitments::field_proof_of_work; + const integral_type expected_mask = integral_type(0xFF80000000000000) << (field_type::modulus_bits - 64); nil::crypto3::zk::transcript::fiat_shamir_heuristic_sequential transcript; auto old_transcript_1 = transcript, old_transcript_2 = transcript; auto result = pow_type::generate(transcript); + BOOST_ASSERT(expected_mask == pow_type::mask); BOOST_ASSERT(pow_type::verify(old_transcript_1, result)); // manually reimplement verify to ensure that changes in implementation didn't break it old_transcript_2(result); auto chal = old_transcript_2.template challenge(); - integral_type int_mask = integral_type(mask) << (field_type::modulus_bits - 64); - BOOST_ASSERT((integral_type(chal.data) & int_mask) == 0); + BOOST_ASSERT((integral_type(chal.data) & expected_mask) == 0); - using hard_pow_type = nil::crypto3::zk::commitments::field_proof_of_work; + using hard_pow_type = nil::crypto3::zk::commitments::field_proof_of_work; // check that random stuff doesn't pass verify BOOST_ASSERT(!hard_pow_type::verify(old_transcript_1, result)); }