diff --git a/crypto3/libs/blueprint/include/nil/blueprint/lookup_library.hpp b/crypto3/libs/blueprint/include/nil/blueprint/lookup_library.hpp index bd406c52e8..961920a6e7 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/lookup_library.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/lookup_library.hpp @@ -86,55 +86,21 @@ namespace nil { virtual std::size_t get_rows_number(){ return 256; } }; - class zkevm_opcode_table: public lookup_table_definition{ + class opcode_push_size_table: public lookup_table_definition{ public: - static constexpr std::size_t opcodes_num = 149; - - zkevm_opcode_table(): lookup_table_definition("zkevm_opcodes"){ - this->subtables["full"] = {{0, 1, 2}, 0, opcodes_num}; - this->subtables["opcodes_only"] = {{0}, 0, opcodes_num}; + opcode_push_size_table(): lookup_table_definition("opcode_push_size") { + this->subtables["full"] = {{0, 1}, 0, 256}; } - virtual void generate(){ - // opcodes - this->_table.push_back({ - 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, //12 - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, //14 - 0x20, //1 - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, //16 - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, //11 - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, //16 - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, //16 - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, //16 - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, //16 - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, //16 - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, //5 - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xfa, 0xfd, 0xfe, 0xff //10 - }); - // push_size - this->_table.push_back({ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, //12 - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, //14 - 0x0, //1 - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, //16 - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, //11 - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, //16 - 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, //16 - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, //16 - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, //16 - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, //16 - 0x0, 0x0, 0x0, 0x0, 0x0, //5 - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 //10 - }); - this->_table.push_back({}); - for( std::size_t i = 0; i < opcodes_num; i++) this->_table[2].push_back(1); + virtual void generate(){ + this->_table.resize(2); + for (size_t i = 0; i < 256; ++i) this->_table[0].push_back(i); - // unselected rows virtualization - this->_table[0].push_back(0); - this->_table[1].push_back(0); - this->_table[2].push_back(0); + this->_table[1].resize(256); + for (size_t i = 1; i <= 32; ++i) this->_table[1][0x5f + i] = i; } - virtual std::size_t get_columns_number(){ return 1; } + + virtual std::size_t get_columns_number(){ return 2; } virtual std::size_t get_rows_number(){ return 256; } }; @@ -574,7 +540,7 @@ namespace nil { tables["keccak_normalize6_table"] = std::shared_ptr(new normalize_base8_table_type(6)); tables["keccak_chi_table"] = std::shared_ptr(new chi_table_type()); tables["byte_range_table"] = std::shared_ptr(new byte_range_table_type()); - tables["zkevm_opcodes"] = std::shared_ptr(new zkevm_opcode_table()); + tables["opcode_push_size"] = std::shared_ptr(new opcode_push_size_table()); tables["byte_and_xor_table"] = std::shared_ptr(new byte_and_xor_table_type()); } diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/big_field/circuits/bytecode.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/big_field/circuits/bytecode.hpp index e5c6f56ee5..6673e3cc6a 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/big_field/circuits/bytecode.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/big_field/circuits/bytecode.hpp @@ -185,9 +185,8 @@ namespace nil::blueprint::bbf::zkevm_big_field{ std::vector tmp = {context_object.relativize(tag[0] * value[0], -1)}; context_object.relative_lookup(tmp, "byte_range_table/full", 0, max_bytecode_size - 1); tmp = {context_object.relativize(std::vector({value[0] * is_opcode[0], - push_size[0] * is_opcode[0], - is_opcode[0]}), -1)}; - context_object.relative_lookup(tmp, "zkevm_opcodes/full", 0, max_bytecode_size - 1); + push_size[0] * is_opcode[0]}), -1)}; + context_object.relative_lookup(tmp, "opcode_push_size/full", 0, max_bytecode_size - 1); tmp = {context_object.relativize(std::vector({ tag[1] + 1 - tag[1], tag[0] * (1 - tag[1]) * value_rlc[0], @@ -198,4 +197,4 @@ namespace nil::blueprint::bbf::zkevm_big_field{ } }; }; -} \ No newline at end of file +} diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/small_field/circuits/bytecode.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/small_field/circuits/bytecode.hpp index 98b329940e..a16106273c 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/small_field/circuits/bytecode.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/small_field/circuits/bytecode.hpp @@ -1,5 +1,6 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Elena Tatuzova +// Copyright (c) 2025 Alexander Vasilyev // // MIT License // @@ -30,323 +31,340 @@ #include namespace nil::blueprint::bbf::zkevm_small_field{ - template - class bytecode : public generic_component { - using typename generic_component::context_type; - using generic_component::allocate; - using generic_component::copy_constrain; - using generic_component::constrain; - using generic_component::lookup; - using generic_component::lookup_table; - - using BytecodeTable = bytecode_table; - using KeccakTable = keccak_table; - using BytecodeHashTable = bytecode_hash_table; - - public: - using typename generic_component::table_params; - using typename generic_component::TYPE; - - struct input_type { - TYPE rlc_challenge; - - BytecodeTable::input_type bytecodes; - KeccakTable::private_input_type keccak_buffers; + +template +class bytecode : public generic_component { + using typename generic_component::context_type; + using generic_component::allocate; + using generic_component::copy_constrain; + using generic_component::constrain; + using generic_component::lookup; + using generic_component::lookup_table; + + using BytecodeTable = bytecode_table; + using KeccakTable = keccak_table; + using BytecodeHashTable = bytecode_hash_table; + + public: + using typename generic_component::table_params; + using typename generic_component::TYPE; + + struct input_type { + TYPE rlc_challenge; + + BytecodeTable::input_type bytecodes; + KeccakTable::private_input_type keccak_buffers; + }; + + size_t max_bytecode_size; + size_t max_keccak_blocks; + size_t max_bytecodes_amount; + + static table_params get_minimal_requirements( + size_t max_bytecode_size, + size_t max_keccak_blocks, + size_t max_bytecodes_amount) { + BOOST_ASSERT(max_bytecode_size > max_keccak_blocks + max_bytecodes_amount); + return { + .witnesses = BytecodeTable::get_witness_amount() + std::max(KeccakTable::get_witness_amount(), BytecodeHashTable::get_witness_amount()) + 16, + .public_inputs = 1, + .constants = 10, + .rows = max_bytecode_size }; + } - std::size_t max_bytecode_size; - std::size_t max_keccak_blocks; - std::size_t max_bytecodes_amount; - - static table_params get_minimal_requirements( - std::size_t max_bytecode_size, - std::size_t max_keccak_blocks, - std::size_t max_bytecodes_amount - ) { - BOOST_ASSERT(max_bytecode_size > max_keccak_blocks + max_bytecodes_amount); - return { - .witnesses = BytecodeTable::get_witness_amount() + std::max(KeccakTable::get_witness_amount(), BytecodeHashTable::get_witness_amount()) + 16, - .public_inputs = 1, - .constants = 10, - .rows = max_bytecode_size - }; + static void allocate_public_inputs( + context_type &context, + input_type &input, + size_t max_bytecode_size, + size_t max_keccak_blocks, + size_t max_bytecodes_amount) { + context.allocate(input.rlc_challenge, 0, 0, column_type::public_input); + } + + bytecode(context_type &context_object, input_type input, + size_t max_bytecode_size_, size_t max_keccak_blocks_, + size_t max_bytecodes_amount_) + : max_bytecode_size(max_bytecode_size_), + max_keccak_blocks(max_keccak_blocks_), + max_bytecodes_amount(max_bytecodes_amount_), + generic_component(context_object) { + BOOST_LOG_TRIVIAL(trace) << "Small field bytecode circuit assignment" << std::endl; + + size_t current_column = 0; + std::vector bytecode_lookup_area; + for (size_t i = 0; i < BytecodeTable::get_witness_amount(); ++i) { + bytecode_lookup_area.push_back(current_column++); } + context_type bytecode_ct = context_object.subcontext(bytecode_lookup_area,0,max_bytecode_size); + BytecodeTable bc_t(bytecode_ct, input.bytecodes, max_bytecode_size); - static void allocate_public_inputs( - context_type &context, input_type &input, - std::size_t max_bytecode_size, - std::size_t max_keccak_blocks, - std::size_t max_bytecodes_amount - ) { - context.allocate(input.rlc_challenge, 0, 0, column_type::public_input); + size_t bytecode_hash_column = current_column; + std::vector bytecode_hash_lookup_area; + for (size_t i = 0; i < BytecodeHashTable::get_witness_amount(); ++i) { + bytecode_hash_lookup_area.push_back(bytecode_hash_column++); } + context_type bytecode_hash_ct = context_object.subcontext(bytecode_hash_lookup_area,0,max_bytecodes_amount); + BytecodeHashTable bytecode_hash_t(bytecode_hash_ct, input.bytecodes, max_bytecodes_amount); - bytecode(context_type &context_object, - input_type input, - std::size_t max_bytecode_size_, - std::size_t max_keccak_blocks_, - std::size_t max_bytecodes_amount_ - ) : max_bytecode_size(max_bytecode_size_), - max_keccak_blocks(max_keccak_blocks_), - max_bytecodes_amount(max_bytecodes_amount_), - generic_component(context_object) - { - BOOST_LOG_TRIVIAL(trace) << "Small field bytecode circuit assignment" << std::endl; - - std::size_t current_column = 0; - std::vector bytecode_lookup_area; - for( std::size_t i = 0; i < BytecodeTable::get_witness_amount(); i++){ - bytecode_lookup_area.push_back(current_column++); - } - context_type bytecode_ct = context_object.subcontext(bytecode_lookup_area,0,max_bytecode_size); - BytecodeTable bc_t(bytecode_ct, input.bytecodes, max_bytecode_size); + size_t keccak_column = current_column; + std::vector keccak_lookup_area; + for (size_t i = 0; i < KeccakTable::get_witness_amount(); ++i) { + keccak_lookup_area.push_back(keccak_column++); + } + context_type keccak_ct = context_object.subcontext(keccak_lookup_area,max_bytecodes_amount,max_keccak_blocks); + KeccakTable keccak_t(keccak_ct, {input.rlc_challenge, input.keccak_buffers}, max_keccak_blocks); - std::size_t bytecode_hash_column = current_column; - std::vector bytecode_hash_lookup_area; - for( std::size_t i = 0; i < BytecodeHashTable::get_witness_amount(); i++){ - bytecode_hash_lookup_area.push_back(bytecode_hash_column++); - } - context_type bytecode_hash_ct = context_object.subcontext(bytecode_hash_lookup_area,0,max_bytecodes_amount); - BytecodeHashTable bytecode_hash_t(bytecode_hash_ct, input.bytecodes, max_bytecodes_amount); + const std::vector &tag = bc_t.tag; + const std::vector &index = bc_t.index; + const std::vector &value = bc_t.value; + const std::vector &is_opcode = bc_t.is_opcode; + const std::vector &bytecode_id = bc_t.bytecode_id; + std::vector length(max_bytecode_size); + std::vector value_rlc(max_bytecode_size); + std::vector push_size(max_bytecode_size); + std::vector push_size_inv(max_bytecode_size); + std::vector bytecode_end_witness(max_bytecode_size); + std::vector is_padding(max_bytecode_size); + std::vector rlc_challenge(max_bytecode_size); - std::size_t keccak_column = current_column; - std::vector keccak_lookup_area; - for( std::size_t i = 0; i < KeccakTable::get_witness_amount(); i++){ - keccak_lookup_area.push_back(keccak_column++); - } - context_type keccak_ct = context_object.subcontext(keccak_lookup_area,max_bytecodes_amount,max_keccak_blocks); - KeccakTable keccak_t(keccak_ct, {input.rlc_challenge, input.keccak_buffers}, max_keccak_blocks); - - const std::vector &tag = bc_t.tag; - const std::vector &index = bc_t.index; - const std::vector &value = bc_t.value; - const std::vector &is_opcode = bc_t.is_opcode; - const std::vector &bytecode_id = bc_t.bytecode_id; - std::vector rlc_challenge(max_bytecode_size); - std::vector push_size(max_bytecode_size); - std::vector length_left(max_bytecode_size); - std::vector metadata_count(max_bytecode_size); - std::vector value_rlc(max_bytecode_size); - std::vector is_header(max_bytecode_size); - std::vector is_executed(max_bytecode_size); - std::vector is_metadata(max_bytecode_size); - std::vector hash_value_rlc(max_bytecodes_amount); - std::vector is_last_byte(max_bytecode_size); - - if constexpr (stage == GenerationStage::ASSIGNMENT) { - const auto &bytecodes = input.bytecodes.get_data(); - std::size_t cur = 0; - - for(std::size_t i = 0; i < bytecodes.size(); i++) { - const auto &buffer = bytecodes[i].first; - std::size_t total_len = buffer.size(); - - // Determine the boundary between executable bytes and metadata - std::size_t exec_boundary = total_len; // Default: all bytes are executable - if (total_len >= 2) { - // Metadata length is encoded in the last two bytes - std::size_t meta_len = (buffer[total_len - 2] << 8) + buffer[total_len - 1]; - - if (meta_len + 2 <= total_len) { - std::size_t boundary = total_len - meta_len - 2 - 1; // Byte before metadata - // Check for stopping opcodes (STOP, INVALID, RETURN) that will - // confirm the length of the metadata - if (boundary < total_len && - (buffer[boundary] == 0x00 || buffer[boundary] == 0xfe || - buffer[boundary] == 0xf3) - ) { - exec_boundary = boundary + 1; // Set boundary after the stopping opcode - } - } - } - BOOST_LOG_TRIVIAL(trace) << "Bytecode " << i << " size = " << total_len; - BOOST_LOG_TRIVIAL(trace) << "Executable bytes boundary: " << exec_boundary; - - // Header - length_left[cur] = total_len; - metadata_count[cur] = 0; - value_rlc[cur] = total_len; - is_header[cur] = 1; - rlc_challenge[cur] = input.rlc_challenge; - cur++; - - // Bytes - std::size_t push_size_value = 0; - for(std::size_t j = 0; j < buffer.size(); j++, cur++){ - length_left[cur] = length_left[cur - 1] - 1; - if( j < exec_boundary ){ - metadata_count[cur] = 0; - is_executed[cur] = 1; - } else { - metadata_count[cur] = metadata_count[cur - 1] + 1; - is_metadata[cur] = 1; - } - auto byte = buffer[j]; - if (push_size_value == 0) { - if (byte > 0x5f && byte < 0x80) push_size_value = byte - 0x5f; // Set PUSH size - } else { - push_size_value--; - } - push_size[cur] = push_size_value; - rlc_challenge[cur] = input.rlc_challenge; - value_rlc[cur] = value_rlc[cur - 1] * input.rlc_challenge + byte; - if( is_opcode[cur] == 1 ) - BOOST_LOG_TRIVIAL(trace) << cur << ". " << std::hex << index[cur] << " " << opcode_from_number(byte); - else if (is_executed[cur] == 1) - BOOST_LOG_TRIVIAL(trace) << cur << ". " << std::hex << index[cur] << " Data 0x" << std::setw(2) << std::setfill('0') << std::size_t(byte) << std::dec; - else - BOOST_LOG_TRIVIAL(trace) << cur << ". " << std::hex << index[cur] << " Metadata 0x" << std::setw(2) << std::setfill('0') << std::size_t(byte) << std::dec; - } - is_last_byte[cur - 1] = 1; - hash_value_rlc[i] = value_rlc[cur - 1]; - } - } + std::vector bytecode_rlc(max_bytecodes_amount); - std::size_t is_last_byte_index = 0; - std::size_t index_index = bytecode_lookup_area[1]; - std::size_t bytecode_id_index = bytecode_lookup_area[4]; - std::size_t value_rlc_index = bytecode_lookup_area[5]; - std::size_t last_column = 0; - for( std::size_t i = 0; i < max_bytecode_size; i++ ){ - current_column = BytecodeTable::get_witness_amount() + std::max(KeccakTable::get_witness_amount(), BytecodeHashTable::get_witness_amount()); - allocate(length_left[i], current_column++, i); - allocate(metadata_count[i], current_column++, i); - value_rlc_index = current_column; allocate(value_rlc[i], current_column++, i); - allocate(push_size[i], current_column++, i); - allocate(rlc_challenge[i], current_column++, i); - allocate(is_header[i], current_column++, i); - allocate(is_executed[i], current_column++, i); - allocate(is_metadata[i], current_column++, i); - is_last_byte_index = current_column; allocate(is_last_byte[i], current_column++, i); - last_column = current_column; - } - for( std::size_t i = 0; i < max_bytecodes_amount; i++ ){ - allocate(hash_value_rlc[i], last_column, i); - } + if constexpr (stage == GenerationStage::ASSIGNMENT) { + const auto &bytecodes = input.bytecodes.get_data(); + rlc_challenge.assign(max_bytecode_size, input.rlc_challenge); + + is_padding[0] = 1; + bytecode_end_witness[0] = 1; + + size_t row = 1; + size_t current_index = 0; + size_t push_size_value = 0; + + auto add_byte = [&](uint8_t byte, bool padding) { + length[row] = length[row - 1]; + value_rlc[row] = value_rlc[row - 1] * input.rlc_challenge + byte; - constrain(bytecode_id[0] - 1); - constrain(is_header[0] - 1); - if constexpr (stage == GenerationStage::CONSTRAINTS) { - std::vector every_row_constraints; - std::vector non_first_row_constraints; - - // 0. Dynamic selectors may be only 0 or 1 - every_row_constraints.push_back(is_header[1] * (is_header[1] - 1)); - every_row_constraints.push_back(is_executed[1] * (is_executed[1] - 1)); - every_row_constraints.push_back(is_metadata[1] * (is_metadata[1] - 1)); - // 1. Only one of them may be 1 on a row - TYPE is_filled = is_header[1] + is_executed[1] + is_metadata[1]; - TYPE is_padding = 1 - is_filled; - every_row_constraints.push_back(is_filled * (is_filled -1)); - // 2. TAG is zeroes, one, two or three - // 0 -- padding - // 1 -- HEADER - // 2 -- BYTE - // 3 -- METADATA - every_row_constraints.push_back(tag[1] - is_header[1] * 1 - is_executed[1] * 2 - is_metadata[1] * 3); - // 3. For HEADER index is 0 - every_row_constraints.push_back(is_header[1] * index[1]); - // 4. In contract header length_left == contract length - every_row_constraints.push_back(is_header[1] * (length_left[1] - value[1])); - // 5. is_opcode is zeroes or ones - every_row_constraints.push_back(is_opcode[1] * (is_opcode[1] - 1)); - // 6. is_opcode on HEADER are zeroes - every_row_constraints.push_back(is_header[1] * is_opcode[1]); - // 7. value_rlc for HEADERS == length_left - every_row_constraints.push_back(is_header[1] * (value_rlc[1] - length_left[1])); - - // 8. INDEX for first contract byte is zero - non_first_row_constraints.push_back(is_header[0] * index[1]); - // 9. INDEX is incremented for all bytes - non_first_row_constraints.push_back((1 - is_header[0]) * (is_executed[1] + is_metadata[1]) * (index[1] - index[0] - 1)); - // 10. Length_left is zero for last byte in the contract - non_first_row_constraints.push_back(is_last_byte[1] * length_left[1]); - // 11. First is_opcode on BYTE after HEADER is 1 - non_first_row_constraints.push_back(is_header[0] * is_executed[1] * (is_opcode[1] - 1)); - // 12. PUSH_SIZE decreases for non-opcodes except metadata - non_first_row_constraints.push_back(is_executed[1] * (1 - is_opcode[1]) * (push_size[0] - push_size[1] - 1)); // Append tag_selectors - // 13. before opcode push_size is always zero - non_first_row_constraints.push_back(is_opcode[1] * push_size[0]); - // 14. for all bytes bytecode_id is similar to previous - non_first_row_constraints.push_back((is_executed[1] + is_metadata[1]) * (bytecode_id[0] - bytecode_id[1])); - // 15. for all bytes RLC is correct - non_first_row_constraints.push_back((is_executed[1] + is_metadata[1]) * (value_rlc[1] - value_rlc[0] * rlc_challenge[1] - value[1])); - // 16. for each BYTEs rlc_challenge are similar - non_first_row_constraints.push_back(is_filled * (rlc_challenge[1] - rlc_challenge[0])); - // 17. is_last_byte is correctly defined - non_first_row_constraints.push_back(is_last_byte[0] - (is_header[1] + is_padding) * (is_metadata[0] + is_executed[0])); - // 18. bytecode_id increased for each bytecode - non_first_row_constraints.push_back(is_header[1] * (bytecode_id[1] - bytecode_id[0] - 1)); - // 19. After metadata is metadata or padding - non_first_row_constraints.push_back(is_metadata[0] * (is_metadata[1] + is_padding - 1)); - // 20. If metadata, is_opcode = 0 - every_row_constraints.push_back(is_metadata[1] * is_opcode[1]); - // 21. Metadata_count does not change if is_executed - non_first_row_constraints.push_back((is_executed[1]) * (metadata_count[1] - metadata_count[0])); - // 22. Metadata count inrement by 1 for metadata - non_first_row_constraints.push_back(is_metadata[1] * (metadata_count[1] - metadata_count[0] - 1)); - // 24. Metadata count is equal to last 2 metadata bytes - non_first_row_constraints.push_back(is_last_byte[1] * metadata_count[1] * (value[1] + value[0] * 256 - metadata_count[1] + 2)); - // 25 Length left decrease by 1 if not padding - non_first_row_constraints.push_back((length_left[0] - length_left[1] - 1) * (is_executed[1] + is_metadata[1])); - // 26. After padding is always padding - every_row_constraints.push_back(is_padding * (is_header[2] + is_executed[2] + is_metadata[2])); - // 27. Last is always padding - constrain(is_header[max_bytecode_size - 1] + is_executed[max_bytecode_size - 1] + is_metadata[max_bytecode_size - 1]); - - // Lookup_table - BOOST_LOG_TRIVIAL(trace) << "zkevm_bytecode_data_with_rlc " - << is_last_byte_index << " " - << bytecode_id_index << " " - << index_index << " " - << value_rlc_index; - context_object.lookup_table("zkevm_bytecode_data_with_rlc", { - is_last_byte_index, - bytecode_id_index, - index_index, - value_rlc_index, - }, 0, max_bytecode_size-1); - - for( auto& constraint: every_row_constraints){ - context_object.relative_constrain(context_object.relativize(constraint, -1), 0, max_bytecode_size-1); + if (push_size_value == 0) { + if (byte >= 0x60 && byte <= 0x7f) + push_size_value = byte - 0x5f; + } else { + --push_size_value; } - for( auto &constraint: non_first_row_constraints ){ - context_object.relative_constrain(context_object.relativize(constraint, -1), 1, max_bytecode_size - 1); + + push_size[row] = push_size_value; + push_size_inv[row] = push_size[row] == 0 ? 0 : push_size[row].inversed(); + + auto length_diff = length[row] - (current_index + 1); + bytecode_end_witness[row] = length_diff == 0 ? 0 : length_diff.inversed(); + + is_padding[row] = padding; + + ++current_index, ++row; + }; + + for (size_t i = 0; i < bytecodes.size(); ++i) { + const auto &buffer = bytecodes[i].first; + BOOST_LOG_TRIVIAL(trace) << "Bytecode " << i << " size = " << buffer.size(); + + // Header + current_index = 0; + length[row] = value_rlc[row] = buffer.size(); + bytecode_end_witness[row] = length[row] == 0 ? 0 : length[row].inversed(); + ++row; + + // Bytes + for (uint8_t byte : buffer) { + BOOST_LOG_TRIVIAL(trace) << row << ". " << current_index; + if (is_opcode[row] == 0) { + BOOST_LOG_TRIVIAL(trace) + << " Push data 0x" << std::hex << std::setw(2) + << std::setfill('0') << size_t(byte) << std::dec; + } else if (auto opcode = opcode_from_number(byte); opcode != static_cast(-1)) { + BOOST_LOG_TRIVIAL(trace) + << ' ' << opcode_to_string(opcode); + } else { + BOOST_LOG_TRIVIAL(trace) + << " Unknown opcode 0x" << std::hex << std::setw(2) + << std::setfill('0') << size_t(byte) << std::dec; + } + + add_byte(byte, false); } - // Lookups - std::vector tmp = {(is_executed[1] + is_metadata[1]) * value[1]}; - context_object.relative_lookup(context_object.relativize(tmp, -1), "byte_range_table/full", 0, max_bytecode_size); - - tmp = { - value[1] * is_opcode[1], - push_size[1] * is_opcode[1], - is_opcode[1] - }; - context_object.relative_lookup(context_object.relativize(tmp, -1), "zkevm_opcodes/full", 0, max_bytecode_size); - - tmp = { - is_last_byte[1], - is_last_byte[1] * bytecode_id[1], - is_last_byte[1] * (index[1] + 1), - }; - context_object.relative_lookup(context_object.relativize(tmp, -1), "zkevm_bytecode_hash", 0, max_bytecode_size); - - tmp = { - bytecode_hash_t.tag[1], - bytecode_hash_t.tag[1] * bytecode_hash_t.bytecode_id[1], - bytecode_hash_t.tag[1] * (bytecode_hash_t.bytecode_size[1] - 1), - bytecode_hash_t.tag[1] * hash_value_rlc[1], - }; - context_object.relative_lookup(context_object.relativize(tmp, -1), "zkevm_bytecode_data_with_rlc", 0, max_bytecodes_amount-1); - - tmp = { - hash_value_rlc[1] - }; - for( std::size_t i = 0; i < 16; i++){ - tmp.push_back(bytecode_hash_t.bytecode_hash[1][i]); + + bytecode_rlc[i] = value_rlc[row - 1]; + + // Implicit zero bytes + BOOST_ASSERT(row + push_size_value + 1 < max_bytecode_size); + + while (push_size_value > 0) { // missing push arguments + add_byte(0, true); } - context_object.relative_lookup(context_object.relativize(tmp, -1), "keccak_table", 0, max_bytecodes_amount-1); + + add_byte(0, true); } - }; + + while (row < max_bytecode_size) add_byte(0, true); + } + + size_t bytecode_id_index = bytecode_lookup_area[4]; + size_t bytecode_length_index; + size_t value_rlc_index; + size_t bytecode_end_witness_index; + size_t last_column = 0; + for (size_t i = 0; i < max_bytecode_size; ++i) { + current_column = BytecodeTable::get_witness_amount() + std::max(KeccakTable::get_witness_amount(), BytecodeHashTable::get_witness_amount()); + allocate(rlc_challenge[i], current_column++, i); + allocate(length[i], bytecode_length_index = current_column++, i); + allocate(value_rlc[i], value_rlc_index = current_column++, i); + allocate(push_size[i], current_column++, i); + allocate(push_size_inv[i], current_column++, i); + allocate(bytecode_end_witness[i], bytecode_end_witness_index = current_column++, i); + allocate(is_padding[i], current_column++, i); + last_column = current_column; + } + + for (size_t i = 0; i < max_bytecodes_amount; ++i) { + allocate(bytecode_rlc[i], last_column, i); + } + + if constexpr (stage == GenerationStage::CONSTRAINTS) { + TYPE zero_constant = typename FieldType::value_type{0}; + TYPE one_constant = typename FieldType::value_type{1}; + allocate(zero_constant, 0, 0, column_type::constant); + allocate(one_constant, 0, 1, column_type::constant); + + // Row 0 is used to allow all-zeros lookups + copy_constrain(tag[0], zero_constant); + // copy_constrain(bytecode_id[0], zero_constant); + + auto constrain_rows = [&](TYPE c, const std::string &name = "") { + context_object.relative_constrain( + context_object.relativize(c, -1), 1, max_bytecode_size-1, + name); + }; + + // RLC challenge correctness: + copy_constrain(rlc_challenge[0], input.rlc_challenge); + constrain_rows(rlc_challenge[1] - rlc_challenge[0], "RLC challenge"); + + // Tag is 0 for headers and 1 for byte rows. + constrain_rows(tag[1] * (tag[1] - 1), "tag is 0 or 1"); + + // First row must be a header: else, it would be possible to replace + // the first bytecode with its suffix, since checks for the initial + // values of index and rlc_value are done on header lines. + copy_constrain(tag[1], zero_constant); + + constrain_rows((1 - tag[1]) * (bytecode_id[1] - (bytecode_id[0] + 1))); + + // For bytes, bytecode id and length are same as in header. + constrain_rows(tag[1] * (bytecode_id[1] - bytecode_id[0]), + "bytecode_id validilty for bytes"); + constrain_rows(tag[1] * (length[1] - length[0]), + "length validity for bytes"); + + // Index is 0 in headers to allow accumulated length computation. + constrain_rows((1 - tag[1]) * index[1], "header index is 0"); + // For bytes, index values start from 0 and increment sequentially. + constrain_rows((1 - tag[0]) * index[1] + + tag[1] * tag[0] * (index[1] - (index[0] + 1)), + "byte index definition"); + // Note that we can skip tag[1] factor in the first part, since + // index is 0 in headers anyway. + + // In headers, RLC is reset to bytecode length and then accumulates + // byte values. + constrain_rows((1 - tag[1]) * (value_rlc[1] - length[1]) + + tag[1] * (value_rlc[1] - + (value_rlc[0] * rlc_challenge[1] + value[1])), + "value RLC definition"); + + // Push size is set to non-zero value at push opcodes, this is + // controlled by a lookup below. After that, it must go all the way + // to zero. + constrain_rows(push_size[0] * (push_size[1] - (push_size[0] - 1)), + "push size decreases to zero"); + // Opcodes are all the bytes that are not used as push arguments, + constrain_rows(is_opcode[1] - tag[1] * (1 - push_size[0] * push_size_inv[0]), + "opcode definition"); + constrain_rows(push_size[1] * (1 - push_size[1] * push_size_inv[1]), + "push_size_inv definition"); + // and it also works for the first byte if push size is zero in headers. + constrain_rows((1 - tag[1]) * push_size[1], "push size is 0 in header"); + // Yep, this is mutual recursion. + + // Finally, bytecode_end marks a row where RLC is finalized, either + // header row of an empty bytecode, or last (explicit) byte otherwise. + TYPE length_diff = length[1] - (tag[1] + index[1]); + constrain_rows(length_diff * (1 - length_diff * bytecode_end_witness[1]), + "witness for bytecode end condition"); + TYPE is_bytecode_end = 1 - length_diff * bytecode_end_witness[1]; + + // After bytecode ends, there are padding zeros: potentially + // missing push arguments and implicitly defined STOP opcode. + TYPE prev_length_diff = length[0] - (tag[0] + index[0]); + TYPE prev_is_end = 1 - prev_length_diff * bytecode_end_witness[0]; + constrain_rows(is_padding[1] - tag[1] * (prev_is_end + is_padding[0]), + "padding definition"); + constrain_rows(is_padding[1] * value[1], "padding bytes are 0s"); + // Note that it is safe mark row 0 as padding. + + // We need to make sure that if a bytecode is present in the table, + // it's hash is checked, i.e. it reaches its last byte. + // We do this by checking for padding row before new bytecode + // starts and at the end of the table; if there is a padding row, + // there must be the bytecode end row before too. + // Note that we do not require all potentially used padding bytes + // to be present: it's ok if lookup fails with malformed assignment, + // we only care for false positive validity checks. + constrain_rows((1 - tag[1]) * (1 - is_padding[0]), "bytecode is completed"); + copy_constrain(is_padding[max_bytecode_size - 1], one_constant); + + // Lookup_table + BOOST_LOG_TRIVIAL(trace) << "zkevm_bytecode_rlc " + << bytecode_id_index << ' ' + << bytecode_length_index << ' ' + << value_rlc_index << ' ' + << bytecode_end_witness_index << std::endl; + context_object.lookup_table("zkevm_bytecode_rlc", { + bytecode_id_index, + bytecode_length_index, + value_rlc_index, + bytecode_end_witness_index, + }, 0, max_bytecode_size - 1); + + // Lookups + std::vector tmp = { + is_opcode[1] * value[1], + is_opcode[1] * push_size[1] + }; + context_object.relative_lookup(context_object.relativize(tmp, -1), "opcode_push_size/full", 0, max_bytecode_size-1); + + tmp = { + is_bytecode_end, + is_bytecode_end * bytecode_id[1], + is_bytecode_end * length[1] + }; + context_object.relative_lookup(context_object.relativize(tmp, -1), "zkevm_bytecode_hash", 1, max_bytecode_size-1); + + tmp = { + bytecode_hash_t.tag[1] * bytecode_hash_t.bytecode_id[1], + bytecode_hash_t.tag[1] * bytecode_hash_t.bytecode_size[1], + bytecode_hash_t.tag[1] * bytecode_rlc[1], + 1 - bytecode_hash_t.tag[1], // if witness is 0, then length_diff is 0! + }; + context_object.relative_lookup(context_object.relativize(tmp, -1), "zkevm_bytecode_rlc", 0, max_bytecodes_amount-1); + + tmp = { + bytecode_rlc[1] + }; + for( size_t i = 0; i < 16; i++){ + tmp.push_back(bytecode_hash_t.bytecode_hash[1][i]); + } + context_object.relative_lookup(context_object.relativize(tmp, -1), "keccak_table", 0, max_bytecodes_amount-1); + } }; -} \ No newline at end of file +}; + +} diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/small_field/circuits/zkevm.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/small_field/circuits/zkevm.hpp index 5cdcaac330..6dc5bb0cb4 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/small_field/circuits/zkevm.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/small_field/circuits/zkevm.hpp @@ -386,8 +386,7 @@ namespace nil::blueprint::bbf::zkevm_small_field{ opcode_selector_sum += opcode_selectors[1 + j][opcode_id]; current_opcode_constraint += opcode_selectors[1 + j][opcode_id] * opcode_to_number(current_opcode); zkevm_opcode_row_selectors[{current_opcode, j}] = opcode_selectors[1 + j][opcode_id]; - // STOP opcode logic is controlled by opcode - if( nil_opcodes.count(current_opcode) == 0 && current_opcode != zkevm_opcode::STOP ){ + if (!nil_opcodes.contains(current_opcode)) { evm_opcode_constraint += opcode_selectors[1 + j][opcode_id]; } } diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/small_field/tables/bytecode.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/small_field/tables/bytecode.hpp index f21e30627b..124028e63b 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/small_field/tables/bytecode.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/small_field/tables/bytecode.hpp @@ -25,132 +25,139 @@ #include -#include +#include "nil/blueprint/zkevm_bbf/types/opcode_enum.hpp" +#include "nil/blueprint/zkevm_bbf/types/hashed_buffers.hpp" namespace nil::blueprint::bbf::zkevm_small_field{ - // Component for bytecode table - - template - class bytecode_table : public generic_component { - using typename generic_component::context_type; - using generic_component::allocate; - using generic_component::copy_constrain; - using generic_component::constrain; - using generic_component::lookup; - using generic_component::lookup_table; - - public: - using typename generic_component::TYPE; - using input_type = std::conditional_t< - stage == GenerationStage::ASSIGNMENT, zkevm_keccak_buffers, std::monostate - >; - - std::size_t max_bytecode_size; // Maximum possible bytecodes sum length - - // interfaces for interaction with other components: - std::vector tag; // Row type: 0(padding), 1 (header), 2 (executable bytes), 3 (metadata) - std::vector index; // Position of the byte within the bytecode - std::vector value; // Byte value (for bytes) or total length (for header) - std::vector is_opcode; // Flags whether the byte is an opcode (1) or not (0) - std::vector bytecode_id; // Bytecode's unique identifier used by zkevm circuit - // We use it to prevent 16-column bytecode hash repeitition - - static std::size_t get_witness_amount(){ - return 5; - } - bytecode_table( +// Component for bytecode table +template +class bytecode_table : public generic_component { + using typename generic_component::context_type; + using generic_component::allocate; + using generic_component::copy_constrain; + using generic_component::constrain; + using generic_component::lookup; + using generic_component::lookup_table; + + public: + using typename generic_component::TYPE; + using input_type = std::conditional_t< + stage == GenerationStage::ASSIGNMENT, zkevm_keccak_buffers, std::monostate + >; + + size_t max_bytecode_size; // Maximum possible bytecodes sum length + + // interfaces for interaction with other components: + std::vector tag; // Row type: 0(padding), 1 (header), 2 (executable bytes), 3 (metadata) + std::vector index; // Position of the byte within the bytecode + std::vector value; // Byte value (for bytes) or total length (for header) + std::vector is_opcode; // Flags whether the byte is an opcode (1) or not (0) + std::vector bytecode_id; // Bytecode's unique identifier used by zkevm circuit + // We use it to prevent 16-column bytecode hash repeitition + + static size_t get_witness_amount() { + return 5; + } + + bytecode_table( context_type &context_object, const input_type &input, - std::size_t max_bytecode_size_ - ) : - max_bytecode_size(max_bytecode_size_), - tag(max_bytecode_size_), - index(max_bytecode_size_), - value(max_bytecode_size_), - is_opcode(max_bytecode_size_), - bytecode_id(max_bytecode_size_), - generic_component(context_object) { - BOOST_LOG_TRIVIAL(trace) << "Small field bytecode table assignment"; - - // If we're in assignment stage, prepare all the values - if constexpr (stage == GenerationStage::ASSIGNMENT) { - const auto &bytecodes = input.get_data(); - std::size_t cur = 0; - - for(std::size_t i = 0; i < bytecodes.size(); i++) { - TYPE push_size = 0; - std::size_t meta_len = 0; - const auto &buffer = bytecodes[i].first; - std::size_t total_len = buffer.size(); - - // Determine the boundary between executable bytes and metadata - std::size_t exec_boundary = total_len; // Default: all bytes are executable - if (total_len >= 2) { - // Metadata length is encoded in the last two bytes - meta_len = (buffer[total_len - 2] << 8) + buffer[total_len - 1]; - if (meta_len + 2 <= total_len) { - std::size_t boundary = total_len - meta_len - 2 - 1; // Byte before metadata - // Check for stopping opcodes (STOP, INVALID, RETURN) that will - // confirm the length of the metadata - if (boundary < total_len && - (buffer[boundary] == 0x00 || buffer[boundary] == 0xfe || - buffer[boundary] == 0xf3) - ) { - exec_boundary = boundary + 1; // Set boundary after the stopping opcode - } - } - } - BOOST_LOG_TRIVIAL(trace) << "Bytecode " << i << " size = " << total_len; - BOOST_LOG_TRIVIAL(trace) << "Executable bytes boundary: " << exec_boundary; - - // Header - BOOST_ASSERT(cur < max_bytecode_size); - tag[cur] = 1; - index[cur] = 0; - value[cur] = total_len; - is_opcode[cur] = 0; - bytecode_id[cur] = i + 1; - cur++; - - // Bytes - for(std::size_t j = 0; j < buffer.size(); j++, cur++){ - BOOST_ASSERT(cur < max_bytecode_size); - auto byte = buffer[j]; - value[cur] = byte; - index[cur] = j; - bytecode_id[cur] = i + 1; - if (j < exec_boundary) { - tag[cur] = 2; - if (push_size == 0) { - is_opcode[cur] = 1; - // Check for PUSH opcodes (0x60 to 0x7f) and set push_size - if (byte > 0x5f && byte < 0x80) { - push_size = byte - 0x5f; - } - } else { // In a PUSH operation - is_opcode[cur] = 0; - push_size--; - } - } else { // Metadata bytes - tag[cur] = 3; - is_opcode[cur] = 0; - push_size = 0; - } + size_t max_bytecode_size_) + : max_bytecode_size(max_bytecode_size_), + tag(max_bytecode_size_), + index(max_bytecode_size_), + value(max_bytecode_size_), + is_opcode(max_bytecode_size_), + bytecode_id(max_bytecode_size_), + generic_component(context_object) { + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + const auto &bytecodes = input.get_data(); + + size_t row = 1; + size_t current_index = 0; + size_t push_size = 0; + + for (size_t i = 0; i < bytecodes.size(); ++i) { + const auto &buffer = bytecodes[i].first; + BOOST_ASSERT(row + 1 + buffer.size() < max_bytecode_size); + + // Header + tag[row] = 0; + index[row] = current_index = 0; + value[row] = 0; + is_opcode[row] = 0; + bytecode_id[row] = i + 1; + ++row; + + size_t push_size = 0; + while (current_index < buffer.size()) { + auto byte = buffer[current_index]; + value[row] = byte; + index[row] = current_index;; + bytecode_id[row] = i + 1; + tag[row] = 1; + + if (push_size == 0) { + is_opcode[row] = 1; + + // Check for PUSH opcodes (0x60 to 0x7f) and set push_size + if (byte >= 0x60 && byte <= 0x7f) + push_size = byte - 0x5f; + } else { // In a PUSH operation + is_opcode[row] = 0; + --push_size; } + + ++current_index, ++row; } + + // Add potentially accessed implicit zero bytes + BOOST_ASSERT(row + push_size + 1 < max_bytecode_size); + + while (push_size > 0) { // missing push arguments + BOOST_ASSERT(row < max_bytecode_size); + tag[row] = 1; + index[row] = current_index; + value[row] = 0; + is_opcode[row] = 0; + bytecode_id[row] = i + 1; + + ++current_index, ++row, --push_size; + } + + // Add implicit STOP instruction + tag[row] = 1; + index[row] = current_index; + value[row] = 0; + is_opcode[row] = 1; + bytecode_id[row] = i + 1; + ++current_index, ++row; } - // allocate everything. NB: this replaces the map from the original component - for(std::size_t i = 0; i < max_bytecode_size; i++) { - allocate(tag[i], 0, i); - allocate(index[i], 1, i); - allocate(value[i], 2, i); - allocate(is_opcode[i], 3, i); - allocate(bytecode_id[i], 4, i); + + while (row < max_bytecode_size) { + tag[row] = 1; + index[row] = current_index; + value[row] = 0; + is_opcode[row] = 1; + bytecode_id[row] = bytecodes.size(); + ++current_index, ++row; } - // declare dynamic lookup table - lookup_table("zkevm_bytecode",std::vector({0,1,2,3,4}), 0, max_bytecode_size); - lookup_table("zkevm_bytecode_copy",std::vector({1,2,4}), 0, max_bytecode_size); - }; + } + + // allocate everything. NB: this replaces the map from the original component + for (size_t i = 0; i < max_bytecode_size; ++i) { + allocate(tag[i], 0, i); + allocate(index[i], 1, i); + allocate(value[i], 2, i); + allocate(is_opcode[i], 3, i); + allocate(bytecode_id[i], 4, i); + } + + lookup_table("zkevm_bytecode", {0,1,2,3,4}, 0, max_bytecode_size); + lookup_table("zkevm_bytecode_copy", {1,2,4}, 0, max_bytecode_size); }; -} \ No newline at end of file +}; + +} diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/types/opcode_enum.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/types/opcode_enum.hpp index 0e5ba30853..53fe488e04 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/types/opcode_enum.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/types/opcode_enum.hpp @@ -528,9 +528,16 @@ namespace nil { if( number == 0x106 ) return zkevm_opcode::end_call; // opcode for end call if( number == 0x107 ) return zkevm_opcode::end_transaction; // opcode for end call if( number == 0x108 ) return zkevm_opcode::end_block; // opcode for end call - std::cout << "Unknown opcode " << std::hex << number << std::dec << std::endl; - BOOST_ASSERT(false); - return zkevm_opcode::padding; + return zkevm_opcode(-1); + } + + bool is_known_opcode_number(size_t opcode) { + switch (opcode) { + #define ENUM_DEF(name) case zkevm_opcode::name: return true; + ZKEVM_OPCODE_ENUM(ENUM_DEF) + #undef ENUM_DEF + default: return false; + } } zkevm_opcode opcode_from_str(const std::string &str){ @@ -571,6 +578,8 @@ namespace nil { #undef ENUM_DEF return result; } + + #undef ZKEVM_OPCODE_ENUM } // namespace bbf } // namespace blueprint } // namespace nil diff --git a/crypto3/libs/blueprint/test/zkevm_bbf/bytecode.cpp b/crypto3/libs/blueprint/test/zkevm_bbf/bytecode.cpp index b193edc749..443a084a4c 100644 --- a/crypto3/libs/blueprint/test/zkevm_bbf/bytecode.cpp +++ b/crypto3/libs/blueprint/test/zkevm_bbf/bytecode.cpp @@ -165,7 +165,7 @@ BOOST_AUTO_TEST_CASE(not_hashed){ test_small_zkevm_bytecode(input, keccak_input, 5000, 50, false); } -BOOST_AUTO_TEST_CASE(new_error, *boost::unit_test::disabled()){ +BOOST_AUTO_TEST_CASE(new_error) { nil::blueprint::bbf::zkevm_keccak_buffers input; std::string bytecode2 = "0x608060405234801561000f575f80fd5b5060043610610029575f3560e01c806364b3cfe61461002d575b5f80fd5b610047600480360381019061004291906100d6565b61005d565b6040516100549190610110565b60405180910390f35b5f8060405180606001604052806029815260200161019e6029913990505f835190505f8081548092919061009090610156565b91905055508092505050919050565b5f80fd5b5f819050919050565b6100b5816100a3565b81146100bf575f80fd5b50565b5f813590506100d0816100ac565b92915050565b5f602082840312156100eb576100ea61009f565b5b5f6100f8848285016100c2565b91505092915050565b61010a816100a3565b82525050565b5f6020820190506101235f830184610101565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610160826100a3565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361019257610191610129565b5b60018201905091905056fe112233445566778899ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";