From 977dcedb2505673b85b8357ca295b888f4d27ef4 Mon Sep 17 00:00:00 2001 From: Antoine Cyr Date: Tue, 25 Feb 2025 10:41:41 -0500 Subject: [PATCH] keccak zkEVM bbf --- .../hashes/keccak/keccak_dynamic.hpp | 8 +- .../nil/blueprint/zkevm_bbf/keccak.hpp | 109 ++++++++++++++---- .../blueprint/zkevm_bbf/opcodes/add_sub.hpp | 6 - .../zkevm_bbf/subcomponents/keccak_table.hpp | 1 - .../libs/blueprint/test/zkevm_bbf/hardhat.cpp | 87 ++++++++------ .../test/zkevm_bbf/opcodes/byte_ops.cpp | 2 +- .../zkevm_bbf/opcodes/opcode_test_fixture.hpp | 9 +- .../commands/detail/io/circuit_io.hpp | 2 +- .../nil/proof-generator/assigner/keccak.hpp | 6 +- .../nil/proof-generator/preset/keccak.hpp | 7 +- verify-proofs.nix | 4 +- 11 files changed, 161 insertions(+), 80 deletions(-) diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp index 86f596bc21..8f6bb4d6a3 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp @@ -196,10 +196,13 @@ namespace nil { context_object.allocate(input.rlc_challenge, 0, 0, column_type::public_input); } + + std::size_t max_blocks; + std::vector m = std::vector(max_blocks); keccak_dynamic(context_type &context_object, input_type instance_input, - std::size_t max_blocks, bool make_links = true) - : generic_component(context_object) { + std::size_t max_blocks_, bool make_links = true) + : max_blocks(max_blocks_), generic_component(context_object) { using integral_type = typename FieldType::integral_type; using value_type = typename FieldType::value_type; @@ -213,7 +216,6 @@ namespace nil { TYPE RLC; // constants - keccak_map m[max_blocks]; std::array state; std::vector msg = std::vector(); std::vector padded_msg = std::vector(); diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/keccak.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/keccak.hpp index 6707c9fe73..0f639defff 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/keccak.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/keccak.hpp @@ -1,5 +1,6 @@ //---------------------------------------------------------------------------// -// Elena Tatuzova +// Copyright (c) 2024 Elena Tatuzova +// Copyright (c) 2025 Antoine Cyr // // MIT License // @@ -23,13 +24,15 @@ //---------------------------------------------------------------------------// #pragma once +#include +#include #include namespace nil { namespace blueprint { namespace bbf { template - class keccak : public generic_component { + class zkevm_keccak : public generic_component { using typename generic_component::context_type; using generic_component::allocate; using generic_component::copy_constrain; @@ -37,39 +40,105 @@ namespace nil { using generic_component::lookup; using generic_component::lookup_table; - public: - using typename generic_component::table_params; - using typename generic_component::TYPE; + public: + using KeccakDynamic = typename bbf::keccak_dynamic; + using KeccakTable = typename bbf::keccak_table; - using private_input_type = std::conditional_t< - stage == GenerationStage::ASSIGNMENT, - std::size_t, std::monostate - >; + using typename generic_component::table_params; + using typename generic_component::TYPE; + using integral_type = nil::crypto3::multiprecision::big_uint<257>; + using private_input_type = + typename std::conditional::type; - struct input_type{ + struct input_type { TYPE rlc_challenge; private_input_type private_input; }; - static table_params get_minimal_requirements() { + static table_params get_minimal_requirements( + std::size_t max_keccak_blocks) { return { .witnesses = 20, .public_inputs = 1, .constants = 3, - .rows = 300 - }; + .rows = KeccakDynamic::get_minimal_requirements(max_keccak_blocks) + .rows}; } - static void allocate_public_inputs(context_type &context, input_type &input) { - context.allocate(input.rlc_challenge, 0, 0, column_type::public_input); + static void allocate_public_inputs(context_type& context, + input_type& input, + std::size_t max_keccak_blocks) { + context.allocate(input.rlc_challenge, 0, 0, + column_type::public_input); } - keccak(context_type &context_object, const input_type &input) :generic_component(context_object) { + zkevm_keccak(context_type& context_object, const input_type& input, + std::size_t max_keccak_blocks) + : generic_component(context_object) { + std::vector keccak_lookup_area; + std::vector keccak_dynamic_lookup_area; + std::size_t current_column = 0; + std::size_t dynamic_rows = + KeccakDynamic::get_minimal_requirements(max_keccak_blocks).rows; + + for (std::size_t i = 0; i < KeccakTable::get_witness_amount(); i++) { + keccak_lookup_area.push_back(current_column++); + } + + for (std::size_t i = 0; + i < KeccakDynamic::get_minimal_requirements(max_keccak_blocks) + .witnesses; + i++) { + keccak_dynamic_lookup_area.push_back(current_column++); + } + + context_type keccak_ct = context_object.subcontext( + keccak_lookup_area, 1, dynamic_rows + 1); + + context_type keccak_dynamic_ct = context_object.subcontext( + keccak_dynamic_lookup_area, 1, dynamic_rows + 1); + typename KeccakDynamic::input_type input_dynamic; + typename KeccakTable::input_type input_keccak_table; + TYPE rlc_challenge; + if constexpr (stage == GenerationStage::ASSIGNMENT) { - std::cout << "Keccak assign = " << input.private_input << std::endl; + rlc_challenge = input.rlc_challenge; + input_dynamic.rlc_challenge = input.rlc_challenge; + for (const auto& item : input.private_input.get_data()) { + const auto& buffer = item.first; + const auto& zkevm_word = item.second; + + TYPE hi = w_hi(zkevm_word); + TYPE lo = w_lo(zkevm_word); + std::pair pair_values = {hi, lo}; + + input_dynamic.input.emplace_back(buffer, pair_values); + } + input_keccak_table.rlc_challenge = input.rlc_challenge; + input_keccak_table.private_input = input.private_input; + } + KeccakTable kt = + KeccakTable(keccak_ct, input_keccak_table, max_keccak_blocks); + + allocate(rlc_challenge, 0, 0); + input_dynamic.rlc_challenge = rlc_challenge; + KeccakDynamic kd = KeccakDynamic(keccak_dynamic_ct, input_dynamic, + max_keccak_blocks); + + if constexpr (stage == GenerationStage::CONSTRAINTS) { + std::vector tmp; + for (std::size_t i = 0; i < max_keccak_blocks; i++) { + tmp = {TYPE(1), kt.RLC[i], kt.hash_hi[i], kt.hash_lo[i], + kt.is_last[i]}; + lookup(tmp, "keccak_dynamic"); + tmp = {kd.m[i].h.is_last, kd.m[i].h.RLC, kd.m[i].h.hash_hi, + kd.m[i].h.hash_lo}; + lookup(tmp, "keccak_table"); + } } } }; - } - } -} + } // namespace bbf + } // namespace blueprint +} // namespace nil diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/add_sub.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/add_sub.hpp index 71a97f3858..7c2ebb556b 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/add_sub.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/add_sub.hpp @@ -80,17 +80,11 @@ namespace nil { carry1 = (A_128.first + B_128.first + carry0 >= two_128); } for( std::size_t i = 0; i < 16; i++){ - std::cout<<"i: "<(A); auto B_128 = chunks16_to_chunks128(B); diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/subcomponents/keccak_table.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/subcomponents/keccak_table.hpp index 7f4afe44f2..3b2451db16 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/subcomponents/keccak_table.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/subcomponents/keccak_table.hpp @@ -74,7 +74,6 @@ namespace nil { ) : max_blocks(max_blocks_), generic_component(context_object) { - std::cout << "a"; if constexpr (stage == GenerationStage::ASSIGNMENT) { TYPE theta = input.rlc_challenge; diff --git a/crypto3/libs/blueprint/test/zkevm_bbf/hardhat.cpp b/crypto3/libs/blueprint/test/zkevm_bbf/hardhat.cpp index 1ab093ed71..dfd432795b 100644 --- a/crypto3/libs/blueprint/test/zkevm_bbf/hardhat.cpp +++ b/crypto3/libs/blueprint/test/zkevm_bbf/hardhat.cpp @@ -110,8 +110,9 @@ class zkEVMHardhatTestFixture: public CircuitTestFixture { auto rw_assignment_input = circuit_inputs.rw_operations(); - typename keccak::input_type keccak_assignment_input; - keccak_assignment_input.private_input = 12345; + typename zkevm_keccak::input_type keccak_assignment_input; + keccak_assignment_input.rlc_challenge = 7; + keccak_assignment_input.private_input = circuit_inputs.keccaks(); typename bytecode::input_type bytecode_assignment_input; bytecode_assignment_input.rlc_challenge = 7; @@ -121,6 +122,18 @@ class zkEVMHardhatTestFixture: public CircuitTestFixture { auto exp_assignment_input = circuit_inputs.exponentiations(); bool result{false}; + // Max_rows, max_bytecode, max_rw + result = test_bbf_component( + "zkevm", + {}, zkevm_assignment_input, + max_zkevm_rows, + max_copy, + max_rw, + max_exponentiations, + max_bytecode + ); + BOOST_ASSERT(result); + std::cout << std::endl; const std::string zkevm_circuit = "zkevm"; if (should_run_circuit(zkevm_circuit)) { @@ -141,8 +154,6 @@ class zkEVMHardhatTestFixture: public CircuitTestFixture { const std::string exp_circuit = "exp"; if (should_run_circuit(exp_circuit)) { - std::cout << "circuit '" << exp_circuit << "'" << std::endl; - // Max_copy, Max_rw, Max_keccak, Max_bytecode result =test_bbf_component( exp_circuit, @@ -173,9 +184,9 @@ class zkEVMHardhatTestFixture: public CircuitTestFixture { std::cout << "circuit '" << keccak_circuit << "'" << std::endl; // Max_keccak - result = test_bbf_component( + result = test_bbf_component( keccak_circuit, - {}, keccak_assignment_input + {}, keccak_assignment_input,max_keccak_blocks ); BOOST_ASSERT(result); std::cout << std::endl; @@ -218,14 +229,14 @@ BOOST_AUTO_TEST_CASE(minimal_math) { auto [bytecodes, pts] = load_hardhat_input("minimal_math/"); l1_size_restrictions max_sizes; - max_sizes.max_keccak_blocks = 10; - max_sizes.max_bytecode = 3000; + max_sizes.max_keccak_blocks = 3; + max_sizes.max_bytecode = 300; max_sizes.max_mpt = 0; max_sizes.max_rw = 500; - max_sizes.max_copy = 500; + max_sizes.max_copy = 70; max_sizes.max_zkevm_rows = 500; - max_sizes.max_exponentiations = 50; - max_sizes.max_exp_rows = 500; + max_sizes.max_exponentiations = 10; + max_sizes.max_exp_rows = 100; complex_test(bytecodes, pts, max_sizes); } @@ -235,14 +246,14 @@ BOOST_AUTO_TEST_CASE(modular_operations) { auto [bytecodes, pts] = load_hardhat_input("modular_operations/"); l1_size_restrictions max_sizes; - max_sizes.max_keccak_blocks = 10; - max_sizes.max_bytecode = 3000; + max_sizes.max_keccak_blocks = 4; + max_sizes.max_bytecode = 300; max_sizes.max_mpt = 0; max_sizes.max_rw = 500; - max_sizes.max_copy = 500; + max_sizes.max_copy = 70; max_sizes.max_zkevm_rows = 500; - max_sizes.max_exponentiations = 50; - max_sizes.max_exp_rows = 500; + max_sizes.max_exponentiations = 10; + max_sizes.max_exp_rows = 100; complex_test(bytecodes, pts, max_sizes); } @@ -252,14 +263,14 @@ BOOST_AUTO_TEST_CASE(exp) { auto [bytecodes, pts] = load_hardhat_input("exp/"); l1_size_restrictions max_sizes; - max_sizes.max_keccak_blocks = 10; - max_sizes.max_bytecode = 3000; + max_sizes.max_keccak_blocks = 4; + max_sizes.max_bytecode = 400; max_sizes.max_mpt = 0; - max_sizes.max_rw = 1000; - max_sizes.max_copy = 500; - max_sizes.max_zkevm_rows = 2000; - max_sizes.max_exp_rows = 500; - max_sizes.max_exponentiations = 50; + max_sizes.max_rw = 950; + max_sizes.max_copy = 80; + max_sizes.max_zkevm_rows = 1250; + max_sizes.max_exponentiations = 10; + max_sizes.max_exp_rows = 100; complex_test(bytecodes, pts, max_sizes); } @@ -269,14 +280,14 @@ BOOST_AUTO_TEST_CASE(keccak) { auto [bytecodes, pts] = load_hardhat_input("keccak/"); l1_size_restrictions max_sizes; - max_sizes.max_keccak_blocks = 10; - max_sizes.max_bytecode = 3000; + max_sizes.max_keccak_blocks = 5; + max_sizes.max_bytecode = 400; max_sizes.max_mpt = 0; - max_sizes.max_rw = 1000; - max_sizes.max_copy = 500; + max_sizes.max_rw = 900; + max_sizes.max_copy = 200; max_sizes.max_zkevm_rows = 500; - max_sizes.max_exponentiations = 50; - max_sizes.max_exp_rows = 500; + max_sizes.max_exponentiations = 10; + max_sizes.max_exp_rows = 100; complex_test(bytecodes, pts, max_sizes); } @@ -286,7 +297,7 @@ BOOST_AUTO_TEST_CASE(mstore8) { auto [bytecodes, pts] = load_hardhat_input("mstore8/"); l1_size_restrictions max_sizes; - max_sizes.max_keccak_blocks = 50; + max_sizes.max_keccak_blocks = 25; max_sizes.max_bytecode = 3000; max_sizes.max_mpt = 0; max_sizes.max_rw = 5000; @@ -303,7 +314,7 @@ BOOST_AUTO_TEST_CASE(meminit) { auto [bytecodes, pts] = load_hardhat_input("mem_init/"); l1_size_restrictions max_sizes; - max_sizes.max_keccak_blocks = 50; + max_sizes.max_keccak_blocks = 10; max_sizes.max_bytecode = 3000; max_sizes.max_mpt = 0; max_sizes.max_rw = 10000; @@ -320,14 +331,14 @@ BOOST_AUTO_TEST_CASE(calldatacopy) { auto [bytecodes, pts] = load_hardhat_input("calldatacopy/"); l1_size_restrictions max_sizes; - max_sizes.max_keccak_blocks = 50; - max_sizes.max_bytecode = 3000; + max_sizes.max_keccak_blocks = 4; + max_sizes.max_bytecode = 300; max_sizes.max_mpt = 0; - max_sizes.max_rw = 5000; - max_sizes.max_copy = 3000; - max_sizes.max_zkevm_rows = 4500; - max_sizes.max_exponentiations = 50; - max_sizes.max_exp_rows = 500; + max_sizes.max_rw = 500; + max_sizes.max_copy = 90; + max_sizes.max_zkevm_rows = 500; + max_sizes.max_exponentiations = 10; + max_sizes.max_exp_rows = 100; complex_test(bytecodes, pts, max_sizes); } diff --git a/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/byte_ops.cpp b/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/byte_ops.cpp index 41cd75ce06..00f92a7b73 100644 --- a/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/byte_ops.cpp +++ b/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/byte_ops.cpp @@ -322,7 +322,7 @@ BOOST_AUTO_TEST_CASE(byte_ops) { opcode_tester.push_opcode(zkevm_opcode::SHL); opcode_tester.push_opcode(zkevm_opcode::STOP); - max_sizes.max_keccak_blocks = 400; + max_sizes.max_keccak_blocks = 30; max_sizes.max_bytecode = 5000; max_sizes.max_mpt = 0; max_sizes.max_rw = 3000; diff --git a/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/opcode_test_fixture.hpp b/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/opcode_test_fixture.hpp index 5bd9c15fc1..3afaadf4e0 100644 --- a/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/opcode_test_fixture.hpp +++ b/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/opcode_test_fixture.hpp @@ -100,8 +100,9 @@ class zkEVMOpcodeTestFixture: public CircuitTestFixture { auto rw_assignment_input = circuit_inputs.rw_operations(); - typename keccak::input_type keccak_assignment_input; - keccak_assignment_input.private_input = 12345; + typename nil::blueprint::bbf::zkevm_keccak::input_type keccak_assignment_input; + keccak_assignment_input.rlc_challenge = 7; + keccak_assignment_input.private_input = circuit_inputs.keccaks(); typename bytecode::input_type bytecode_assignment_input; bytecode_assignment_input.rlc_challenge = 7; @@ -164,9 +165,9 @@ class zkEVMOpcodeTestFixture: public CircuitTestFixture { std::cout << std::endl; // Max_keccak - result = test_bbf_component( + result = test_bbf_component( "keccak", - {}, keccak_assignment_input + {}, keccak_assignment_input , max_keccak_blocks ); BOOST_CHECK(result); std::cout << std::endl; diff --git a/proof-producer/bin/proof-producer/include/nil/proof-generator/commands/detail/io/circuit_io.hpp b/proof-producer/bin/proof-producer/include/nil/proof-generator/commands/detail/io/circuit_io.hpp index db8298ed57..50ea6d2a4d 100644 --- a/proof-producer/bin/proof-producer/include/nil/proof-generator/commands/detail/io/circuit_io.hpp +++ b/proof-producer/bin/proof-producer/include/nil/proof-generator/commands/detail/io/circuit_io.hpp @@ -77,7 +77,7 @@ namespace nil { return CommandResult::Error(ResultCode::IOError, "No circuit is currently loaded"); } - std::ofstream out(circuit_file_path_, std::ios::binary | std::ios::out); + std::ofstream out(circuit_file_path_.string(), std::ios::binary | std::ios::out); if (!out.is_open()) { return CommandResult::Error(ResultCode::IOError, "Failed to open file {}", circuit_file_path_.string()); } diff --git a/proof-producer/libs/assigner/include/nil/proof-generator/assigner/keccak.hpp b/proof-producer/libs/assigner/include/nil/proof-generator/assigner/keccak.hpp index ebb5292755..51356d062e 100644 --- a/proof-producer/libs/assigner/include/nil/proof-generator/assigner/keccak.hpp +++ b/proof-producer/libs/assigner/include/nil/proof-generator/assigner/keccak.hpp @@ -19,7 +19,7 @@ namespace nil { const AssignerOptions& options) { BOOST_LOG_TRIVIAL(debug) << "fill keccak table from " << trace_base_path << "\n"; - using ComponentType = nil::blueprint::bbf::keccak; + using ComponentType = nil::blueprint::bbf::zkevm_keccak; typename nil::blueprint::bbf::context context_object(assignment_table, options.circuits_limits.max_total_rows); @@ -33,10 +33,12 @@ namespace nil { } // TODO(oclaw) adjust input // input = std::move(keccak_operations->value); + std::size_t max_keccak_blocks = 25; //TODO: current max_keccak_blocks is a placeholder value ComponentType instance( context_object, - input + input, + max_keccak_blocks // ,options.circuits_limits.max_total_rows, // options.circuits_limits.max_keccak_blocks ); diff --git a/proof-producer/libs/preset/include/nil/proof-generator/preset/keccak.hpp b/proof-producer/libs/preset/include/nil/proof-generator/preset/keccak.hpp index fe52808be2..689382b3a1 100644 --- a/proof-producer/libs/preset/include/nil/proof-generator/preset/keccak.hpp +++ b/proof-producer/libs/preset/include/nil/proof-generator/preset/keccak.hpp @@ -26,8 +26,11 @@ namespace nil { using ConstraintSystem = typename PresetTypes::ConstraintSystem; using AssignmentTable = typename PresetTypes::AssignmentTable; - // TODO(oclaw): add circuits_limits.max_total_rows, circuits_limits.max_keccak_blocks? - blueprint::bbf::circuit_builder builder; + // TODO(oclaw): circuits_limits.max_keccak_blocks? + std::size_t max_keccak_blocks = 25; //TODO: current max_keccak_blocks is a placeholder value + blueprint::bbf::circuit_builder< + BlueprintFieldType, nil::blueprint::bbf::zkevm_keccak, std::size_t + > builder(max_keccak_blocks); keccak_circuit = std::make_shared(builder.get_circuit()); diff --git a/verify-proofs.nix b/verify-proofs.nix index 0627cb990a..89ff6d378a 100644 --- a/verify-proofs.nix +++ b/verify-proofs.nix @@ -48,8 +48,8 @@ in stdenv.mkDerivation rec { "-DBUILD_PARALLEL_CRYPTO3_TESTS=TRUE" (if sanitize then "-DSANITIZE=ON" else "-DSANITIZE=OFF") "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON" # to allow VSCode navigation/completion/etc - "-G Ninja" - ]; + "-G Ninja" + ]; buildPhase = '' ninja blueprint_multi_thread_zkevm_bbf_hardhat_test