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;
91 for (
size_t i = 2; i < circuit.
num_gates - 1; i += 2) {
101 const std::vector p_x_binary_limbs = { p_x_0, p_x_1, p_x_2, p_x_3 };
110 const std::vector p_y_binary_limbs = { p_y_0, p_y_1, p_y_2, p_y_3 };
120 const std::vector z_1_binary_limbs = { z_1_lo, z_1_hi };
121 const std::vector z_2_binary_limbs = { z_2_lo, z_2_hi };
123 Fr low_wide_relation_limb = circuit.
get_variable(relation_wide_limbs_wire[i]);
124 Fr high_wide_relation_limb = circuit.
get_variable(relation_wide_limbs_wire[i + 1]);
127 const std::vector current_accumulator_binary_limbs = {
128 circuit.
get_variable(accumulators_binary_limbs_0_wire[i]),
129 circuit.
get_variable(accumulators_binary_limbs_1_wire[i]),
130 circuit.
get_variable(accumulators_binary_limbs_2_wire[i]),
131 circuit.
get_variable(accumulators_binary_limbs_3_wire[i]),
135 const std::vector previous_accumulator_binary_limbs = {
136 circuit.
get_variable(accumulators_binary_limbs_0_wire[i + 1]),
137 circuit.
get_variable(accumulators_binary_limbs_1_wire[i + 1]),
138 circuit.
get_variable(accumulators_binary_limbs_2_wire[i + 1]),
139 circuit.
get_variable(accumulators_binary_limbs_3_wire[i + 1]),
143 const std::vector quotient_binary_limbs = {
147 circuit.
get_variable(quotient_high_binary_limbs[i + 1]),
153 auto p_x_micro_chunks = {
154 get_sequential_micro_chunks(i, WireIds::P_X_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
155 get_sequential_micro_chunks(i + 1, WireIds::P_X_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
156 get_sequential_micro_chunks(i, WireIds::P_X_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
157 get_sequential_micro_chunks(i + 1, WireIds::P_X_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS)
159 auto p_y_micro_chunks = {
160 get_sequential_micro_chunks(i, WireIds::P_Y_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
161 get_sequential_micro_chunks(i + 1, WireIds::P_Y_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
162 get_sequential_micro_chunks(i, WireIds::P_Y_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
163 get_sequential_micro_chunks(i + 1, WireIds::P_Y_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS)
165 auto z_1_micro_chunks = {
166 get_sequential_micro_chunks(i, WireIds::Z_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
167 get_sequential_micro_chunks(i, WireIds::Z_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
170 auto z_2_micro_chunks = {
172 get_sequential_micro_chunks(i + 1, WireIds::Z_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
173 get_sequential_micro_chunks(i + 1, WireIds::Z_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS)
176 auto current_accumulator_micro_chunks = {
177 get_sequential_micro_chunks(i, WireIds::ACCUMULATOR_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
178 get_sequential_micro_chunks(i + 1, WireIds::ACCUMULATOR_LOW_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
179 get_sequential_micro_chunks(i, WireIds::ACCUMULATOR_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
180 get_sequential_micro_chunks(i + 1, WireIds::ACCUMULATOR_HIGH_LIMBS_RANGE_CONSTRAINT_0, NUM_MICRO_LIMBS),
182 auto quotient_micro_chunks = {
183 get_sequential_micro_chunks(i, WireIds::QUOTIENT_LOW_LIMBS_RANGE_CONSTRAIN_0, NUM_MICRO_LIMBS),
184 get_sequential_micro_chunks(i + 1, WireIds::QUOTIENT_LOW_LIMBS_RANGE_CONSTRAIN_0, NUM_MICRO_LIMBS),
185 get_sequential_micro_chunks(i, WireIds::QUOTIENT_HIGH_LIMBS_RANGE_CONSTRAIN_0, NUM_MICRO_LIMBS),
186 get_sequential_micro_chunks(i + 1, WireIds::QUOTIENT_HIGH_LIMBS_RANGE_CONSTRAIN_0, NUM_MICRO_LIMBS),
191 auto check_wide_limb_into_binary_limb_relation = [](
const std::vector<Fr>& wide_limbs,
192 const std::vector<Fr>& binary_limbs) {
193 BB_ASSERT_EQ(wide_limbs.size() * 2, binary_limbs.size());
194 for (
size_t i = 0; i < wide_limbs.size(); i++) {
195 if ((binary_limbs[i * 2] +
Fr(
Builder::SHIFT_1) * binary_limbs[i * 2 + 1]) != wide_limbs[i]) {
206 if (!(check_wide_limb_into_binary_limb_relation({ p_x_lo, p_x_hi }, p_x_binary_limbs) &&
207 check_wide_limb_into_binary_limb_relation({ p_y_lo, p_y_hi }, p_y_binary_limbs) &&
208 check_wide_limb_into_binary_limb_relation({ z_1 }, z_1_binary_limbs) &&
209 check_wide_limb_into_binary_limb_relation({ z_2 }, z_2_binary_limbs))) {
211 return report_fail(
"wide limb decomposition failied at row = ", i);
214 enum LimbSeriesType { STANDARD_COORDINATE, Z_SCALAR, QUOTIENT };
218 auto check_micro_limb_decomposition_correctness = [&accumulate_limb_from_micro_chunks](
219 const std::vector<Fr>& binary_limbs,
221 const LimbSeriesType limb_series_type) {
223 constexpr auto SHIFT_12_TO_14 =
Fr(4);
224 constexpr auto SHIFT_10_TO_14 =
Fr(16);
225 constexpr auto SHIFT_8_TO_14 =
Fr(64);
226 constexpr auto SHIFT_4_TO_14 =
Fr(1024);
230 for (
auto& micro_limb_series : micro_limbs) {
231 for (
auto& micro_limb : micro_limb_series) {
239 const size_t SKIPPED_FOR_LOW_LIMBS = 1;
240 for (
size_t i = 0; i < binary_limbs.size() - 1; i++) {
241 if (binary_limbs[i] != accumulate_limb_from_micro_chunks(micro_limbs[i], SKIPPED_FOR_LOW_LIMBS)) {
245 if (micro_limbs[i][NUM_MICRO_LIMBS - 1] != (SHIFT_12_TO_14 * micro_limbs[i][NUM_MICRO_LIMBS - 2])) {
250 const size_t SKIPPED_FOR_STANDARD = 2;
251 const size_t SKIPPED_FOR_Z_SCALARS = 1;
252 const size_t SKIPPED_FOR_QUOTIENT = 2;
253 switch (limb_series_type) {
254 case STANDARD_COORDINATE:
256 if (binary_limbs[binary_limbs.size() - 1] !=
257 accumulate_limb_from_micro_chunks(micro_limbs[binary_limbs.size() - 1], SKIPPED_FOR_STANDARD)) {
261 if (micro_limbs[binary_limbs.size() - 1][NUM_MICRO_LIMBS - SKIPPED_FOR_STANDARD] !=
263 micro_limbs[binary_limbs.size() - 1][NUM_MICRO_LIMBS - SKIPPED_FOR_STANDARD - 1])) {
270 if (binary_limbs[binary_limbs.size() - 1] !=
271 accumulate_limb_from_micro_chunks(micro_limbs[binary_limbs.size() - 1],
272 SKIPPED_FOR_Z_SCALARS)) {
276 if (micro_limbs[binary_limbs.size() - 1][NUM_MICRO_LIMBS - SKIPPED_FOR_Z_SCALARS] !=
278 micro_limbs[binary_limbs.size() - 1][NUM_MICRO_LIMBS - SKIPPED_FOR_Z_SCALARS - 1])) {
284 if (binary_limbs[binary_limbs.size() - 1] !=
285 accumulate_limb_from_micro_chunks(micro_limbs[binary_limbs.size() - 1], SKIPPED_FOR_QUOTIENT)) {
289 if (micro_limbs[binary_limbs.size() - 1][NUM_MICRO_LIMBS - SKIPPED_FOR_QUOTIENT] !=
291 micro_limbs[binary_limbs.size() - 1][NUM_MICRO_LIMBS - SKIPPED_FOR_QUOTIENT - 1])) {
302 if (!check_micro_limb_decomposition_correctness(p_x_binary_limbs, p_x_micro_chunks, STANDARD_COORDINATE)) {
305 if (!check_micro_limb_decomposition_correctness(p_y_binary_limbs, p_y_micro_chunks, STANDARD_COORDINATE)) {
308 if (!check_micro_limb_decomposition_correctness(z_1_binary_limbs, z_1_micro_chunks, Z_SCALAR)) {
311 if (!check_micro_limb_decomposition_correctness(z_2_binary_limbs, z_2_micro_chunks, Z_SCALAR)) {
314 if (!check_micro_limb_decomposition_correctness(
315 current_accumulator_binary_limbs, current_accumulator_micro_chunks, STANDARD_COORDINATE)) {
318 if (!check_micro_limb_decomposition_correctness(quotient_binary_limbs, quotient_micro_chunks, QUOTIENT)) {
363 Fr low_wide_limb_relation_check =
365 (previous_accumulator_binary_limbs[0] * relation_inputs.
x_limbs[0] + op_code +
368 quotient_binary_limbs[0] * NEGATIVE_MODULUS_LIMBS[0] - current_accumulator_binary_limbs[0]) +
369 (previous_accumulator_binary_limbs[1] * relation_inputs.
x_limbs[0] +
372 quotient_binary_limbs[1] * NEGATIVE_MODULUS_LIMBS[0] +
373 previous_accumulator_binary_limbs[0] * relation_inputs.
x_limbs[1] +
376 quotient_binary_limbs[0] * NEGATIVE_MODULUS_LIMBS[1] - current_accumulator_binary_limbs[1]) *
378 if (low_wide_limb_relation_check != (low_wide_relation_limb * SHIFT_2)) {
381 Fr high_wide_relation_limb_check =
382 low_wide_relation_limb + previous_accumulator_binary_limbs[2] * relation_inputs.
x_limbs[0] +
383 previous_accumulator_binary_limbs[1] * relation_inputs.
x_limbs[1] +
384 previous_accumulator_binary_limbs[0] * relation_inputs.
x_limbs[2] + relation_inputs.
v_limbs[2] * p_x_0 +
385 relation_inputs.
v_limbs[1] * p_x_1 + relation_inputs.
v_limbs[0] * p_x_2 +
389 relation_inputs.
v_quarted_limbs[1] * z_2_hi + quotient_binary_limbs[2] * NEGATIVE_MODULUS_LIMBS[0] +
390 quotient_binary_limbs[1] * NEGATIVE_MODULUS_LIMBS[1] +
391 quotient_binary_limbs[0] * NEGATIVE_MODULUS_LIMBS[2] - current_accumulator_binary_limbs[2] +
392 (previous_accumulator_binary_limbs[3] * relation_inputs.
x_limbs[0] +
393 previous_accumulator_binary_limbs[2] * relation_inputs.
x_limbs[1] +
394 previous_accumulator_binary_limbs[1] * relation_inputs.
x_limbs[2] +
395 previous_accumulator_binary_limbs[0] * relation_inputs.
x_limbs[3] +
396 relation_inputs.
v_limbs[3] * p_x_0 + relation_inputs.
v_limbs[2] * p_x_1 +
397 relation_inputs.
v_limbs[1] * p_x_2 + relation_inputs.
v_limbs[0] * p_x_3 +
402 quotient_binary_limbs[3] * NEGATIVE_MODULUS_LIMBS[0] +
403 quotient_binary_limbs[2] * NEGATIVE_MODULUS_LIMBS[1] +
404 quotient_binary_limbs[1] * NEGATIVE_MODULUS_LIMBS[2] +
405 quotient_binary_limbs[0] * NEGATIVE_MODULUS_LIMBS[3] - current_accumulator_binary_limbs[3]) *
407 if (high_wide_relation_limb_check != (high_wide_relation_limb * SHIFT_2)) {
413 auto reconstructed_p_x = (p_x_0 + p_x_1 * SHIFT_1 + p_x_2 * SHIFT_2 + p_x_3 * SHIFT_3);
414 auto reconstructed_p_y = (p_y_0 + p_y_1 * SHIFT_1 + p_y_2 * SHIFT_2 + p_y_3 * SHIFT_3);
415 auto reconstructed_current_accumulator =
416 (current_accumulator_binary_limbs[0] + current_accumulator_binary_limbs[1] * SHIFT_1 +
417 current_accumulator_binary_limbs[2] * SHIFT_2 + current_accumulator_binary_limbs[3] * SHIFT_3);
418 auto reconstructed_previous_accumulator =
419 (previous_accumulator_binary_limbs[0] + previous_accumulator_binary_limbs[1] * SHIFT_1 +
420 previous_accumulator_binary_limbs[2] * SHIFT_2 + previous_accumulator_binary_limbs[3] * SHIFT_3);
422 auto reconstructed_z1 = (z_1_lo + z_1_hi * SHIFT_1);
423 auto reconstructed_z2 = (z_2_lo + z_2_hi * SHIFT_1);
424 auto reconstructed_quotient = (quotient_binary_limbs[0] + quotient_binary_limbs[1] * SHIFT_1 +
425 quotient_binary_limbs[2] * SHIFT_2 + quotient_binary_limbs[3] * SHIFT_3);
428 if (!(reconstructed_previous_accumulator * reconstructed_evaluation_input_x + op_code +
429 reconstructed_p_x * reconstructed_batching_evaluation_v +
430 reconstructed_p_y * reconstructed_batching_evaluation_v2 +
431 reconstructed_z1 * reconstructed_batching_evaluation_v3 +
432 reconstructed_z2 * reconstructed_batching_evaluation_v4 +
433 reconstructed_quotient * NEGATIVE_MODULUS_LIMBS[4] - reconstructed_current_accumulator)
439 size_t odd_gate_index = i + 1;
441 const std::vector current_accumulator_binary_limbs_copy = {
442 circuit.
get_variable(accumulators_binary_limbs_0_wire[odd_gate_index]),
443 circuit.
get_variable(accumulators_binary_limbs_1_wire[odd_gate_index]),
444 circuit.
get_variable(accumulators_binary_limbs_2_wire[odd_gate_index]),
445 circuit.
get_variable(accumulators_binary_limbs_3_wire[odd_gate_index]),
447 if (odd_gate_index < circuit.
num_gates - 1) {
448 size_t next_even_gate_index = i + 2;
449 const std::vector current_accumulator_binary_limbs = {
450 circuit.
get_variable(accumulators_binary_limbs_0_wire[next_even_gate_index]),
451 circuit.
get_variable(accumulators_binary_limbs_1_wire[next_even_gate_index]),
452 circuit.
get_variable(accumulators_binary_limbs_2_wire[next_even_gate_index]),
453 circuit.
get_variable(accumulators_binary_limbs_3_wire[next_even_gate_index]),
456 for (
size_t j = 0; j < current_accumulator_binary_limbs.size(); j++) {
457 if (current_accumulator_binary_limbs_copy[j] != current_accumulator_binary_limbs[j]) {
458 return report_fail(
"accumulator copy failed at row = ", odd_gate_index);
463 for (
const auto& limb : current_accumulator_binary_limbs_copy) {
465 return report_fail(
"accumulator doesn't start with 0 = ", odd_gate_index);