1
1
// ---------------------------------------------------------------------------//
2
2
// Copyright (c) 2024 Elena Tatuzova <[email protected] >
3
+ // Copyright (c) 2025 Antoine Cyr <[email protected] >
3
4
//
4
5
// MIT License
5
6
//
30
31
namespace nil {
31
32
namespace blueprint {
32
33
namespace bbf {
33
- // Component for bytecode table
34
-
35
34
template <typename FieldType, GenerationStage stage>
36
35
class bytecode_table : public generic_component <FieldType, stage> {
37
36
using typename generic_component<FieldType, stage>::context_type;
@@ -41,86 +40,104 @@ namespace nil {
41
40
using generic_component<FieldType, stage>::lookup;
42
41
using generic_component<FieldType, stage>::lookup_table;
43
42
44
- public:
45
- using typename generic_component<FieldType,stage>::TYPE;
43
+ public:
44
+ using TYPE = typename generic_component<FieldType, stage>::TYPE;
46
45
using input_type = std::conditional_t <
47
46
stage == GenerationStage::ASSIGNMENT, zkevm_keccak_buffers, std::monostate
48
47
>;
49
48
50
49
std::size_t max_bytecode_size;
51
50
52
- // interfaces for interaction with other components:
53
- std::vector<TYPE> tag = std::vector<TYPE>(max_bytecode_size);
54
- std::vector<TYPE> index = std::vector<TYPE>(max_bytecode_size);
55
- std::vector<TYPE> value = std::vector<TYPE>(max_bytecode_size);
56
- std::vector<TYPE> is_opcode = std::vector<TYPE>(max_bytecode_size);
57
- std::vector<TYPE> hash_hi = std::vector<TYPE>(max_bytecode_size);
58
- std::vector<TYPE> hash_lo = std::vector<TYPE>(max_bytecode_size);
51
+ std::vector<TYPE> tag = std::vector<TYPE>(max_bytecode_size); // 0: header, 1: executable bytes, 2: metadata
52
+ std::vector<TYPE> index = std::vector<TYPE>(max_bytecode_size); // Position in bytecode
53
+ std::vector<TYPE> value = std::vector<TYPE>(max_bytecode_size); // Byte value or total length
54
+ std::vector<TYPE> is_opcode = std::vector<TYPE>(max_bytecode_size); // 1 if opcode, 0 otherwise
55
+ std::vector<TYPE> hash_hi = std::vector<TYPE>(max_bytecode_size); // High 128 bits of hash
56
+ std::vector<TYPE> hash_lo = std::vector<TYPE>(max_bytecode_size); // Low 128 bits of hash
59
57
60
- static std::size_t get_witness_amount (){
61
- return 6 ;
62
- }
58
+ static std::size_t get_witness_amount () { return 6 ; }
63
59
64
60
bytecode_table (context_type &context_object,
65
- const input_type &input,
66
- std::size_t max_bytecode_size_,
67
- bool make_links = true ) :
68
- max_bytecode_size (max_bytecode_size_),
69
- generic_component<FieldType,stage>(context_object) {
61
+ const input_type &input,
62
+ std::size_t max_bytecode_size_,
63
+ bool make_links = true )
64
+ : max_bytecode_size(max_bytecode_size_),
65
+ generic_component<FieldType, stage>(context_object) {
70
66
71
- // if we're in assignment stage, prepare all the values
72
67
if constexpr (stage == GenerationStage::ASSIGNMENT) {
73
68
auto bytecodes = input.get_data ();
74
-
75
69
std::size_t cur = 0 ;
76
- for (std::size_t i = 0 ; i < bytecodes.size (); i++) {
70
+
71
+ for (std::size_t i = 0 ; i < bytecodes.size (); i++) {
77
72
TYPE hash_hi_val = w_hi<FieldType>(bytecodes[i].second );
78
73
TYPE hash_lo_val = w_lo<FieldType>(bytecodes[i].second );
79
74
TYPE push_size = 0 ;
80
75
const auto &buffer = bytecodes[i].first ;
81
- for (std::size_t j = 0 ; j < buffer.size (); j++, cur++){
76
+ std::size_t total_len = buffer.size ();
77
+
78
+ // Compute metadata length from the last two bytes
79
+ std::size_t exec_boundary = total_len; // Default: all bytes executable
80
+ if (total_len >= 2 ) {
81
+ std::size_t meta_len = (buffer[total_len - 2 ] << 8 ) + buffer[total_len - 1 ];
82
+ if (meta_len + 2 <= total_len) {
83
+ std::size_t boundary = total_len - meta_len - 2 - 1 ; // Byte before metadata
84
+ if (boundary < total_len && (buffer[boundary] == 0x00 || buffer[boundary] == 0xfe || buffer[boundary] == 0xf3 )) {
85
+ exec_boundary = boundary + 1 ; // After stopping opcode
86
+ }
87
+ }
88
+ }
89
+
90
+ // Header
91
+ BOOST_ASSERT (cur < max_bytecode_size);
92
+ tag[cur] = 0 ;
93
+ index[cur] = 0 ;
94
+ value[cur] = total_len;
95
+ is_opcode[cur] = 0 ;
96
+ hash_hi[cur] = hash_hi_val;
97
+ hash_lo[cur] = hash_lo_val;
98
+ cur++;
99
+
100
+ // Bytes
101
+ for (std::size_t j = 0 ; j < buffer.size (); j++, cur++) {
82
102
BOOST_ASSERT (cur < max_bytecode_size);
83
103
std::uint8_t byte = buffer[j];
84
- hash_hi[cur] = hash_hi_val;
85
- hash_lo[cur] = hash_lo_val;
86
- if ( j == 0 ) { // HEADER
87
- value[cur] = buffer.size ();
88
- tag[cur] = 0 ;
89
- index[cur] = 0 ;
90
- is_opcode[cur] = 0 ;
91
- push_size = 0 ; // might be unnecessary
92
- cur++;
93
- }
94
- // BYTE
95
104
value[cur] = byte;
96
105
hash_hi[cur] = hash_hi_val;
97
106
hash_lo[cur] = hash_lo_val;
98
- tag[cur] = 1 ;
99
107
index[cur] = j;
100
- if (push_size == 0 ) {
101
- is_opcode[cur] = 1 ;
102
- if (byte > 0x5f && byte < 0x80 ) push_size = byte - 0x5f ;
103
- } else {
108
+
109
+ if (j < exec_boundary) { // Executable bytes
110
+ tag[cur] = 1 ;
111
+ if (push_size == 0 ) {
112
+ is_opcode[cur] = 1 ;
113
+ if (byte > 0x5f && byte < 0x80 ) {
114
+ push_size = byte - 0x5f ;
115
+ }
116
+ } else {
117
+ is_opcode[cur] = 0 ;
118
+ push_size--;
119
+ }
120
+ } else { // Metadata bytes
121
+ tag[cur] = 2 ;
104
122
is_opcode[cur] = 0 ;
105
- push_size--;
123
+ push_size = 0 ; // Reset to avoid carry-over
106
124
}
107
125
// std::cout << cur << ". " << std::hex << std::size_t(byte) << " " << is_opcode[cur] << " " << push_size << std::dec << std::endl;
108
126
}
109
127
}
110
128
}
111
- // allocate everything. NB: this replaces the map from the original component
112
- for (std::size_t i = 0 ; i < max_bytecode_size; i++) {
113
- allocate (tag[i],0 , i);
114
- allocate (index[i],1 , i);
115
- allocate (value[i],2 , i);
116
- allocate (is_opcode[i],3 , i);
117
- allocate (hash_hi[i],4 , i);
118
- allocate (hash_lo[i],5 , i);
129
+
130
+ for (std::size_t i = 0 ; i < max_bytecode_size; i++) {
131
+ allocate (tag[i], 0 , i);
132
+ allocate (index[i], 1 , i);
133
+ allocate (value[i], 2 , i);
134
+ allocate (is_opcode[i], 3 , i);
135
+ allocate (hash_hi[i], 4 , i);
136
+ allocate (hash_lo[i], 5 , i);
119
137
}
120
- // declare dynamic lookup table
121
- lookup_table (" zkevm_bytecode" ,std::vector<std::size_t >({0 ,1 ,2 ,3 ,4 ,5 }),0 ,max_bytecode_size);
122
- };
123
- };
138
+ lookup_table (" zkevm_bytecode" , std::vector<std::size_t >({0 , 1 , 2 , 3 , 4 , 5 }), 0 , max_bytecode_size);
139
+ }
140
+ };
124
141
}
125
142
}
126
- }
143
+ }
0 commit comments