From 2685a5b183495a509f5813abd7351783cd89cef6 Mon Sep 17 00:00:00 2001 From: Antoine Cyr Date: Thu, 28 Nov 2024 11:44:24 -0500 Subject: [PATCH] signextend --- .../blueprint/zkevm_bbf/opcodes/div_mod.hpp | 26 +- .../zkevm_bbf/opcodes/signextend.hpp | 250 ++++++++++++++++-- .../test/zkevm_bbf/opcodes/byte_ops.cpp | 20 +- 3 files changed, 257 insertions(+), 39 deletions(-) diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/div_mod.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/div_mod.hpp index 994d98613a..80a12febec 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/div_mod.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/div_mod.hpp @@ -326,18 +326,18 @@ namespace nil { 3); // rw_counter transition std::vector tmp; - // tmp = {TYPE(rw_op_to_num(rw_operation_type::stack)), - // current_state.call_id(0), - // current_state.stack_size(0) - 1, - // TYPE(0), // storage_key_hi - // TYPE(0), // storage_key_lo - // TYPE(0), // field - // current_state.rw_counter(0), - // TYPE(0), // is_write - // A0, - // A1}; - // lookup(tmp, "zkevm_rw"); - /* + tmp = {TYPE(rw_op_to_num(rw_operation_type::stack)), + current_state.call_id(0), + current_state.stack_size(0) - 1, + TYPE(0), // storage_key_hi + TYPE(0), // storage_key_lo + TYPE(0), // field + current_state.rw_counter(0), + TYPE(0), // is_write + A0, + A1}; + lookup(tmp, "zkevm_rw"); + tmp = {TYPE(rw_op_to_num(rw_operation_type::stack)), current_state.call_id(0), current_state.stack_size(0) - 2, @@ -360,7 +360,7 @@ namespace nil { TYPE(1), // is_write Res0, Res1}; - lookup(tmp, "zkevm_rw");*/ + lookup(tmp, "zkevm_rw"); } } diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/signextend.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/signextend.hpp index b43fb240fa..c791573680 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/signextend.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/signextend.hpp @@ -1,5 +1,6 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Alexey Yashunsky +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -24,33 +25,250 @@ #pragma once -#include #include - +#include #include #include +#include namespace nil { namespace blueprint { - namespace bbf{ + namespace bbf { template class opcode_abstract; + template + class zkevm_signextend_bbf : public generic_component { + using generic_component::allocate; + using generic_component::copy_constrain; + using generic_component::constrain; + using generic_component::lookup; + using generic_component::lookup_table; + + using value_type = typename FieldType::value_type; + + constexpr static const std::size_t chunk_amount = 16; + constexpr static const value_type two_16 = 65536; + constexpr static const value_type two_32 = 4294967296; + constexpr static const value_type two_48 = 281474976710656; + constexpr static const value_type two_64 = 0x10000000000000000_cppui_modular254; + constexpr static const value_type two_128 = + 0x100000000000000000000000000000000_cppui_modular254; + constexpr static const value_type two_192 = + 0x1000000000000000000000000000000000000000000000000_cppui_modular254; + + public: + using typename generic_component::TYPE; + using typename generic_component::context_type; + + std::vector res; + + public: + zkevm_signextend_bbf(context_type &context_object, + const opcode_input_type ¤t_state) + : generic_component(context_object, false), + res(chunk_amount) { + using integral_type = boost::multiprecision::number< + boost::multiprecision::backends::cpp_int_modular_backend<257>>; + + std::vector b_chunks(chunk_amount); + std::vector x_chunks(chunk_amount); + std::vector r_chunks(chunk_amount); + std::vector indic(chunk_amount); + std::vector cur_i(chunk_amount); + std::vector val_n(chunk_amount); + + TYPE sum_b; + TYPE x_sum; + TYPE sum_b_inverse; + TYPE b0p; + TYPE parity; + TYPE n; + TYPE xn; + TYPE xp; + TYPE xpp; + TYPE sb; + TYPE sgn; + TYPE saux; + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + zkevm_word_type b = current_state.stack_top(); + zkevm_word_type x = current_state.stack_top(1); + + int len = (integral_type(b) < 32) ? int(integral_type(b)) + 1 : 32; + integral_type sign = (integral_type(x) << (8 * (32 - len) + 1)) >> 256; + word_type result = + word_type((((integral_type(1) << 8 * (32 - len)) - 1) << 8 * len) * + sign) + + word_type((integral_type(x) << (8 * (32 - len) + 1)) >> + (8 * (32 - len) + 1)); + // +1 because integral type is 257 bits long + + unsigned int b0 = static_cast(integral_type(b) % 65536); + b0p = (integral_type(b) > 65535) ? 32 : b0; + parity = b0p % 2; + n = (b0p - parity) / 2; + xn = static_cast( + (integral_type(x) << (16 * (n > 15 ? 16 : 15 - n) + 1)) >> + (16 * 15 + 1)); + // +1 because integral_type is 257 bits long + xpp = xn % 256; + xp = (xn - xpp) / 256; + sb = (parity == 0) ? xpp : xp; + sgn = (sb > 128); + saux = sb + 128 - sgn * 256; + + b_chunks = zkevm_word_to_field_element(b); + x_chunks = zkevm_word_to_field_element(x); + r_chunks = zkevm_word_to_field_element(result); + for (std::size_t i = 0; i < chunk_amount; i++) { + cur_i[i] = i; + val_n[i] = n; + indic[i] = (cur_j == val_n) ? 0 : (cur_j - val_n).inversed(); + } + + sum_b = 0; + for (std::size_t i = 1; j < chunk_amount; i++) { + sum_b += b_chunks[i]; + } + sum_b_inverse = sum_b.is_zero() ? 0 : sum_b.inversed(); + + x_sum = 0; + for(std::size_t i = 0; i < chunk_amount; i++) { + x_sum += x_chunks[i] * (1 - (i - n)*indic[i]); + } + } + + allocate(n); + for (std::size_t i = 0; i < chunk_amount; i++) { + allocate(b_chunks[i], i, 0); + allocate(x_chunks[i], i + chunk_amount, 0); + allocate(r_chunks[i], i + chunk_amount, 1); + allocate(indic); + res[i] = r_chunks[i]; + constrain((i - n)*(1 - (i - n)*indic[i])); + } + + allocate(b_sum); + allocate(b_sum_inverse); + allocate(x_sum); + allocate(b0p); + allocate(parity); + allocate(xn); + allocate(xp); + allocate(xpp); + allocate(sb); + allocate(sgn); + allocate(saux); + + constrain(b_sum * (1 - b_sum_inverse * b_sum)); + constrain((b0p - b_chunks[0]*(1 - b_sum*b_sum_inverse) - 32*b_sum*b_sum_inverse)); + constrain(parity*(1-parity)); + constrain(b0p - parity - 2*n); + //n < 32768 range check + allocate(2 * n); + //xp, xpp,saux < 256 + allocate(256 * xp); + allocate(256 * xpp); + allocate(256 * saux); + + + constrain(xn - x_sum); + constrain(xn - xp*256 - xpp); + + constrain(sb - (1-parity)*xpp - parity*xp); + constrain(sgn * (1-sgn)); + constrain(sb + 128 - saux - 256*sgn); + + // auto B_128 = chunks16_to_chunks128_reversed(b_chunks); + // auto X_128 = chunks16_to_chunks128_reversed(x_chunks); + // auto Res_128 = chunks16_to_chunks128_reversed(res); + + // TYPE B0, B1, X0, X1, Res0, Res1; + // A0 = A_128.first; + // A1 = A_128.second; + // B0 = B_128.first; + // B1 = B_128.second; + // Res0 = Res_128.first; + // Res1 = Res_128.second; + // allocate(A0, 36, 0); + // allocate(A1, 37, 0); + // allocate(B0, 38, 0); + // allocate(B1, 39, 0); + // allocate(Res0, 40, 0); + // allocate(Res1, 41, 0); + + if constexpr (stage == GenerationStage::CONSTRAINTS) { + /* + constrain(current_state.pc_next() - current_state.pc(2) - + 1); // PC transition + constrain(current_state.gas(2) - current_state.gas_next() - + 3); // GAS transition + constrain(current_state.stack_size(2) - current_state.stack_size_next() - + 1); // stack_size transition + constrain(current_state.memory_size(2) - + current_state.memory_size_next()); // memory_size transition + constrain(current_state.rw_counter_next() - current_state.rw_counter(2) - + 3); // rw_counter transition + std::vector tmp; + tmp = {TYPE(rw_op_to_num(rw_operation_type::stack)), + current_state.call_id(0), + current_state.stack_size(0) - 1, + TYPE(0), // storage_key_hi + TYPE(0), // storage_key_lo + TYPE(0), // field + current_state.rw_counter(0), + TYPE(0), // is_write + B0, + B1}; + lookup(tmp, "zkevm_rw"); + tmp = {TYPE(rw_op_to_num(rw_operation_type::stack)), + current_state.call_id(1), + current_state.stack_size(1) - 2, + TYPE(0), // storage_key_hi + TYPE(0), // storage_key_lo + TYPE(0), // field + current_state.rw_counter(1) + 1, + TYPE(0), // is_write + A0, + A1}; + lookup(tmp, "zkevm_rw"); + tmp = {TYPE(rw_op_to_num(rw_operation_type::stack)), + current_state.call_id(0), + current_state.stack_size(0) - 2, + TYPE(0), // storage_key_hi + TYPE(0), // storage_key_lo + TYPE(0), // field + current_state.rw_counter(0) + 2, + TYPE(1), // is_write + Res0, + Res1}; + lookup(tmp, "zkevm_rw");*/ + } + } + }; + template - class zkevm_signextend_operation : public opcode_abstract { - public: + class zkevm_signextend_bbf : public opcode_abstract { + public: virtual void fill_context( - typename generic_component::context_type &context, - const opcode_input_type ¤t_state - ) {} + typename generic_component::context_type + &context, + const opcode_input_type + ¤t_state) { + zkevm_signextend_bbf bbf_obj( + context, current_state); + } virtual void fill_context( - typename generic_component::context_type &context, - const opcode_input_type ¤t_state - ) {} - virtual std::size_t rows_amount() override { - return 2; + typename generic_component::context_type &context, + const opcode_input_type + ¤t_state) { + zkevm_signextend_bbf bbf_obj( + context, current_state); } + virtual std::size_t rows_amount() override { return 2; } }; - } // namespace bbf - } // namespace blueprint -} // namespace nil + } // namespace bbf + } // namespace blueprint +} // namespace nil 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 60b9387cda..052fffe147 100644 --- a/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/byte_ops.cpp +++ b/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/byte_ops.cpp @@ -74,7 +74,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::BYTE); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0xFb70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); - // opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); + opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0xFb70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::SHL); @@ -89,7 +89,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::BYTE); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x8b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32,0); - // opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); + opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x8b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32, 0); opcode_tester.push_opcode(zkevm_opcode::SHL); @@ -104,7 +104,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::BYTE); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x8b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32,10); - // opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); + opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x8b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32, 10); opcode_tester.push_opcode(zkevm_opcode::SHL); @@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::BYTE); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x8b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32,257); - // opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); + opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x8b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32, 257); opcode_tester.push_opcode(zkevm_opcode::SHL); @@ -134,7 +134,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::BYTE); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x8b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32,65538); - // opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); + opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x8b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32, 65538); opcode_tester.push_opcode(zkevm_opcode::SHL); @@ -149,7 +149,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::BYTE); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32,10); - // opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); + opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32, 10); opcode_tester.push_opcode(zkevm_opcode::SHL); @@ -164,7 +164,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::BYTE); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32,30); - // opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); + opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32, 30); opcode_tester.push_opcode(zkevm_opcode::SHL); @@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::BYTE); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32,50); - // opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); + opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32, 50); opcode_tester.push_opcode(zkevm_opcode::SHL); @@ -194,7 +194,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::BYTE); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x1234567890_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32,1); - // opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); + opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1234567890_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32, 1); opcode_tester.push_opcode(zkevm_opcode::SHL); @@ -209,7 +209,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::BYTE); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x1234567890_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32,31); - // opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); + opcode_tester.push_opcode(zkevm_opcode::SIGNEXTEND); opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1234567890_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32, 31); opcode_tester.push_opcode(zkevm_opcode::SHL);