23 auto wires = circuit.
wires;
25 auto report_fail = [&](
const char* message,
size_t row_idx) {
26 info(message, row_idx);
61 auto get_sequential_micro_chunks = [&](
size_t gate_index,
WireIds starting_wire_index,
size_t chunk_count) {
62 std::vector<Fr> chunks;
63 for (
size_t i = starting_wire_index; i < starting_wire_index + chunk_count; i++) {
77 auto accumulate_limb_from_micro_chunks = [](
const std::vector<Fr>& chunks,
const int skipped_at_end = 1) {
78 Fr mini_accumulator(0);
79 auto end = chunks.end();
81 for (
auto it = end; it != chunks.begin();) {
85 return mini_accumulator;
88 auto check_binary_limbs_equality = [&](
const std::vector<Fr>& first,
const std::vector<Fr>& second,
size_t gate) {
89 for (
const auto [first_limb, second_limb] :
zip_view(first, second)) {
90 if (first_limb != second_limb) {
91 return report_fail(
"Binary limbs are not equal = ", gate);
97 auto check_accumulator_transfer = [&](
const std::vector<Fr>& previous_accumulator,
size_t gate) {
99 return report_fail(
"accumulator transfer should only be checked at odd gates = ", gate);
103 const std::vector next_gate_current_accumulator = {
104 circuit.
get_variable(accumulators_binary_limbs_0_wire[gate + 1]),
105 circuit.
get_variable(accumulators_binary_limbs_1_wire[gate + 1]),
106 circuit.
get_variable(accumulators_binary_limbs_2_wire[gate + 1]),
107 circuit.
get_variable(accumulators_binary_limbs_3_wire[gate + 1]),
109 if (!check_binary_limbs_equality(next_gate_current_accumulator, previous_accumulator, gate + 1)) {
114 for (
const auto& limb : previous_accumulator) {
116 return report_fail(
"accumulator doesn't start with 0 = ", gate + 1);
124 [&](
const std::vector<Fr>& current_accumulator,
const std::vector<Fr>& previous_accumulator,
size_t gate) {
125 if (!check_binary_limbs_equality(current_accumulator, previous_accumulator, gate)) {
128 return check_accumulator_transfer(previous_accumulator, gate + 1);
131 auto check_random_op_code = [&](
const Fr op_code,
size_t gate) {
133 if (op_code ==
Fr(0) || op_code ==
Fr(3) || op_code ==
Fr(4) || op_code ==
Fr(8)) {
134 return report_fail(
"Opcode should be random value at even gate = ", gate);
137 if (op_code ==
Fr(0)) {
138 return report_fail(
"Opcode should be 0 at odd gate = ", gate);
146 auto in_random_range = [&](
size_t i) {
151 for (
size_t i = 2; i < circuit.
num_gates - 1; i += 2) {
155 if (in_random_range(i)) {
156 check_random_op_code(op_code, i);
158 check_random_op_code(op_code_next, i + 1);
163 const std::vector current_accumulator_binary_limbs = {
164 circuit.
get_variable(accumulators_binary_limbs_0_wire[i]),
165 circuit.
get_variable(accumulators_binary_limbs_1_wire[i]),
166 circuit.
get_variable(accumulators_binary_limbs_2_wire[i]),
167 circuit.
get_variable(accumulators_binary_limbs_3_wire[i]),
171 const std::vector previous_accumulator_binary_limbs = {
172 circuit.
get_variable(accumulators_binary_limbs_0_wire[i + 1]),
173 circuit.
get_variable(accumulators_binary_limbs_1_wire[i + 1]),
174 circuit.
get_variable(accumulators_binary_limbs_2_wire[i + 1]),
175 circuit.
get_variable(accumulators_binary_limbs_3_wire[i + 1]),
179 if (!check_no_op(current_accumulator_binary_limbs, previous_accumulator_binary_limbs, i)) {
191 const std::vector p_x_binary_limbs = { p_x_0, p_x_1, p_x_2, p_x_3 };
200 const std::vector p_y_binary_limbs = { p_y_0, p_y_1, p_y_2, p_y_3 };
210 const std::vector z_1_binary_limbs = { z_1_lo, z_1_hi };
211 const std::vector z_2_binary_limbs = { z_2_lo, z_2_hi };
213 Fr low_wide_relation_limb = circuit.
get_variable(relation_wide_limbs_wire[i]);
214 Fr high_wide_relation_limb = circuit.
get_variable(relation_wide_limbs_wire[i + 1]);
217 const std::vector quotient_binary_limbs = {
221 circuit.
get_variable(quotient_high_binary_limbs[i + 1]),
227 auto p_x_micro_chunks = {
228 get_sequential_micro_chunks(i, WireIds::P_X_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
229 get_sequential_micro_chunks(i + 1, WireIds::P_X_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
230 get_sequential_micro_chunks(i, WireIds::P_X_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
231 get_sequential_micro_chunks(i + 1, WireIds::P_X_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS)
233 auto p_y_micro_chunks = {
234 get_sequential_micro_chunks(i, WireIds::P_Y_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
235 get_sequential_micro_chunks(i + 1, WireIds::P_Y_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
236 get_sequential_micro_chunks(i, WireIds::P_Y_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
237 get_sequential_micro_chunks(i + 1, WireIds::P_Y_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS)
239 auto z_1_micro_chunks = {
240 get_sequential_micro_chunks(i, WireIds::Z_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
241 get_sequential_micro_chunks(i, WireIds::Z_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
244 auto z_2_micro_chunks = {
246 get_sequential_micro_chunks(i + 1, WireIds::Z_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
247 get_sequential_micro_chunks(i + 1, WireIds::Z_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS)
250 auto current_accumulator_micro_chunks = {
251 get_sequential_micro_chunks(i, WireIds::ACCUMULATOR_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
252 get_sequential_micro_chunks(i + 1, WireIds::ACCUMULATOR_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
253 get_sequential_micro_chunks(i, WireIds::ACCUMULATOR_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
254 get_sequential_micro_chunks(i + 1, WireIds::ACCUMULATOR_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
256 auto quotient_micro_chunks = {
257 get_sequential_micro_chunks(i, WireIds::QUOTIENT_LOW_LIMBS_RANGE_CONSTRAIN_0, NUM_MICRO_LIMBS),
258 get_sequential_micro_chunks(i + 1, WireIds::QUOTIENT_LOW_LIMBS_RANGE_CONSTRAIN_0, NUM_MICRO_LIMBS),
259 get_sequential_micro_chunks(i, WireIds::QUOTIENT_HIGH_LIMBS_RANGE_CONSTRAIN_0, NUM_MICRO_LIMBS),
260 get_sequential_micro_chunks(i + 1, WireIds::QUOTIENT_HIGH_LIMBS_RANGE_CONSTRAIN_0, NUM_MICRO_LIMBS),
265 auto check_wide_limb_into_binary_limb_relation = [](
const std::vector<Fr>& wide_limbs,
266 const std::vector<Fr>& binary_limbs) {
267 BB_ASSERT_EQ(wide_limbs.size() * 2, binary_limbs.size());
268 for (
size_t i = 0; i < wide_limbs.size(); i++) {
269 if ((binary_limbs[i * 2] +
Fr(
Builder::SHIFT_1) * binary_limbs[i * 2 + 1]) != wide_limbs[i]) {
280 if (!(check_wide_limb_into_binary_limb_relation({ p_x_lo, p_x_hi }, p_x_binary_limbs) &&
281 check_wide_limb_into_binary_limb_relation({ p_y_lo, p_y_hi }, p_y_binary_limbs) &&
282 check_wide_limb_into_binary_limb_relation({ z_1 }, z_1_binary_limbs) &&
283 check_wide_limb_into_binary_limb_relation({ z_2 }, z_2_binary_limbs))) {
285 return report_fail(
"wide limb decomposition failied at row = ", i);
288 enum LimbSeriesType { STANDARD_COORDINATE, Z_SCALAR, QUOTIENT };
292 auto check_micro_limb_decomposition_correctness = [&accumulate_limb_from_micro_chunks](
293 const std::vector<Fr>& binary_limbs,
295 const LimbSeriesType limb_series_type) {
297 constexpr auto SHIFT_12_TO_14 =
Fr(4);
298 constexpr auto SHIFT_10_TO_14 =
Fr(16);
299 constexpr auto SHIFT_8_TO_14 =
Fr(64);
300 constexpr auto SHIFT_4_TO_14 =
Fr(1024);
304 for (
auto& micro_limb_series : micro_limbs) {
305 for (
auto& micro_limb : micro_limb_series) {
313 const size_t SKIPPED_FOR_LOW_LIMBS = 1;
314 for (
size_t i = 0; i < binary_limbs.size() - 1; i++) {
315 if (binary_limbs[i] != accumulate_limb_from_micro_chunks(micro_limbs[i], SKIPPED_FOR_LOW_LIMBS)) {
319 if (micro_limbs[i][NUM_MICRO_LIMBS - 1] != (SHIFT_12_TO_14 * micro_limbs[i][NUM_MICRO_LIMBS - 2])) {
324 const size_t SKIPPED_FOR_STANDARD = 2;
325 const size_t SKIPPED_FOR_Z_SCALARS = 1;
326 const size_t SKIPPED_FOR_QUOTIENT = 2;
327 switch (limb_series_type) {
328 case STANDARD_COORDINATE:
330 if (binary_limbs[binary_limbs.size() - 1] !=
331 accumulate_limb_from_micro_chunks(micro_limbs[binary_limbs.size() - 1], SKIPPED_FOR_STANDARD)) {
335 if (micro_limbs[binary_limbs.size() - 1][NUM_MICRO_LIMBS - SKIPPED_FOR_STANDARD] !=
337 micro_limbs[binary_limbs.size() - 1][NUM_MICRO_LIMBS - SKIPPED_FOR_STANDARD - 1])) {
344 if (binary_limbs[binary_limbs.size() - 1] !=
345 accumulate_limb_from_micro_chunks(micro_limbs[binary_limbs.size() - 1], SKIPPED_FOR_Z_SCALARS)) {
349 if (micro_limbs[binary_limbs.size() - 1][NUM_MICRO_LIMBS - SKIPPED_FOR_Z_SCALARS] !=
351 micro_limbs[binary_limbs.size() - 1][NUM_MICRO_LIMBS - SKIPPED_FOR_Z_SCALARS - 1])) {
357 if (binary_limbs[binary_limbs.size() - 1] !=
358 accumulate_limb_from_micro_chunks(micro_limbs[binary_limbs.size() - 1], SKIPPED_FOR_QUOTIENT)) {
362 if (micro_limbs[binary_limbs.size() - 1][NUM_MICRO_LIMBS - SKIPPED_FOR_QUOTIENT] !=
364 micro_limbs[binary_limbs.size() - 1][NUM_MICRO_LIMBS - SKIPPED_FOR_QUOTIENT - 1])) {
375 if (!check_micro_limb_decomposition_correctness(p_x_binary_limbs, p_x_micro_chunks, STANDARD_COORDINATE)) {
378 if (!check_micro_limb_decomposition_correctness(p_y_binary_limbs, p_y_micro_chunks, STANDARD_COORDINATE)) {
381 if (!check_micro_limb_decomposition_correctness(z_1_binary_limbs, z_1_micro_chunks, Z_SCALAR)) {
384 if (!check_micro_limb_decomposition_correctness(z_2_binary_limbs, z_2_micro_chunks, Z_SCALAR)) {
387 if (!check_micro_limb_decomposition_correctness(
388 current_accumulator_binary_limbs, current_accumulator_micro_chunks, STANDARD_COORDINATE)) {
391 if (!check_micro_limb_decomposition_correctness(quotient_binary_limbs, quotient_micro_chunks, QUOTIENT)) {
436 Fr low_wide_limb_relation_check =
438 (previous_accumulator_binary_limbs[0] * relation_inputs.
x_limbs[0] + op_code +
441 quotient_binary_limbs[0] * NEGATIVE_MODULUS_LIMBS[0] - current_accumulator_binary_limbs[0]) +
442 (previous_accumulator_binary_limbs[1] * relation_inputs.
x_limbs[0] + relation_inputs.
v_limbs[1] * p_x_0 +
444 relation_inputs.
v_quarted_limbs[1] * z_2_lo + quotient_binary_limbs[1] * NEGATIVE_MODULUS_LIMBS[0] +
445 previous_accumulator_binary_limbs[0] * relation_inputs.
x_limbs[1] + relation_inputs.
v_limbs[0] * p_x_1 +
447 relation_inputs.
v_quarted_limbs[0] * z_2_hi + quotient_binary_limbs[0] * NEGATIVE_MODULUS_LIMBS[1] -
448 current_accumulator_binary_limbs[1]) *
450 if (low_wide_limb_relation_check != (low_wide_relation_limb * SHIFT_2)) {
453 Fr high_wide_relation_limb_check =
454 low_wide_relation_limb + previous_accumulator_binary_limbs[2] * relation_inputs.
x_limbs[0] +
455 previous_accumulator_binary_limbs[1] * relation_inputs.
x_limbs[1] +
456 previous_accumulator_binary_limbs[0] * relation_inputs.
x_limbs[2] + relation_inputs.
v_limbs[2] * p_x_0 +
457 relation_inputs.
v_limbs[1] * p_x_1 + relation_inputs.
v_limbs[0] * p_x_2 +
461 relation_inputs.
v_quarted_limbs[1] * z_2_hi + quotient_binary_limbs[2] * NEGATIVE_MODULUS_LIMBS[0] +
462 quotient_binary_limbs[1] * NEGATIVE_MODULUS_LIMBS[1] +
463 quotient_binary_limbs[0] * NEGATIVE_MODULUS_LIMBS[2] - current_accumulator_binary_limbs[2] +
464 (previous_accumulator_binary_limbs[3] * relation_inputs.
x_limbs[0] +
465 previous_accumulator_binary_limbs[2] * relation_inputs.
x_limbs[1] +
466 previous_accumulator_binary_limbs[1] * relation_inputs.
x_limbs[2] +
467 previous_accumulator_binary_limbs[0] * relation_inputs.
x_limbs[3] + relation_inputs.
v_limbs[3] * p_x_0 +
468 relation_inputs.
v_limbs[2] * p_x_1 + relation_inputs.
v_limbs[1] * p_x_2 +
473 relation_inputs.
v_quarted_limbs[2] * z_2_hi + quotient_binary_limbs[3] * NEGATIVE_MODULUS_LIMBS[0] +
474 quotient_binary_limbs[2] * NEGATIVE_MODULUS_LIMBS[1] +
475 quotient_binary_limbs[1] * NEGATIVE_MODULUS_LIMBS[2] +
476 quotient_binary_limbs[0] * NEGATIVE_MODULUS_LIMBS[3] - current_accumulator_binary_limbs[3]) *
478 if (high_wide_relation_limb_check != (high_wide_relation_limb * SHIFT_2)) {
484 auto reconstructed_p_x = (p_x_0 + p_x_1 * SHIFT_1 + p_x_2 * SHIFT_2 + p_x_3 * SHIFT_3);
485 auto reconstructed_p_y = (p_y_0 + p_y_1 * SHIFT_1 + p_y_2 * SHIFT_2 + p_y_3 * SHIFT_3);
486 auto reconstructed_current_accumulator =
487 (current_accumulator_binary_limbs[0] + current_accumulator_binary_limbs[1] * SHIFT_1 +
488 current_accumulator_binary_limbs[2] * SHIFT_2 + current_accumulator_binary_limbs[3] * SHIFT_3);
489 auto reconstructed_previous_accumulator =
490 (previous_accumulator_binary_limbs[0] + previous_accumulator_binary_limbs[1] * SHIFT_1 +
491 previous_accumulator_binary_limbs[2] * SHIFT_2 + previous_accumulator_binary_limbs[3] * SHIFT_3);
493 auto reconstructed_z1 = (z_1_lo + z_1_hi * SHIFT_1);
494 auto reconstructed_z2 = (z_2_lo + z_2_hi * SHIFT_1);
495 auto reconstructed_quotient = (quotient_binary_limbs[0] + quotient_binary_limbs[1] * SHIFT_1 +
496 quotient_binary_limbs[2] * SHIFT_2 + quotient_binary_limbs[3] * SHIFT_3);
499 if (!(reconstructed_previous_accumulator * reconstructed_evaluation_input_x + op_code +
500 reconstructed_p_x * reconstructed_batching_evaluation_v +
501 reconstructed_p_y * reconstructed_batching_evaluation_v2 +
502 reconstructed_z1 * reconstructed_batching_evaluation_v3 +
503 reconstructed_z2 * reconstructed_batching_evaluation_v4 +
504 reconstructed_quotient * NEGATIVE_MODULUS_LIMBS[4] - reconstructed_current_accumulator)
509 if (!check_accumulator_transfer(previous_accumulator_binary_limbs, i + 1)) {