Skip to content

Commit 6df7022

Browse files
committed
bytecode relative constraint
1 parent fe3fb47 commit 6df7022

File tree

1 file changed

+97
-77
lines changed
  • crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf

1 file changed

+97
-77
lines changed

crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/bytecode.hpp

Lines changed: 97 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -160,97 +160,117 @@ namespace nil {
160160
}
161161

162162
static const auto zerohash = zkevm_keccak_hash({});
163-
for (std::size_t i = 0; i < max_bytecode_size; i++) {
163+
if constexpr (stage == GenerationStage::CONSTRAINTS) {
164+
std::vector<TYPE> every;
165+
std::vector<TYPE> non_first;
166+
std::vector<TYPE> bytes;
167+
168+
// Every constraints
164169
// 0. TAG is zeroes, one or two
165-
constrain(tag[i] * (tag[i] - 1) * (tag[i] - 2));
170+
every.push_back(context_object.relativize(
171+
tag[0] * (tag[0] - 1) * (tag[0] - 2), -1));
166172
// 1. INDEX for HEADER and unused bytes is zero
167-
constrain((tag[i] - 2) * (tag[i] - 1) * index[i]);
173+
every.push_back(context_object.relativize(
174+
(tag[0] - 2) * (tag[0] - 1) * index[0], -1));
168175
// 4. In contract header length_left == contract length
169-
constrain((tag[i] - 2) * (tag[i] - 1) *
170-
(length_left[i] - value[i]));
176+
every.push_back(context_object.relativize(
177+
(tag[0] - 2) * (tag[0] - 1) * (length_left[0] - value[0]),
178+
-1));
171179
// 7. is_opcode is zeroes or ones
172-
constrain(is_opcode[i] * (is_opcode[i] - 1));
180+
every.push_back(context_object.relativize(
181+
is_opcode[0] * (is_opcode[0] - 1), -1));
173182
// 8. is_opcode on HEADER are zeroes
174-
constrain((tag[i] - 2) * (tag[i] - 1) * is_opcode[i]);
183+
every.push_back(context_object.relativize(
184+
(tag[0] - 2) * (tag[0] - 1) * is_opcode[0], -1));
175185
// 14. value_rlc for HEADERS == length_left
176-
constrain((tag[i] - 2) * (tag[i] - 1) *
177-
(value_rlc[i] - length_left[i]));
186+
every.push_back(context_object.relativize(
187+
(tag[0] - 2) * (tag[0] - 1) * (value_rlc[0] - length_left[0]),
188+
-1));
178189

179-
if (i > 0) {
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]));
208-
}
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]));
213-
}
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");
190+
// Non-first row constraints
191+
// 2. INDEX for first contract byte is zero
192+
non_first.push_back(context_object.relativize(
193+
(tag[0] - 2) * (tag[0] - 1) * index[1], -1));
194+
// 3. INDEX is incremented for all bytes
195+
non_first.push_back(context_object.relativize(
196+
tag[0] * tag[1] * (index[1] - index[0] - 1), -1));
197+
// 5. In contract bytes each row decrement length_left
198+
non_first.push_back(context_object.relativize(
199+
tag[1] * (length_left[0] - length_left[1] - 1), -1));
200+
// 6. Length_left is zero for last byte in the contract
201+
non_first.push_back(context_object.relativize(
202+
tag[0] * (tag[1] - 2) * (tag[1] - 1) * length_left[0], -1));
203+
// 9. First is_opcode on BYTE after HEADER is 1
204+
non_first.push_back(context_object.relativize(
205+
(tag[1] - 2) * (tag[0] - 1) * tag[1] * (is_opcode[1] - 1),
206+
-1));
207+
// 10. PUSH_SIZE decreases for non-opcodes except metadata
208+
non_first.push_back(context_object.relativize(
209+
(tag[1] - 2) * tag[1] * (is_opcode[1] - 1) *
210+
(push_size[0] - push_size[1] - 1),
211+
-1));
212+
// 11. before opcode push_size is always zero
213+
non_first.push_back(
214+
context_object.relativize(is_opcode[1] * push_size[0], -1));
215+
// 12. for all bytes hash is similar to previous
216+
non_first.push_back(context_object.relativize(
217+
tag[1] * (hash_hi[0] - hash_hi[1]), -1));
218+
// 13. for all bytes hash is similar to previous
219+
non_first.push_back(context_object.relativize(
220+
tag[1] * (hash_lo[0] - hash_lo[1]), -1));
221+
// 15. for all bytes RLC is correct
222+
non_first.push_back(context_object.relativize(
223+
tag[1] * (value_rlc[1] - value_rlc[0] * rlc_challenge[1] -
224+
value[1]),
225+
-1));
226+
// 16. for each BYTEs rlc_challenge are similar
227+
non_first.push_back(context_object.relativize(
228+
tag[1] * (rlc_challenge[1] - rlc_challenge[0]), -1));
229+
230+
// Bytes constraint
231+
// 17. rlc_challenge is similar for different contracts
232+
bytes.push_back(context_object.relativize(
233+
tag[2] * (rlc_challenge[1] - rlc_challenge[0]), -1));
219234

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");
235+
// Apply constraints
236+
for (std::size_t i = 0; i < every.size(); i++) {
237+
context_object.relative_constrain(every[i], 0,
238+
max_bytecode_size - 1);
235239
}
236240
for (std::size_t i = 0; i < non_first.size(); i++) {
237-
context_object.relative_constrain(non_first[i], 1, max_bytecode_size - 1);
241+
context_object.relative_constrain(non_first[i], 1,
242+
max_bytecode_size - 1);
238243
}
239244
for (std::size_t i = 0; i < bytes.size(); i++) {
240-
context_object.relative_constrain(bytes[i], 1, max_bytecode_size - 2);
245+
context_object.relative_constrain(bytes[i], 1,
246+
max_bytecode_size - 2);
241247
}
242248

243-
std::vector<TYPE> tmp = {context_object.relativize(tag[0] * value[0], -1)};
244-
context_object.relative_lookup(tmp, "byte_range_table/full", 0, max_bytecode_size - 1);
245-
tmp = {context_object.relativize(std::vector<TYPE>({value[0] * is_opcode[0],
246-
push_size[0] * is_opcode[0],
247-
is_opcode[0]}), -1)};
248-
context_object.relative_lookup(tmp, "zkevm_opcodes/full", 0, max_bytecode_size - 1);
249-
tmp = {context_object.relativize(std::vector<TYPE>({tag[1] + 1 - tag[1], //TODO: update math::expression constructor with constant parameter
250-
tag[0] * (1 - tag[1]) * value_rlc[0],
251-
tag[0] * (1 - tag[1]) * hash_hi[0] + (1 - tag[0] * (1 - tag[1])) * w_hi<FieldType>(zerohash),
252-
tag[0] * (1 - tag[1]) * hash_lo[0] + (1 - tag[0] * (1 - tag[1])) * w_lo<FieldType>(zerohash)}), -1)};
253-
context_object.relative_lookup(tmp, "keccak_table", 1, max_bytecode_size - 1);
249+
// Lookups
250+
std::vector<TYPE> tmp = {context_object.relativize(
251+
tag[0] * value[0] * (2 - tag[0]), -1)};
252+
context_object.relative_lookup(tmp, "byte_range_table/full", 0,
253+
max_bytecode_size - 1);
254+
tmp = {context_object.relativize(
255+
std::vector<TYPE>({value[0] * is_opcode[0],
256+
push_size[0] * is_opcode[0],
257+
is_opcode[0]}),
258+
-1)};
259+
context_object.relative_lookup(tmp, "zkevm_opcodes/full", 0,
260+
max_bytecode_size - 1);
261+
tmp = {context_object.relativize(
262+
std::vector<TYPE>(
263+
{tag[1] + 1 - tag[1],
264+
is_byte[0] * (1 - is_byte[1]) * value_rlc[0],
265+
is_byte[0] * (1 - is_byte[1]) * hash_hi[0] +
266+
(1 - is_byte[0] * (1 - is_byte[1])) *
267+
w_hi<FieldType>(zerohash),
268+
is_byte[0] * (1 - is_byte[1]) * hash_lo[0] +
269+
(1 - is_byte[0] * (1 - is_byte[1])) *
270+
w_lo<FieldType>(zerohash)}),
271+
-1)};
272+
context_object.relative_lookup(tmp, "keccak_table", 1,
273+
max_bytecode_size - 1);
254274
}
255275
};
256276
};

0 commit comments

Comments
 (0)