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 28be4b534..3e3f7c766 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 @@ -104,19 +104,19 @@ namespace nil { while( true ) { transcript_type tmp_transcript = transcript; - tmp_transcript(proof_of_work); + tmp_transcript(std::array{proof_of_work}); result = integral_type(tmp_transcript.template challenge().data); if ((result & mask) == 0) break; proof_of_work++; } - transcript(proof_of_work); + transcript(std::array{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, std::size_t GrindingBits=16) { - transcript(proof_of_work); + transcript(std::array{proof_of_work}); integral_type mask = (GrindingBits > 0 ? ((integral_type(1) << GrindingBits) - 1) << (FieldType::modulus_bits - GrindingBits) diff --git a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/preprocessor.hpp b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/preprocessor.hpp index d2118043e..29880f4bf 100644 --- a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/preprocessor.hpp +++ b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/preprocessor.hpp @@ -117,7 +117,7 @@ namespace nil { // TODO: KZG fixed_values_commitments are vector // need operator<<(ostream,vector)? - ss << constraint_system_with_params_hash /*<< " " << fixed_values_commitment*/; + ss << constraint_system_with_params_hash[0] /*<< " " << fixed_values_commitment*/; // HACK return ss.str(); } }; diff --git a/include/nil/crypto3/zk/transcript/fiat_shamir.hpp b/include/nil/crypto3/zk/transcript/fiat_shamir.hpp index c8887f150..4eec8eb1a 100644 --- a/include/nil/crypto3/zk/transcript/fiat_shamir.hpp +++ b/include/nil/crypto3/zk/transcript/fiat_shamir.hpp @@ -30,23 +30,19 @@ #include #include -#include #include -#include #include +#include +#include +#include +#include #include #include -#include - -#include -#include -#include -#include -#include -#include +#include #include + namespace nil { namespace crypto3 { namespace zk { @@ -88,10 +84,18 @@ namespace nil { template void operator()(TAny data) { - nil::marshalling::status_type status; - typename hash_type::construction::type::block_type byte_data = - nil::marshalling::pack(data, status); - acc(byte_data); + if constexpr (algebra::is_field_element::value) { + BOOST_STATIC_ASSERT_MSG( + algebra::is_field_element::value, + "Hash type consumes field elements, but provided value is not a field element" + ); + acc(data); + } else { + nil::marshalling::status_type status; + typename hash_type::construction::type::block_type byte_data = + nil::marshalling::pack(data, status); + acc(byte_data); + } } template @@ -127,7 +131,6 @@ namespace nil { } }; - template struct fiat_shamir_heuristic_sequential { @@ -196,55 +199,91 @@ namespace nil { typename hash_type::digest_type state; }; - // Specialize for posseidon. + // Specialize for Nil Posseidon. template struct fiat_shamir_heuristic_sequential< - Hash, - typename std::enable_if_t::value>> { - - typedef Hash hash_type; - using field_type = nil::crypto3::algebra::curves::pallas::base_field_type; - using poseidon_policy = nil::crypto3::hashes::detail::mina_poseidon_policy; - using permutation_type = nil::crypto3::hashes::detail::poseidon_permutation; - using state_type = typename permutation_type::state_type; - - fiat_shamir_heuristic_sequential() { + Hash, + typename std::enable_if_t< + nil::crypto3::hashes::is_specialization_of< + nil::crypto3::hashes::nil_poseidon, + Hash + >::value + > + > { + // Differences from other hashes fiat_shamir_heuristic_sequential are: + // challenge(), int_challange(), no-args ctor and last_call_was_challenge_ field + + using hash_type = Hash; + + fiat_shamir_heuristic_sequential() : state{0} { } template - fiat_shamir_heuristic_sequential(const InputRange &r) { - if(r.size() != 0) { - sponge.absorb(hash(r)); - } + fiat_shamir_heuristic_sequential(const InputRange &r) : state(hash(r)) { } template - fiat_shamir_heuristic_sequential(InputIterator first, InputIterator last) { - sponge.absorb(hash(first, last)); - } - - void operator()(const typename hash_type::digest_type input) { - sponge.absorb(input); + fiat_shamir_heuristic_sequential(InputIterator first, InputIterator last) : + state(hash(first, last)) { } template void operator()(const InputRange &r) { - sponge.absorb(hash(r)); + auto acc_convertible = hash(state); + state = accumulators::extract::hash( + hash(r, static_cast &>(acc_convertible))); + last_call_was_challenge_ = false; } template void operator()(InputIterator first, InputIterator last) { - sponge.absorb(hash(first, last)); + auto acc_convertible = hash(state); + state = accumulators::extract::hash( + hash(first, last, static_cast &>(acc_convertible))); + last_call_was_challenge_ = false; } template typename Field::value_type challenge() { - return sponge.squeeze(); + // After refactoring an attempt to remove this Nil Poseidon specialization was made. + // The difference between challenge() for other hashes and for Nil Poseidon is + // how the second challenge is produced. For the first call things are the same: + // we feed the result A (aka state in current code) of hash from operator() to hash, it + // puts A to sponge_state[1] (read about nil_poseidon_sponge, if you're wondered why not + // sponge_state[0]), then calls squeeze(). But for the second challenge thigs are + // different: other hashes feed state B to hash again (in case of Nil Poseidon state will + // be put to sponge_state[1]), but here we just run squeeze() (B is located in sponge_state[0]). + std::cout << "in challange, state before extraction: " << std::endl; + for (const auto& el : state) { + std::cout << el << std::endl; + } + + if (last_call_was_challenge_) { + // In case previous called func was challenge() as well, we want to + // mimic sequential squeeze() calls + typename hash_type::construction::type::state_type sponge_state{}; + std::move(state.begin(), state.end(), sponge_state.begin()); + typename hash_type::construction::type sponge{ + typename hash_type::construction::type::state_type{sponge_state} + }; + state = sponge.digest(); + } else { + accumulator_set acc; + for (auto& el : state) { + acc(std::move(el)); + } + state = accumulators::extract::hash(acc); + } + + nil::marshalling::status_type status; + nil::crypto3::multiprecision::cpp_int raw_result = nil::marshalling::pack(state, status); + last_call_was_challenge_ = true; + return raw_result; } template Integral int_challenge() { - auto c = challenge(); + auto c = challenge(); nil::crypto3::multiprecision::cpp_int intermediate_result = c.data.template convert_to(); @@ -272,7 +311,8 @@ namespace nil { } private: - hashes::detail::poseidon_sponge_construction sponge; + typename hash_type::digest_type state; + bool last_call_was_challenge_ = false; // Ctors call absorb }; } // namespace transcript diff --git a/test/commitment/proof_of_work.cpp b/test/commitment/proof_of_work.cpp index b9efa0b16..ec1f41dff 100644 --- a/test/commitment/proof_of_work.cpp +++ b/test/commitment/proof_of_work.cpp @@ -59,7 +59,7 @@ BOOST_AUTO_TEST_CASE(pow_poseidon_basic_test) { BOOST_ASSERT(pow_type::verify(old_transcript_1, result, 9)); // manually reimplement verify to ensure that changes in implementation didn't break it - old_transcript_2(result); + old_transcript_2(std::vector{result}); auto chal = old_transcript_2.template challenge(); BOOST_ASSERT((integral_type(chal.data) & expected_mask) == 0); diff --git a/test/transcript/transcript.cpp b/test/transcript/transcript.cpp index e961ecd3e..8a37822c7 100644 --- a/test/transcript/transcript.cpp +++ b/test/transcript/transcript.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -71,10 +72,12 @@ BOOST_AUTO_TEST_SUITE(zk_poseidon_transcript_test_suite) BOOST_AUTO_TEST_CASE(zk_poseidon_transcript_init_test) { using curve_type = algebra::curves::pallas; using field_type = typename curve_type::base_field_type; - using poseidon_type = hashes::poseidon>; + using poseidon_type = hashes::nil_poseidon>; std::vector init_blob {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - transcript::fiat_shamir_heuristic_sequential tr(init_blob); + transcript::fiat_shamir_heuristic_sequential tr{ + hashes::block_to_field_elements_wrapper>(init_blob) + }; auto ch1 = tr.challenge(); auto ch2 = tr.challenge(); int ch_int = tr.int_challenge(); @@ -87,7 +90,7 @@ BOOST_AUTO_TEST_CASE(zk_poseidon_transcript_init_test) { BOOST_AUTO_TEST_CASE(zk_poseidon_transcript_no_init_test) { using curve_type = algebra::curves::pallas; using field_type = typename curve_type::base_field_type; - using poseidon_type = hashes::poseidon>; + using poseidon_type = hashes::nil_poseidon>; transcript::fiat_shamir_heuristic_sequential tr; auto ch1 = tr.challenge();