From 724ace035d4f3ad03d9b91f5e205ffc6d0752775 Mon Sep 17 00:00:00 2001 From: "e.tatuzova" Date: Tue, 26 Nov 2024 09:11:38 +0400 Subject: [PATCH] SAR and NOT added #95 --- .../opcode_tester_input_generator.hpp | 39 +- .../nil/blueprint/zkevm_bbf/opcodes/not.hpp | 63 +- .../nil/blueprint/zkevm_bbf/opcodes/sar.hpp | 540 +++++++++++++++++- crypto3/libs/blueprint/test/CMakeLists.txt | 3 + .../test/zkevm_bbf/opcodes/byte_ops.cpp | 22 +- .../blueprint/test/zkevm_bbf/opcodes/div.cpp | 126 ++++ .../test/zkevm_bbf/opcodes/jumps.cpp | 127 ++++ .../blueprint/test/zkevm_bbf/opcodes/not.cpp | 87 +++ 8 files changed, 970 insertions(+), 37 deletions(-) create mode 100644 crypto3/libs/blueprint/test/zkevm_bbf/opcodes/div.cpp create mode 100644 crypto3/libs/blueprint/test/zkevm_bbf/opcodes/jumps.cpp create mode 100644 crypto3/libs/blueprint/test/zkevm_bbf/opcodes/not.cpp diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/input_generators/opcode_tester_input_generator.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/input_generators/opcode_tester_input_generator.hpp index 105642f7ca..0d2543ae97 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/input_generators/opcode_tester_input_generator.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/input_generators/opcode_tester_input_generator.hpp @@ -69,9 +69,8 @@ namespace nil { const std::map memory; const std::map storage; - for( std::size_t ind = 0; ind < tester.get_opcodes().size(); ind++ ){ - auto opcode = tester.get_opcodes()[ind].first; - auto additional_input = tester.get_opcodes()[ind].second; + while(true){ + auto [opcode,additional_input] = tester.get_opcode_by_pc(pc); zkevm_state state; // TODO:optimize state.tx_hash = 0; // * change it @@ -82,7 +81,7 @@ namespace nil { state.rw_counter = rw_counter; state.bytecode_hash = _bytecodes.get_data()[current_buffer_id].second; state.additional_input = additional_input; - state.tx_finish = (ind == tester.get_opcodes().size() - 1); + //state.tx_finish = (ind == tester.get_opcodes().size() - 1); state.stack_size = stack.size(); state.memory_size = memory.size(); state.stack_slice = stack; @@ -305,6 +304,16 @@ namespace nil { stack.push_back(result); pc++; gas -= 3; + } else if(opcode == zkevm_opcode::NOT) { + // 0x18 + zkevm_word_type a = stack.back(); + stack.pop_back(); + _rw_operations.push_back(stack_rw_operation(call_id, stack.size(), rw_counter++, false, a)); + zkevm_word_type result = zkevm_word_type(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_cppui_modular257) - a;; + _rw_operations.push_back(stack_rw_operation(call_id, stack.size(), rw_counter++, true, result)); + stack.push_back(result); + pc++; + gas -= 3; }else if(opcode == zkevm_opcode::SHL) { // 0x1b zkevm_word_type b = stack.back(); @@ -334,6 +343,28 @@ namespace nil { stack.push_back(result); pc++; gas -= 3; + }else if(opcode == zkevm_opcode::SAR) { + //0x1d + zkevm_word_type b = stack.back(); + stack.pop_back(); + _rw_operations.push_back(stack_rw_operation(call_id, stack.size(), rw_counter++, false, b)); + zkevm_word_type input_a = stack.back(); + stack.pop_back(); + _rw_operations.push_back(stack_rw_operation(call_id, stack.size(), rw_counter++, false, input_a)); + auto is_negative = [](zkevm_word_type x) { + return (integral_type(x) > zkevm_modulus / 2 - 1);}; + auto negate_word = [](zkevm_word_type x) { + return zkevm_word_type(zkevm_modulus - integral_type(x));}; + auto abs_word = [&is_negative, &negate_word](zkevm_word_type x) { + return is_negative(x) ? negate_word(x) : x;}; + zkevm_word_type a = abs_word(input_a); + int shift = (integral_type(b) < 256) ? int(integral_type(b)) : 256; + integral_type r_integral = integral_type(a) >> shift; + zkevm_word_type result = is_negative(a) ? ((r_integral == 0)? zkevm_word_type(zkevm_modulus-1) : negate_word(zkevm_word_type(r_integral))) : zkevm_word_type(r_integral); + _rw_operations.push_back(stack_rw_operation(call_id, stack.size(), rw_counter++, true, result)); + stack.push_back(result); + pc++; + gas -= 3; } else if (opcode == zkevm_opcode::PUSH0){ // 0x5f _rw_operations.push_back(stack_rw_operation(call_id, stack.size(), rw_counter++, true, additional_input)); diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/not.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/not.hpp index a254c26af4..1d0678de81 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/not.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/not.hpp @@ -51,13 +51,62 @@ namespace nil { generic_component(context_object, false) { // NOT checked by current test - // if constexpr( stage == GenerationStage::CONSTRAINTS ){ - // constrain(current_state.pc_next() - current_state.pc(0) - 1); // PC transition - // constrain(current_state.gas(0) - current_state.gas_next() - 3); // GAS transition - // constrain(current_state.stack_size(0) - current_state.stack_size_next()); // stack_size transition - // constrain(current_state.memory_size(0) - current_state.memory_size_next()); // memory_size transition - // constrain(current_state.rw_counter_next() - current_state.rw_counter(0) - 2); // rw_counter transition - // } + std::vector A(16); + std::vector R(16); + + if constexpr( stage == GenerationStage::ASSIGNMENT ){ + auto a = w_to_16(current_state.stack_top()); + for( std::size_t i = 0; i < 16; i++ ){ + A[i] = a[i]; + R[i] = 0xFFFF - a[i]; + } + } + for( std::size_t i = 0; i < 16; i++ ){ + allocate(A[i], i, 0); + allocate(R[i], i + 16, 0); + } + for( std::size_t i = 0; i < 16; i++ ){ + constrain(R[i] + A[i] - 0xFFFF); + } + + auto A_128 = chunks16_to_chunks128(A); + auto R_128 = chunks16_to_chunks128(R); + if constexpr( stage == GenerationStage::CONSTRAINTS ){ + constrain(current_state.pc_next() - current_state.pc(0) - 1); // PC transition + constrain(current_state.gas(0) - current_state.gas_next() - 3); // GAS transition + constrain(current_state.stack_size(0) - current_state.stack_size_next()); // stack_size transition + constrain(current_state.memory_size(0) - current_state.memory_size_next()); // memory_size transition + constrain(current_state.rw_counter_next() - current_state.rw_counter(0) - 2); // rw_counter transition + std::vector tmp; + tmp = { + TYPE(rw_op_to_num(rw_operation_type::stack)), + current_state.call_id(1), + current_state.stack_size(1) - 1, + TYPE(0),// storage_key_hi + TYPE(0),// storage_key_lo + TYPE(0),// field + current_state.rw_counter(1), + TYPE(0),// is_write + A_128.first, + A_128.second + }; + lookup(tmp, "zkevm_rw"); + tmp = { + TYPE(rw_op_to_num(rw_operation_type::stack)), + current_state.call_id(1), + current_state.stack_size(1) - 1, + TYPE(0),// storage_key_hi + TYPE(0),// storage_key_lo + TYPE(0),// field + current_state.rw_counter(1) + 1, + TYPE(1),// is_write + R_128.first, + R_128.second + }; + lookup(tmp, "zkevm_rw"); + } else { + std::cout << "Assignment implemented" << std::endl; + } } }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/sar.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/sar.hpp index f12687fc3c..d06adb9d5d 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/sar.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/opcodes/sar.hpp @@ -1,5 +1,6 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Alexey Yashunsky +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -24,33 +25,542 @@ #pragma once -#include #include - +#include #include #include +#include namespace nil { namespace blueprint { - namespace bbf{ + namespace bbf { template class opcode_abstract; + template + class zkevm_sar_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 std::size_t carry_amount = 16 / 3 + 1; + 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; + + template + T chunk_sum_64(const std::vector &chunks, const unsigned char chunk_idx) const { + BOOST_ASSERT(chunk_idx < 4); + return chunks[4 * chunk_idx] + chunks[4 * chunk_idx + 1] * two_16 + + chunks[4 * chunk_idx + 2] * two_32 + chunks[4 * chunk_idx + 3] * two_48; + } + + template + T first_carryless_construct(const std::vector &a_64_chunks, + const std::vector &b_64_chunks, + const std::vector &r_64_chunks, + const std::vector &q_64_chunks) const { + return r_64_chunks[0] * b_64_chunks[0] + q_64_chunks[0] + + two_64 * (r_64_chunks[0] * b_64_chunks[1] + + r_64_chunks[1] * b_64_chunks[0] + q_64_chunks[1]) - + a_64_chunks[0] - two_64 * a_64_chunks[1]; + } + + template + T second_carryless_construct(const std::vector &a_64_chunks, + const std::vector &b_64_chunks, + const std::vector &r_64_chunks, + const std::vector &q_64_chunks) const { + return (r_64_chunks[0] * b_64_chunks[2] + r_64_chunks[1] * b_64_chunks[1] + + r_64_chunks[2] * b_64_chunks[0] + q_64_chunks[2] - a_64_chunks[2]) + + two_64 * + (r_64_chunks[0] * b_64_chunks[3] + r_64_chunks[1] * b_64_chunks[2] + + r_64_chunks[2] * b_64_chunks[1] + r_64_chunks[3] * b_64_chunks[0] + + q_64_chunks[3] - a_64_chunks[3]); + } + + template + T third_carryless_construct(const std::vector &b_64_chunks, + const std::vector &r_64_chunks) const { + return (r_64_chunks[1] * b_64_chunks[3] + r_64_chunks[2] * b_64_chunks[2] + + r_64_chunks[3] * b_64_chunks[1]) + + two_64 * + (r_64_chunks[2] * b_64_chunks[3] + r_64_chunks[3] * b_64_chunks[2]); + } + + TYPE carry_on_addition_constraint(TYPE a_0, TYPE a_1, TYPE a_2, TYPE b_0, TYPE b_1, + TYPE b_2, TYPE r_0, TYPE r_1, TYPE r_2, + TYPE last_carry, TYPE result_carry, + bool first_constraint = false) { + TYPE res; + if (first_constraint) { + // no last carry for first constraint + res = (a_0 + b_0) + (a_1 + b_1) * two_16 + (a_2 + b_2) * two_32 - r_0 - + r_1 * two_16 - r_2 * two_32 - result_carry * two_48; + } else { + res = last_carry + (a_0 + b_0) + (a_1 + b_1) * two_16 + + (a_2 + b_2) * two_32 - r_0 - r_1 * two_16 - r_2 * two_32 - + result_carry * two_48; + } + return res; + }; + TYPE last_carry_on_addition_constraint(TYPE a_0, TYPE b_0, TYPE r_0, + TYPE last_carry, TYPE result_carry) { + TYPE res = (last_carry + a_0 + b_0 - r_0 - result_carry * two_16); + return res; + }; + + std::vector res; + + public: + zkevm_sar_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>>; + + TYPE first_carryless; + TYPE second_carryless; + TYPE third_carryless; + + TYPE b0p; + TYPE b0pp; + TYPE b0ppp; + TYPE b0p_range_check; + TYPE b0pp_range_check; + TYPE b0ppp_range_check; + TYPE I1; + TYPE I2; + TYPE z; + TYPE tp; + TYPE two_powers; + TYPE sum_part_b; + TYPE b_sum; + TYPE b_sum_inverse; + TYPE r_sum; + TYPE r_sum_inverse; + TYPE a_neg; + + std::vector a_64_chunks(4); + std::vector b_64_chunks(4); + std::vector r_64_chunks(4); + std::vector q_64_chunks(4); + + std::vector c_1_chunks(4); + std::vector c_3_chunks(4); + TYPE c_1; + TYPE c_2; + TYPE c_3; + TYPE c_4; + + TYPE c_1_64; + TYPE c_3_64; + + TYPE c_zero; + TYPE c_one; + TYPE b_zero; + + std::vector input_a_chunks(chunk_amount); + std::vector input_b_chunks(chunk_amount); + std::vector results_chunks(chunk_amount); + std::vector a_chunks(chunk_amount); + std::vector b_chunks(chunk_amount); + std::vector r_chunks(chunk_amount); + std::vector q_chunks(chunk_amount); + std::vector v_chunks(chunk_amount); + + TYPE carry[3][carry_amount + 1]; + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + zkevm_word_type input_b = current_state.stack_top(); + zkevm_word_type input_a = current_state.stack_top(1); + + auto is_negative = [](zkevm_word_type x) { + return (integral_type(x) > zkevm_modulus / 2 - 1); + }; + auto negate_word = [](zkevm_word_type x) { + return zkevm_word_type(zkevm_modulus - integral_type(x)); + }; + auto abs_word = [&is_negative, &negate_word](zkevm_word_type x) { + return is_negative(x) ? negate_word(x) : x; + }; + + zkevm_word_type a = abs_word(input_a); + + int shift = + (integral_type(input_b) < 256) ? int(integral_type(input_b)) : 256; + integral_type r_integral = integral_type(a) >> shift; + + zkevm_word_type result = + is_negative(input_a) + ? ((r_integral == 0) ? zkevm_word_type(zkevm_modulus - 1) + : negate_word(zkevm_word_type(r_integral))) + : zkevm_word_type(r_integral); + + zkevm_word_type b = zkevm_word_type(integral_type(1) << shift); + + zkevm_word_type r = zkevm_word_type::backend_type(r_integral.backend()); + zkevm_word_type q = b != 0u ? a % b : a; + + bool t_last = integral_type(q) < integral_type(b); + zkevm_word_type v = zkevm_word_type(integral_type(q) + + integral_type(t_last) * zkevm_modulus - + integral_type(b)); + a_neg = is_negative(input_a); + + input_a_chunks = zkevm_word_to_field_element(input_a); + input_b_chunks = zkevm_word_to_field_element(input_b); + results_chunks = zkevm_word_to_field_element(result); + a_chunks = zkevm_word_to_field_element(a); + b_chunks = zkevm_word_to_field_element(b); + r_chunks = zkevm_word_to_field_element(r); + q_chunks = zkevm_word_to_field_element(q); + v_chunks = zkevm_word_to_field_element(v); + + integral_type two_15 = 32768; + integral_type biggest_input_a_chunk = integral_type(input_a) >> (256 - 16); + + b0p = integral_type(input_b) % 16; + b0pp = (integral_type(input_b) / 16) % 16; + b0ppp = (integral_type(input_b) % 65536) / 256; + I1 = b0ppp.is_zero() ? 0 : b0ppp.inversed(); + + sum_part_b = 0; + b_sum = std::accumulate(b_chunks.begin(), b_chunks.end(), value_type(0)); + for (std::size_t i = 1; i < chunk_amount; i++) { + sum_part_b += input_b_chunks[i]; + } + I2 = sum_part_b.is_zero() ? 0 : sum_part_b.inversed(); + z = (1 - b0ppp * I1) * + (1 - + sum_part_b * I2); // z is zero if input_b >= 256, otherwise it is 1 + two_powers = + (static_cast(1) << int(integral_type(input_b) % 16)); + b_sum_inverse = b_sum.is_zero() ? 0 : b_sum.inversed(); + b_zero = 1 - b_sum_inverse * b_sum; + + // note that we don't assign 64-chunks for a/b, as we can build them from + // 16-chunks with constraints under the same logic we only assign the 16 - + // bit + + // chunks for carries + for (std::size_t i = 0; i < 4; i++) { + a_64_chunks.push_back(chunk_sum_64(a_chunks, i)); + b_64_chunks.push_back(chunk_sum_64(b_chunks, i)); + r_64_chunks.push_back(chunk_sum_64(r_chunks, i)); + q_64_chunks.push_back(chunk_sum_64(q_chunks, i)); + } + // caluclate first row carries + first_carryless = first_carryless_construct(a_64_chunks, b_64_chunks, + r_64_chunks, q_64_chunks); + auto first_row_carries = first_carryless_construct(a_64_chunks, b_64_chunks, + r_64_chunks, q_64_chunks) + .data >> + 128; + c_1 = static_cast(first_row_carries & (two_64 - 1).data); + c_2 = static_cast(first_row_carries >> 64); + BOOST_ASSERT(first_carryless - c_1 * two_128 - c_2 * two_192 == 0); + c_1_chunks = chunk_64_to_16(c_1); + // no need for c_2 chunks as there is only a single chunk + second_carryless = second_carryless_construct( + a_64_chunks, b_64_chunks, r_64_chunks, q_64_chunks); + c_1_64 = chunk_sum_64(c_1_chunks, 0); + + third_carryless = third_carryless_construct(b_64_chunks, r_64_chunks); + + // lookup constrain b0p < 16, b0pp < 16, b0ppp < 256 + b0p_range_check = 4096 * b0p; + b0pp_range_check = 4096 * b0pp; + b0ppp_range_check = 256 * b0ppp; + + carry[0][0] = 0; + // input_a + |input_a| = 2^256 carries + for (std::size_t i = 0; i < carry_amount - 1; i++) { + carry[0][i + 1] = + (carry[0][i] + input_a_chunks[3 * i] + a_chunks[3 * i] + + (input_a_chunks[3 * i + 1] + a_chunks[3 * i + 1]) * two_16 + + (input_a_chunks[3 * i + 2] + a_chunks[3 * i + 2]) * two_32) >= + two_48; + } + // The last carry, if input_a + |input_a| is ever needed, should be 1 + // anyway, so we don't store it + + r_sum = std::accumulate(r_chunks.begin(), r_chunks.end(), value_type(0)); + r_sum_inverse = r_sum.is_zero() ? 0 : r_sum.inversed(); + + carry[1][0] = 0; + // result + r = 2^256 carries + for (std::size_t i = 0; i < carry_amount - 1; i++) { + carry[1][i + 1] = + (carry[1][i] + results_chunks[3 * i] + r_chunks[3 * i] + + (results_chunks[3 * i + 1] + r_chunks[3 * i + 1]) * two_16 + + (results_chunks[3 * i + 2] + r_chunks[3 * i + 2]) * two_32) >= + two_48; + } + // The last carry, if result + r is ever needed, should be 1 anyway, so we + // don't store it + + carry[2][0] = 0; + for (std::size_t i = 0; i < carry_amount - 1; i++) { + carry[2][i + 1] = + (carry[2][i] + b_chunks[3 * i] + v_chunks[3 * i] + + (b_chunks[3 * i + 1] + v_chunks[3 * i + 1]) * two_16 + + (b_chunks[3 * i + 2] + v_chunks[3 * i + 2]) * two_32) >= two_48; + } + carry[2][carry_amount] = + (carry[2][carry_amount - 1] + b_chunks[3 * (carry_amount - 1)] + + v_chunks[3 * (carry_amount - 1)]) >= two_16; + + c_zero = 0; + c_one = c_zero + 1; + b_zero = 1 - b_sum_inverse * b_sum; + } + + allocate(b0p_range_check, 0, 4); + allocate(b0pp_range_check, 1, 4); + allocate(b0ppp_range_check, 2, 4); + allocate(b_zero, 39, 1); + for (std::size_t i = 0; i < 4; i++) { + allocate(c_1_chunks[i], 3 + i, 4); + } + + for (std::size_t i = 0; i < chunk_amount; i++) { + allocate(input_a_chunks[i], i, 0); + allocate(a_chunks[i], i + chunk_amount, 0); + allocate(results_chunks[i], i, 1); + allocate(r_chunks[i], i + chunk_amount, 1); + allocate(q_chunks[i], i, 2); + allocate(v_chunks[i], i + chunk_amount, 2); + allocate(b_chunks[i], i, 3); + allocate(input_b_chunks[i], i + chunk_amount, 3); + res[i] = r_chunks[i]; + constrain(b_zero * r_chunks[i]); + } + + tp = z * two_powers; + allocate(tp, 35, 3); + allocate(z, 36, 3); + allocate(I1, 37, 3); + allocate(I2, 38, 3); + allocate(two_powers, 39, 3); + + allocate(b0p, 32, 3); + allocate(b0pp, 33, 3); + allocate(b0ppp, 34, 3); + allocate(sum_part_b, 40, 3); + allocate(b_sum, 40, 1); + allocate(b_sum_inverse, 41, 1); + + constrain(b_sum_inverse * (b_sum_inverse * b_sum - 1)); + constrain(b_sum * (b_sum_inverse * b_sum - 1)); + constrain(input_b_chunks[0] - b0p - 16 * b0pp - 256 * b0ppp); + constrain(b0ppp * (1 - b0ppp * I1)); + + constrain(sum_part_b * (1 - sum_part_b * I2)); + constrain((z - (1 - b0ppp * I1) * (1 - sum_part_b * I2))); + + allocate(first_carryless, 32, 4); + allocate(second_carryless, 35, 4); + allocate(third_carryless, 36, 4); + allocate(c_1_64, 33, 4); + allocate(c_2, 34, 4); + + allocate(b_64_chunks[3], 7, 4); + allocate(r_64_chunks[3], 8, 4); + + constrain(first_carryless - c_1_64 * two_128 - c_2 * two_192); + constrain(second_carryless + c_1_64 + c_2 * two_64); + constrain(c_2 * (c_2 - 1)); + constrain(third_carryless); + constrain(b_64_chunks[3] * r_64_chunks[3]); + + allocate(c_zero, 42, 1); + allocate(c_one, 43, 1); + allocate(a_neg, 44, 1); + allocate(r_sum, 45, 1); + allocate(r_sum_inverse, 46, 1); + constrain(c_one - c_zero - 1); + + // force r = 0 if b = 0 + constrain(1 - b_sum_inverse * b_sum - b_zero); + for (std::size_t i = 0; i < chunk_amount; i++) { + constrain(b_zero * r_chunks[i]); + } + + allocate(carry[0][0], 32, 0); + for (std::size_t i = 0; i < carry_amount - 1; i++) { + allocate(carry[0][i + 1], 33 + i, 0); + constrain(a_neg * carry_on_addition_constraint( + input_a_chunks[3 * i], input_a_chunks[3 * i + 1], + input_a_chunks[3 * i + 2], a_chunks[3 * i], + a_chunks[3 * i + 1], a_chunks[3 * i + 2], c_zero, + c_zero, c_zero, carry[0][i], carry[0][i + 1], + i == 0)); + constrain(a_neg * carry[0][i + 1] * (1 - carry[0][i + 1])); + } + allocate(carry[0][carry_amount], 38, 0); + constrain(a_neg * last_carry_on_addition_constraint( + input_a_chunks[3 * (carry_amount - 1)], + a_chunks[3 * (carry_amount - 1)], c_zero, + carry[0][carry_amount - 1], c_one)); + + // ^^^ if ever input_a + |input_a| = 2^256 is used, the last carry should be 1 + // since it is actually an overflow if a_neg = 0, we should have input_a= a + for (std::size_t i = 0; i < chunk_amount; i++) { + constrain((1 - a_neg) * (input_a_chunks[i] - a_chunks[i])); + } + + constrain(r_sum * (1 - r_sum_inverse * r_sum)); + + allocate(carry[1][0], 32, 1); + for (std::size_t i = 0; i < carry_amount - 1; i++) { + allocate(carry[1][i + 1], 33 + i, 1); + constrain(a_neg * r_sum * + carry_on_addition_constraint( + results_chunks[3 * i], results_chunks[3 * i + 1], + results_chunks[3 * i + 2], r_chunks[3 * i], + r_chunks[3 * i + 1], r_chunks[3 * i + 2], c_zero, c_zero, + c_zero, carry[1][i], carry[1][i + 1], i == 0)); + constrain(a_neg * r_sum * carry[1][i + 1] * (1 - carry[1][i + 1])); + } + allocate(carry[1][carry_amount], 38, 1); + constrain( + a_neg * r_sum * + last_carry_on_addition_constraint(results_chunks[3 * (carry_amount - 1)], + r_chunks[3 * (carry_amount - 1)], c_zero, + carry[1][carry_amount - 1], c_one)); + + // ^^^ if ever result + r = 2^256 is used, the last carry should be 1 since itis + // actually an overflow if a_neg = 0, we should have result = r, if a_neg = 1 + // and r_sum_0 = 0 we should have result = 2^257 - 1, i.e. every chunk of result + // should be 2^16 - 1 + for (std::size_t i = 0; i < chunk_amount; i++) { + constrain((1 - a_neg) * (results_chunks[i] - r_chunks[i]) + + a_neg * (1 - r_sum * r_sum_inverse) * + (two_16 - 1 - results_chunks[i])); + }; + + allocate(carry[2][0], 32, 2); + for (std::size_t i = 0; i < carry_amount - 1; i++) { + allocate(carry[2][i + 1], 33 + i, 2); + constrain(carry_on_addition_constraint( + b_chunks[3 * i], b_chunks[3 * i + 1], b_chunks[3 * i + 2], + v_chunks[3 * i], v_chunks[3 * i + 1], v_chunks[3 * i + 2], + q_chunks[3 * i], q_chunks[3 * i + 1], q_chunks[3 * i + 2], carry[2][i], + carry[2][i + 1], i == 0)); + constrain(carry[2][i + 1] * (1 - carry[2][i + 1])); + } + allocate(carry[2][carry_amount], 38, 2); + constrain(last_carry_on_addition_constraint( + b_chunks[3 * (carry_amount - 1)], v_chunks[3 * (carry_amount - 1)], + q_chunks[3 * (carry_amount - 1)], carry[2][carry_amount - 1], + carry[2][carry_amount])); + + // last carry is 0 or 1, but should be 1 if z = 1 + + constrain((z + (1 - z) * carry[2][carry_amount]) * + (1 - carry[2][carry_amount])); + + auto A_128 = chunks16_to_chunks128_reversed(input_a_chunks); + auto B_128 = chunks16_to_chunks128_reversed(input_b_chunks); + auto Res_128 = chunks16_to_chunks128_reversed(res); + + TYPE A0, A1, B0, B1, 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, 39, 0); + allocate(A1, 40, 0); + allocate(B0, 39, 2); + allocate(B1, 40, 2); + allocate(Res0, 41, 0); + allocate(Res1, 41, 2); + + if constexpr (stage == GenerationStage::CONSTRAINTS) { + constrain(current_state.pc_next() - current_state.pc(4) - 1); // PC transition + constrain(current_state.gas(4) - current_state.gas_next() - 3); // GAS transition + constrain(current_state.stack_size(4) - current_state.stack_size_next() - 1); // stack_size transition + constrain(current_state.memory_size(4) - current_state.memory_size_next()); // memory_size transition + constrain(current_state.rw_counter_next() - current_state.rw_counter(4) - + 3); // rw_counter transition + std::vector tmp; + tmp = {TYPE(rw_op_to_num(rw_operation_type::stack)), + current_state.call_id(1), + current_state.stack_size(1) - 1, + TYPE(0), // storage_key_hi + TYPE(0), // storage_key_lo + TYPE(0), // field + current_state.rw_counter(1), + 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(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) + 2, + TYPE(1), // is_write + Res0, + Res1}; + lookup(tmp, "zkevm_rw"); + } + }; + }; + template class zkevm_sar_operation : public opcode_abstract { - public: + 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_sar_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 6; + typename generic_component::context_type &context, + const opcode_input_type + ¤t_state) { + zkevm_sar_bbf bbf_obj(context, + current_state); } + virtual std::size_t rows_amount() override { return 5; } }; - } // namespace bbf - } // namespace blueprint -} // namespace nil + } // namespace bbf + } // namespace blueprint +} // namespace nil \ No newline at end of file diff --git a/crypto3/libs/blueprint/test/CMakeLists.txt b/crypto3/libs/blueprint/test/CMakeLists.txt index 0a1a587d48..ec0b5de4fe 100644 --- a/crypto3/libs/blueprint/test/CMakeLists.txt +++ b/crypto3/libs/blueprint/test/CMakeLists.txt @@ -235,6 +235,9 @@ set(ZKEVM_BBF_TESTS_FILES "zkevm_bbf/opcodes/add_sub" "zkevm_bbf/opcodes/byte_ops" "zkevm_bbf/opcodes/mul" + "zkevm_bbf/opcodes/div" + "zkevm_bbf/opcodes/jumps" + "zkevm_bbf/opcodes/not" ) 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 1833070c35..a2687a2154 100644 --- a/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/byte_ops.cpp +++ b/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/byte_ops.cpp @@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::SHR); 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::SAR); + opcode_tester.push_opcode(zkevm_opcode::SAR); 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::BYTE); @@ -98,7 +98,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::SHR); 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::SAR); + opcode_tester.push_opcode(zkevm_opcode::SAR); 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::BYTE); @@ -113,7 +113,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::SHR); 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::SAR); + opcode_tester.push_opcode(zkevm_opcode::SAR); 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::BYTE); @@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::SHR); 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::SAR); + opcode_tester.push_opcode(zkevm_opcode::SAR); 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::BYTE); @@ -143,7 +143,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::SHR); 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::SAR); + opcode_tester.push_opcode(zkevm_opcode::SAR); 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::BYTE); @@ -158,7 +158,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::SHR); 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::SAR); + opcode_tester.push_opcode(zkevm_opcode::SAR); 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::BYTE); @@ -173,7 +173,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::SHR); 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::SAR); + opcode_tester.push_opcode(zkevm_opcode::SAR); 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::BYTE); @@ -188,7 +188,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::SHR); 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::SAR); + opcode_tester.push_opcode(zkevm_opcode::SAR); 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::BYTE); @@ -203,7 +203,7 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::SHR); 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::SAR); + opcode_tester.push_opcode(zkevm_opcode::SAR); 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::BYTE); @@ -218,10 +218,10 @@ BOOST_AUTO_TEST_CASE(byte_ops_cppui) { opcode_tester.push_opcode(zkevm_opcode::SHR); 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::SAR); + opcode_tester.push_opcode(zkevm_opcode::SAR); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x33_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x1_cppui_modular257)); - // opcode_tester.push_opcode(zkevm_opcode::SAR); + opcode_tester.push_opcode(zkevm_opcode::SAR); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x33_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::PUSH32,zwordc(0x1_cppui_modular257)); opcode_tester.push_opcode(zkevm_opcode::SHR); diff --git a/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/div.cpp b/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/div.cpp new file mode 100644 index 0000000000..07bdb5b78a --- /dev/null +++ b/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/div.cpp @@ -0,0 +1,126 @@ +//---------------------------------------------------------------------------// +// 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 blueprint_plonk_opcodes_test + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../test_l1_wrapper.hpp" + +using namespace nil::crypto3; +using namespace nil::blueprint::bbf; + +// Remember that in production sizes should be preset. +// Here they are different for different tests just for fast and easy testing +BOOST_AUTO_TEST_SUITE(zkevm_opcode_test_suite) + +BOOST_AUTO_TEST_CASE(divs) { + using field_type = typename algebra::curves::pallas::base_field_type; + zkevm_opcode_tester opcode_tester; + + l1_size_restrictions max_sizes; + + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1234567890_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::GT); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1234567890_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::LT); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1234567890_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::EQ); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1234567890_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::SGT); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1234567890_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::SLT); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0xFb70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0xFb70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::GT); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0xFb70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0xFb70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::LT); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0xFb70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0xFb70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::EQ); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0xFb70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0xFb70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::SGT); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0xFb70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0xFb70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::SLT); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1234567890_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::GT); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1234567890_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::LT); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1234567890_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::EQ); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1234567890_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::SGT); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1234567890_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::SLT); + opcode_tester.push_opcode(zkevm_opcode::STOP); + + max_sizes.max_keccak_blocks = 10; + max_sizes.max_bytecode = 3000; + max_sizes.max_mpt = 0; + max_sizes.max_rw = 500; + max_sizes.max_copy = 500; + max_sizes.max_zkevm_rows = 300; + complex_opcode_test(opcode_tester, max_sizes); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/jumps.cpp b/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/jumps.cpp new file mode 100644 index 0000000000..922aa54d9c --- /dev/null +++ b/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/jumps.cpp @@ -0,0 +1,127 @@ +//---------------------------------------------------------------------------// +// 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 blueprint_plonk_opcodes_test + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../test_l1_wrapper.hpp" + +using namespace nil::crypto3; +using namespace nil::blueprint::bbf; + +// Remember that in production sizes should be preset. +// Here they are different for different tests just for fast and easy testing +BOOST_AUTO_TEST_SUITE(zkevm_opcode_test_suite) + +BOOST_AUTO_TEST_CASE(jump) { + using field_type = typename algebra::curves::pallas::base_field_type; + zkevm_opcode_tester opcode_tester; + + l1_size_restrictions max_sizes; + + opcode_tester.push_opcode(zkevm_opcode::PUSH1, 1); + opcode_tester.push_opcode(zkevm_opcode::PUSH1, 2); + opcode_tester.push_opcode(zkevm_opcode::PUSH1, 8); + opcode_tester.push_opcode(zkevm_opcode::JUMP); + opcode_tester.push_opcode(zkevm_opcode::ADD); + opcode_tester.push_opcode(zkevm_opcode::JUMPDEST); + opcode_tester.push_opcode(zkevm_opcode::SUB); + opcode_tester.push_opcode(zkevm_opcode::STOP); + + max_sizes.max_keccak_blocks = 10; + max_sizes.max_bytecode = 3000; + max_sizes.max_mpt = 0; + max_sizes.max_rw = 500; + max_sizes.max_copy = 500; + max_sizes.max_zkevm_rows = 300; + complex_opcode_test(opcode_tester, max_sizes); +} + +BOOST_AUTO_TEST_CASE(jumpi) { + using field_type = typename algebra::curves::pallas::base_field_type; + zkevm_opcode_tester opcode_tester; + + l1_size_restrictions max_sizes; + + // SUB opcode should be executed and ADD -- not + opcode_tester.push_opcode(zkevm_opcode::PUSH1, 1); // 0 + opcode_tester.push_opcode(zkevm_opcode::PUSH1, 2); // 2 + opcode_tester.push_opcode(zkevm_opcode::PUSH1, 3); // 4 + opcode_tester.push_opcode(zkevm_opcode::PUSH1, 0); // 6 // Condition + opcode_tester.push_opcode(zkevm_opcode::PUSH1, 123); // 8 // Address is not important + opcode_tester.push_opcode(zkevm_opcode::JUMPI); // 10 + opcode_tester.push_opcode(zkevm_opcode::ADD); // 11 + opcode_tester.push_opcode(zkevm_opcode::JUMPDEST); // 12 + opcode_tester.push_opcode(zkevm_opcode::SUB); // 13 + opcode_tester.push_opcode(zkevm_opcode::PUSH1, 1); // 0 + opcode_tester.push_opcode(zkevm_opcode::PUSH1, 2); // 2 + opcode_tester.push_opcode(zkevm_opcode::PUSH1, 3); // 4 + opcode_tester.push_opcode(zkevm_opcode::PUSH1, 1); // 14 // Condition + opcode_tester.push_opcode(zkevm_opcode::PUSH1, 26); //16 // Address + opcode_tester.push_opcode(zkevm_opcode::JUMPI); // 18 + opcode_tester.push_opcode(zkevm_opcode::ADD); // 19 + opcode_tester.push_opcode(zkevm_opcode::JUMPDEST); // 20 + opcode_tester.push_opcode(zkevm_opcode::SUB); // 21 + // Correct cotract finishing + opcode_tester.push_opcode(zkevm_opcode::PUSH1, 1); + opcode_tester.push_opcode(zkevm_opcode::PUSH1, 2); + opcode_tester.push_opcode(zkevm_opcode::STOP); + + max_sizes.max_keccak_blocks = 10; + max_sizes.max_bytecode = 3000; + max_sizes.max_mpt = 0; + max_sizes.max_rw = 500; + max_sizes.max_copy = 500; + max_sizes.max_zkevm_rows = 300; + complex_opcode_test(opcode_tester, max_sizes); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/not.cpp b/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/not.cpp new file mode 100644 index 0000000000..44788898a5 --- /dev/null +++ b/crypto3/libs/blueprint/test/zkevm_bbf/opcodes/not.cpp @@ -0,0 +1,87 @@ +//---------------------------------------------------------------------------// +// 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 blueprint_plonk_opcodes_test + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../test_l1_wrapper.hpp" + +using namespace nil::crypto3; +using namespace nil::blueprint::bbf; + +// Remember that in production sizes should be preset. +// Here they are different for different tests just for fast and easy testing +BOOST_AUTO_TEST_SUITE(zkevm_opcode_test_suite) + +BOOST_AUTO_TEST_CASE(mul) { + using field_type = typename algebra::curves::pallas::base_field_type; + zkevm_opcode_tester opcode_tester; + + l1_size_restrictions max_sizes; + + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1234567890_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::NOT); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0x1b70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::NOT); + opcode_tester.push_opcode(zkevm_opcode::PUSH32, zwordc(0xFb70726fb8d3a24da9ff9647225a18412b8f010425938504d73ebc8801e2e016_cppui_modular257)); + opcode_tester.push_opcode(zkevm_opcode::NOT); + opcode_tester.push_opcode(zkevm_opcode::STOP); + + max_sizes.max_keccak_blocks = 10; + max_sizes.max_bytecode = 3000; + max_sizes.max_mpt = 0; + max_sizes.max_rw = 500; + max_sizes.max_copy = 500; + max_sizes.max_zkevm_rows = 300; + complex_opcode_test(opcode_tester, max_sizes); +} +BOOST_AUTO_TEST_SUITE_END()