From 3e188aed12bbf8bd7fa85a49226b20416b2df9c2 Mon Sep 17 00:00:00 2001 From: x-mass <36629999+x-mass@users.noreply.github.com> Date: Mon, 20 Jan 2025 11:22:29 +0000 Subject: [PATCH] feat(proof-producer): enable exp traces after fix --- .../nil/blueprint/zkevm_bbf/opcodes/logx.hpp | 15 +++++++++++++++ .../zkevm_bbf/opcodes/zkevm_opcodes.hpp | 8 ++++++++ .../proof-generator/assigner/trace_parser.hpp | 1 - .../nil/proof-generator/assigner/zkevm.hpp | 13 ++++++------- .../resources/traces/exp/exp.bc.bin | Bin 0 -> 883 bytes .../resources/traces/exp/exp.copy.bin | Bin 0 -> 128 bytes .../resources/traces/exp/exp.exp.bin | Bin 0 -> 105 bytes .../resources/traces/exp/exp.mpt.bin | Bin 0 -> 1889 bytes .../resources/traces/exp/exp.rw.bin | Bin 0 -> 9100 bytes .../resources/traces/exp/exp.zkevm.bin | Bin 0 -> 37358 bytes .../resources/traces/increment_simple.msg.bin | Bin 2 -> 0 bytes .../proof-producer/test_zkevm_bbf_circuits.cpp | 7 +++++++ 12 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/logx.hpp create mode 100644 proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.bc.bin create mode 100644 proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.copy.bin create mode 100644 proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.exp.bin create mode 100644 proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.mpt.bin create mode 100644 proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.rw.bin create mode 100644 proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.zkevm.bin delete mode 100644 proof-producer/tests/bin/proof-producer/resources/traces/increment_simple.msg.bin diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/logx.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/logx.hpp new file mode 100644 index 0000000000..2a628ef0ae --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/logx.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include +#include +#include + +namespace nil { + namespace blueprint { + namespace bbf{ + + template + using zkevm_logx_operation = zkevm_dummy_operation; + } // namespace bbf + } // namespace blueprint +} // namespace nil diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/zkevm_opcodes.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/zkevm_opcodes.hpp index 612f9f7767..39b368e893 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/zkevm_opcodes.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/zkevm_opcodes.hpp @@ -81,6 +81,7 @@ #include #include #include +#include "nil/blueprint/zkevm_bbf/opcodes/logx.hpp" namespace nil { namespace blueprint { @@ -733,6 +734,13 @@ namespace nil { opcodes[zkevm_opcode::SWAP15] = std::make_shared>(15); opcodes[zkevm_opcode::SWAP16] = std::make_shared>(16); + // // LOG + opcodes[zkevm_opcode::LOG0] = std::make_shared>(); + opcodes[zkevm_opcode::LOG1] = std::make_shared>(); + opcodes[zkevm_opcode::LOG2] = std::make_shared>(); + opcodes[zkevm_opcode::LOG3] = std::make_shared>(); + opcodes[zkevm_opcode::LOG4] = std::make_shared>(); + // // fake opcodes for errors and padding opcodes[zkevm_opcode::err0] = std::make_shared>(); opcodes[zkevm_opcode::err1] = std::make_shared>(); diff --git a/proof-producer/libs/assigner/include/nil/proof-generator/assigner/trace_parser.hpp b/proof-producer/libs/assigner/include/nil/proof-generator/assigner/trace_parser.hpp index 7706cbc84a..744d053fcf 100644 --- a/proof-producer/libs/assigner/include/nil/proof-generator/assigner/trace_parser.hpp +++ b/proof-producer/libs/assigner/include/nil/proof-generator/assigner/trace_parser.hpp @@ -387,7 +387,6 @@ namespace nil { std::vector exps; exps.reserve(pb_traces->exp_ops_size()); for (const auto& pb_exp_op : pb_traces->exp_ops()) { - BOOST_LOG_TRIVIAL(trace) << "base: " << proto_uint256_to_zkevm_word(pb_exp_op.base()) << " , exponent: " << proto_uint256_to_zkevm_word(pb_exp_op.exponent()) << std::endl; exps.emplace_back( proto_uint256_to_zkevm_word(pb_exp_op.base()), proto_uint256_to_zkevm_word(pb_exp_op.exponent()) diff --git a/proof-producer/libs/assigner/include/nil/proof-generator/assigner/zkevm.hpp b/proof-producer/libs/assigner/include/nil/proof-generator/assigner/zkevm.hpp index dad2f928f9..649f764510 100644 --- a/proof-producer/libs/assigner/include/nil/proof-generator/assigner/zkevm.hpp +++ b/proof-producer/libs/assigner/include/nil/proof-generator/assigner/zkevm.hpp @@ -62,13 +62,12 @@ namespace nil { } input.copy_events = std::move(copy_events->value); - // TODO: fix assignment table filling - // const auto exp_trace_path = get_exp_trace_path(trace_base_path); - // const auto exp_operations = deserialize_exp_traces_from_file(exp_trace_path, options, contract_bytecodes->index); - // if (!exp_operations) { - // return "can't read exp operations from file: " + exp_trace_path.string(); - // } - // input.exponentiations = std::move(exp_operations->value); + const auto exp_trace_path = get_exp_trace_path(trace_base_path); + const auto exp_operations = deserialize_exp_traces_from_file(exp_trace_path, options, contract_bytecodes->index); + if (!exp_operations) { + return "can't read exp operations from file: " + exp_trace_path.string(); + } + input.exponentiations = std::move(exp_operations->value); ComponentType instance( context_object, diff --git a/proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.bc.bin b/proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.bc.bin new file mode 100644 index 0000000000000000000000000000000000000000..2141665c9c0473f4ddee4c291ed654cce4e1ae67 GIT binary patch literal 883 zcmb7DO=#3W6wZvThgC3@b_MC7f}m8yY&JL_8?!t=5@r>qStU%Y5(Ud*7S)O{Orvwa}|w z*EFrvu&uJ8^%;h4T772IulP;dw}&j#^qRV6G%C<6@BH4*1758eK^G`HT*lTY;cb=* zis3SouXG3A((KAaCnyy+@Rsi$yd&T-mr5ciRZvblR1xSTD032V#8?#7K^e?aKzkfI zMM#*QC1cY+FWRHSYhS9plUG(p&JP@FSKmIFIJNld-G%4s%!g4Coq*Q39wgjLCT{Obj!V(kZg8_Ll<1L=UuemTZ$*)L>IMCBpV)ho&SqUVZW5!JEbVUzaZJ zu2!JzgKjk%mMxw}+17Q>C|g6GVQG5VG)&(%8l|RJ(tWD}pf|wx!M62^3BCuqUHSzj CMnYTw literal 0 HcmV?d00001 diff --git a/proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.copy.bin b/proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.copy.bin new file mode 100644 index 0000000000000000000000000000000000000000..ab8fe93edfd7386161423dd08e36ab182d70926c GIT binary patch literal 128 zcmd-w;$qckU=&~wV&PyGV363)tfatzAFv3Ve6;M^k;R`b}nOT~e zCL3EC86}$-o24e3m>C!uo0^!WS(+pnrX(90rI}eICK@FrrlloXS{hlHCZ;7P8d(|w E06`fWE&u=k literal 0 HcmV?d00001 diff --git a/proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.exp.bin b/proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.exp.bin new file mode 100644 index 0000000000000000000000000000000000000000..32f254712de5ad538c0feb8ccead85a249d23e3d GIT binary patch literal 105 zcmd;*=3?VwVParl5Q5TDK$-=}S6IU$aPrZzYeyD;x{xR3V3BB?mS|*_lw@XUYMN|p zX=IdaVr-V0Y+`0$WNd0;nr3N|WSEj{Xq0AVk(g+dl$e&5XlZF=VVanhoM>ce2mq=< B8b|;D literal 0 HcmV?d00001 diff --git a/proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.mpt.bin b/proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.mpt.bin new file mode 100644 index 0000000000000000000000000000000000000000..dabe9c31dc803486c9fa15f2c59141232ce423ab GIT binary patch literal 1889 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 PP*k_1aifxg`nCTJIW`MC literal 0 HcmV?d00001 diff --git a/proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.zkevm.bin b/proof-producer/tests/bin/proof-producer/resources/traces/exp/exp.zkevm.bin new file mode 100644 index 0000000000000000000000000000000000000000..d60b775ead6c5e621dd93b10442742505df9bb40 GIT binary patch literal 37358 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