From 569c1b49e3307461c1fc0a351761762960a5f5a2 Mon Sep 17 00:00:00 2001 From: x-mass <36629999+x-mass@users.noreply.github.com> Date: Tue, 2 Apr 2024 17:09:26 +0000 Subject: [PATCH 1/2] Refactor poseidon usage --- .../basic_batched_fri_compile_time_size.hpp | 56 ++++----- .../basic_batched_fri_runtime_size.hpp | 42 +++---- .../detail/polynomial/basic_fri.hpp | 75 ++++++------ .../crypto3/zk/commitments/polynomial/kzg.hpp | 43 ++++++- .../zk/commitments/polynomial/kzg_v2.hpp | 47 +++++++- .../zk/detail/field_element_consumer.hpp | 111 ++++++++++++++++++ .../transcript_initialization_context.hpp | 10 +- .../nil/crypto3/zk/transcript/fiat_shamir.hpp | 63 ++++++---- test/transcript/transcript.cpp | 5 +- 9 files changed, 321 insertions(+), 131 deletions(-) create mode 100644 include/nil/crypto3/zk/detail/field_element_consumer.hpp diff --git a/include/nil/crypto3/zk/commitments/detail/polynomial/basic_batched_fri_compile_time_size.hpp b/include/nil/crypto3/zk/commitments/detail/polynomial/basic_batched_fri_compile_time_size.hpp index 9105b9a34..dbe9a79d8 100644 --- a/include/nil/crypto3/zk/commitments/detail/polynomial/basic_batched_fri_compile_time_size.hpp +++ b/include/nil/crypto3/zk/commitments/detail/polynomial/basic_batched_fri_compile_time_size.hpp @@ -128,7 +128,8 @@ namespace nil { const std::array , list_size> &poly, const std::shared_ptr > &D) { - std::vector > y_data; + using namespace algorithms; + std::vector , detail::leaf_data_size_multiplier * list_size>> y_data; y_data.resize(D->m); std::array , list_size> poly_dfs; for (std::size_t i = 0; i < list_size; i++) { @@ -139,10 +140,8 @@ namespace nil { for (std::size_t i = 0; i < D->m; i++) { for (std::size_t j = 0; j < list_size; j++) { - - field_element_type y_val(poly_dfs[j][i]); - auto write_iter = y_data[i].begin() + field_element_type::length() * j; - y_val.write(write_iter, field_element_type::length()); + auto write_iter = y_data[i].begin() + detail::leaf_data_size_multiplier * j; + detail::write_field_element_to_iter(write_iter, poly_dfs[j][i]); } } @@ -278,6 +277,7 @@ namespace nil { std::size_t r = fri_params.r; for (std::size_t i = 0; i < r; i++) { + using namespace algorithms; typename FieldType::value_type alpha = transcript.template challenge(); typename FieldType::value_type x_next = fri_params.q.evaluate(x); @@ -293,16 +293,13 @@ namespace nil { } for (std::size_t j = 0; j < m; j++) { - std::array < std::uint8_t, field_element_type::length() * leaf_size > leaf_data; - for (std::size_t polynom_index = 0; polynom_index < leaf_size; polynom_index++) { + std::array < detail::leaf_data_type, detail::leaf_data_size_multiplier * leaf_size > leaf_data; - typename FieldType::value_type leaf = proof.round_proofs[i].y[polynom_index][j]; - - field_element_type leaf_val(leaf); + for (std::size_t polynom_index = 0; polynom_index < leaf_size; polynom_index++) { auto write_iter = - leaf_data.begin() + field_element_type::length() * polynom_index; - leaf_val.write(write_iter, field_element_type::length()); + leaf_data.begin() + detail::leaf_data_size_multiplier * polynom_index; + detail::write_field_element_to_iter(write_iter, proof.round_proofs[i].y[polynom_index][j]); } if (!proof.round_proofs[i].p[j].validate(leaf_data)) { @@ -310,7 +307,7 @@ namespace nil { } } - std::array < std::uint8_t, field_element_type::length() * leaf_size > leaf_data; + std::array < detail::leaf_data_type, detail::leaf_data_size_multiplier * leaf_size > leaf_data; for (std::size_t polynom_index = 0; polynom_index < leaf_size; polynom_index++) { @@ -341,7 +338,7 @@ namespace nil { field_element_type leaf_val(leaf); auto write_iter = leaf_data.begin() + field_element_type::length() * polynom_index; - leaf_val.write(write_iter, field_element_type::length()); + detail::write_field_element_to_iter(write_iter, leaf); if (interpolant.evaluate(alpha) != proof.round_proofs[i].colinear_value[polynom_index]) { @@ -388,6 +385,7 @@ namespace nil { std::size_t r = fri_params.r; for (std::size_t i = 0; i < r; i++) { + using namespace algorithms; typename FieldType::value_type alpha = transcript.template challenge(); typename FieldType::value_type x_next = fri_params.q.evaluate(x); @@ -403,16 +401,15 @@ namespace nil { } for (std::size_t j = 0; j < m; j++) { - std::array < std::uint8_t, field_element_type::length() * leaf_size > leaf_data; + std::array < detail::leaf_data_type, detail::leaf_data_size_multiplier * leaf_size > leaf_data; for (std::size_t polynom_index = 0; polynom_index < leaf_size; polynom_index++) { typename FieldType::value_type leaf = proof.round_proofs[i].y[polynom_index][j]; - field_element_type leaf_val(leaf); auto write_iter = - leaf_data.begin() + field_element_type::length() * polynom_index; - leaf_val.write(write_iter, field_element_type::length()); + leaf_data.begin() + detail::leaf_data_size_multiplier * polynom_index; + detail::write_field_element_to_iter(write_iter, leaf); } if (!proof.round_proofs[i].p[j].validate(leaf_data)) { @@ -420,7 +417,7 @@ namespace nil { } } - std::array < std::uint8_t, field_element_type::length() * leaf_size > leaf_data; + std::array < detail::leaf_data_type, detail::leaf_data_size_multiplier * leaf_size > leaf_data; for (std::size_t polynom_index = 0; polynom_index < leaf_size; polynom_index++) { @@ -449,9 +446,8 @@ namespace nil { typename FieldType::value_type leaf = proof.round_proofs[i].colinear_value[polynom_index]; - field_element_type leaf_val(leaf); - auto write_iter = leaf_data.begin() + field_element_type::length() * polynom_index; - leaf_val.write(write_iter, field_element_type::length()); + auto write_iter = leaf_data.begin() + detail::leaf_data_size_multiplier * polynom_index; + detail::write_field_element_to_iter(write_iter, leaf); if (interpolant.evaluate(alpha) != proof.round_proofs[i].colinear_value[polynom_index]) { @@ -496,6 +492,7 @@ namespace nil { std::size_t r = fri_params.r; for (std::size_t i = 0; i < r; i++) { + using namespace algorithms; typename FieldType::value_type alpha = transcript.template challenge(); typename FieldType::value_type x_next = fri_params.q.evaluate(x); @@ -511,17 +508,16 @@ namespace nil { } for (std::size_t j = 0; j < m; j++) { - std::array < std::uint8_t, field_element_type::length() * leaf_size > leaf_data; + std::array < detail::leaf_data_type, detail::leaf_data_size_multiplier * leaf_size > leaf_data; for (std::size_t polynom_index = 0; polynom_index < leaf_size; polynom_index++) { typename FieldType::value_type leaf = proof.round_proofs[i].y[polynom_index][j]; - field_element_type leaf_val(leaf); auto write_iter = leaf_data.begin() + - field_element_type::length() * polynom_index; - leaf_val.write(write_iter, field_element_type::length()); + detail::leaf_data_size_multiplier * polynom_index; + detail::write_field_element_to_iter(write_iter, leaf); } if (!proof.round_proofs[i].p[j].validate(leaf_data)) { @@ -529,7 +525,7 @@ namespace nil { } } - std::array < std::uint8_t, field_element_type::length() * leaf_size > leaf_data; + std::array < detail::leaf_data_type, detail::leaf_data_size_multiplier * leaf_size > leaf_data; for (std::size_t polynom_index = 0; polynom_index < leaf_size; polynom_index++) { @@ -558,10 +554,8 @@ namespace nil { typename FieldType::value_type leaf = proof.round_proofs[i].colinear_value[polynom_index]; - - field_element_type leaf_val(leaf); - auto write_iter = leaf_data.begin() + field_element_type::length() * polynom_index; - leaf_val.write(write_iter, field_element_type::length()); + auto write_iter = leaf_data.begin() + detail::leaf_data_size_multiplier * polynom_index; + detail::write_field_element_to_iter(write_iter, leaf); if (interpolant.evaluate(alpha) != proof.round_proofs[i].colinear_value[polynom_index]) { diff --git a/include/nil/crypto3/zk/commitments/detail/polynomial/basic_batched_fri_runtime_size.hpp b/include/nil/crypto3/zk/commitments/detail/polynomial/basic_batched_fri_runtime_size.hpp index 7b78c5385..c7d51fae3 100644 --- a/include/nil/crypto3/zk/commitments/detail/polynomial/basic_batched_fri_runtime_size.hpp +++ b/include/nil/crypto3/zk/commitments/detail/polynomial/basic_batched_fri_runtime_size.hpp @@ -123,8 +123,9 @@ namespace nil { precommit(const std::vector > &poly, const std::shared_ptr > &D) { + using namespace algorithms; std::size_t leaf_size = poly.size(); - std::vector > y_data; + std::vector >> y_data; y_data.resize(D->m); std::vector > poly_dfs(leaf_size); for (std::size_t i = 0; i < leaf_size; i++) { @@ -135,11 +136,10 @@ namespace nil { for (std::size_t i = 0; i < D->m; i++) { for (std::size_t j = 0; j < leaf_size; j++) { - y_data[i].resize(field_element_type::length() * leaf_size); + y_data[i].resize(detail::leaf_data_size_multiplier * leaf_size); - field_element_type y_val(poly_dfs[j][i]); - auto write_iter = y_data[i].begin() + field_element_type::length() * j; - y_val.write(write_iter, field_element_type::length()); + auto write_iter = y_data[i].begin() + detail::leaf_data_size_multiplier * j; + detail::write_field_element_to_iter(write_iter, poly_dfs[j][i]); } } @@ -284,6 +284,7 @@ namespace nil { std::size_t r = fri_params.r; for (std::size_t i = 0; i < r; i++) { + using namespace algorithms; typename FieldType::value_type alpha = transcript.template challenge(); typename FieldType::value_type x_next = fri_params.q.evaluate(x); @@ -299,17 +300,16 @@ namespace nil { } for (std::size_t j = 0; j < m; j++) { - std::vector leaf_data(field_element_type::length() * leaf_size); + std::vector > leaf_data(detail::leaf_data_size_multiplier * leaf_size); for (std::size_t polynom_index = 0; polynom_index < leaf_size; polynom_index++) { typename FieldType::value_type leaf = proof.round_proofs[i].y[polynom_index][j]; - field_element_type leaf_val(leaf); auto write_iter = leaf_data.begin() + - field_element_type::length() * polynom_index; - leaf_val.write(write_iter, field_element_type::length()); + detail::leaf_data_size_multiplier * polynom_index; + detail::write_field_element_to_iter(write_iter, leaf); } if (!proof.round_proofs[i].p[j].validate(leaf_data)) { @@ -317,7 +317,7 @@ namespace nil { } } - std::vector leaf_data(field_element_type::length() * leaf_size); + std::vector > leaf_data(detail::leaf_data_size_multiplier * leaf_size); for (std::size_t polynom_index = 0; polynom_index < leaf_size; polynom_index++) { @@ -346,10 +346,8 @@ namespace nil { typename FieldType::value_type leaf = proof.round_proofs[i].colinear_value[polynom_index]; - - field_element_type leaf_val(leaf); - auto write_iter = leaf_data.begin() + field_element_type::length() * polynom_index; - leaf_val.write(write_iter, field_element_type::length()); + auto write_iter = leaf_data.begin() + detail::leaf_data_size_multiplier * polynom_index; + detail::write_field_element_to_iter(write_iter, leaf); if (interpolant.evaluate(alpha) != proof.round_proofs[i].colinear_value[polynom_index]) { @@ -398,6 +396,7 @@ namespace nil { std::size_t r = fri_params.r; for (std::size_t i = 0; i < r; i++) { + using namespace algorithms; typename FieldType::value_type alpha = transcript.template challenge(); typename FieldType::value_type x_next = fri_params.q.evaluate(x); @@ -413,17 +412,16 @@ namespace nil { } for (std::size_t j = 0; j < m; j++) { - std::vector leaf_data(field_element_type::length() * leaf_size); + std::vector > leaf_data(detail::leaf_data_size_multiplier * leaf_size); for (std::size_t polynom_index = 0; polynom_index < leaf_size; polynom_index++) { typename FieldType::value_type leaf = proof.round_proofs[i].y[polynom_index][j]; - field_element_type leaf_val(leaf); auto write_iter = leaf_data.begin() + - field_element_type::length() * polynom_index; - leaf_val.write(write_iter, field_element_type::length()); + detail::leaf_data_size_multiplier * polynom_index; + detail::write_field_element_to_iter(write_iter, leaf); } if (!proof.round_proofs[i].p[j].validate(leaf_data)) { @@ -431,7 +429,7 @@ namespace nil { } } - std::vector leaf_data(field_element_type::length() * leaf_size); + std::vector > leaf_data(detail::leaf_data_size_multiplier * leaf_size); for (std::size_t polynom_index = 0; polynom_index < leaf_size; polynom_index++) { @@ -460,10 +458,8 @@ namespace nil { typename FieldType::value_type leaf = proof.round_proofs[i].colinear_value[polynom_index]; - - field_element_type leaf_val(leaf); - auto write_iter = leaf_data.begin() + field_element_type::length() * polynom_index; - leaf_val.write(write_iter, field_element_type::length()); + auto write_iter = leaf_data.begin() + detail::leaf_data_size_multiplier * polynom_index; + detail::write_field_element_to_iter(write_iter, leaf); if (interpolant.evaluate(alpha) != proof.round_proofs[i].colinear_value[polynom_index]) { diff --git a/include/nil/crypto3/zk/commitments/detail/polynomial/basic_fri.hpp b/include/nil/crypto3/zk/commitments/detail/polynomial/basic_fri.hpp index 4734d690c..93fdf108b 100644 --- a/include/nil/crypto3/zk/commitments/detail/polynomial/basic_fri.hpp +++ b/include/nil/crypto3/zk/commitments/detail/polynomial/basic_fri.hpp @@ -35,8 +35,6 @@ #include #include -#include - #include #include #include @@ -52,6 +50,7 @@ #include #include #include +#include #include namespace nil { @@ -301,6 +300,15 @@ namespace nil { } // namespace commitments namespace algorithms { + namespace detail { + template + using fri_field_element_consumer = ::nil::crypto3::zk::detail::field_element_consumer< + typename FRI::field_type, + typename FRI::merkle_tree_hash_type::word_type, + typename FRI::field_element_type + >; + } // namespace detail + templatesize(); std::size_t coset_size = 1 << fri_step; std::size_t leafs_number = domain_size / coset_size; - std::size_t leaf_bytes = coset_size * FRI::field_element_type::length(); - std::vector> y_data(leafs_number, std::vector(leaf_bytes)); + std::vector> y_data( + leafs_number, + detail::fri_field_element_consumer(coset_size) + ); for (std::size_t x_index = 0; x_index < leafs_number; x_index++) { std::vector> s_indices(coset_size / FRI::m); s_indices[0][0] = x_index; s_indices[0][1] = get_paired_index(x_index, domain_size); - auto write_iter = y_data[x_index].begin(); - typename FRI::field_element_type y_val0(f[s_indices[0][0]]); - y_val0.write(write_iter, FRI::field_element_type::length()); - typename FRI::field_element_type y_val1(f[s_indices[0][1]]); - y_val1.write(write_iter, FRI::field_element_type::length()); + auto& element_consumer = y_data[x_index].reset_cursor(); + element_consumer.consume(f[s_indices[0][0]]); + element_consumer.consume(f[s_indices[0][1]]); std::size_t base_index = domain_size / (FRI::m * FRI::m); std::size_t prev_half_size = 1; @@ -386,10 +394,8 @@ namespace nil { s_indices[i][0] = (base_index + s_indices[j][0]) % domain_size; s_indices[i][1] = get_paired_index(s_indices[i][0], domain_size); - typename FRI::field_element_type y_val0(f[s_indices[i][0]]); - y_val0.write(write_iter, FRI::field_element_type::length()); - typename FRI::field_element_type y_val1(f[s_indices[i][1]]); - y_val1.write(write_iter, FRI::field_element_type::length()); + element_consumer.consume(f[s_indices[i][0]]); + element_consumer.consume(f[s_indices[i][1]]); i++; } @@ -452,21 +458,20 @@ namespace nil { std::size_t list_size = poly.size(); std::size_t coset_size = 1 << fri_step; std::size_t leafs_number = domain_size / coset_size; - std::vector> y_data( - leafs_number, - std::vector(coset_size * FRI::field_element_type::length() * list_size)); + std::vector> y_data( + leafs_number, + detail::fri_field_element_consumer(coset_size * list_size) + ); for (std::size_t x_index = 0; x_index < leafs_number; x_index++) { - auto write_iter = y_data[x_index].begin(); + auto& element_consumer = y_data[x_index].reset_cursor(); for (std::size_t polynom_index = 0; polynom_index < list_size; polynom_index++) { std::vector> s_indices(coset_size / FRI::m); s_indices[0][0] = x_index; s_indices[0][1] = get_paired_index(x_index, domain_size); - typename FRI::field_element_type y_val0(poly[polynom_index][s_indices[0][0]]); - y_val0.write(write_iter, FRI::field_element_type::length()); - typename FRI::field_element_type y_val1(poly[polynom_index][s_indices[0][1]]); - y_val1.write(write_iter, FRI::field_element_type::length()); + element_consumer.consume(poly[polynom_index][s_indices[0][0]]); + element_consumer.consume(poly[polynom_index][s_indices[0][1]]); std::size_t base_index = domain_size / (FRI::m * FRI::m); std::size_t prev_half_size = 1; @@ -475,10 +480,8 @@ namespace nil { for (std::size_t j = 0; j < prev_half_size; j++) { s_indices[i][0] = (base_index + s_indices[j][0]) % domain_size; s_indices[i][1] = get_paired_index(s_indices[i][0], domain_size); - typename FRI::field_element_type y_val0(poly[polynom_index][s_indices[i][0]]); - y_val0.write(write_iter, FRI::field_element_type::length()); - typename FRI::field_element_type y_val1(poly[polynom_index][s_indices[i][1]]); - y_val1.write(write_iter, FRI::field_element_type::length()); + element_consumer.consume(poly[polynom_index][s_indices[i][0]]); + element_consumer.consume(poly[polynom_index][s_indices[i][1]]); i++; } @@ -988,19 +991,12 @@ namespace nil { return false; } - std::vector leaf_data(coset_size * FRI::field_element_type::length() * query_proof.initial_proof.at(k).values.size()); - auto write_iter = leaf_data.begin(); + detail::fri_field_element_consumer leaf_data(coset_size * query_proof.initial_proof.at(k).values.size()); for (std::size_t i = 0; i < query_proof.initial_proof.at(k).values.size(); i++) { for (auto [idx, pair_idx] : correct_order_idx) { - typename FRI::field_element_type leaf_val0( - query_proof.initial_proof.at(k).values[i][idx][0] - ); - leaf_val0.write(write_iter, FRI::field_element_type::length()); - typename FRI::field_element_type leaf_val1( - query_proof.initial_proof.at(k).values[i][idx][1] - ); - leaf_val1.write(write_iter, FRI::field_element_type::length()); + leaf_data.consume(query_proof.initial_proof.at(k).values[i][idx][0]); + leaf_data.consume(query_proof.initial_proof.at(k).values[i][idx][1]); } } if (!query_proof.initial_proof.at(k).p.validate(leaf_data)) { @@ -1049,15 +1045,12 @@ namespace nil { std::tie(s, s_indices) = calculate_s(x, x_index, fri_params.step_list[i], fri_params.D[t]); - std::vector leaf_data(coset_size * FRI::field_element_type::length()); - auto write_iter = leaf_data.begin(); + detail::fri_field_element_consumer leaf_data(coset_size); auto correct_order_idx = get_correct_order(x_index, domain_size, fri_params.step_list[i], s_indices); for (auto [idx, pair_idx]: correct_order_idx) { - typename FRI::field_element_type leaf_val0(y[idx][0]); - leaf_val0.write(write_iter, FRI::field_element_type::length()); - typename FRI::field_element_type leaf_val1(y[idx][1]); - leaf_val1.write(write_iter, FRI::field_element_type::length()); + leaf_data.consume(y[idx][0]); + leaf_data.consume(y[idx][1]); } if (!query_proof.round_proofs[i].p.validate(leaf_data)) { std::cout << "Wrong round merkle proof on " << i << "-th round" << std::endl; diff --git a/include/nil/crypto3/zk/commitments/polynomial/kzg.hpp b/include/nil/crypto3/zk/commitments/polynomial/kzg.hpp index b8bb181be..bd2279d91 100644 --- a/include/nil/crypto3/zk/commitments/polynomial/kzg.hpp +++ b/include/nil/crypto3/zk/commitments/polynomial/kzg.hpp @@ -47,6 +47,7 @@ #include #include #include +#include #include @@ -335,14 +336,24 @@ namespace nil { std::vector byteblob = nil::marshalling::pack(commit, status); BOOST_ASSERT(status == nil::marshalling::status_type::success); - transcript(byteblob); + transcript( + ::nil::crypto3::hashes::conditional_block_to_field_elements_wrapper< + typename KZG::transcript_hash_type::word_type, + decltype(byteblob) + >(byteblob) + ); } for (const auto &S : public_key.S) { for (const auto &s : S) { std::vector byteblob = nil::marshalling::pack(s, status); BOOST_ASSERT(status == nil::marshalling::status_type::success); - transcript(byteblob); + transcript( + ::nil::crypto3::hashes::conditional_block_to_field_elements_wrapper< + typename KZG::transcript_hash_type::word_type, + decltype(byteblob) + >(byteblob) + ); } } for (const auto &r : public_key.r) { @@ -350,7 +361,12 @@ namespace nil { std::vector byteblob = nil::marshalling::pack(r[i], status); BOOST_ASSERT(status == nil::marshalling::status_type::success); - transcript(byteblob); + transcript( + ::nil::crypto3::hashes::conditional_block_to_field_elements_wrapper< + typename KZG::transcript_hash_type::word_type, + decltype(byteblob) + >(byteblob) + ); } } } @@ -676,7 +692,12 @@ namespace nil { * #295 */ // Push commitments to transcript - transcript(_commitments[batch_ind]); + transcript( + ::nil::crypto3::hashes::conditional_block_to_field_elements_wrapper< + typename KZGScheme::transcript_hash_type::word_type, + decltype(_commitments[batch_ind]) + >(_commitments[batch_ind]) + ); // Push evaluation points to transcript for( std::size_t i = 0; i < this->_z.get_batch_size(batch_ind); i++){ @@ -685,7 +706,12 @@ namespace nil { std::vector byteblob = nil::marshalling::pack(this->_z.get(batch_ind, i, j), status); BOOST_ASSERT(status == nil::marshalling::status_type::success); - transcript(byteblob); + transcript( + ::nil::crypto3::hashes::conditional_block_to_field_elements_wrapper< + typename KZGScheme::transcript_hash_type::word_type, + decltype(byteblob) + >(byteblob) + ); } } @@ -697,7 +723,12 @@ namespace nil { std::vector byteblob = nil::marshalling::pack(poly[j], status); BOOST_ASSERT(status == nil::marshalling::status_type::success); - transcript(byteblob); + transcript( + ::nil::crypto3::hashes::conditional_block_to_field_elements_wrapper< + typename KZGScheme::transcript_hash_type::word_type, + decltype(byteblob) + >(byteblob) + ); } } } diff --git a/include/nil/crypto3/zk/commitments/polynomial/kzg_v2.hpp b/include/nil/crypto3/zk/commitments/polynomial/kzg_v2.hpp index 718501dcd..16b995fa4 100644 --- a/include/nil/crypto3/zk/commitments/polynomial/kzg_v2.hpp +++ b/include/nil/crypto3/zk/commitments/polynomial/kzg_v2.hpp @@ -54,6 +54,7 @@ #include #include +#include using namespace nil::crypto3::math; @@ -105,6 +106,10 @@ namespace nil { } }; using endianness = nil::marshalling::option::big_endian; + using field_element_type = nil::crypto3::marshalling::types::field_element< + nil::marshalling::field_type, + commitment_type + >; private: params_type _params; std::map _commitments; @@ -145,7 +150,12 @@ namespace nil { * #295 */ // Push commitments to transcript - transcript(_commitments[batch_ind]); + transcript( + ::nil::crypto3::hashes::conditional_block_to_field_elements_wrapper< + typename KZGScheme::transcript_hash_type::word_type, + decltype(_commitments[batch_ind]) + >(_commitments[batch_ind]) + ); // Push evaluation points to transcript for( std::size_t i = 0; i < this->_z.get_batch_size(batch_ind); i++){ @@ -154,7 +164,12 @@ namespace nil { std::vector byteblob = nil::marshalling::pack(this->_z.get(batch_ind, i, j), status); BOOST_ASSERT(status == nil::marshalling::status_type::success); - transcript(byteblob); + transcript( + ::nil::crypto3::hashes::conditional_block_to_field_elements_wrapper< + typename KZGScheme::transcript_hash_type::word_type, + decltype(byteblob) + >(byteblob) + ); } } @@ -166,7 +181,12 @@ namespace nil { std::vector byteblob = nil::marshalling::pack(poly[j], status); BOOST_ASSERT(status == nil::marshalling::status_type::success); - transcript(byteblob); + transcript( + ::nil::crypto3::hashes::conditional_block_to_field_elements_wrapper< + typename KZGScheme::transcript_hash_type::word_type, + decltype(byteblob) + >(byteblob) + ); } } } @@ -244,7 +264,12 @@ namespace nil { std::vector pi1_byteblob = nil::marshalling::pack(pi_1, status); BOOST_ASSERT(status == nil::marshalling::status_type::success); - transcript(pi1_byteblob); + transcript( + ::nil::crypto3::hashes::conditional_block_to_field_elements_wrapper< + typename KZGScheme::transcript_hash_type::word_type, + decltype(pi1_byteblob) + >(pi1_byteblob) + ); auto theta_2 = transcript.template challenge(); math::polynomial theta_2_vanish = { -theta_2, 1 }; @@ -273,7 +298,12 @@ namespace nil { /* TODO: Review the necessity of sending pi_2 to transcript */ std::vector pi2_byteblob = nil::marshalling::pack(pi_2, status); BOOST_ASSERT(status == nil::marshalling::status_type::success); - transcript(pi2_byteblob); + transcript( + ::nil::crypto3::hashes::conditional_block_to_field_elements_wrapper< + typename KZGScheme::transcript_hash_type::word_type, + decltype(pi2_byteblob) + >(pi2_byteblob) + ); return {this->_z, pi_1, pi_2}; } @@ -296,7 +326,12 @@ namespace nil { nil::marshalling::status_type status; std::vector byteblob = nil::marshalling::pack(proof.pi_1, status); BOOST_ASSERT(status == nil::marshalling::status_type::success); - transcript(byteblob); + transcript( + ::nil::crypto3::hashes::conditional_block_to_field_elements_wrapper< + typename KZGScheme::transcript_hash_type::word_type, + decltype(byteblob) + >(byteblob) + ); auto theta_2 = transcript.template challenge(); auto theta_i = KZGScheme::scalar_value_type::one(); diff --git a/include/nil/crypto3/zk/detail/field_element_consumer.hpp b/include/nil/crypto3/zk/detail/field_element_consumer.hpp new file mode 100644 index 000000000..1a4ab8ba7 --- /dev/null +++ b/include/nil/crypto3/zk/detail/field_element_consumer.hpp @@ -0,0 +1,111 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Iosif (x-mass) +// +// 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. +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_ZK_DETAIL_FIELD_ELEMENT_CONSUMER_HPP +#define CRYPTO3_ZK_DETAIL_FIELD_ELEMENT_CONSUMER_HPP + +#include + +namespace nil { + namespace crypto3 { + namespace zk { + namespace detail { + + /** + * @brief Consuming field elements and choose either to serialize field element to vector of bytes + * or to keep field elements as is. Could be used in places, where hash is computed, to + * avoid unnecessary serialization in case of algebraic hashes. + * + * @tparam Field + * @tparam Target A type that determines whether to store Field's value_type directly or as bytes. + * The decision is based on whether Target is identified as a field element by the + * `algebra::is_field_element` trait. + * @tparam Marshalling A type of marshalled strucutre to use for serialization in case of keepeng + * serialized values. + */ + template + class field_element_consumer : public std::vector::value, + typename Field::value_type, + std::uint8_t + >> { + public: // TODO: make private + using base_class = std::vector::value, + typename Field::value_type, + std::uint8_t + >>; + using iterator = typename base_class::iterator; + + /** + * @brief Constant expression that determines the size multiplier. + * If the word type is a field element, the size is 1; otherwise, + * it multiplies by the length of the field element representation. + */ + static constexpr std::size_t field_element_holder_size_multiplier = std::conditional_t< + algebra::is_field_element::value, + std::integral_constant, + std::integral_constant + >::value; + + // Default ctor is used for single values + field_element_consumer() : field_element_consumer(1) { + }; + + field_element_consumer(std::size_t size) + : base_class(size * field_element_holder_size_multiplier) { + reset_cursor(); + } + + explicit field_element_consumer(const typename Field::value_type& field_element) + : field_element_consumer() { + consume(field_element); + } + + + void consume(const typename Field::value_type& field_element) { + BOOST_ASSERT(current_iter <= this->end() - field_element_holder_size_multiplier); + if constexpr (algebra::is_field_element::value) { + *current_iter++ = field_element; + } else { + Marshalling field_val(field_element); + field_val.write(current_iter, Marshalling::length()); + } + } + + field_element_consumer& reset_cursor() { + current_iter = this->begin(); + return *this; + } + + private: + iterator current_iter; + }; + + } // namespace detail + } // namespace zk + } // namespace crypto3 +} // namespace nil + +#endif // CRYPTO3_ZK_DETAIL_FIELD_ELEMENT_CONSUMER_HPP diff --git a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/detail/transcript_initialization_context.hpp b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/detail/transcript_initialization_context.hpp index 2e071be75..db7e6cd2c 100644 --- a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/detail/transcript_initialization_context.hpp +++ b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/detail/transcript_initialization_context.hpp @@ -28,6 +28,9 @@ #ifndef CRYPTO3_PLONK_PLACEHOLDER_TRANSCRIPT_INITIALIZATION_CONTEXT_HPP #define CRYPTO3_PLONK_PLACEHOLDER_TRANSCRIPT_INITIALIZATION_CONTEXT_HPP +#include +#include + #include #include #include @@ -135,7 +138,12 @@ namespace nil { filled_constraint_system.write(write_iter, filled_constraint_system.length()); // Return hash of "cv", which contains concatenated constraint system and other initialization parameters. - return hash(cv); + return hash( + hashes::conditional_block_to_field_elements_wrapper< + typename transcript_hash_type::word_type, + decltype(cv) + >(cv) + ); } } // namespace detail } // namespace snark diff --git a/include/nil/crypto3/zk/transcript/fiat_shamir.hpp b/include/nil/crypto3/zk/transcript/fiat_shamir.hpp index c8887f150..95a51e006 100644 --- a/include/nil/crypto3/zk/transcript/fiat_shamir.hpp +++ b/include/nil/crypto3/zk/transcript/fiat_shamir.hpp @@ -30,23 +30,20 @@ #include #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 +85,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 +132,6 @@ namespace nil { } }; - template struct fiat_shamir_heuristic_sequential { @@ -196,11 +200,26 @@ 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>> { + Hash, + typename std::enable_if_t< + nil::crypto3::hashes::is_specialization_of< + nil::crypto3::hashes::poseidon, + Hash + >::value + > + > { + // 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]). + // Not to replace current hacks with new bigger ones, we'll just keep it. typedef Hash hash_type; using field_type = nil::crypto3::algebra::curves::pallas::base_field_type; @@ -214,7 +233,7 @@ namespace nil { template fiat_shamir_heuristic_sequential(const InputRange &r) { if(r.size() != 0) { - sponge.absorb(hash(r)); + sponge.absorb(static_cast(hash(r))); } } @@ -229,7 +248,7 @@ namespace nil { template void operator()(const InputRange &r) { - sponge.absorb(hash(r)); + sponge.absorb(static_cast(hash(r))); } template @@ -271,8 +290,8 @@ namespace nil { return result; } - private: - hashes::detail::poseidon_sponge_construction sponge; + public: + hashes::detail::nil_poseidon_sponge_construction sponge; }; } // namespace transcript diff --git a/test/transcript/transcript.cpp b/test/transcript/transcript.cpp index e961ecd3e..5fb5c2cea 100644 --- a/test/transcript/transcript.cpp +++ b/test/transcript/transcript.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -74,7 +75,9 @@ BOOST_AUTO_TEST_CASE(zk_poseidon_transcript_init_test) { using poseidon_type = hashes::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(); From ab085551bdbb2d0d0098cfbcd790ea311a82f2cf Mon Sep 17 00:00:00 2001 From: x-mass <36629999+x-mass@users.noreply.github.com> Date: Fri, 26 Apr 2024 08:31:03 +0000 Subject: [PATCH 2/2] Add transcript poseidon empty init_blob test --- test/transcript/transcript.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/transcript/transcript.cpp b/test/transcript/transcript.cpp index 5fb5c2cea..8b5a651eb 100644 --- a/test/transcript/transcript.cpp +++ b/test/transcript/transcript.cpp @@ -85,6 +85,16 @@ BOOST_AUTO_TEST_CASE(zk_poseidon_transcript_init_test) { BOOST_CHECK_EQUAL(ch1.data, field_type::value_type(0x27B1BE8A820DE1A5E91A441F59F29D42D9DB9FC7778A0852819F331D5CD60B43_cppui256).data); BOOST_CHECK_EQUAL(ch2.data, field_type::value_type(0x12096E03B2ADEC9B317042D36F048C06AF123EED4A3FC040579E66DCE46C0AEE_cppui256).data); BOOST_CHECK_EQUAL(ch_int, 0x6296); + + init_blob = {}; + tr = transcript::fiat_shamir_heuristic_sequential(init_blob); + ch1 = tr.challenge(); + ch2 = tr.challenge(); + ch_int = tr.int_challenge(); + + BOOST_CHECK_EQUAL(ch1.data, field_type::value_type(0x35626947FA1063436F4E5434029CCAEC64075C9FC80034C0923054A2B1D30BD2_cppui256).data); + BOOST_CHECK_EQUAL(ch2.data, field_type::value_type(0x1B961886411EE8722DD6B576CBA5876EB30999B5237FE0E14255E6D006CFF63C_cppui256).data); + BOOST_CHECK_EQUAL(ch_int, 0xC92); } BOOST_AUTO_TEST_CASE(zk_poseidon_transcript_no_init_test) {