From 9b1d27b727771871b9c444393e50f7ef6a7da81c Mon Sep 17 00:00:00 2001 From: "e.tatuzova" Date: Fri, 6 Sep 2024 14:41:28 +0400 Subject: [PATCH] Component with compact dynamic lookup table added #422 --- .../hashes/keccak/keccak_component.hpp | 265 ++++++++++++++++++ .../hashes/keccak/keccak_dynamic.hpp | 31 +- .../components/hashes/keccak/keccak_table.hpp | 232 +++++++++++++++ .../blueprint/utils/satisfiability_check.hpp | 7 + test/CMakeLists.txt | 1 + test/hashes/plonk/keccak_component.cpp | 192 +++++++++++++ test/hashes/plonk/keccak_dynamic.cpp | 4 +- 7 files changed, 706 insertions(+), 26 deletions(-) create mode 100644 include/nil/blueprint/components/hashes/keccak/keccak_component.hpp create mode 100644 include/nil/blueprint/components/hashes/keccak/keccak_table.hpp create mode 100644 test/hashes/plonk/keccak_component.cpp diff --git a/include/nil/blueprint/components/hashes/keccak/keccak_component.hpp b/include/nil/blueprint/components/hashes/keccak/keccak_component.hpp new file mode 100644 index 00000000..11a34e42 --- /dev/null +++ b/include/nil/blueprint/components/hashes/keccak/keccak_component.hpp @@ -0,0 +1,265 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Elena Tatuzova +// +// 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_BLUEPRINT_COMPONENTS_KECCAK_COMPONENT_HPP +#define CRYPTO3_BLUEPRINT_COMPONENTS_KECCAK_COMPONENT_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace nil { + namespace blueprint { + namespace components { + // Easiest configuration with single keccak_table component and single keccak_dynamic + template + class keccak_component; + + template + class keccak_component> + : public plonk_component + { + public: + using component_type = plonk_component; + using var = typename component_type::var; + using manifest_type = plonk_component_manifest; + + using table_component_type = plonk_keccak_table; + using dynamic_component_type = keccak_dynamic_component; + + table_component_type table_component; + dynamic_component_type dynamic_component; + std::size_t max_blocks; + std::size_t limit_permutation_columns; + + class gate_manifest_type : public component_gate_manifest { + public: + std::uint32_t gates_amount() const override { + return 41; + } + }; + + static gate_manifest get_gate_manifest(std::size_t witness_amount, std::size_t max_blocks, std::size_t limit_permutation_columns) { + gate_manifest manifest = gate_manifest(gate_manifest_type()); + return manifest; + } + + static manifest_type get_manifest() { + static manifest_type manifest = manifest_type( + std::shared_ptr(new manifest_single_value_param(15)), + false + ); + return manifest; + } + + constexpr static std::size_t get_rows_amount(std::size_t witness_amount, std::size_t max_blocks, std::size_t limit_permutation_column) { + std::cout << "Whole component rows amount = " << max_blocks + dynamic_component_type::get_rows_amount(witness_amount, max_blocks, limit_permutation_column) << std::endl; + return max_blocks + dynamic_component_type::get_rows_amount(witness_amount, max_blocks, limit_permutation_column); + } + + std::map component_lookup_tables() { + std::map lookup_tables; + lookup_tables["keccak_pack_table/extended"] = 0; // REQUIRED_TABLE + lookup_tables["keccak_pack_table/extended_swap"] = 0; // REQUIRED_TABLE + lookup_tables["keccak_pack_table/range_check"] = 0; // REQUIRED_TABLE + lookup_tables["keccak_pack_table/range_check_135"] = 0; // REQUIRED_TABLE + lookup_tables["keccak_pack_table/range_check_16bit"] = 0; // REQUIRED_TABLE + lookup_tables["keccak_pack_table/sparse_16bit"] = 0; // REQUIRED_TABLE + lookup_tables["keccak_sign_bit_table/full"] = 0; // REQUIRED_TABLE + lookup_tables["keccak_normalize3_table/full"] = 0; // REQUIRED_TABLE + lookup_tables["keccak_normalize4_table/full"] = 0; // REQUIRED_TABLE + lookup_tables["keccak_normalize6_table/full"] = 0; // REQUIRED_TABLE + lookup_tables["keccak_chi_table/full"] = 0; // REQUIRED_TABLE + lookup_tables["keccak_pack_table/range_check_sparse"] = 0; // REQUIRED_TABLE + lookup_tables["keccak_table"] = 1; // DYNAMIC_TABLE + lookup_tables["sparsed_keccak_table"] = 1; // DYNAMIC_TABLE + return lookup_tables; + } + + constexpr static const std::size_t gates_amount = 0; + constexpr static const std::size_t lookup_gates_amount = 2; + std::size_t rows_amount = get_rows_amount(this->witness_amount(), max_blocks, limit_permutation_columns); + + struct input_type { + var rlc_challenge; + std::vector, + std::pair + >> input; + + std::vector> all_vars() { + std::vector> res; + res.push_back(rlc_challenge); + return res; + } + }; + + struct result_type { + result_type(const keccak_component &component, std::size_t start_row_index) { + } + + std::vector> all_vars() { + std::vector> result; + + return result; + } + }; + + template + explicit keccak_component(ContainerType witness, std::size_t _max_blocks) : + component_type(witness, {}, {}, get_manifest()), max_blocks(_max_blocks) + {}; + + template + keccak_component(WitnessContainerType witness, ConstantContainerType constant, + PublicInputContainerType public_input, + std::size_t _max_blocks, + std::size_t _limit_permuted_columns + ) : component_type(witness, constant, public_input, get_manifest()), max_blocks(_max_blocks), + limit_permutation_columns(_limit_permuted_columns), + table_component(witness, constant, public_input, _max_blocks), + dynamic_component(witness, constant, public_input, _max_blocks, _limit_permuted_columns) + {}; + + keccak_component( + std::initializer_list witnesses, + std::initializer_list + constants, + std::initializer_list + public_inputs, + std::size_t _max_blocks, + std::size_t _limit_permuted_columns + ) : component_type(witnesses, constants, public_inputs, get_manifest()), max_blocks(_max_blocks), + limit_permutation_columns(_limit_permuted_columns), + table_component(witnesses, constants, public_inputs, max_blocks), + dynamic_component(witnesses, constants, public_inputs, max_blocks, _limit_permuted_columns) + {}; + }; + + template + using plonk_keccak_component = + keccak_component>; + + template + typename plonk_keccak_component::result_type generate_assignments( + const plonk_keccak_component &component, + assignment> + &assignment, + const typename plonk_keccak_component::input_type + &instance_input, + const std::uint32_t start_row_index + ) { + using component_type = plonk_keccak_component; + using value_type = typename BlueprintFieldType::value_type; + + typename component_type::table_component_type::input_type table_input; + table_input.input = instance_input.input; + table_input.rlc_challenge = instance_input.rlc_challenge; + generate_assignments(component.table_component, assignment, table_input, start_row_index); + + typename component_type::dynamic_component_type::input_type dynamic_input; + dynamic_input.input = instance_input.input; + dynamic_input.rlc_challenge = instance_input.rlc_challenge; + generate_assignments(component.dynamic_component, assignment, dynamic_input, start_row_index + component.table_component.rows_amount); + return typename component_type::result_type(component, start_row_index); + } + + template + typename plonk_keccak_component::result_type generate_circuit( + const plonk_keccak_component &component, + circuit> &bp, + assignment> + &assignment, + const typename plonk_keccak_component::input_type + &instance_input, + const std::size_t start_row_index + ) { + using component_type = plonk_keccak_component; + using var = typename component_type::var; + + typename component_type::table_component_type::input_type table_input; + table_input.input = instance_input.input; + table_input.rlc_challenge = instance_input.rlc_challenge; + generate_circuit(component.table_component, bp, assignment, table_input, start_row_index); + + typename component_type::dynamic_component_type::input_type dynamic_input; + dynamic_input.input = instance_input.input; + dynamic_input.rlc_challenge = instance_input.rlc_challenge; + generate_circuit(component.dynamic_component, bp, assignment, dynamic_input, start_row_index + component.table_component.rows_amount); + + std::size_t selector_id = bp.get_dynamic_lookup_table_selector(); + typename component_type::dynamic_component_type::keccak_map m(component.dynamic_component); + + bp.register_dynamic_table("sparsed_keccak_table"); + crypto3::zk::snark::plonk_lookup_table sparsed_table; + sparsed_table.tag_index = selector_id; + sparsed_table.columns_number = 4;// + sparsed_table.lookup_options = {{ + m.h.is_last, + m.h.RLC, + m.h.hash_hi, + m.h.hash_lo + }}; + bp.define_dynamic_table("sparsed_keccak_table", sparsed_table); + + using lookup_constraint_type = typename crypto3::zk::snark::plonk_lookup_constraint; + auto lookup_tables_indices = bp.get_reserved_indices(); + + lookup_constraint_type check = {lookup_tables_indices.at("keccak_table"),{m.h.is_last, m.h.RLC, m.h.hash_hi, m.h.hash_lo}}; + bp.add_lookup_gate(selector_id, {check}); + for( std::size_t i = 0; i < component.max_blocks; i++){ + assignment.enable_selector( + selector_id, + start_row_index + component.table_component.rows_amount + i * component.dynamic_component.block_rows_amount + ); + } + + typename component_type::table_component_type::keccak_table_map t(component.table_component); + lookup_constraint_type tcheck = {lookup_tables_indices.at("sparsed_keccak_table"),{t.is_last, t.RLC, t.hash_hi, t.hash_lo}}; + std::size_t tselector_id = bp.add_lookup_gate({tcheck}); + for( std::size_t i = 0; i < component.max_blocks; i++){ + assignment.enable_selector( + tselector_id, + start_row_index + i + ); + } + + return typename component_type::result_type(component, start_row_index); + } + } + } +} +#endif \ No newline at end of file diff --git a/include/nil/blueprint/components/hashes/keccak/keccak_dynamic.hpp b/include/nil/blueprint/components/hashes/keccak/keccak_dynamic.hpp index e9508a10..05dbd5a6 100644 --- a/include/nil/blueprint/components/hashes/keccak/keccak_dynamic.hpp +++ b/include/nil/blueprint/components/hashes/keccak/keccak_dynamic.hpp @@ -46,12 +46,10 @@ namespace nil { template class keccak_dynamic> : public plonk_component { - + public: using component_type = plonk_component; using value_type = typename BlueprintFieldType::value_type; using integral_type = typename BlueprintFieldType::integral_type; - - public: using var = typename component_type::var; using round_component_type = @@ -109,17 +107,7 @@ namespace nil { const std::size_t max_blocks; const std::size_t limit_permutation_column; const std::size_t bytes_per_block = 136; // 17*8 -/* - const std::size_t num_round_calls = calculate_num_round_calls(num_blocks, num_bits); - const std::size_t num_configs = 4 + calculate_padded_length(num_blocks, num_bits); - - const std::size_t pack_chunk_size = 8; - const std::size_t pack_num_chunks = 8; - const std::size_t unpack_chunk_size = 24; - const std::size_t unpack_num_chunks = 8; - const std::size_t pack_cells = 2 * (pack_num_chunks + 1); - const std::size_t pack_buff = (this->witness_amount() == 15) * 2; -*/ + round_component_type round_tt; round_component_type round_tf; round_component_type round_ff; @@ -130,14 +118,7 @@ namespace nil { const std::size_t rounds_rows_amount = get_rounds_rows_amount(this->witness_amount(), this->limit_permutation_column); const std::size_t unsparser_rows_amount = get_unsparser_rows_amount(this->witness_amount()); const std::size_t block_rows_amount = get_block_rows_amount(this->witness_amount(), this->limit_permutation_column); -/* - std::vector full_configuration = - configure_all(this->witness_amount(), num_configs, num_round_calls, limit_permutation_column); - const std::map> gates_configuration_map = configure_map( - this->witness_amount(), num_blocks, num_bits, range_check_input, limit_permutation_column); - const std::vector> gates_configuration = configure_gates( - this->witness_amount(), num_blocks, num_bits, range_check_input, limit_permutation_column); -*/ + const std::size_t rows_amount = get_rows_amount(this->witness_amount(), max_blocks, limit_permutation_column); const std::size_t gates_amount = get_gates_amount(this->witness_amount(), max_blocks, limit_permutation_column); @@ -772,9 +753,9 @@ namespace nil { std::size_t header_row = start_row_index + block * component.block_rows_amount; assignment.enable_selector(header_selector, header_row); if( block != 0 ) - assignment.enable_selector(non_first_header_selector, start_row_index + header_row); + assignment.enable_selector(non_first_header_selector, header_row); else - assignment.enable_selector(first_header_selector, start_row_index + header_row); + assignment.enable_selector(first_header_selector, header_row); std::size_t state_row = header_row + component.header_rows_amount; for( std::size_t j = 0; j < component.state_rows_amount; j++ ){ @@ -905,6 +886,7 @@ namespace nil { l = msg.size() - block * 136; bool is_first = (block == 0? 1: 0); bool is_last = ((block == padded_msg.size()/136 - 1 )? 1: 0); + std::cout << "Is_last = " << is_last << std::endl; if (is_first) rlc = msg.size(); assignment.witness(m.h.is_first.index, header_row) = is_first; @@ -1176,7 +1158,6 @@ namespace nil { ); } } - } // namespace components } // namespace blueprint } // namespace nil diff --git a/include/nil/blueprint/components/hashes/keccak/keccak_table.hpp b/include/nil/blueprint/components/hashes/keccak/keccak_table.hpp new file mode 100644 index 00000000..ec73367a --- /dev/null +++ b/include/nil/blueprint/components/hashes/keccak/keccak_table.hpp @@ -0,0 +1,232 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Elena Tatuzova +// +// 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_BLUEPRINT_COMPONENTS_KECCAK_TABLE_HPP +#define CRYPTO3_BLUEPRINT_COMPONENTS_KECCAK_TABLE_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace nil { + namespace blueprint { + namespace components { + template + class keccak_table; + + template + class keccak_table> + : public plonk_component + { + public: + using component_type = plonk_component; + using var = typename component_type::var; + using manifest_type = plonk_component_manifest; + + std::size_t max_blocks; + + struct keccak_table_map { + var is_last; + var hash_hi; + var hash_lo; + var RLC; + + keccak_table_map(const keccak_table &component){ + is_last = var(component.W(0), 0); + RLC = var(component.W(1), 0); + hash_hi = var(component.W(2), 0); + hash_lo = var(component.W(3), 0); + } + }; + + class gate_manifest_type : public component_gate_manifest { + public: + std::uint32_t gates_amount() const override { + return 0; + } + }; + + static gate_manifest get_gate_manifest(std::size_t witness_amount, std::size_t max_blocks) { + gate_manifest manifest = gate_manifest(gate_manifest_type()); + return manifest; + } + + static manifest_type get_manifest() { + static manifest_type manifest = manifest_type( + std::shared_ptr(new manifest_single_value_param(4)), + false + ); + return manifest; + } + + constexpr static std::size_t get_rows_amount(std::size_t witness_amount, std::size_t max_blocks) { + return max_blocks; + } + + constexpr static const std::size_t gates_amount = 0; + constexpr static const std::size_t lookup_gates_amount = 0; + std::size_t rows_amount = max_blocks; + + struct input_type { + var rlc_challenge; + std::vector, + std::pair + >> input; + + std::vector> all_vars() { + std::vector> res; + res.push_back(rlc_challenge); + return res; + } + }; + + struct result_type { + result_type(const keccak_table &component, std::size_t start_row_index) { + } + + std::vector> all_vars() { + std::vector> result; + return result; + } + }; + + template + explicit keccak_table(ContainerType witness, std::size_t _max_blocks) : + component_type(witness, {}, {}, get_manifest()), max_blocks(_max_blocks) + {}; + + template + keccak_table(WitnessContainerType witness, ConstantContainerType constant, + PublicInputContainerType public_input, + std::size_t _max_blocks + ) : component_type(witness, constant, public_input, get_manifest()), max_blocks(_max_blocks) {}; + + keccak_table( + std::initializer_list witnesses, + std::initializer_list + constants, + std::initializer_list + public_inputs, + std::size_t _max_blocks + ) : component_type(witnesses, constants, public_inputs, get_manifest()), max_blocks(_max_blocks){}; + }; + + template + using plonk_keccak_table = + keccak_table>; + + template + typename plonk_keccak_table::result_type generate_assignments( + const plonk_keccak_table &component, + assignment> + &assignment, + const typename plonk_keccak_table::input_type + &instance_input, + const std::uint32_t start_row_index + ) { + using component_type = plonk_keccak_table; + using value_type = typename BlueprintFieldType::value_type; + + value_type theta = var_value(assignment, instance_input.rlc_challenge); + std::size_t input_idx = 0; + std::size_t block_counter = 0; + std::vector msg; + std::pair hash; + typename component_type::keccak_table_map t(component); + std::cout << "Keccak table generate assignments" << std::endl; + while( block_counter < component.max_blocks ) { + if( input_idx < instance_input.input.size() ){ + msg = std::get<0>(instance_input.input[input_idx]); + hash = std::get<1>(instance_input.input[input_idx]); + input_idx++; + } else { + msg = {0}; + hash = {0xbc36789e7a1e281436464229828f817d_cppui_modular254, 0x6612f7b477d66591ff96a9e064bcc98a_cppui_modular254}; + } + value_type RLC = calculateRLC(msg, theta); + for( std::size_t block = 0; block < std::ceil(float(msg.size() + 1)/136); block++){ + if( block != std::ceil(float(msg.size() + 1)/136) - 1){ + std::cout << "0 "; + assignment.witness(t.is_last.index, start_row_index + block_counter) = 0; + } else { + std::cout << "1 "; + assignment.witness(t.is_last.index, start_row_index + block_counter) = 1; + } + std::cout << std::hex << RLC << " " << hash.first << " " << hash.second << std::dec << std::endl; + assignment.witness(t.RLC.index, start_row_index + block_counter) = RLC; + assignment.witness(t.hash_hi.index, start_row_index + block_counter) = hash.first; + assignment.witness(t.hash_lo.index, start_row_index + block_counter) = hash.second; + block_counter++; + } + } + std::cout << "Keccak table assignments generated" << std::endl; + return typename component_type::result_type(component, start_row_index); + } + + template + typename plonk_keccak_table::result_type generate_circuit( + const plonk_keccak_table &component, + circuit> &bp, + assignment> + &assignment, + const typename plonk_keccak_table::input_type + &instance_input, + const std::size_t start_row_index + ) { + using component_type = plonk_keccak_table; + using var = typename component_type::var; + + bp.register_dynamic_table("keccak_table"); + std::size_t selector_index = bp.get_dynamic_lookup_table_selector(); + assignment.enable_selector(selector_index, start_row_index, start_row_index + component.rows_amount - 1); + + crypto3::zk::snark::plonk_lookup_table keccak_table; + typename component_type::keccak_table_map t(component); + + keccak_table.tag_index = selector_index; + keccak_table.columns_number = 4;// + keccak_table.lookup_options = {{ + t.is_last, + t.RLC, + t.hash_hi, + t.hash_lo + }}; + bp.define_dynamic_table("keccak_table", keccak_table); + + return typename component_type::result_type(component, start_row_index); + } + } + } +} +#endif \ No newline at end of file diff --git a/include/nil/blueprint/utils/satisfiability_check.hpp b/include/nil/blueprint/utils/satisfiability_check.hpp index 72b77e23..fe8d1d03 100644 --- a/include/nil/blueprint/utils/satisfiability_check.hpp +++ b/include/nil/blueprint/utils/satisfiability_check.hpp @@ -180,6 +180,13 @@ namespace nil { std::cout << lookup_input << std::endl; } } + std::cout << "Possible values: " << std::endl; + for( auto &value : used_dynamic_tables[table_name]){ + for (std::size_t k = 0; k < value.size(); k++) { + std::cout << std::hex << value[k] << std::dec << " "; + } + std::cout << std::endl; + } return false; } continue; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ad0ab816..101211c2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -123,6 +123,7 @@ set(PLONK_TESTS_FILES "hashes/plonk/keccak_padding" "hashes/plonk/keccak_static" "hashes/plonk/keccak_dynamic" + "hashes/plonk/keccak_component" "hashes/plonk/decomposition" "hashes/plonk/detail/sha_table_generators_base4" "hashes/plonk/detail/sha_table_generators_base7" diff --git a/test/hashes/plonk/keccak_component.cpp b/test/hashes/plonk/keccak_component.cpp new file mode 100644 index 00000000..903c8260 --- /dev/null +++ b/test/hashes/plonk/keccak_component.cpp @@ -0,0 +1,192 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Elena Tatuzova +// +// 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 plonk_keccak_component_test + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +// #include +#include +// #include + +#include + +#include +#include +#include +#include + +#include "../../test_plonk_component.hpp" +#include "../../random_test_initializer.hpp" + +template +void test_keccaks( + std::vector, + std::pair + >> input, + nil::test_tools::random_test_initializer &rnd +){ + std::cout << "Test keccak with " << input.size() << " messages" << std::endl; + + constexpr std::size_t WitnessesAmount = 15; // May be changed in next version + constexpr std::size_t PublicInputColumns = 1; + constexpr std::size_t ConstantColumns = 8; + constexpr std::size_t SelectorColumns = 60; + nil::crypto3::zk::snark::plonk_table_description desc(WitnessesAmount, PublicInputColumns, + ConstantColumns, SelectorColumns); + using ArithmetizationType = nil::crypto3::zk::snark::plonk_constraint_system; + using AssignmentType = nil::blueprint::assignment; + using hash_type = nil::crypto3::hashes::keccak_1600<256>; + constexpr std::size_t Lambda = 1; + + using component_type = nil::blueprint::components::keccak_component; + using var = nil::crypto3::zk::snark::plonk_variable; + + var rlc_challenge(0, 0, false, var::column_type::public_input); + typename component_type::input_type instance_input; + instance_input.rlc_challenge = rlc_challenge; + instance_input.input = input; + + std::size_t limit_permutation_columns = 15; + + auto result_check = [](AssignmentType &assignment, typename component_type::result_type &real_res) {}; + + if (!(WitnessesAmount == 15)) { + BOOST_ASSERT_MSG(false, "Please add support for WitnessesAmount that you passed here!"); + } + std::array witnesses; + for (std::uint32_t i = 0; i < WitnessesAmount; i++) { + witnesses[i] = i; + } + + std::vector public_input = {rnd.alg_random_engines.template get_alg_engine()()}; + + // Last parameter is LPC + component_type component_instance = + component_type(witnesses, std::array {0}, std::array {0}, max_blocks, limit_permutation_columns); + + nil::crypto3::test_component( + component_instance, desc, public_input, result_check, instance_input, + nil::blueprint::connectedness_check_type::type::NONE, + max_blocks, limit_permutation_columns); +} + +template +std::pair +calculate_hash(std::vector input){ + hashes::keccak_1600<256>::digest_type d = nil::crypto3::hash>(input); + nil::crypto3::algebra::fields::field<256>::integral_type n(d); + nil::crypto3::algebra::fields::field<256>::integral_type mask = ((nil::crypto3::algebra::fields::field<256>::integral_type(1) << 128) - 1); + std::pair result; + result.first = typename BlueprintFieldType::value_type(n >> 128); + result.second = typename BlueprintFieldType::value_type(n & mask); + + std::cout << "Message hash = " << std::hex << result.first << " " << result.second << std::dec << std::endl; + return result; +} + +BOOST_AUTO_TEST_SUITE(bn254_test_suite) + using field_type = nil::crypto3::algebra::curves::alt_bn128_254::base_field_type; +BOOST_AUTO_TEST_CASE(keccak_1_short_message) { + nil::test_tools::random_test_initializer rnd; + test_keccaks({{{0},calculate_hash({0})}}, rnd); +} +BOOST_AUTO_TEST_CASE(keccak_2_short_messages) { + nil::test_tools::random_test_initializer rnd; + test_keccaks({{{0, 0},calculate_hash({0, 0})}, {{1,2,3,4,5}, calculate_hash({1,2,3,4,5})}}, rnd); +} +BOOST_AUTO_TEST_CASE(keccak_1_N_message) { + nil::test_tools::random_test_initializer rnd; + std::size_t N = 5; + for (std::size_t i = 0; i < std::size_t(boost::unit_test::framework::master_test_suite().argc - 1); i++) { + std:: cout << boost::unit_test::framework::master_test_suite().argv[i] << std::endl; + if (std::string(boost::unit_test::framework::master_test_suite().argv[i]) == "--n") { + if (std::regex_match(boost::unit_test::framework::master_test_suite().argv[i + 1], + std::regex(("((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?")))) { + N = atoi(boost::unit_test::framework::master_test_suite().argv[i + 1]); + break; + } + } + } + std::vector msg(N); + for( std::size_t i = 0; i < N; i++ ){ msg[i] = (rnd.generic_random_engine()) % 256; } + test_keccaks({{msg,calculate_hash(msg)}}, rnd); +} +BOOST_AUTO_TEST_CASE(keccak_1_N_zeroes) { + nil::test_tools::random_test_initializer rnd; + std::size_t N = 5; + for (std::size_t i = 0; i < std::size_t(boost::unit_test::framework::master_test_suite().argc - 1); i++) { + std:: cout << boost::unit_test::framework::master_test_suite().argv[i] << std::endl; + if (std::string(boost::unit_test::framework::master_test_suite().argv[i]) == "--n") { + if (std::regex_match(boost::unit_test::framework::master_test_suite().argv[i + 1], + std::regex(("((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?")))) { + N = atoi(boost::unit_test::framework::master_test_suite().argv[i + 1]); + break; + } + } + } + std::vector msg(N, 0x0); + test_keccaks({{msg,calculate_hash(msg)}}, rnd); +} +BOOST_AUTO_TEST_CASE(keccak_1_long_message) { + nil::test_tools::random_test_initializer rnd; + std::vector msg(500, 5); + test_keccaks({{msg,calculate_hash(msg)}}, rnd); +} +BOOST_AUTO_TEST_CASE(keccak_2_long_messages) { + nil::test_tools::random_test_initializer rnd; + std::vector msg1(136, 6); + std::vector msg2(277, 7); + test_keccaks({{msg1,calculate_hash(msg1)}, {msg2,calculate_hash(msg2)}}, rnd); +} + +BOOST_AUTO_TEST_CASE(keccak_test_hello_world){ + nil::test_tools::random_test_initializer rnd; + std::vector msg = { + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0x68, + 0x65, 0x6c, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c}; + test_keccaks({{msg, calculate_hash(msg)}}, rnd); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/hashes/plonk/keccak_dynamic.cpp b/test/hashes/plonk/keccak_dynamic.cpp index 9ad30e4d..af5b5df2 100644 --- a/test/hashes/plonk/keccak_dynamic.cpp +++ b/test/hashes/plonk/keccak_dynamic.cpp @@ -47,7 +47,9 @@ #include #include +#include #include +#include #include "../../test_plonk_component.hpp" #include "../../random_test_initializer.hpp" @@ -81,7 +83,7 @@ void test_keccaks( instance_input.rlc_challenge = rlc_challenge; instance_input.input = input; - std::size_t limit_permutation_columns = 7; + std::size_t limit_permutation_columns = 15; auto result_check = [](AssignmentType &assignment, typename component_type::result_type &real_res) {};