Skip to content

Commit 24c1a66

Browse files
committed
bytecode comments and formating
1 parent 2fe42e1 commit 24c1a66

File tree

2 files changed

+253
-193
lines changed

2 files changed

+253
-193
lines changed
Lines changed: 141 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//---------------------------------------------------------------------------//
22
// Copyright (c) 2024 Elena Tatuzova <[email protected]>
3+
// Copyright (c) 2025 Antoine Cyr <[email protected]>
34
//
45
// MIT License
56
//
@@ -23,13 +24,16 @@
2324
//---------------------------------------------------------------------------//
2425
#pragma once
2526

26-
#include <nil/blueprint/zkevm_bbf/types/hashed_buffers.hpp>
2727
#include <nil/blueprint/zkevm_bbf/subcomponents/bytecode_table.hpp>
2828
#include <nil/blueprint/zkevm_bbf/subcomponents/keccak_table.hpp>
29+
#include <nil/blueprint/zkevm_bbf/types/hashed_buffers.hpp>
2930

3031
namespace nil {
3132
namespace blueprint {
3233
namespace bbf {
34+
// Input: zkevm_keccak_buffers, rlc_challenge
35+
// Integrates bytecode_table and keccak_table with additional constraints and
36+
// lookups to verify zkEVM bytecode properties.
3337
template<typename FieldType, GenerationStage stage>
3438
class bytecode : public generic_component<FieldType, stage> {
3539
using typename generic_component<FieldType, stage>::context_type;
@@ -39,74 +43,81 @@ namespace nil {
3943
using generic_component<FieldType, stage>::lookup;
4044
using generic_component<FieldType, stage>::lookup_table;
4145

42-
using BytecodeTable = bytecode_table<FieldType,stage>;
43-
using KeccakTable = keccak_table<FieldType,stage>;
46+
using BytecodeTable = bytecode_table<FieldType, stage>;
47+
using KeccakTable = keccak_table<FieldType, stage>;
4448

45-
public:
49+
public:
4650
using typename generic_component<FieldType, stage>::table_params;
47-
using typename generic_component<FieldType,stage>::TYPE;
51+
using typename generic_component<FieldType, stage>::TYPE;
4852

4953
struct input_type {
50-
TYPE rlc_challenge;
51-
52-
BytecodeTable::input_type bytecodes;
53-
KeccakTable::private_input_type keccak_buffers;
54+
TYPE rlc_challenge; // Random linear combination challenge
55+
BytecodeTable::input_type bytecodes; // Bytecode buffers with hashes
56+
KeccakTable::private_input_type
57+
keccak_buffers; // Keccak-specific input
5458
};
5559

5660
std::size_t max_bytecode_size;
5761
std::size_t max_keccak_blocks;
5862

59-
static table_params get_minimal_requirements(std::size_t max_bytecode_size,
60-
std::size_t max_keccak_blocks) {
61-
return {
62-
.witnesses = 15,
63-
.public_inputs = 1,
64-
.constants = 10,
65-
.rows = max_bytecode_size + max_keccak_blocks
66-
};
63+
static table_params get_minimal_requirements(
64+
std::size_t max_bytecode_size, std::size_t max_keccak_blocks) {
65+
return {.witnesses = 15,
66+
.public_inputs = 1,
67+
.constants = 10,
68+
.rows = max_bytecode_size + max_keccak_blocks};
6769
}
6870

69-
static void allocate_public_inputs(
70-
context_type &context, input_type &input,
71-
std::size_t max_bytecode_size, std::size_t max_keccak_blocks) {
72-
context.allocate(input.rlc_challenge, 0, 0, column_type::public_input);
71+
static void allocate_public_inputs(context_type &context,
72+
input_type &input,
73+
std::size_t max_bytecode_size,
74+
std::size_t max_keccak_blocks) {
75+
context.allocate(input.rlc_challenge, 0, 0,
76+
column_type::public_input);
7377
}
7478

75-
bytecode(context_type &context_object,
76-
input_type input,
77-
std::size_t max_bytecode_size_,
78-
std::size_t max_keccak_blocks_
79-
) : max_bytecode_size(max_bytecode_size_),
80-
max_keccak_blocks(max_keccak_blocks_),
81-
generic_component<FieldType,stage>(context_object)
82-
{
83-
std::vector<std::size_t> bytecode_lookup_area = {0,1,2,3,4,5};
84-
std::vector<std::size_t> keccak_lookup_area = {0,1,2,3};
85-
context_type bytecode_ct = context_object.subcontext(bytecode_lookup_area,0,max_bytecode_size);
86-
context_type keccak_ct = context_object.subcontext( keccak_lookup_area, max_bytecode_size, max_bytecode_size + max_keccak_blocks);
79+
bytecode(context_type &context_object, input_type input,
80+
std::size_t max_bytecode_size_, std::size_t max_keccak_blocks_)
81+
: max_bytecode_size(max_bytecode_size_),
82+
max_keccak_blocks(max_keccak_blocks_),
83+
generic_component<FieldType, stage>(context_object) {
84+
std::vector<std::size_t> bytecode_lookup_area = {0, 1, 2, 3, 4, 5};
85+
std::vector<std::size_t> keccak_lookup_area = {0, 1, 2, 3};
86+
context_type bytecode_ct = context_object.subcontext(
87+
bytecode_lookup_area, 0, max_bytecode_size);
88+
context_type keccak_ct =
89+
context_object.subcontext(keccak_lookup_area, max_bytecode_size,
90+
max_bytecode_size + max_keccak_blocks);
8791

8892
BytecodeTable bc_t(bytecode_ct, input.bytecodes, max_bytecode_size);
89-
KeccakTable(keccak_ct, {input.rlc_challenge, input.keccak_buffers}, max_keccak_blocks);
93+
KeccakTable(keccak_ct, {input.rlc_challenge, input.keccak_buffers},
94+
max_keccak_blocks);
9095

9196
const std::vector<TYPE> &tag = bc_t.tag;
9297
const std::vector<TYPE> &index = bc_t.index;
9398
const std::vector<TYPE> &value = bc_t.value;
9499
const std::vector<TYPE> &is_opcode = bc_t.is_opcode;
95100
const std::vector<TYPE> &hash_hi = bc_t.hash_hi;
96101
const std::vector<TYPE> &hash_lo = bc_t.hash_lo;
97-
std::vector<TYPE> rlc_challenge = std::vector<TYPE>(max_bytecode_size);
98-
std::vector<TYPE> push_size = std::vector<TYPE>(max_bytecode_size);
99-
std::vector<TYPE> length_left = std::vector<TYPE>(max_bytecode_size);
100-
std::vector<TYPE> value_rlc = std::vector<TYPE>(max_bytecode_size);
101-
std::vector<TYPE> is_byte = std::vector<TYPE>(max_bytecode_size);
102+
std::vector<TYPE> rlc_challenge(
103+
max_bytecode_size); // RLC challenge per row
104+
std::vector<TYPE> push_size(
105+
max_bytecode_size); // Tracks PUSH operation size
106+
std::vector<TYPE> length_left(
107+
max_bytecode_size); // Remaining length of bytecode
108+
std::vector<TYPE> value_rlc(
109+
max_bytecode_size); // RLC of bytecode values
110+
std::vector<TYPE> is_byte(
111+
max_bytecode_size); // Flags if row is a byte
102112

103113
if constexpr (stage == GenerationStage::ASSIGNMENT) {
104114
std::size_t cur = 0;
105115
const auto &bytecodes = input.bytecodes.get_data();
106-
for(std::size_t i = 0; i < bytecodes.size(); i++){
116+
for (std::size_t i = 0; i < bytecodes.size(); i++) {
107117
TYPE push_size_value = 0;
108118
auto buffer = bytecodes[i].first;
109119
TYPE length_left_value = buffer.size();
120+
110121
// HEADER
111122
rlc_challenge[cur] = input.rlc_challenge;
112123
push_size[cur] = 0;
@@ -116,75 +127,115 @@ namespace nil {
116127
push_size_value = 0;
117128
length_left_value--;
118129
cur++;
130+
119131
// BYTES
120-
for(std::size_t j = 0; j < bytecodes[i].first.size(); j++, cur++){
132+
for (std::size_t j = 0; j < bytecodes[i].first.size();
133+
j++, cur++) {
121134
auto byte = buffer[j];
122-
if(push_size_value == 0){
123-
if(byte > 0x5f && byte < 0x80) push_size_value = byte - 0x5f;
135+
if (push_size_value == 0) {
136+
if (byte > 0x5f && byte < 0x80)
137+
push_size_value = byte - 0x5f; // Set PUSH size
124138
} else {
125139
push_size_value--;
126140
}
127-
is_byte[cur] = tag[cur] * (3 - tag[cur]) * TYPE(2).inversed();
141+
is_byte[cur] =
142+
tag[cur] * (3 - tag[cur]) * TYPE(2).inversed();
128143
push_size[cur] = push_size_value;
129144
rlc_challenge[cur] = input.rlc_challenge;
130145
length_left[cur] = length_left_value;
131-
value_rlc[cur] = value_rlc[cur - 1] * input.rlc_challenge + byte;
146+
value_rlc[cur] =
147+
value_rlc[cur - 1] * input.rlc_challenge + byte;
132148
length_left_value--;
133149
}
134150
}
135151
}
136-
// allocate things that are not part of bytecode_table
137-
for(std::size_t i = 0; i < max_bytecode_size; i++) {
138-
allocate(push_size[i],6,i);
139-
allocate(value_rlc[i],7,i);
140-
allocate(length_left[i],8,i);
141-
allocate(rlc_challenge[i],9,i);
142-
allocate(is_byte[i],10,i);
152+
153+
// Allocate columns that are not part of the bytecode_table
154+
for (std::size_t i = 0; i < max_bytecode_size; i++) {
155+
allocate(push_size[i], 6, i);
156+
allocate(value_rlc[i], 7, i);
157+
allocate(length_left[i], 8, i);
158+
allocate(rlc_challenge[i], 9, i);
159+
allocate(is_byte[i], 10, i);
143160
}
144-
// constrain all bytecode values
145-
// if (make_links) {
146-
// copy_constrain(input.rlc_challenge, rlc_challenge[0]);
147-
// }
161+
148162
static const auto zerohash = zkevm_keccak_hash({});
149-
for(std::size_t i = 0; i < max_bytecode_size; i++) {
150-
constrain(tag[i] * (tag[i] - 1) * (tag[i] - 2)); // 0. TAG is zeroes, one or two
151-
constrain((tag[i] - 2) * (tag[i] - 1) * index[i]); // 1. INDEX for HEADER and unused bytes is zero
152-
constrain((tag[i] - 2) * (tag[i] - 1) * (length_left[i] - value[i])); // 4. In contract header length_left == contract length
153-
constrain(is_opcode[i] * (is_opcode[i] - 1)); // 7. is_opcode is zeroes or ones
154-
constrain((tag[i] - 2) * (tag[i] - 1) * is_opcode[i]); // 8. is_opcode on HEADER are zeroes
155-
constrain((tag[i] - 2) * (tag[i] - 1) * (value_rlc[i] - length_left[i])); // 14. value_rlc for HEADERS == 0;
163+
for (std::size_t i = 0; i < max_bytecode_size; i++) {
164+
// 0. TAG is zeroes, one or two
165+
constrain(tag[i] * (tag[i] - 1) * (tag[i] - 2));
166+
// 1. INDEX for HEADER and unused bytes is zero
167+
constrain((tag[i] - 2) * (tag[i] - 1) * index[i]);
168+
// 4. In contract header length_left == contract length
169+
constrain((tag[i] - 2) * (tag[i] - 1) *
170+
(length_left[i] - value[i]));
171+
// 7. is_opcode is zeroes or ones
172+
constrain(is_opcode[i] * (is_opcode[i] - 1));
173+
// 8. is_opcode on HEADER are zeroes
174+
constrain((tag[i] - 2) * (tag[i] - 1) * is_opcode[i]);
175+
// 14. value_rlc for HEADERS == length_left
176+
constrain((tag[i] - 2) * (tag[i] - 1) *
177+
(value_rlc[i] - length_left[i]));
156178

157179
if (i > 0) {
158-
constrain((tag[i-1] - 2) * (tag[i-1] - 1) * index[i]); // 2. INDEX for first contract byte is zero
159-
constrain(tag[i-1] * tag[i] * (index[i] - index[i-1] - 1)); // 3. INDEX is incremented for all bytes
160-
constrain(tag[i] * (length_left[i-1] - length_left[i] - 1)); // 5. In contract bytes each row decrement length_left
161-
constrain(tag[i-1] * (tag[i] - 2) * (tag[i] - 1) * length_left[i-1]); // 6. Length_left is zero for last byte in the contract
162-
constrain((tag[i] - 2) * (tag[i-1] - 1) * tag[i] * (is_opcode[i] - 1)); // 9. Fist is_opcode on BYTE after HEADER is 1
163-
constrain((tag[i] - 2) * tag[i] * (is_opcode[i] - 1) * (push_size[i-1] - push_size[i] - 1)); // 10. PUSH_SIZE decreases for non-opcodes except metadata
164-
constrain(is_opcode[i] * push_size[i-1]); // 11. before opcode push_size is always zero
165-
constrain(tag[i] * (hash_hi[i-1] - hash_hi[i])); //12. for all bytes hash is similar to previous
166-
constrain(tag[i] * (hash_lo[i-1] - hash_lo[i])); //13. for all bytes hash is similar to previous
167-
constrain(tag[i] * (value_rlc[i] - value_rlc[i-1] * rlc_challenge[i] - value[i])); // 15. for all bytes RLC is correct
168-
constrain(tag[i] * (rlc_challenge[i] - rlc_challenge[i-1])); //16. for each BYTEs rlc_challenge are similar
180+
// 2. INDEX for first contract byte is zero
181+
constrain((tag[i - 1] - 2) * (tag[i - 1] - 1) * index[i]);
182+
// 3. INDEX is incremented for all bytes
183+
constrain(tag[i - 1] * tag[i] *
184+
(index[i] - index[i - 1] - 1));
185+
// 5. In contract bytes each row decrement length_left
186+
constrain(tag[i] * (length_left[i - 1] - length_left[i] - 1));
187+
// 6. Length_left is zero for last byte in the contract
188+
constrain(tag[i - 1] * (tag[i] - 2) * (tag[i] - 1) *
189+
length_left[i - 1]);
190+
// 9. First is_opcode on BYTE after HEADER is 1
191+
constrain((tag[i] - 2) * (tag[i - 1] - 1) * tag[i] *
192+
(is_opcode[i] - 1));
193+
// 10. PUSH_SIZE decreases for non-opcodes except metadata
194+
constrain((tag[i] - 2) * tag[i] * (is_opcode[i] - 1) *
195+
(push_size[i - 1] - push_size[i] - 1));
196+
// 11. before opcode push_size is always zero
197+
constrain(is_opcode[i] * push_size[i - 1]);
198+
// 12. for all bytes hash is similar to previous
199+
constrain(tag[i] * (hash_hi[i - 1] - hash_hi[i]));
200+
// 13. for all bytes hash is similar to previous
201+
constrain(tag[i] * (hash_lo[i - 1] - hash_lo[i]));
202+
// 15. for all bytes RLC is correct
203+
constrain(tag[i] *
204+
(value_rlc[i] -
205+
value_rlc[i - 1] * rlc_challenge[i] - value[i]));
206+
// 16. for each BYTEs rlc_challenge are similar
207+
constrain(tag[i] * (rlc_challenge[i] - rlc_challenge[i - 1]));
169208
}
170-
if (i> 0 && i < max_bytecode_size-1) {
171-
constrain(tag[i+1] * (rlc_challenge[i] - rlc_challenge[i-1])); //17. rlc_challenge is similar for different contracts
209+
if (i > 0 && i < max_bytecode_size - 1) {
210+
// 17. rlc_challenge is similar for different contracts
211+
constrain(tag[i + 1] *
212+
(rlc_challenge[i] - rlc_challenge[i - 1]));
172213
}
173-
lookup(tag[i]*value[i]*(2-tag[i]),"byte_range_table/full");
174-
lookup(std::vector<TYPE>({value[i]*is_opcode[i], push_size[i]*is_opcode[i], is_opcode[i]}),"zkevm_opcodes/full");
175-
176-
if( i > 0 ){
177-
//is last
178-
lookup(std::vector<TYPE>({
179-
tag[i] + 1 - tag[i], // TODO: update math::expression constructor with constant parameter
180-
is_byte[i-1] * (1 - is_byte[i]) * value_rlc[i-1],
181-
is_byte[i-1] * (1 - is_byte[i]) * hash_hi[i-1] + (1 - is_byte[i-1] * (1 - is_byte[i])) * w_hi<FieldType>(zerohash),
182-
is_byte[i-1] * (1 - is_byte[i]) * hash_lo[i-1] + (1 - is_byte[i-1] * (1 - is_byte[i])) * w_lo<FieldType>(zerohash)
183-
}), "keccak_table");
214+
lookup(tag[i] * value[i] * (2 - tag[i]), "byte_range_table/full");
215+
lookup(std::vector<TYPE>({value[i] * is_opcode[i],
216+
push_size[i] * is_opcode[i],
217+
is_opcode[i]}),
218+
"zkevm_opcodes/full");
219+
220+
if (i > 0) {
221+
// Lookup for last byte
222+
lookup(
223+
std::vector<TYPE>(
224+
{// TODO: update math::expression constructor with
225+
// constant parameter
226+
tag[i] + 1 - tag[i],
227+
is_byte[i - 1] * (1 - is_byte[i]) * value_rlc[i - 1],
228+
is_byte[i - 1] * (1 - is_byte[i]) * hash_hi[i - 1] +
229+
(1 - is_byte[i - 1] * (1 - is_byte[i])) *
230+
w_hi<FieldType>(zerohash),
231+
is_byte[i - 1] * (1 - is_byte[i]) * hash_lo[i - 1] +
232+
(1 - is_byte[i - 1] * (1 - is_byte[i])) *
233+
w_lo<FieldType>(zerohash)}),
234+
"keccak_table");
184235
}
185236
}
186237
};
187238
};
188-
}
189-
}
190-
}
239+
} // namespace bbf
240+
} // namespace blueprint
241+
} // namespace nil

0 commit comments

Comments
 (0)