17 const int BATCHED_RELATION_PARTIAL_LENGTH = 8;
18 const int NUMBER_OF_SUBRELATIONS = 28;
19 const int NUMBER_OF_ALPHAS = NUMBER_OF_SUBRELATIONS - 1;
20 const int START_POINTER = 0x1000;
21 const int SCRATCH_SPACE_POINTER = 0x100;
22 const int BARYCENTRIC_DOMAIN_SIZE = 8;
24 std::ostringstream out;
27 auto print_header_centered = [&](
const std::string& text) {
28 const std::string top =
"/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/";
29 const std::string bottom =
"/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/";
30 size_t width =
static_cast<size_t>(top.length()) - 4;
31 std::string centered =
32 "/*" + std::string(
static_cast<size_t>((width - text.length()) / 2),
' ') + text +
33 std::string(
static_cast<size_t>(width - text.length() - (width - text.length()) / 2),
' ') +
"*/";
34 out <<
"\n" << top <<
"\n" << centered <<
"\n" << bottom <<
"\n";
37 auto print_loc = [&](
int pointer,
const std::string& name) {
38 out <<
"uint256 internal constant " << name <<
" = " <<
std::showbase <<
std::hex << pointer <<
";\n";
41 auto print_fr = print_loc;
43 auto print_g1 = [&](
int pointer,
const std::string& name) {
44 print_loc(pointer, name +
"_X_LOC");
45 print_loc(pointer + 32, name +
"_Y_LOC");
49 const std::vector<std::string> vk_fr = {
"VK_CIRCUIT_SIZE_LOC",
50 "VK_NUM_PUBLIC_INPUTS_LOC",
51 "VK_PUB_INPUTS_OFFSET_LOC" };
53 const std::vector<std::string> vk_g1 = {
"Q_M",
65 "Q_POSEIDON_2_EXTERNAL",
66 "Q_POSEIDON_2_INTERNAL",
82 const std::vector<std::string> proof_fr = {
"PROOF_CIRCUIT_SIZE",
83 "PROOF_NUM_PUBLIC_INPUTS",
84 "PROOF_PUB_INPUTS_OFFSET" };
86 const std::vector<std::string> pairing_points = {
"PAIRING_POINT_0",
"PAIRING_POINT_1",
"PAIRING_POINT_2",
87 "PAIRING_POINT_3",
"PAIRING_POINT_4",
"PAIRING_POINT_5",
88 "PAIRING_POINT_6",
"PAIRING_POINT_7",
"PAIRING_POINT_8",
89 "PAIRING_POINT_9",
"PAIRING_POINT_10",
"PAIRING_POINT_11",
90 "PAIRING_POINT_12",
"PAIRING_POINT_13",
"PAIRING_POINT_14",
93 const std::vector<std::string> proof_g1 = {
94 "W_L",
"W_R",
"W_O",
"LOOKUP_READ_COUNTS",
"LOOKUP_READ_TAGS",
"W_4",
"LOOKUP_INVERSES",
"Z_PERM"
97 const std::vector<std::string> entities = {
"QM",
109 "QPOSEIDON2_EXTERNAL",
110 "QPOSEIDON2_INTERNAL",
131 "LOOKUP_READ_COUNTS",
139 const std::vector<std::string> challenges = {
"ETA",
148 "PUBLIC_INPUTS_DELTA_NUMERATOR",
149 "PUBLIC_INPUTS_DELTA_DENOMINATOR" };
151 const std::vector<std::string> subrelation_intermediates = {
"AUX_NON_NATIVE_FIELD_IDENTITY",
152 "AUX_LIMB_ACCUMULATOR_IDENTITY",
153 "AUX_RAM_CONSISTENCY_CHECK_IDENTITY",
154 "AUX_ROM_CONSISTENCY_CHECK_IDENTITY",
155 "AUX_MEMORY_CHECK_IDENTITY" };
157 const std::vector<std::string> general_intermediates = {
"FINAL_ROUND_TARGET_LOC",
"POW_PARTIAL_EVALUATION_LOC" };
159 int pointer = START_POINTER;
162 print_header_centered(
"VK INDICIES");
163 for (
const auto& item : vk_fr) {
164 print_fr(pointer, item);
167 for (
const auto& item : vk_g1) {
168 print_g1(pointer, item);
173 print_header_centered(
"PROOF INDICIES");
174 for (
const auto& item : pairing_points) {
175 print_fr(pointer, item);
178 for (
const auto& item : proof_g1) {
179 print_g1(pointer, item);
184 print_header_centered(
"PROOF INDICIES - SUMCHECK UNIVARIATES");
185 for (
int size = 0; size < log_n; ++size) {
186 for (
int relation_len = 0; relation_len < BATCHED_RELATION_PARTIAL_LENGTH; ++relation_len) {
189 print_fr(pointer, name);
195 print_header_centered(
"PROOF INDICIES - SUMCHECK EVALUATIONS");
196 for (
const auto& entity : entities) {
197 print_fr(pointer, entity +
"_EVAL_LOC");
202 print_header_centered(
"PROOF INDICIES - GEMINI FOLDING COMMS");
203 for (
int size = 0; size < log_n - 1; ++size) {
204 print_g1(pointer,
"GEMINI_FOLD_UNIVARIATE_" +
std::to_string(size));
209 print_header_centered(
"PROOF INDICIES - GEMINI FOLDING EVALUATIONS");
210 for (
int size = 0; size < log_n; ++size) {
214 print_g1(pointer,
"SHPLONK_Q");
216 print_g1(pointer,
"KZG_QUOTIENT");
219 print_header_centered(
"PROOF INDICIES - COMPLETE");
222 print_header_centered(
"CHALLENGES");
223 for (
const auto& chall : challenges) {
224 print_fr(pointer, chall +
"_CHALLENGE");
227 for (
int alpha = 0; alpha < NUMBER_OF_ALPHAS; ++alpha) {
231 for (
int gate = 0; gate < log_n; ++gate) {
235 for (
int sum_u = 0; sum_u < log_n; ++sum_u) {
239 print_header_centered(
"CHALLENGES - COMPLETE");
242 print_header_centered(
"SUMCHECK - RUNTIME MEMORY");
243 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - BARYCENTRIC");
246 int bary_pointer = SCRATCH_SPACE_POINTER;
247 for (
int i = 0; i < BARYCENTRIC_DOMAIN_SIZE; ++i) {
248 print_fr(bary_pointer,
"BARYCENTRIC_LAGRANGE_DENOMINATOR_" +
std::to_string(i) +
"_LOC");
251 for (
int i = 0; i < log_n; ++i) {
252 for (
int j = 0; j < BARYCENTRIC_DOMAIN_SIZE; ++j) {
253 print_fr(bary_pointer,
258 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - BARYCENTRIC COMPLETE");
261 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - SUBRELATION EVALUATIONS");
262 for (
int i = 0; i < NUMBER_OF_SUBRELATIONS; ++i) {
263 print_fr(pointer,
"SUBRELATION_EVAL_" +
std::to_string(i) +
"_LOC");
266 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - SUBRELATION EVALUATIONS COMPLETE");
269 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - SUBRELATION INTERMEDIATES");
270 for (
const auto& item : general_intermediates) {
271 print_fr(pointer, item);
274 for (
const auto& item : subrelation_intermediates) {
275 print_fr(pointer, item);
278 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - COMPLETE");
281 print_header_centered(
"SHPLEMINI - RUNTIME MEMORY");
282 print_header_centered(
"SHPLEMINI - POWERS OF EVALUATION CHALLENGE");
283 out <<
"/// {{ UNROLL_SECTION_START POWERS_OF_EVALUATION_CHALLENGE }}\n";
284 for (
int i = 0; i < log_n; ++i) {
285 print_fr(pointer,
"POWERS_OF_EVALUATION_CHALLENGE_" +
std::to_string(i) +
"_LOC");
288 out <<
"/// {{ UNROLL_SECTION_END POWERS_OF_EVALUATION_CHALLENGE }}\n";
289 print_header_centered(
"SHPLEMINI - POWERS OF EVALUATION CHALLENGE COMPLETE");
292 print_header_centered(
"SHPLEMINI - RUNTIME MEMORY - BATCH SCALARS");
293 const int BATCH_SIZE = 69;
294 for (
int i = 0; i < BATCH_SIZE; ++i) {
298 print_header_centered(
"SHPLEMINI - RUNTIME MEMORY - BATCH SCALARS COMPLETE");
301 print_header_centered(
"SHPLEMINI - RUNTIME MEMORY - INVERSIONS");
304 int inv_pointer = SCRATCH_SPACE_POINTER;
305 for (
int i = 0; i < log_n + 1; ++i) {
306 print_fr(inv_pointer,
"INVERTED_GEMINI_DENOMINATOR_" +
std::to_string(i) +
"_LOC");
311 for (
int i = 0; i < log_n; ++i) {
312 print_fr(inv_pointer,
"BATCH_EVALUATION_ACCUMULATOR_INVERSION_" +
std::to_string(i) +
"_LOC");
317 print_fr(inv_pointer,
"BATCHED_EVALUATION_LOC");
319 print_fr(inv_pointer,
"CONSTANT_TERM_ACCUMULATOR_LOC");
323 print_fr(inv_pointer,
"POS_INVERTED_DENOMINATOR");
325 print_fr(inv_pointer,
"NEG_INVERTED_DENOMINATOR");
329 out <<
"// LOG_N challenge pow minus u\n";
330 for (
int i = 0; i < log_n; ++i) {
331 print_fr(inv_pointer,
"INVERTED_CHALLENEGE_POW_MINUS_U_" +
std::to_string(i) +
"_LOC");
336 out <<
"// LOG_N pos_inverted_off\n";
337 for (
int i = 0; i < log_n; ++i) {
338 print_fr(inv_pointer,
"POS_INVERTED_DENOM_" +
std::to_string(i) +
"_LOC");
343 out <<
"// LOG_N neg_inverted_off\n";
344 for (
int i = 0; i < log_n; ++i) {
345 print_fr(inv_pointer,
"NEG_INVERTED_DENOM_" +
std::to_string(i) +
"_LOC");
350 for (
int i = 0; i < log_n; ++i) {
351 print_fr(inv_pointer,
"FOLD_POS_EVALUATIONS_" +
std::to_string(i) +
"_LOC");
355 print_header_centered(
"SHPLEMINI RUNTIME MEMORY - INVERSIONS - COMPLETE");
356 print_header_centered(
"SHPLEMINI RUNTIME MEMORY - COMPLETE");
359 print_fr(pointer,
"LATER_SCRATCH_SPACE");
363 print_header_centered(
"Temporary space");
364 for (
int i = 0; i < 3 * log_n; ++i) {
368 print_header_centered(
"Temporary space - COMPLETE");
372 out <<
"// Aliases for scratch space\n";
373 out <<
"// TODO: work out the stack scheduling for these\n";
374 print_fr(0x00,
"CHALL_POW_LOC");
375 print_fr(0x20,
"SUMCHECK_U_LOC");
376 print_fr(0x40,
"GEMINI_A_LOC");
378 print_fr(0x00,
"SS_POS_INV_DENOM_LOC");
379 print_fr(0x20,
"SS_NEG_INV_DENOM_LOC");
380 print_fr(0x40,
"SS_GEMINI_EVALS_LOC");
384 out <<
"// Aliases\n";
385 out <<
"// Aliases for wire values (Elliptic curve gadget)\n";
386 print_header_centered(
"SUMCHECK - MEMORY ALIASES");
394static const char HONK_CONTRACT_OPT_SOURCE[] = R
"(
395// SPDX-License-Identifier: Apache-2.0
396// Copyright 2022 Aztec
397pragma solidity ^0.8.27;
400 function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool);
405uint256 constant NUMBER_OF_SUBRELATIONS = 28;
406uint256 constant BATCHED_RELATION_PARTIAL_LENGTH = 8;
407uint256 constant ZK_BATCHED_RELATION_PARTIAL_LENGTH = 9;
408uint256 constant NUMBER_OF_ENTITIES = 41;
409uint256 constant NUMBER_UNSHIFTED = 36;
410uint256 constant NUMBER_TO_BE_SHIFTED = 5;
411uint256 constant PAIRING_POINTS_SIZE = 16;
413uint256 constant VK_HASH = {{ VK_HASH }};
414uint256 constant CIRCUIT_SIZE = {{ CIRCUIT_SIZE }};
415uint256 constant LOG_N = {{ LOG_CIRCUIT_SIZE }};
416uint256 constant NUMBER_PUBLIC_INPUTS = {{ NUM_PUBLIC_INPUTS }};
417uint256 constant REAL_NUMBER_PUBLIC_INPUTS = {{ NUM_PUBLIC_INPUTS }} - 16;
418uint256 constant PUBLIC_INPUTS_OFFSET = 1;
420uint256 constant NUMBER_OF_BARYCENTRIC_INVERSES = {{ NUMBER_OF_BARYCENTRIC_INVERSES }};
422error PUBLIC_INPUT_TOO_LARGE();
423error SUMCHECK_FAILED();
424error PAIRING_FAILED();
425error BATCH_ACCUMULATION_FAILED();
426error MODEXP_FAILED();
428contract HonkVerifier is IVerifier {
429 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
430 /* SLAB ALLOCATION */
431 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
440 // {{ SECTION_START MEMORY_LAYOUT }}
441 // {{ SECTION_END MEMORY_LAYOUT }}
443 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
444 /* SUMCHECK - MEMORY ALIASES */
445 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
446 uint256 internal constant EC_X_1 = W2_EVAL_LOC;
447 uint256 internal constant EC_Y_1 = W3_EVAL_LOC;
448 uint256 internal constant EC_X_2 = W1_SHIFT_EVAL_LOC;
449 uint256 internal constant EC_Y_2 = W4_SHIFT_EVAL_LOC;
450 uint256 internal constant EC_Y_3 = W3_SHIFT_EVAL_LOC;
451 uint256 internal constant EC_X_3 = W2_SHIFT_EVAL_LOC;
453 // Aliases for selectors (Elliptic curve gadget)
454 uint256 internal constant EC_Q_SIGN = QL_EVAL_LOC;
455 uint256 internal constant EC_Q_IS_DOUBLE = QM_EVAL_LOC;
457 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
459 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
460 uint256 internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = 17; // -(-17)
462 // Auxiliary relation constants
463 // In the Non Native Field Arithmetic Relation, large field elements are broken up into 4 LIMBs of 68 `LIMB_SIZE` bits each.
464 uint256 internal constant LIMB_SIZE = 0x100000000000000000; // 2<<68
466 // In the Delta Range Check Relation, there is a range checking relation that can validate 14-bit range checks with only 1
467 // extra relation in the execution trace.
468 // For large range checks, we decompose them into a collection of 14-bit range checks.
469 uint256 internal constant SUBLIMB_SHIFT = 0x4000; // 2<<14
471 // Poseidon2 internal constants
472 // https://github.com/HorizenLabs/poseidon2/blob/main/poseidon2_rust_params.sage - derivation code
473 uint256 internal constant POS_INTERNAL_MATRIX_D_0 =
474 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7;
475 uint256 internal constant POS_INTERNAL_MATRIX_D_1 =
476 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b;
477 uint256 internal constant POS_INTERNAL_MATRIX_D_2 =
478 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15;
479 uint256 internal constant POS_INTERNAL_MATRIX_D_3 =
480 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b;
482 // Constants inspecting proof components
483 uint256 internal constant NUMBER_OF_UNSHIFTED_ENTITIES = 36;
484 // Shifted columns are columes that are duplicates of existing columns but right-shifted by 1
485 uint256 internal constant NUMBER_OF_SHIFTED_ENTITIES = 5;
486 uint256 internal constant TOTAL_NUMBER_OF_ENTITIES = 41;
488 // Constants for performing batch multiplication
489 uint256 internal constant ACCUMULATOR = 0x00;
490 uint256 internal constant ACCUMULATOR_2 = 0x40;
491 uint256 internal constant G1_LOCATION = 0x60;
492 uint256 internal constant G1_Y_LOCATION = 0x80;
493 uint256 internal constant SCALAR_LOCATION = 0xa0;
495 uint256 internal constant LOWER_127_MASK = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // 127 bits
498 uint256 internal constant Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; // EC group order
500 // Field order constants
502 uint256 internal constant NEG_HALF_MODULO_P = 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000;
503 uint256 internal constant P = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
504 uint256 internal constant P_SUB_1 = 21888242871839275222246405745257275088548364400416034343698204186575808495616;
505 uint256 internal constant P_SUB_2 = 21888242871839275222246405745257275088548364400416034343698204186575808495615;
506 uint256 internal constant P_SUB_3 = 21888242871839275222246405745257275088548364400416034343698204186575808495614;
507 uint256 internal constant P_SUB_4 = 21888242871839275222246405745257275088548364400416034343698204186575808495613;
508 uint256 internal constant P_SUB_5 = 21888242871839275222246405745257275088548364400416034343698204186575808495612;
509 uint256 internal constant P_SUB_6 = 21888242871839275222246405745257275088548364400416034343698204186575808495611;
510 uint256 internal constant P_SUB_7 = 21888242871839275222246405745257275088548364400416034343698204186575808495610;
512 // Barycentric evaluation constants
513 uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_0 =
514 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51;
515 uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_1 =
516 0x00000000000000000000000000000000000000000000000000000000000002d0;
517 uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_2 =
518 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffff11;
519 uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_3 =
520 0x0000000000000000000000000000000000000000000000000000000000000090;
521 uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_4 =
522 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffff71;
523 uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_5 =
524 0x00000000000000000000000000000000000000000000000000000000000000f0;
525 uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_6 =
526 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31;
527 uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_7 =
528 0x00000000000000000000000000000000000000000000000000000000000013b0;
530 // Constants for computing public input delta
531 uint256 constant PERMUTATION_ARGUMENT_VALUE_SEPARATOR = 1 << 28;
533 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
535 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
536 uint256 internal constant PUBLIC_INPUT_TOO_LARGE_SELECTOR = 0x803bff7c;
537 uint256 internal constant SUMCHECK_FAILED_SELECTOR = 0x7d06dd7fa;
538 uint256 internal constant PAIRING_FAILED_SELECTOR = 0xd71fd2634;
539 uint256 internal constant BATCH_ACCUMULATION_FAILED_SELECTOR = 0xfef01a9a4;
540 uint256 internal constant MODEXP_FAILED_SELECTOR = 0xf442f1632;
541 uint256 internal constant PROOF_POINT_NOT_ON_CURVE_SELECTOR = 0x661e012dec;
545 function verify(bytes calldata, /*proof*/ bytes32[] calldata /*public_inputs*/ )
551 // Load the proof from calldata in one large chunk
553 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
554 /* LOAD VERIFCATION KEY */
555 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
556 // Write the verification key into memory
558 // Although defined at the top of the file, it is used towards the end of the algorithm when batching in the commitment scheme.
560 mstore(Q_L_X_LOC, {{ Q_L_X_LOC }})
561 mstore(Q_L_Y_LOC, {{ Q_L_Y_LOC }})
562 mstore(Q_R_X_LOC, {{ Q_R_X_LOC }})
563 mstore(Q_R_Y_LOC, {{ Q_R_Y_LOC }})
564 mstore(Q_O_X_LOC, {{ Q_O_X_LOC }})
565 mstore(Q_O_Y_LOC, {{ Q_O_Y_LOC }})
566 mstore(Q_4_X_LOC, {{ Q_4_X_LOC }})
567 mstore(Q_4_Y_LOC, {{ Q_4_Y_LOC }})
568 mstore(Q_M_X_LOC, {{ Q_M_X_LOC }})
569 mstore(Q_M_Y_LOC, {{ Q_M_Y_LOC }})
570 mstore(Q_C_X_LOC, {{ Q_C_X_LOC }})
571 mstore(Q_C_Y_LOC, {{ Q_C_Y_LOC }})
572 mstore(Q_LOOKUP_X_LOC, {{ Q_LOOKUP_X_LOC }})
573 mstore(Q_LOOKUP_Y_LOC, {{ Q_LOOKUP_Y_LOC }})
574 mstore(Q_ARITH_X_LOC, {{ Q_ARITH_X_LOC }})
575 mstore(Q_ARITH_Y_LOC, {{ Q_ARITH_Y_LOC }})
576 mstore(Q_DELTA_RANGE_X_LOC, {{ Q_DELTA_RANGE_X_LOC }})
577 mstore(Q_DELTA_RANGE_Y_LOC, {{ Q_DELTA_RANGE_Y_LOC }})
578 mstore(Q_ELLIPTIC_X_LOC, {{ Q_ELLIPTIC_X_LOC }})
579 mstore(Q_ELLIPTIC_Y_LOC, {{ Q_ELLIPTIC_Y_LOC }})
580 mstore(Q_MEMORY_X_LOC, {{ Q_MEMORY_X_LOC }})
581 mstore(Q_MEMORY_Y_LOC, {{ Q_MEMORY_Y_LOC }})
582 mstore(Q_NNF_X_LOC, {{ Q_NNF_X_LOC }})
583 mstore(Q_NNF_Y_LOC, {{ Q_NNF_Y_LOC }})
584 mstore(Q_POSEIDON_2_EXTERNAL_X_LOC, {{ Q_POSEIDON_2_EXTERNAL_X_LOC }})
585 mstore(Q_POSEIDON_2_EXTERNAL_Y_LOC, {{ Q_POSEIDON_2_EXTERNAL_Y_LOC }})
586 mstore(Q_POSEIDON_2_INTERNAL_X_LOC, {{ Q_POSEIDON_2_INTERNAL_X_LOC }})
587 mstore(Q_POSEIDON_2_INTERNAL_Y_LOC, {{ Q_POSEIDON_2_INTERNAL_Y_LOC }})
588 mstore(SIGMA_1_X_LOC, {{ SIGMA_1_X_LOC }})
589 mstore(SIGMA_1_Y_LOC, {{ SIGMA_1_Y_LOC }})
590 mstore(SIGMA_2_X_LOC, {{ SIGMA_2_X_LOC }})
591 mstore(SIGMA_2_Y_LOC, {{ SIGMA_2_Y_LOC }})
592 mstore(SIGMA_3_X_LOC, {{ SIGMA_3_X_LOC }})
593 mstore(SIGMA_3_Y_LOC, {{ SIGMA_3_Y_LOC }})
594 mstore(SIGMA_4_X_LOC, {{ SIGMA_4_X_LOC }})
595 mstore(SIGMA_4_Y_LOC, {{ SIGMA_4_Y_LOC }})
596 mstore(TABLE_1_X_LOC, {{ TABLE_1_X_LOC }})
597 mstore(TABLE_1_Y_LOC, {{ TABLE_1_Y_LOC }})
598 mstore(TABLE_2_X_LOC, {{ TABLE_2_X_LOC }})
599 mstore(TABLE_2_Y_LOC, {{ TABLE_2_Y_LOC }})
600 mstore(TABLE_3_X_LOC, {{ TABLE_3_X_LOC }})
601 mstore(TABLE_3_Y_LOC, {{ TABLE_3_Y_LOC }})
602 mstore(TABLE_4_X_LOC, {{ TABLE_4_X_LOC }})
603 mstore(TABLE_4_Y_LOC, {{ TABLE_4_Y_LOC }})
604 mstore(ID_1_X_LOC, {{ ID_1_X_LOC }})
605 mstore(ID_1_Y_LOC, {{ ID_1_Y_LOC }})
606 mstore(ID_2_X_LOC, {{ ID_2_X_LOC }})
607 mstore(ID_2_Y_LOC, {{ ID_2_Y_LOC }})
608 mstore(ID_3_X_LOC, {{ ID_3_X_LOC }})
609 mstore(ID_3_Y_LOC, {{ ID_3_Y_LOC }})
610 mstore(ID_4_X_LOC, {{ ID_4_X_LOC }})
611 mstore(ID_4_Y_LOC, {{ ID_4_Y_LOC }})
612 mstore(LAGRANGE_FIRST_X_LOC, {{ LAGRANGE_FIRST_X_LOC }})
613 mstore(LAGRANGE_FIRST_Y_LOC, {{ LAGRANGE_FIRST_Y_LOC }})
614 mstore(LAGRANGE_LAST_X_LOC, {{ LAGRANGE_LAST_X_LOC }})
615 mstore(LAGRANGE_LAST_Y_LOC, {{ LAGRANGE_LAST_Y_LOC }})
618 // Prime field order - placing on the stack
622 let proof_ptr := add(calldataload(0x04), 0x24)
624 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
625 /* GENERATE CHALLENGES */
626 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
628 * Proof points (affine coordinates) in the proof are in the following format, where offset is
629 * the offset in the entire proof until the first bit of the x coordinate
634 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
635 /* GENERATE ETA CHALLENGE */
636 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
637 /* Eta challenge participants
639 * - number of public inputs
640 * - public inputs offset
645 * Where circuit size, number of public inputs and public inputs offset are all 32 byte values
646 * and w1,w2,w3 are all proof points values
649 mstore(0x00, VK_HASH)
651 let public_inputs_start := add(calldataload(0x24), 0x24)
652 let public_inputs_size := mul(REAL_NUMBER_PUBLIC_INPUTS, 0x20)
654 // Copy the public inputs into the eta buffer
655 calldatacopy(0x20, public_inputs_start, public_inputs_size)
657 // Copy Pairing points into eta buffer
658 let public_inputs_end := add(0x20, public_inputs_size)
660 calldatacopy(public_inputs_end, proof_ptr, 0x200)
663 // End of public inputs + pairing point
664 calldatacopy(add(0x220, public_inputs_size), add(proof_ptr, 0x200), 0x100)
666 // 0x2e0 = 1 * 32 bytes + 3 * 64 bytes for (w1,w2,w3) + 0x200 for pairing points
667 let eta_input_length := add(0x2e0, public_inputs_size)
669 let prev_challenge := mod(keccak256(0x00, eta_input_length), p)
670 mstore(0x00, prev_challenge)
672 let eta := and(prev_challenge, LOWER_127_MASK)
673 let etaTwo := shr(127, prev_challenge)
675 mstore(ETA_CHALLENGE, eta)
676 mstore(ETA_TWO_CHALLENGE, etaTwo)
678 prev_challenge := mod(keccak256(0x00, 0x20), p)
680 mstore(0x00, prev_challenge)
681 let eta_three := and(prev_challenge, LOWER_127_MASK)
682 mstore(ETA_THREE_CHALLENGE, eta_three)
684 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
685 /* LOAD PROOF INTO MEMORY */
686 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
687 // As all of our proof points are written in contiguous parts of memory, we call use a single
688 // calldatacopy to place all of our proof into the correct memory regions
689 // We copy the entire proof into memory as we must hash each proof section for challenge
691 // The last item in the proof, and the first item in the proof (pairing point 0)
692 let proof_size := sub(ETA_CHALLENGE, PAIRING_POINT_0)
694 calldatacopy(PAIRING_POINT_0, proof_ptr, proof_size)
696 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
697 /* GENERATE BETA and GAMMAA CHALLENGE */
698 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
700 // Generate Beta and Gamma Chalenges
702 // - LOOKUP_READ_COUNTS
703 // - LOOKUP_READ_TAGS
705 mcopy(0x20, LOOKUP_READ_COUNTS_X_LOC, 0xc0)
707 prev_challenge := mod(keccak256(0x00, 0xe0), p)
708 mstore(0x00, prev_challenge)
709 let beta := and(prev_challenge, LOWER_127_MASK)
710 let gamma := shr(127, prev_challenge)
712 mstore(BETA_CHALLENGE, beta)
713 mstore(GAMMA_CHALLENGE, gamma)
715 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
716 /* ALPHA CHALLENGES */
717 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
718 // Generate Alpha challenges - non-linearise the gate contributions
720 // There are 26 total subrelations in this honk relation, we do not need to non linearise the first sub relation.
721 // There are 25 total gate contributions, a gate contribution is analogous to
722 // a custom gate, it is an expression which must evaluate to zero for each
723 // row in the constraint matrix
725 // If we do not non-linearise sub relations, then sub relations which rely
726 // on the same wire will interact with each other's sums.
728 mcopy(0x20, LOOKUP_INVERSES_X_LOC, 0x80)
730 // Generate single alpha challenge and compute its powers
731 prev_challenge := mod(keccak256(0x00, 0xa0), p)
732 mstore(0x00, prev_challenge)
733 let alpha := and(prev_challenge, LOWER_127_MASK)
734 mstore(ALPHA_CHALLENGE_0, alpha)
736 // Compute powers of alpha: alpha^2, alpha^3, ..., alpha^26
737 let alpha_off_set := ALPHA_CHALLENGE_1
738 for {} lt(alpha_off_set, add(ALPHA_CHALLENGE_26, 0x20)) {} {
739 let prev_alpha := mload(sub(alpha_off_set, 0x20))
740 mstore(alpha_off_set, mulmod(prev_alpha, alpha, p))
741 alpha_off_set := add(alpha_off_set, 0x20)
744 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
745 /* GATE CHALLENGES */
746 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
748 // Store the first gate challenge
749 prev_challenge := mod(keccak256(0x00, 0x20), p)
750 mstore(0x00, prev_challenge)
751 let gate_challenge := and(prev_challenge, LOWER_127_MASK)
752 mstore(GATE_CHALLENGE_0, gate_challenge)
754 let gate_off := GATE_CHALLENGE_1
755 for {} lt(gate_off, SUM_U_CHALLENGE_0) {} {
756 let prev := mload(sub(gate_off, 0x20))
758 mstore(gate_off, mulmod(prev, prev, p))
759 gate_off := add(gate_off, 0x20)
762 // Sumcheck Univariate challenges
763 // The algebraic relations of the Honk protocol are max degree-7.
764 // To prove satifiability, we multiply the relation by a random (POW) polynomial. We do this as we want all of our relations
765 // to be zero on every row - not for the sum of the relations to be zero. (Which is all sumcheck can do without this modification)
767 // As a result, in every round of sumcheck, the prover sends an degree-8 univariate polynomial.
768 // The sumcheck univariate challenge produces a challenge for each round of sumcheck, hashing the prev_challenge with
769 // a hash of the degree 8 univariate polynomial provided by the prover.
771 // 8 points are sent as it is enough to uniquely identify the polynomial
772 let read_off := SUMCHECK_UNIVARIATE_0_0_LOC
773 let write_off := SUM_U_CHALLENGE_0
774 for {} lt(read_off, QM_EVAL_LOC) {} {
775 // Increase by 20 * batched relation length (8)
776 // 0x20 * 0x8 = 0x100
777 mcopy(0x20, read_off, 0x100)
779 // Hash 0x100 + 0x20 (prev hash) = 0x120
780 prev_challenge := mod(keccak256(0x00, 0x120), p)
781 mstore(0x00, prev_challenge)
783 let sumcheck_u_challenge := and(prev_challenge, LOWER_127_MASK)
784 mstore(write_off, sumcheck_u_challenge)
786 // Progress read / write pointers
787 read_off := add(read_off, 0x100)
788 write_off := add(write_off, 0x20)
791 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
793 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
794 // The RHO challenge is the hash of the evaluations of all of the wire values
795 // As per usual, it includes the previous challenge
796 // Evaluations of the following wires and their shifts (for relevant wires):
808 // - QNNF (NNF = Non Native Field)
809 // - QPOSEIDON2_EXTERNAL
810 // - QPOSEIDON2_INTERNAL
829 // - LOOKUP_READ_COUNTS
830 // - LOOKUP_READ_TAGS
837 // Hash of all of the above evaluations
838 // Number of bytes to copy = 0x20 * NUMBER_OF_ENTITIES (41) = 0x520
839 mcopy(0x20, QM_EVAL_LOC, 0x520)
840 prev_challenge := mod(keccak256(0x00, 0x540), p)
841 mstore(0x00, prev_challenge)
843 let rho := and(prev_challenge, LOWER_127_MASK)
845 mstore(RHO_CHALLENGE, rho)
847 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
848 /* GEMINI R CHALLENGE */
849 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
850 // The Gemini R challenge contains a of all of commitments to all of the univariates
851 // evaluated in the Gemini Protocol
852 // So for multivariate polynomials in l variables, we will hash l - 1 commitments.
853 // For this implementation, we have logN number of of rounds and thus logN - 1 committments
854 // The format of these commitments are proof points, which are explained above
857 mcopy(0x20, GEMINI_FOLD_UNIVARIATE_0_X_LOC, {{ GEMINI_FOLD_UNIVARIATE_LENGTH }})
859 prev_challenge := mod(keccak256(0x00, {{ GEMINI_FOLD_UNIVARIATE_HASH_LENGTH }}), p)
860 mstore(0x00, prev_challenge)
862 let geminiR := and(prev_challenge, LOWER_127_MASK)
864 mstore(GEMINI_R_CHALLENGE, geminiR)
866 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
867 /* SHPLONK NU CHALLENGE */
868 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
869 // The shplonk nu challenge hashes the evaluations of the above gemini univariates
870 // 0x20 * logN = 0x20 * 15 = 0x1e0
872 mcopy(0x20, GEMINI_A_EVAL_0, {{ GEMINI_EVALS_LENGTH }})
873 prev_challenge := mod(keccak256(0x00, {{ GEMINI_EVALS_HASH_LENGTH }}), p)
874 mstore(0x00, prev_challenge)
876 let shplonkNu := and(prev_challenge, LOWER_127_MASK)
877 mstore(SHPLONK_NU_CHALLENGE, shplonkNu)
879 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
880 /* SHPLONK Z CHALLENGE */
881 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
882 // Generate Shplonk Z
883 // Hash of the single shplonk Q commitment
884 mcopy(0x20, SHPLONK_Q_X_LOC, 0x40)
885 prev_challenge := mod(keccak256(0x00, 0x60), p)
887 let shplonkZ := and(prev_challenge, LOWER_127_MASK)
888 mstore(SHPLONK_Z_CHALLENGE, shplonkZ)
890 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
891 /* CHALLENGES COMPLETE */
892 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
895 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
896 /* PUBLIC INPUT DELTA */
897 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
927 let beta := mload(BETA_CHALLENGE)
928 let gamma := mload(GAMMA_CHALLENGE)
929 let pub_off := PUBLIC_INPUTS_OFFSET
931 let numerator_value := 1
932 let denominator_value := 1
934 let p_clone := p // move p to the front of the stack
936 // Assume offset is less than p
937 // numerator_acc = gamma + (beta * (PERMUTATION_ARGUMENT_VALUE_SEPARATOR + offset))
939 addmod(gamma, mulmod(beta, add(PERMUTATION_ARGUMENT_VALUE_SEPARATOR, pub_off), p_clone), p_clone)
940 // demonimator_acc = gamma - (beta * (offset + 1))
941 let beta_x_off := mulmod(beta, add(pub_off, 1), p_clone)
942 let denominator_acc := addmod(gamma, sub(p_clone, beta_x_off), p_clone)
944 let valid_inputs := true
945 // Load the starting point of the public inputs (jump over the selector and the length of public inputs [0x24])
946 let public_inputs_ptr := add(calldataload(0x24), 0x24)
948 // endpoint_ptr = public_inputs_ptr + num_inputs * 0x20. // every public input is 0x20 bytes
949 let endpoint_ptr := add(public_inputs_ptr, mul(REAL_NUMBER_PUBLIC_INPUTS, 0x20))
951 for {} lt(public_inputs_ptr, endpoint_ptr) { public_inputs_ptr := add(public_inputs_ptr, 0x20) } {
952 // Get public inputs from calldata
953 let input := calldataload(public_inputs_ptr)
955 valid_inputs := and(valid_inputs, lt(input, p_clone))
957 numerator_value := mulmod(numerator_value, addmod(numerator_acc, input, p_clone), p_clone)
958 denominator_value := mulmod(denominator_value, addmod(denominator_acc, input, p_clone), p_clone)
960 numerator_acc := addmod(numerator_acc, beta, p_clone)
961 denominator_acc := addmod(denominator_acc, sub(p_clone, beta), p_clone)
964 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
965 /* PUBLIC INPUT DELTA - Pairing points accum */
966 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
967 // Pairing points contribution to public inputs delta
968 let pairing_points_ptr := PAIRING_POINT_0
969 for {} lt(pairing_points_ptr, W_L_X_LOC) { pairing_points_ptr := add(pairing_points_ptr, 0x20) } {
970 let input := mload(pairing_points_ptr)
972 numerator_value := mulmod(numerator_value, addmod(numerator_acc, input, p_clone), p_clone)
973 denominator_value := mulmod(denominator_value, addmod(denominator_acc, input, p_clone), p_clone)
975 numerator_acc := addmod(numerator_acc, beta, p_clone)
976 denominator_acc := addmod(denominator_acc, sub(p_clone, beta), p_clone)
979 // Revert if not all public inputs are field elements (i.e. < p)
980 if iszero(valid_inputs) {
981 mstore(0x00, PUBLIC_INPUT_TOO_LARGE_SELECTOR)
985 mstore(PUBLIC_INPUTS_DELTA_NUMERATOR_CHALLENGE, numerator_value)
986 mstore(PUBLIC_INPUTS_DELTA_DENOMINATOR_CHALLENGE, denominator_value)
988 // TODO: batch with barycentric inverses
994 mstore(0x60, denominator_value)
995 mstore(0x80, P_SUB_2)
997 if iszero(staticcall(gas(), 0x05, 0x00, 0xc0, 0x00, 0x20)) {
998 mstore(0x00, MODEXP_FAILED_SELECTOR)
1001 // 1 / (0 . 1 . 2 . 3 . 4 . 5 . 6 . 7)
1002 dom_inverse := mload(0x00)
1004 // Calculate the public inputs delta
1005 mstore(PUBLIC_INPUTS_DELTA_NUMERATOR_CHALLENGE, mulmod(numerator_value, dom_inverse, p))
1007 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
1008 /* PUBLIC INPUT DELTA - complete */
1009 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
1011 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
1013 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
1015 // Sumcheck is used to prove that every relation 0 on each row of the witness.
1017 // Given each of the columns of our trace is a multilinear polynomial 𝑃1,…,𝑃𝑁∈𝔽[𝑋0,…,𝑋𝑑−1]. We run sumcheck over the polynomial
1019 // 𝐹̃ (𝑋0,…,𝑋𝑑−1)=𝑝𝑜𝑤𝛽(𝑋0,…,𝑋𝑑−1)⋅𝐹(𝑃1(𝑋0,…,𝑋𝑑−1),…,𝑃𝑁(𝑋0,…,𝑋𝑑−1))
1021 // The Pow polynomial is a random polynomial that allows us to ceritify that the relations sum to 0 on each row of the witness,
1022 // rather than the entire sum just targeting 0.
1024 // Each polynomial P in our implementation are the polys in the proof and the verification key. (W_1, W_2, W_3, W_4, Z_PERM, etc....)
1026 // We start with a LOG_N variate multilinear polynomial, each round fixes a variable to a challenge value.
1027 // Each round the prover sends a round univariate poly, since the degree of our honk relations is 7 + the pow polynomial the prover
1028 // sends a degree-8 univariate on each round.
1029 // This is sent efficiently by sending 8 values, enough to represent a unique polynomial.
1030 // Barycentric evaluation is used to evaluate the polynomial at any point on the domain, given these 8 unique points.
1032 // In the sumcheck protocol, the target sum for each round is the sum of the round univariate evaluated on 0 and 1.
1033 // 𝜎𝑖=?𝑆̃ 𝑖(0)+𝑆̃ 𝑖(1)
1034 // This is efficiently checked as S(0) and S(1) are sent by the prover as values of the round univariate.
1036 // We compute the next challenge by evaluating the round univariate at a random challenge value.
1038 // This evaluation is performed via barycentric evaluation.
1040 // Once we have reduced the multilinear polynomials into single dimensional polys, we check the entire sumcheck relation matches the target sum.
1042 // Below this is composed of 8 relations:
1043 // 1. Arithmetic relation - constrains arithmetic
1044 // 2. Permutaiton Relation - efficiently encodes copy constraints
1045 // 3. Log Derivative Lookup Relation - used for lookup operations
1046 // 4. Delta Range Relation - used for efficient range checks
1047 // 5. Memory Relation - used for efficient memory operations
1048 // 6. NNF Relation - used for efficient Non Native Field operations
1049 // 7. Poseidon2 External Relation - used for efficient in-circuit hashing
1050 // 8. Poseidon2 Internal Relation - used for efficient in-circuit hashing
1052 // These are batched together and evaluated at the same time using the alpha challenges.
1055 // We write the barycentric domain values into memory
1056 // These are written once per program execution, and reused across all
1058 mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_0_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_0)
1059 mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_1_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_1)
1060 mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_2_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_2)
1061 mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_3_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_3)
1062 mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_4_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_4)
1063 mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_5_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_5)
1064 mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_6_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_6)
1065 mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_7_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_7)
1067 // Compute the target sums for each round of sumcheck
1069 // This requires the barycentric inverses to be computed for each round
1070 // Write all of the non inverted barycentric denominators into memory
1071 let accumulator := 1
1072 let temp := LATER_SCRATCH_SPACE
1073 let bary_centric_inverses_off := BARYCENTRIC_DENOMINATOR_INVERSES_0_0_LOC
1075 let round_challenge_off := SUM_U_CHALLENGE_0
1076 for { let round := 0 } lt(round, LOG_N) { round := add(round, 1) } {
1077 let round_challenge := mload(round_challenge_off)
1078 let bary_lagrange_denominator_off := BARYCENTRIC_LAGRANGE_DENOMINATOR_0_LOC
1080 // Unrolled as this loop as it only has 8 iterations
1082 let bary_lagrange_denominator := mload(bary_lagrange_denominator_off)
1085 bary_lagrange_denominator,
1086 addmod(round_challenge, p, p), // sub(p, 0) = p
1089 mstore(bary_centric_inverses_off, pre_inv)
1090 temp := add(temp, 0x20)
1091 mstore(temp, accumulator)
1092 accumulator := mulmod(accumulator, pre_inv, p)
1095 bary_lagrange_denominator_off := add(bary_lagrange_denominator_off, 0x20)
1096 bary_centric_inverses_off := add(bary_centric_inverses_off, 0x20)
1098 // barycentric_index = 1
1099 bary_lagrange_denominator := mload(bary_lagrange_denominator_off)
1100 pre_inv := mulmod(bary_lagrange_denominator, addmod(round_challenge, P_SUB_1, p), p)
1101 mstore(bary_centric_inverses_off, pre_inv)
1102 temp := add(temp, 0x20)
1103 mstore(temp, accumulator)
1104 accumulator := mulmod(accumulator, pre_inv, p)
1107 bary_lagrange_denominator_off := add(bary_lagrange_denominator_off, 0x20)
1108 bary_centric_inverses_off := add(bary_centric_inverses_off, 0x20)
1110 // barycentric_index = 2
1111 bary_lagrange_denominator := mload(bary_lagrange_denominator_off)
1112 pre_inv := mulmod(bary_lagrange_denominator, addmod(round_challenge, P_SUB_2, p), p)
1113 mstore(bary_centric_inverses_off, pre_inv)
1114 temp := add(temp, 0x20)
1115 mstore(temp, accumulator)
1116 accumulator := mulmod(accumulator, pre_inv, p)
1119 bary_lagrange_denominator_off := add(bary_lagrange_denominator_off, 0x20)
1120 bary_centric_inverses_off := add(bary_centric_inverses_off, 0x20)
1122 // barycentric_index = 3
1123 bary_lagrange_denominator := mload(bary_lagrange_denominator_off)
1124 pre_inv := mulmod(bary_lagrange_denominator, addmod(round_challenge, P_SUB_3, p), p)
1125 mstore(bary_centric_inverses_off, pre_inv)
1126 temp := add(temp, 0x20)
1127 mstore(temp, accumulator)
1128 accumulator := mulmod(accumulator, pre_inv, p)
1131 bary_lagrange_denominator_off := add(bary_lagrange_denominator_off, 0x20)
1132 bary_centric_inverses_off := add(bary_centric_inverses_off, 0x20)
1134 // barycentric_index = 4
1135 bary_lagrange_denominator := mload(bary_lagrange_denominator_off)
1136 pre_inv := mulmod(bary_lagrange_denominator, addmod(round_challenge, P_SUB_4, p), p)
1137 mstore(bary_centric_inverses_off, pre_inv)
1138 temp := add(temp, 0x20)
1139 mstore(temp, accumulator)
1140 accumulator := mulmod(accumulator, pre_inv, p)
1143 bary_lagrange_denominator_off := add(bary_lagrange_denominator_off, 0x20)
1144 bary_centric_inverses_off := add(bary_centric_inverses_off, 0x20)
1146 // barycentric_index = 5
1147 bary_lagrange_denominator := mload(bary_lagrange_denominator_off)
1148 pre_inv := mulmod(bary_lagrange_denominator, addmod(round_challenge, P_SUB_5, p), p)
1149 mstore(bary_centric_inverses_off, pre_inv)
1150 temp := add(temp, 0x20)
1151 mstore(temp, accumulator)
1152 accumulator := mulmod(accumulator, pre_inv, p)
1155 bary_lagrange_denominator_off := add(bary_lagrange_denominator_off, 0x20)
1156 bary_centric_inverses_off := add(bary_centric_inverses_off, 0x20)
1158 // barycentric_index = 6
1159 bary_lagrange_denominator := mload(bary_lagrange_denominator_off)
1160 pre_inv := mulmod(bary_lagrange_denominator, addmod(round_challenge, P_SUB_6, p), p)
1161 mstore(bary_centric_inverses_off, pre_inv)
1162 temp := add(temp, 0x20)
1163 mstore(temp, accumulator)
1164 accumulator := mulmod(accumulator, pre_inv, p)
1167 bary_lagrange_denominator_off := add(bary_lagrange_denominator_off, 0x20)
1168 bary_centric_inverses_off := add(bary_centric_inverses_off, 0x20)
1170 // barycentric_index = 7
1171 bary_lagrange_denominator := mload(bary_lagrange_denominator_off)
1172 pre_inv := mulmod(bary_lagrange_denominator, addmod(round_challenge, P_SUB_7, p), p)
1173 mstore(bary_centric_inverses_off, pre_inv)
1174 temp := add(temp, 0x20)
1175 mstore(temp, accumulator)
1176 accumulator := mulmod(accumulator, pre_inv, p)
1179 bary_lagrange_denominator_off := add(bary_lagrange_denominator_off, 0x20)
1180 bary_centric_inverses_off := add(bary_centric_inverses_off, 0x20)
1182 round_challenge_off := add(round_challenge_off, 0x20)
1186 // Invert all of the barycentric denominators as a single batch
1192 mstore(0x60, accumulator)
1193 mstore(0x80, P_SUB_2)
1195 if iszero(staticcall(gas(), 0x05, 0x00, 0xc0, 0x00, 0x20)) {
1196 mstore(0x00, MODEXP_FAILED_SELECTOR)
1200 accumulator := mload(0x00)
1203 // Normalise as last loop will have incremented the offset
1204 bary_centric_inverses_off := sub(bary_centric_inverses_off, 0x20)
1205 for {} gt(bary_centric_inverses_off, BARYCENTRIC_LAGRANGE_DENOMINATOR_7_LOC) {
1206 bary_centric_inverses_off := sub(bary_centric_inverses_off, 0x20)
1208 let tmp := mulmod(accumulator, mload(temp), p)
1209 accumulator := mulmod(accumulator, mload(bary_centric_inverses_off), p)
1210 mstore(bary_centric_inverses_off, tmp)
1212 temp := sub(temp, 0x20)
1218 let round_target := 0
1219 let pow_partial_evaluation := 1
1220 let gate_challenge_off := GATE_CHALLENGE_0
1221 let round_univariates_off := SUMCHECK_UNIVARIATE_0_0_LOC
1223 let challenge_off := SUM_U_CHALLENGE_0
1224 let bary_inverses_off := BARYCENTRIC_DENOMINATOR_INVERSES_0_0_LOC
1226 for { let round := 0 } lt(round, LOG_N) { round := add(round, 1) } {
1227 let round_challenge := mload(challenge_off)
1229 // Total sum = u[0] + u[1]
1230 let total_sum := addmod(mload(round_univariates_off), mload(add(round_univariates_off, 0x20)), p)
1231 valid := and(valid, eq(total_sum, round_target))
1233 // Compute next target sum
1234 let numerator_value := round_challenge
1235 numerator_value := mulmod(numerator_value, addmod(round_challenge, P_SUB_1, p), p)
1236 numerator_value := mulmod(numerator_value, addmod(round_challenge, P_SUB_2, p), p)
1237 numerator_value := mulmod(numerator_value, addmod(round_challenge, P_SUB_3, p), p)
1238 numerator_value := mulmod(numerator_value, addmod(round_challenge, P_SUB_4, p), p)
1239 numerator_value := mulmod(numerator_value, addmod(round_challenge, P_SUB_5, p), p)
1240 numerator_value := mulmod(numerator_value, addmod(round_challenge, P_SUB_6, p), p)
1241 numerator_value := mulmod(numerator_value, addmod(round_challenge, P_SUB_7, p), p)
1243 // // Compute the next round target
1245 for { let i := 0 } lt(i, BATCHED_RELATION_PARTIAL_LENGTH) { i := add(i, 1) } {
1246 let term := mload(round_univariates_off)
1247 let inverse := mload(bary_inverses_off)
1249 term := mulmod(term, inverse, p)
1250 round_target := addmod(round_target, term, p)
1251 round_univariates_off := add(round_univariates_off, 0x20)
1252 bary_inverses_off := add(bary_inverses_off, 0x20)
1255 round_target := mulmod(round_target, numerator_value, p)
1257 // Partially evaluate POW
1258 let gate_challenge := mload(gate_challenge_off)
1259 let gate_challenge_minus_one := sub(gate_challenge, 1)
1261 let univariate_evaluation := addmod(1, mulmod(round_challenge, gate_challenge_minus_one, p), p)
1263 pow_partial_evaluation := mulmod(pow_partial_evaluation, univariate_evaluation, p)
1265 gate_challenge_off := add(gate_challenge_off, 0x20)
1266 challenge_off := add(challenge_off, 0x20)
1270 mstore(0x00, SUMCHECK_FAILED_SELECTOR)
1274 // The final sumcheck round; accumulating evaluations
1275 // Uses pow partial evaluation as the gate scaling factor
1277 mstore(POW_PARTIAL_EVALUATION_LOC, pow_partial_evaluation)
1278 mstore(FINAL_ROUND_TARGET_LOC, round_target)
1280 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
1281 /* LOGUP RELATION */
1282 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
1319 let w1q1 := mulmod(mload(W1_EVAL_LOC), mload(QL_EVAL_LOC), p)
1320 let w2q2 := mulmod(mload(W2_EVAL_LOC), mload(QR_EVAL_LOC), p)
1321 let w3q3 := mulmod(mload(W3_EVAL_LOC), mload(QO_EVAL_LOC), p)
1322 let w4q3 := mulmod(mload(W4_EVAL_LOC), mload(Q4_EVAL_LOC), p)
1324 let q_arith := mload(QARITH_EVAL_LOC)
1325 // w1w2qm := (w_1 . w_2 . q_m . (QARITH_EVAL_LOC - 3)) / 2
1329 mulmod(mulmod(mload(W1_EVAL_LOC), mload(W2_EVAL_LOC), p), mload(QM_EVAL_LOC), p),
1330 addmod(q_arith, P_SUB_3, p),
1337 // (w_1 . w_2 . q_m . (q_arith - 3)) / -2) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c
1341 addmod(w4q3, addmod(w3q3, addmod(w2q2, addmod(w1q1, w1w2qm, p), p), p), p),
1345 // if q_arith == 3 we evaluate an additional mini addition gate (on top of the regular one), where:
1346 // w_1 + w_4 - w_1_omega + q_m = 0
1347 // we use this gate to save an addition gate when adding or subtracting non-native field elements
1348 // α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m)
1349 let extra_small_addition_gate_identity :=
1351 addmod(q_arith, P_SUB_2, p),
1355 sub(p, mload(W1_SHIFT_EVAL_LOC)), addmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p), p
1362 // Split up the two relations
1363 let contribution_0 :=
1364 addmod(identity, mulmod(addmod(q_arith, P_SUB_1, p), mload(W4_SHIFT_EVAL_LOC), p), p)
1365 contribution_0 := mulmod(mulmod(contribution_0, q_arith, p), mload(POW_PARTIAL_EVALUATION_LOC), p)
1366 mstore(SUBRELATION_EVAL_0_LOC, contribution_0)
1368 let contribution_1 := mulmod(extra_small_addition_gate_identity, addmod(q_arith, P_SUB_1, p), p)
1369 contribution_1 := mulmod(contribution_1, q_arith, p)
1370 contribution_1 := mulmod(contribution_1, mload(POW_PARTIAL_EVALUATION_LOC), p)
1371 mstore(SUBRELATION_EVAL_1_LOC, contribution_1)
1374 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
1375 /* PERMUTATION RELATION */
1376 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
1378 let beta := mload(BETA_CHALLENGE)
1379 let gamma := mload(GAMMA_CHALLENGE)
1391 add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(ID1_EVAL_LOC), p)),
1392 add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(ID2_EVAL_LOC), p)),
1397 add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(ID3_EVAL_LOC), p)),
1398 add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(ID4_EVAL_LOC), p)),
1401 let numerator := mulmod(t1, t2, p)
1404 add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA1_EVAL_LOC), p)),
1405 add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA2_EVAL_LOC), p)),
1410 add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA3_EVAL_LOC), p)),
1411 add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA4_EVAL_LOC), p)),
1414 let denominator := mulmod(t1, t2, p)
1418 mulmod(addmod(mload(Z_PERM_EVAL_LOC), mload(LAGRANGE_FIRST_EVAL_LOC), p), numerator, p)
1427 mload(Z_PERM_SHIFT_EVAL_LOC),
1429 mload(LAGRANGE_LAST_EVAL_LOC),
1430 mload(PUBLIC_INPUTS_DELTA_NUMERATOR_CHALLENGE),
1442 acc := mulmod(acc, mload(POW_PARTIAL_EVALUATION_LOC), p)
1443 mstore(SUBRELATION_EVAL_2_LOC, acc)
1447 mulmod(mload(LAGRANGE_LAST_EVAL_LOC), mload(Z_PERM_SHIFT_EVAL_LOC), p),
1448 mload(POW_PARTIAL_EVALUATION_LOC),
1451 mstore(SUBRELATION_EVAL_3_LOC, acc)
1455 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
1456 /* LOGUP WIDGET EVALUATION */
1457 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
1459 let eta := mload(ETA_CHALLENGE)
1460 let eta_two := mload(ETA_TWO_CHALLENGE)
1461 let eta_three := mload(ETA_THREE_CHALLENGE)
1463 let beta := mload(BETA_CHALLENGE)
1464 let gamma := mload(GAMMA_CHALLENGE)
1467 addmod(addmod(mload(TABLE1_EVAL_LOC), gamma, p), mulmod(mload(TABLE2_EVAL_LOC), eta, p), p)
1469 addmod(mulmod(mload(TABLE3_EVAL_LOC), eta_two, p), mulmod(mload(TABLE4_EVAL_LOC), eta_three, p), p)
1470 let write_term := addmod(t0, t1, p)
1474 addmod(mload(W1_EVAL_LOC), gamma, p), mulmod(mload(QR_EVAL_LOC), mload(W1_SHIFT_EVAL_LOC), p), p
1476 t1 := addmod(mload(W2_EVAL_LOC), mulmod(mload(QM_EVAL_LOC), mload(W2_SHIFT_EVAL_LOC), p), p)
1477 let t2 := addmod(mload(W3_EVAL_LOC), mulmod(mload(QC_EVAL_LOC), mload(W3_SHIFT_EVAL_LOC), p), p)
1479 let read_term := addmod(t0, mulmod(t1, eta, p), p)
1480 read_term := addmod(read_term, mulmod(t2, eta_two, p), p)
1481 read_term := addmod(read_term, mulmod(mload(QO_EVAL_LOC), eta_three, p), p)
1483 let read_inverse := mulmod(mload(LOOKUP_INVERSES_EVAL_LOC), write_term, p)
1484 let write_inverse := mulmod(mload(LOOKUP_INVERSES_EVAL_LOC), read_term, p)
1486 let inverse_exists_xor := addmod(mload(LOOKUP_READ_TAGS_EVAL_LOC), mload(QLOOKUP_EVAL_LOC), p)
1487 inverse_exists_xor :=
1490 sub(p, mulmod(mload(LOOKUP_READ_TAGS_EVAL_LOC), mload(QLOOKUP_EVAL_LOC), p)),
1494 let accumulator_none := mulmod(mulmod(read_term, write_term, p), mload(LOOKUP_INVERSES_EVAL_LOC), p)
1495 accumulator_none := addmod(accumulator_none, sub(p, inverse_exists_xor), p)
1496 accumulator_none := mulmod(accumulator_none, mload(POW_PARTIAL_EVALUATION_LOC), p)
1498 let accumulator_one := mulmod(mload(QLOOKUP_EVAL_LOC), read_inverse, p)
1500 addmod(accumulator_one, sub(p, mulmod(mload(LOOKUP_READ_COUNTS_EVAL_LOC), write_inverse, p)), p)
1502 let read_tag := mload(LOOKUP_READ_TAGS_EVAL_LOC)
1503 let read_tag_boolean_relation := mulmod(read_tag, addmod(read_tag, P_SUB_1, p), p)
1504 read_tag_boolean_relation := mulmod(read_tag_boolean_relation, mload(POW_PARTIAL_EVALUATION_LOC), p)
1506 mstore(SUBRELATION_EVAL_4_LOC, accumulator_none)
1507 mstore(SUBRELATION_EVAL_5_LOC, accumulator_one)
1508 mstore(SUBRELATION_EVAL_6_LOC, read_tag_boolean_relation)
1511 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
1512 /* DELTA RANGE RELATION */
1513 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
1515 // TODO(md): optimise the calculations
1516 let minus_one := P_SUB_1
1517 let minus_two := P_SUB_2
1518 let minus_three := P_SUB_3
1520 let delta_1 := addmod(mload(W2_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p)
1521 let delta_2 := addmod(mload(W3_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p)
1522 let delta_3 := addmod(mload(W4_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p)
1523 let delta_4 := addmod(mload(W1_SHIFT_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p)
1527 acc := mulmod(acc, addmod(delta_1, minus_one, p), p)
1528 acc := mulmod(acc, addmod(delta_1, minus_two, p), p)
1529 acc := mulmod(acc, addmod(delta_1, minus_three, p), p)
1530 acc := mulmod(acc, mload(QRANGE_EVAL_LOC), p)
1531 acc := mulmod(acc, mload(POW_PARTIAL_EVALUATION_LOC), p)
1532 mstore(SUBRELATION_EVAL_7_LOC, acc)
1537 acc := mulmod(acc, addmod(delta_2, minus_one, p), p)
1538 acc := mulmod(acc, addmod(delta_2, minus_two, p), p)
1539 acc := mulmod(acc, addmod(delta_2, minus_three, p), p)
1540 acc := mulmod(acc, mload(QRANGE_EVAL_LOC), p)
1541 acc := mulmod(acc, mload(POW_PARTIAL_EVALUATION_LOC), p)
1542 mstore(SUBRELATION_EVAL_8_LOC, acc)
1547 acc := mulmod(acc, addmod(delta_3, minus_one, p), p)
1548 acc := mulmod(acc, addmod(delta_3, minus_two, p), p)
1549 acc := mulmod(acc, addmod(delta_3, minus_three, p), p)
1550 acc := mulmod(acc, mload(QRANGE_EVAL_LOC), p)
1551 acc := mulmod(acc, mload(POW_PARTIAL_EVALUATION_LOC), p)
1552 mstore(SUBRELATION_EVAL_9_LOC, acc)
1557 acc := mulmod(acc, addmod(delta_4, minus_one, p), p)
1558 acc := mulmod(acc, addmod(delta_4, minus_two, p), p)
1559 acc := mulmod(acc, addmod(delta_4, minus_three, p), p)
1560 acc := mulmod(acc, mload(QRANGE_EVAL_LOC), p)
1561 acc := mulmod(acc, mload(POW_PARTIAL_EVALUATION_LOC), p)
1562 mstore(SUBRELATION_EVAL_10_LOC, acc)
1566 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
1567 /* ELLIPTIC CURVE RELATION */
1568 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
1570 // Contribution 10 point addition, x-coordinate check
1571 // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0
1572 let x_diff := addmod(mload(EC_X_2), sub(p, mload(EC_X_1)), p)
1573 let y1_sqr := mulmod(mload(EC_Y_1), mload(EC_Y_1), p)
1575 let y2_sqr := mulmod(mload(EC_Y_2), mload(EC_Y_2), p)
1576 let y1y2 := mulmod(mulmod(mload(EC_Y_1), mload(EC_Y_2), p), mload(EC_Q_SIGN), p)
1577 let x_add_identity := addmod(mload(EC_X_3), addmod(mload(EC_X_2), mload(EC_X_1), p), p)
1578 x_add_identity := mulmod(mulmod(x_add_identity, x_diff, p), x_diff, p)
1579 x_add_identity := addmod(x_add_identity, sub(p, y2_sqr), p)
1580 x_add_identity := addmod(x_add_identity, sub(p, y1_sqr), p)
1581 x_add_identity := addmod(x_add_identity, y1y2, p)
1582 x_add_identity := addmod(x_add_identity, y1y2, p)
1584 let eval := mulmod(x_add_identity, mload(POW_PARTIAL_EVALUATION_LOC), p)
1585 eval := mulmod(eval, mload(QELLIPTIC_EVAL_LOC), p)
1586 eval := mulmod(eval, addmod(1, sub(p, mload(EC_Q_IS_DOUBLE)), p), p)
1587 mstore(SUBRELATION_EVAL_11_LOC, eval)
1591 let y1_plus_y3 := addmod(mload(EC_Y_1), mload(EC_Y_3), p)
1592 let y_diff := mulmod(mload(EC_Y_2), mload(EC_Q_SIGN), p)
1593 y_diff := addmod(y_diff, sub(p, mload(EC_Y_1)), p)
1594 let y_add_identity := mulmod(y1_plus_y3, x_diff, p)
1596 addmod(y_add_identity, mulmod(addmod(mload(EC_X_3), sub(p, mload(EC_X_1)), p), y_diff, p), p)
1598 let eval := mulmod(y_add_identity, mload(POW_PARTIAL_EVALUATION_LOC), p)
1599 eval := mulmod(eval, mload(QELLIPTIC_EVAL_LOC), p)
1600 eval := mulmod(eval, addmod(1, sub(p, mload(EC_Q_IS_DOUBLE)), p), p)
1601 mstore(SUBRELATION_EVAL_12_LOC, eval)
1605 let x_pow_4 := mulmod(addmod(y1_sqr, GRUMPKIN_CURVE_B_PARAMETER_NEGATED, p), mload(EC_X_1), p)
1606 let y1_sqr_mul_4 := addmod(y1_sqr, y1_sqr, p)
1607 y1_sqr_mul_4 := addmod(y1_sqr_mul_4, y1_sqr_mul_4, p)
1609 let x1_pow_4_mul_9 := mulmod(x_pow_4, 9, p)
1611 let ep_x_double_identity := addmod(mload(EC_X_3), addmod(mload(EC_X_1), mload(EC_X_1), p), p)
1612 ep_x_double_identity := mulmod(ep_x_double_identity, y1_sqr_mul_4, p)
1613 ep_x_double_identity := addmod(ep_x_double_identity, sub(p, x1_pow_4_mul_9), p)
1615 let acc := mulmod(ep_x_double_identity, mload(POW_PARTIAL_EVALUATION_LOC), p)
1616 acc := mulmod(mulmod(acc, mload(QELLIPTIC_EVAL_LOC), p), mload(EC_Q_IS_DOUBLE), p)
1617 acc := addmod(acc, mload(SUBRELATION_EVAL_11_LOC), p)
1619 // Add to existing contribution - and double check that numbers here
1620 mstore(SUBRELATION_EVAL_11_LOC, acc)
1625 mulmod(addmod(addmod(mload(EC_X_1), mload(EC_X_1), p), mload(EC_X_1), p), mload(EC_X_1), p)
1626 let y_double_identity :=
1627 mulmod(x1_sqr_mul_3, addmod(mload(EC_X_1), sub(p, mload(EC_X_3)), p), p)
1628 y_double_identity :=
1634 addmod(mload(EC_Y_1), mload(EC_Y_1), p), addmod(mload(EC_Y_1), mload(EC_Y_3), p), p
1640 let acc := mulmod(y_double_identity, mload(POW_PARTIAL_EVALUATION_LOC), p)
1641 acc := mulmod(mulmod(acc, mload(QELLIPTIC_EVAL_LOC), p), mload(EC_Q_IS_DOUBLE), p)
1642 acc := addmod(acc, mload(SUBRELATION_EVAL_12_LOC), p)
1644 // Add to existing contribution - and double check that numbers here
1645 mstore(SUBRELATION_EVAL_12_LOC, acc)
1649 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
1650 /* MEMORY RELATION */
1651 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
1705 // TODO(md): update these - formula has changed with lower degree
1706 let memory_record_check := mulmod(mload(W3_EVAL_LOC), mload(ETA_THREE_CHALLENGE), p)
1707 memory_record_check :=
1708 addmod(memory_record_check, mulmod(mload(W2_EVAL_LOC), mload(ETA_TWO_CHALLENGE), p), p)
1709 memory_record_check :=
1710 addmod(memory_record_check, mulmod(mload(W1_EVAL_LOC), mload(ETA_CHALLENGE), p), p)
1711 memory_record_check := addmod(memory_record_check, mload(QC_EVAL_LOC), p)
1713 let partial_record_check := memory_record_check
1714 memory_record_check := addmod(memory_record_check, sub(p, mload(W4_EVAL_LOC)), p)
1716 mstore(AUX_MEMORY_CHECK_IDENTITY, memory_record_check)
1733 // index_delta = w_1_omega - w_1
1734 let index_delta := addmod(mload(W1_SHIFT_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p)
1736 // record_delta = w_4_omega - w_4
1737 let record_delta := addmod(mload(W4_SHIFT_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p)
1739 // index_is_monotonically_increasing = index_delta * (index_delta - 1)
1740 let index_is_monotonically_increasing := mulmod(index_delta, addmod(index_delta, P_SUB_1, p), p)
1742 // adjacent_values_match_if_adjacent_indices_match = record_delta * (1 - index_delta)
1743 let adjacent_values_match_if_adjacent_indices_match :=
1744 mulmod(record_delta, addmod(1, sub(p, index_delta), p), p)
1747 SUBRELATION_EVAL_14_LOC,
1749 adjacent_values_match_if_adjacent_indices_match,
1754 mulmod(mload(QMEMORY_EVAL_LOC), mload(POW_PARTIAL_EVALUATION_LOC), p),
1763 // ROM_CONSISTENCY_CHECK_2
1765 SUBRELATION_EVAL_15_LOC,
1767 index_is_monotonically_increasing,
1772 mulmod(mload(QMEMORY_EVAL_LOC), mload(POW_PARTIAL_EVALUATION_LOC), p),
1782 AUX_ROM_CONSISTENCY_CHECK_IDENTITY,
1783 mulmod(memory_record_check, mulmod(mload(QL_EVAL_LOC), mload(QR_EVAL_LOC), p), p)
1813 let next_gate_access_type := mulmod(mload(W3_SHIFT_EVAL_LOC), mload(ETA_THREE_CHALLENGE), p)
1814 next_gate_access_type :=
1816 next_gate_access_type, mulmod(mload(W2_SHIFT_EVAL_LOC), mload(ETA_TWO_CHALLENGE), p), p
1818 next_gate_access_type :=
1819 addmod(next_gate_access_type, mulmod(mload(W1_SHIFT_EVAL_LOC), mload(ETA_CHALLENGE), p), p)
1820 next_gate_access_type := addmod(mload(W4_SHIFT_EVAL_LOC), sub(p, next_gate_access_type), p)
1822 // value_delta = w_3_omega - w_3
1823 let value_delta := addmod(mload(W3_SHIFT_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p)
1824 // adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = (1 - index_delta) * value_delta * (1 - next_gate_access_type);
1826 let adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation :=
1828 addmod(1, sub(p, index_delta), p),
1829 mulmod(value_delta, addmod(1, sub(p, next_gate_access_type), p), p),
1833 // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the
1834 // next gate would make the identity fail). We need to validate that its 'access type' bool is correct. Can't
1835 // do with an arithmetic gate because of the `eta` factors. We need to check that the *next* gate's access
1836 // type is correct, to cover this edge case
1843 let access_type := addmod(mload(W4_EVAL_LOC), sub(p, partial_record_check), p)
1844 let access_check := mulmod(access_type, addmod(access_type, P_SUB_1, p), p)
1845 let next_gate_access_type_is_boolean :=
1846 mulmod(next_gate_access_type, addmod(next_gate_access_type, P_SUB_1, p), p)
1848 // scaled_activation_selector = q_arith * q_aux * alpha
1849 let scaled_activation_selector :=
1852 mulmod(mload(QMEMORY_EVAL_LOC), mload(POW_PARTIAL_EVALUATION_LOC), p),
1857 SUBRELATION_EVAL_16_LOC,
1859 adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation,
1860 scaled_activation_selector,
1866 SUBRELATION_EVAL_17_LOC,
1867 mulmod(index_is_monotonically_increasing, scaled_activation_selector, p)
1871 SUBRELATION_EVAL_18_LOC,
1872 mulmod(next_gate_access_type_is_boolean, scaled_activation_selector, p)
1875 mstore(AUX_RAM_CONSISTENCY_CHECK_IDENTITY, mulmod(access_check, mload(QO_EVAL_LOC), p))
1879 // timestamp_delta = w_2_omega - w_2
1880 let timestamp_delta := addmod(mload(W2_SHIFT_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p)
1882 // RAM_timestamp_check_identity = (1 - index_delta) * timestamp_delta - w_3
1883 let RAM_TIMESTAMP_CHECK_IDENTITY :=
1885 mulmod(timestamp_delta, addmod(1, sub(p, index_delta), p), p),
1886 sub(p, mload(W3_EVAL_LOC)),
1901 let memory_identity := mload(AUX_ROM_CONSISTENCY_CHECK_IDENTITY)
1906 RAM_TIMESTAMP_CHECK_IDENTITY, mulmod(mload(Q4_EVAL_LOC), mload(QL_EVAL_LOC), p), p
1915 mload(AUX_MEMORY_CHECK_IDENTITY),
1916 mulmod(mload(QM_EVAL_LOC), mload(QL_EVAL_LOC), p),
1921 memory_identity := addmod(memory_identity, mload(AUX_RAM_CONSISTENCY_CHECK_IDENTITY), p)
1926 mulmod(mload(QMEMORY_EVAL_LOC), mload(POW_PARTIAL_EVALUATION_LOC), p),
1929 mstore(SUBRELATION_EVAL_13_LOC, memory_identity)
1934 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
1935 /* NON NATIVE FIELD RELATION */
1936 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
1957 let limb_subproduct :=
1959 mulmod(mload(W1_EVAL_LOC), mload(W2_SHIFT_EVAL_LOC), p),
1960 mulmod(mload(W1_SHIFT_EVAL_LOC), mload(W2_EVAL_LOC), p),
1964 let non_native_field_gate_2 :=
1967 mulmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p),
1968 mulmod(mload(W2_EVAL_LOC), mload(W3_EVAL_LOC), p),
1971 sub(p, mload(W3_SHIFT_EVAL_LOC)),
1974 non_native_field_gate_2 := mulmod(non_native_field_gate_2, LIMB_SIZE, p)
1975 non_native_field_gate_2 := addmod(non_native_field_gate_2, sub(p, mload(W4_SHIFT_EVAL_LOC)), p)
1976 non_native_field_gate_2 := addmod(non_native_field_gate_2, limb_subproduct, p)
1977 non_native_field_gate_2 := mulmod(non_native_field_gate_2, mload(Q4_EVAL_LOC), p)
1979 limb_subproduct := mulmod(limb_subproduct, LIMB_SIZE, p)
1981 addmod(limb_subproduct, mulmod(mload(W1_SHIFT_EVAL_LOC), mload(W2_SHIFT_EVAL_LOC), p), p)
1983 let non_native_field_gate_1 :=
1985 addmod(limb_subproduct, sub(p, addmod(mload(W3_EVAL_LOC), mload(W4_EVAL_LOC), p)), p),
1990 let non_native_field_gate_3 :=
1993 addmod(limb_subproduct, mload(W4_EVAL_LOC), p),
1994 sub(p, addmod(mload(W3_SHIFT_EVAL_LOC), mload(W4_SHIFT_EVAL_LOC), p)),
2000 let non_native_field_identity :=
2002 addmod(addmod(non_native_field_gate_1, non_native_field_gate_2, p), non_native_field_gate_3, p),
2007 mstore(AUX_NON_NATIVE_FIELD_IDENTITY, non_native_field_identity)
2024 let limb_accumulator_1 := mulmod(mload(W2_SHIFT_EVAL_LOC), SUBLIMB_SHIFT, p)
2025 limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_SHIFT_EVAL_LOC), p)
2026 limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)
2027 limb_accumulator_1 := addmod(limb_accumulator_1, mload(W3_EVAL_LOC), p)
2028 limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)
2029 limb_accumulator_1 := addmod(limb_accumulator_1, mload(W2_EVAL_LOC), p)
2030 limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)
2031 limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_EVAL_LOC), p)
2032 limb_accumulator_1 := addmod(limb_accumulator_1, sub(p, mload(W4_EVAL_LOC)), p)
2033 limb_accumulator_1 := mulmod(limb_accumulator_1, mload(Q4_EVAL_LOC), p)
2048 let limb_accumulator_2 := mulmod(mload(W3_SHIFT_EVAL_LOC), SUBLIMB_SHIFT, p)
2049 limb_accumulator_2 := addmod(limb_accumulator_2, mload(W2_SHIFT_EVAL_LOC), p)
2050 limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)
2051 limb_accumulator_2 := addmod(limb_accumulator_2, mload(W1_SHIFT_EVAL_LOC), p)
2052 limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)
2053 limb_accumulator_2 := addmod(limb_accumulator_2, mload(W4_EVAL_LOC), p)
2054 limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)
2055 limb_accumulator_2 := addmod(limb_accumulator_2, mload(W3_EVAL_LOC), p)
2056 limb_accumulator_2 := addmod(limb_accumulator_2, sub(p, mload(W4_SHIFT_EVAL_LOC)), p)
2057 limb_accumulator_2 := mulmod(limb_accumulator_2, mload(QM_EVAL_LOC), p)
2059 let limb_accumulator_identity := addmod(limb_accumulator_1, limb_accumulator_2, p)
2060 limb_accumulator_identity := mulmod(limb_accumulator_identity, mload(QO_EVAL_LOC), p)
2062 let nnf_identity := addmod(mload(AUX_NON_NATIVE_FIELD_IDENTITY), limb_accumulator_identity, p)
2064 mulmod(nnf_identity, mulmod(mload(QNNF_EVAL_LOC), mload(POW_PARTIAL_EVALUATION_LOC), p), p)
2066 mstore(SUBRELATION_EVAL_19_LOC, nnf_identity)
2070 * Poseidon External Relation
2073 let s1 := addmod(mload(W1_EVAL_LOC), mload(QL_EVAL_LOC), p)
2074 let s2 := addmod(mload(W2_EVAL_LOC), mload(QR_EVAL_LOC), p)
2075 let s3 := addmod(mload(W3_EVAL_LOC), mload(QO_EVAL_LOC), p)
2076 let s4 := addmod(mload(W4_EVAL_LOC), mload(Q4_EVAL_LOC), p)
2078 // u1 := s1 * s1 * s1 * s1 * s1;
2079 let t0 := mulmod(s1, s1, p)
2080 let u1 := mulmod(t0, mulmod(t0, s1, p), p)
2082 // u2 := s2 * s2 * s2 * s2 * s2;
2083 t0 := mulmod(s2, s2, p)
2084 let u2 := mulmod(t0, mulmod(t0, s2, p), p)
2086 // u3 := s3 * s3 * s3 * s3 * s3;
2087 t0 := mulmod(s3, s3, p)
2088 let u3 := mulmod(t0, mulmod(t0, s3, p), p)
2090 // u4 := s4 * s4 * s4 * s4 * s4;
2091 t0 := mulmod(s4, s4, p)
2092 let u4 := mulmod(t0, mulmod(t0, s4, p), p)
2094 // matrix mul v = M_E * u with 14 additions
2095 t0 := addmod(u1, u2, p)
2096 let t1 := addmod(u3, u4, p)
2098 let t2 := addmod(u2, u2, p)
2099 t2 := addmod(t2, t1, p)
2101 let t3 := addmod(u4, u4, p)
2102 t3 := addmod(t3, t0, p)
2104 let v4 := addmod(t1, t1, p)
2105 v4 := addmod(v4, v4, p)
2106 v4 := addmod(v4, t3, p)
2108 let v2 := addmod(t0, t0, p)
2109 v2 := addmod(v2, v2, p)
2110 v2 := addmod(v2, t2, p)
2112 let v1 := addmod(t3, v2, p)
2113 let v3 := addmod(t2, v4, p)
2115 let q_pos_by_scaling :=
2116 mulmod(mload(QPOSEIDON2_EXTERNAL_EVAL_LOC), mload(POW_PARTIAL_EVALUATION_LOC), p)
2119 SUBRELATION_EVAL_20_LOC,
2120 mulmod(q_pos_by_scaling, addmod(v1, sub(p, mload(W1_SHIFT_EVAL_LOC)), p), p)
2124 SUBRELATION_EVAL_21_LOC,
2125 mulmod(q_pos_by_scaling, addmod(v2, sub(p, mload(W2_SHIFT_EVAL_LOC)), p), p)
2129 SUBRELATION_EVAL_22_LOC,
2130 mulmod(q_pos_by_scaling, addmod(v3, sub(p, mload(W3_SHIFT_EVAL_LOC)), p), p)
2134 SUBRELATION_EVAL_23_LOC,
2135 mulmod(q_pos_by_scaling, addmod(v4, sub(p, mload(W4_SHIFT_EVAL_LOC)), p), p)
2140 * Poseidon Internal Relation
2143 let s1 := addmod(mload(W1_EVAL_LOC), mload(QL_EVAL_LOC), p)
2145 // apply s-box round
2146 let t0 := mulmod(s1, s1, p)
2147 let u1 := mulmod(t0, mulmod(t0, s1, p), p)
2148 let u2 := mload(W2_EVAL_LOC)
2149 let u3 := mload(W3_EVAL_LOC)
2150 let u4 := mload(W4_EVAL_LOC)
2152 // matrix mul v = M_I * u 4 muls and 7 additions
2153 let u_sum := addmod(u1, u2, p)
2154 u_sum := addmod(u_sum, addmod(u3, u4, p), p)
2156 let q_pos_by_scaling :=
2157 mulmod(mload(QPOSEIDON2_INTERNAL_EVAL_LOC), mload(POW_PARTIAL_EVALUATION_LOC), p)
2159 let v1 := addmod(mulmod(u1, POS_INTERNAL_MATRIX_D_0, p), u_sum, p)
2162 SUBRELATION_EVAL_24_LOC,
2163 mulmod(q_pos_by_scaling, addmod(v1, sub(p, mload(W1_SHIFT_EVAL_LOC)), p), p)
2165 let v2 := addmod(mulmod(u2, POS_INTERNAL_MATRIX_D_1, p), u_sum, p)
2168 SUBRELATION_EVAL_25_LOC,
2169 mulmod(q_pos_by_scaling, addmod(v2, sub(p, mload(W2_SHIFT_EVAL_LOC)), p), p)
2171 let v3 := addmod(mulmod(u3, POS_INTERNAL_MATRIX_D_2, p), u_sum, p)
2174 SUBRELATION_EVAL_26_LOC,
2175 mulmod(q_pos_by_scaling, addmod(v3, sub(p, mload(W3_SHIFT_EVAL_LOC)), p), p)
2178 let v4 := addmod(mulmod(u4, POS_INTERNAL_MATRIX_D_3, p), u_sum, p)
2180 SUBRELATION_EVAL_27_LOC,
2181 mulmod(q_pos_by_scaling, addmod(v4, sub(p, mload(W4_SHIFT_EVAL_LOC)), p), p)
2185 // Scale and batch subrelations by subrelation challenges
2186 // linear combination of subrelations
2187 let accumulator := mload(SUBRELATION_EVAL_0_LOC)
2189 // Below is an unrolled variant of the following loop
2190 // for (uint256 i = 1; i < NUMBER_OF_SUBRELATIONS; ++i) {
2191 // accumulator = accumulator + evaluations[i] * subrelationChallenges[i - 1];
2195 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_1_LOC), mload(ALPHA_CHALLENGE_0), p), p)
2197 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_2_LOC), mload(ALPHA_CHALLENGE_1), p), p)
2199 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_3_LOC), mload(ALPHA_CHALLENGE_2), p), p)
2201 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_4_LOC), mload(ALPHA_CHALLENGE_3), p), p)
2203 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_5_LOC), mload(ALPHA_CHALLENGE_4), p), p)
2205 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_6_LOC), mload(ALPHA_CHALLENGE_5), p), p)
2207 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_7_LOC), mload(ALPHA_CHALLENGE_6), p), p)
2209 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_8_LOC), mload(ALPHA_CHALLENGE_7), p), p)
2211 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_9_LOC), mload(ALPHA_CHALLENGE_8), p), p)
2213 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_10_LOC), mload(ALPHA_CHALLENGE_9), p), p)
2215 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_11_LOC), mload(ALPHA_CHALLENGE_10), p), p)
2217 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_12_LOC), mload(ALPHA_CHALLENGE_11), p), p)
2219 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_13_LOC), mload(ALPHA_CHALLENGE_12), p), p)
2221 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_14_LOC), mload(ALPHA_CHALLENGE_13), p), p)
2223 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_15_LOC), mload(ALPHA_CHALLENGE_14), p), p)
2225 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_16_LOC), mload(ALPHA_CHALLENGE_15), p), p)
2227 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_17_LOC), mload(ALPHA_CHALLENGE_16), p), p)
2229 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_18_LOC), mload(ALPHA_CHALLENGE_17), p), p)
2231 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_19_LOC), mload(ALPHA_CHALLENGE_18), p), p)
2233 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_20_LOC), mload(ALPHA_CHALLENGE_19), p), p)
2235 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_21_LOC), mload(ALPHA_CHALLENGE_20), p), p)
2237 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_22_LOC), mload(ALPHA_CHALLENGE_21), p), p)
2239 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_23_LOC), mload(ALPHA_CHALLENGE_22), p), p)
2241 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_24_LOC), mload(ALPHA_CHALLENGE_23), p), p)
2243 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_25_LOC), mload(ALPHA_CHALLENGE_24), p), p)
2245 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_26_LOC), mload(ALPHA_CHALLENGE_25), p), p)
2247 addmod(accumulator, mulmod(mload(SUBRELATION_EVAL_27_LOC), mload(ALPHA_CHALLENGE_26), p), p)
2249 let sumcheck_valid := eq(accumulator, mload(FINAL_ROUND_TARGET_LOC))
2251 if iszero(sumcheck_valid) {
2252 mstore(0x00, SUMCHECK_FAILED_SELECTOR)
2257 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
2258 /* SUMCHECK -- Complete */
2259 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
2261 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
2263 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
2265 // Compute powers of evaluation challenge
2266 let cache := mload(GEMINI_R_CHALLENGE)
2267 let off := POWERS_OF_EVALUATION_CHALLENGE_0_LOC
2270 for { let i := 1 } lt(i, LOG_N) { i := add(i, 1) } {
2271 off := add(off, 0x20)
2272 cache := mulmod(cache, cache, p)
2276 // Compute Inverted Gemini Denominators
2277 let eval_challenge := mload(SHPLONK_Z_CHALLENGE)
2279 // TO be inverted in the batch invert below
2280 // TODO: maybe not needed to go in memory
2282 INVERTED_GEMINI_DENOMINATOR_0_LOC,
2283 addmod(eval_challenge, sub(p, mload(POWERS_OF_EVALUATION_CHALLENGE_0_LOC)), p)
2287 POS_INVERTED_DENOM_0_LOC, addmod(eval_challenge, sub(p, mload(POWERS_OF_EVALUATION_CHALLENGE_0_LOC)), p)
2289 mstore(NEG_INVERTED_DENOM_0_LOC, addmod(eval_challenge, mload(POWERS_OF_EVALUATION_CHALLENGE_0_LOC), p))
2291 // Compute Fold Pos Evaluatios
2293 // In order to compute fold pos evaluations we need
2294 let store_off := INVERTED_CHALLENEGE_POW_MINUS_U_{{ LOG_N_MINUS_ONE }}_LOC
2295 let pow_off := POWERS_OF_EVALUATION_CHALLENGE_{{ LOG_N_MINUS_ONE }}_LOC
2296 let sumcheck_u_off := SUM_U_CHALLENGE_{{ LOG_N_MINUS_ONE }}
2298 // TODO: challengePower * (ONE - u) can be cached - measure performance
2299 for { let i := LOG_N } gt(i, 0) { i := sub(i, 1) } {
2300 let u := mload(sumcheck_u_off)
2302 let challPowerMulMinusU := mulmod(mload(pow_off), addmod(1, sub(p, u), p), p)
2304 mstore(store_off, addmod(challPowerMulMinusU, u, p))
2306 store_off := sub(store_off, 0x20)
2307 pow_off := sub(pow_off, 0x20)
2308 sumcheck_u_off := sub(sumcheck_u_off, 0x20)
2313 let pos_inverted_off := POS_INVERTED_DENOM_1_LOC
2314 let neg_inverted_off := NEG_INVERTED_DENOM_1_LOC
2315 pow_off := POWERS_OF_EVALUATION_CHALLENGE_1_LOC
2317 let shplonk_z := mload(SHPLONK_Z_CHALLENGE)
2318 for { let i := 0 } lt(i, sub(LOG_N, 1)) { i := add(i, 1) } {
2319 let pow := mload(pow_off)
2321 let pos_inv := addmod(shplonk_z, sub(p, pow), p)
2322 mstore(pos_inverted_off, pos_inv)
2324 let neg_inv := addmod(shplonk_z, pow, p)
2325 mstore(neg_inverted_off, neg_inv)
2327 pow_off := add(pow_off, 0x20)
2328 pos_inverted_off := add(pos_inverted_off, 0x20)
2329 neg_inverted_off := add(neg_inverted_off, 0x20)
2334 // From: computeFoldPosEvaluations
2335 // Series of challengePower * (ONE - u)
2336 // gemini r challenge
2337 // Inverted denominators
2338 // (shplonkZ - powers of evaluaion challenge[i + 1])
2339 // (shplonkZ + powers of evaluation challenge[i + 1])
2341 // Use scratch space for temps
2343 let accumulator := mload(GEMINI_R_CHALLENGE)
2352 mstore(0x60, accumulator)
2353 mstore(0x80, P_SUB_2)
2355 if iszero(staticcall(gas(), 0x05, 0x00, 0xc0, 0x00, 0x20)) {
2356 mstore(0x00, MODEXP_FAILED_SELECTOR)
2359 accumulator := mload(0x00)
2365 let inverted_gemini_r := accumulator
2367 let unshifted_scalar := 0
2368 let shifted_scalar := 0
2370 let pos_inverted_denominator := mload(POS_INVERTED_DENOM_0_LOC)
2371 let neg_inverted_denominator := mload(NEG_INVERTED_DENOM_0_LOC)
2372 let shplonk_nu := mload(SHPLONK_NU_CHALLENGE)
2374 unshifted_scalar := addmod(pos_inverted_denominator, mulmod(shplonk_nu, neg_inverted_denominator, p), p)
2376 // accumulator takes the value of `INVERTED_GEMINI_DENOMINATOR_0` here
2379 accumulator, // (1 / gemini_r_challenge)
2380 // (inverse_vanishing_evals[0]) - (shplonk_nu * inverse_vanishing_evals[1])
2382 pos_inverted_denominator,
2383 // - (shplonk_nu * inverse_vanishing_evals[1])
2384 sub(p, mulmod(shplonk_nu, neg_inverted_denominator, p)),
2391 // TODO: Write a comment that describes the process of accumulating commitments and scalars
2392 // into one large value that will be used on the rhs of the pairing check
2395 let batching_challenge := 1
2396 let batched_evaluation := 0
2398 let neg_unshifted_scalar := sub(p, unshifted_scalar)
2399 let neg_shifted_scalar := sub(p, shifted_scalar)
2401 mstore(BATCH_SCALAR_0_LOC, 1)
2402 let rho := mload(RHO_CHALLENGE)
2404 // Unrolled for the loop below - where NUMBER_UNSHIFTED = 36
2405 // for (uint256 i = 1; i <= NUMBER_UNSHIFTED; ++i) {
2406 // scalars[i] = mem.unshiftedScalar.neg() * mem.batchingChallenge;
2407 // mem.batchedEvaluation = mem.batchedEvaluation + (proof.sumcheckEvaluations[i - 1] * mem.batchingChallenge);
2408 // mem.batchingChallenge = mem.batchingChallenge * tp.rho;
2411 // Calculate the scalars and batching challenge for the unshifted entities
2413 mstore(BATCH_SCALAR_1_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2414 batched_evaluation := addmod(batched_evaluation, mulmod(mload(QM_EVAL_LOC), batching_challenge, p), p)
2415 batching_challenge := mulmod(batching_challenge, rho, p)
2418 mstore(BATCH_SCALAR_2_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2419 batched_evaluation := addmod(batched_evaluation, mulmod(mload(QC_EVAL_LOC), batching_challenge, p), p)
2420 batching_challenge := mulmod(batching_challenge, rho, p)
2423 mstore(BATCH_SCALAR_3_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2424 batched_evaluation := addmod(batched_evaluation, mulmod(mload(QL_EVAL_LOC), batching_challenge, p), p)
2425 batching_challenge := mulmod(batching_challenge, rho, p)
2428 mstore(BATCH_SCALAR_4_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2429 batched_evaluation := addmod(batched_evaluation, mulmod(mload(QR_EVAL_LOC), batching_challenge, p), p)
2430 batching_challenge := mulmod(batching_challenge, rho, p)
2433 mstore(BATCH_SCALAR_5_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2434 batched_evaluation := addmod(batched_evaluation, mulmod(mload(QO_EVAL_LOC), batching_challenge, p), p)
2435 batching_challenge := mulmod(batching_challenge, rho, p)
2438 mstore(BATCH_SCALAR_6_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2439 batched_evaluation := addmod(batched_evaluation, mulmod(mload(Q4_EVAL_LOC), batching_challenge, p), p)
2440 batching_challenge := mulmod(batching_challenge, rho, p)
2442 // 6: QLOOKUP_EVAL_LOC
2443 mstore(BATCH_SCALAR_7_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2444 batched_evaluation := addmod(batched_evaluation, mulmod(mload(QLOOKUP_EVAL_LOC), batching_challenge, p), p)
2445 batching_challenge := mulmod(batching_challenge, rho, p)
2447 // 7: QARITH_EVAL_LOC
2448 mstore(BATCH_SCALAR_8_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2449 batched_evaluation := addmod(batched_evaluation, mulmod(mload(QARITH_EVAL_LOC), batching_challenge, p), p)
2450 batching_challenge := mulmod(batching_challenge, rho, p)
2452 // 8: QRANGE_EVAL_LOC
2453 mstore(BATCH_SCALAR_9_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2454 batched_evaluation := addmod(batched_evaluation, mulmod(mload(QRANGE_EVAL_LOC), batching_challenge, p), p)
2455 batching_challenge := mulmod(batching_challenge, rho, p)
2457 // 9: QELLIPTIC_EVAL_LOC
2458 mstore(BATCH_SCALAR_10_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2459 batched_evaluation :=
2460 addmod(batched_evaluation, mulmod(mload(QELLIPTIC_EVAL_LOC), batching_challenge, p), p)
2461 batching_challenge := mulmod(batching_challenge, rho, p)
2463 // 10: QMEMORY_EVAL_LOC
2464 mstore(BATCH_SCALAR_11_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2465 batched_evaluation := addmod(batched_evaluation, mulmod(mload(QMEMORY_EVAL_LOC), batching_challenge, p), p)
2466 batching_challenge := mulmod(batching_challenge, rho, p)
2468 // 11: QNNF_EVAL_LOC
2469 mstore(BATCH_SCALAR_12_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2470 batched_evaluation := addmod(batched_evaluation, mulmod(mload(QNNF_EVAL_LOC), batching_challenge, p), p)
2471 batching_challenge := mulmod(batching_challenge, rho, p)
2473 // 12: QPOSEIDON2_EXTERNAL_EVAL_LOC
2474 mstore(BATCH_SCALAR_13_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2475 batched_evaluation :=
2476 addmod(batched_evaluation, mulmod(mload(QPOSEIDON2_EXTERNAL_EVAL_LOC), batching_challenge, p), p)
2477 batching_challenge := mulmod(batching_challenge, rho, p)
2479 // 13: QPOSEIDON2_INTERNAL_EVAL_LOC
2480 mstore(BATCH_SCALAR_14_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2481 batched_evaluation :=
2482 addmod(batched_evaluation, mulmod(mload(QPOSEIDON2_INTERNAL_EVAL_LOC), batching_challenge, p), p)
2483 batching_challenge := mulmod(batching_challenge, rho, p)
2485 // 14: SIGMA1_EVAL_LOC
2486 mstore(BATCH_SCALAR_15_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2487 batched_evaluation := addmod(batched_evaluation, mulmod(mload(SIGMA1_EVAL_LOC), batching_challenge, p), p)
2488 batching_challenge := mulmod(batching_challenge, rho, p)
2490 // 15: SIGMA2_EVAL_LOC
2491 mstore(BATCH_SCALAR_16_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2492 batched_evaluation := addmod(batched_evaluation, mulmod(mload(SIGMA2_EVAL_LOC), batching_challenge, p), p)
2493 batching_challenge := mulmod(batching_challenge, rho, p)
2495 // 16: SIGMA3_EVAL_LOC
2496 mstore(BATCH_SCALAR_17_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2497 batched_evaluation := addmod(batched_evaluation, mulmod(mload(SIGMA3_EVAL_LOC), batching_challenge, p), p)
2498 batching_challenge := mulmod(batching_challenge, rho, p)
2500 // 17: SIGMA4_EVAL_LOC
2501 mstore(BATCH_SCALAR_18_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2502 batched_evaluation := addmod(batched_evaluation, mulmod(mload(SIGMA4_EVAL_LOC), batching_challenge, p), p)
2503 batching_challenge := mulmod(batching_challenge, rho, p)
2506 mstore(BATCH_SCALAR_19_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2507 batched_evaluation := addmod(batched_evaluation, mulmod(mload(ID1_EVAL_LOC), batching_challenge, p), p)
2508 batching_challenge := mulmod(batching_challenge, rho, p)
2511 mstore(BATCH_SCALAR_20_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2512 batched_evaluation := addmod(batched_evaluation, mulmod(mload(ID2_EVAL_LOC), batching_challenge, p), p)
2513 batching_challenge := mulmod(batching_challenge, rho, p)
2516 mstore(BATCH_SCALAR_21_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2517 batched_evaluation := addmod(batched_evaluation, mulmod(mload(ID3_EVAL_LOC), batching_challenge, p), p)
2518 batching_challenge := mulmod(batching_challenge, rho, p)
2521 mstore(BATCH_SCALAR_22_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2522 batched_evaluation := addmod(batched_evaluation, mulmod(mload(ID4_EVAL_LOC), batching_challenge, p), p)
2523 batching_challenge := mulmod(batching_challenge, rho, p)
2525 // 22: TABLE1_EVAL_LOC
2526 mstore(BATCH_SCALAR_23_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2527 batched_evaluation := addmod(batched_evaluation, mulmod(mload(TABLE1_EVAL_LOC), batching_challenge, p), p)
2528 batching_challenge := mulmod(batching_challenge, rho, p)
2530 // 23: TABLE2_EVAL_LOC
2531 mstore(BATCH_SCALAR_24_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2532 batched_evaluation := addmod(batched_evaluation, mulmod(mload(TABLE2_EVAL_LOC), batching_challenge, p), p)
2533 batching_challenge := mulmod(batching_challenge, rho, p)
2535 // 24: TABLE3_EVAL_LOC
2536 mstore(BATCH_SCALAR_25_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2537 batched_evaluation := addmod(batched_evaluation, mulmod(mload(TABLE3_EVAL_LOC), batching_challenge, p), p)
2538 batching_challenge := mulmod(batching_challenge, rho, p)
2540 // 25: TABLE4_EVAL_LOC
2541 mstore(BATCH_SCALAR_26_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2542 batched_evaluation := addmod(batched_evaluation, mulmod(mload(TABLE4_EVAL_LOC), batching_challenge, p), p)
2543 batching_challenge := mulmod(batching_challenge, rho, p)
2545 // 26: LAGRANGE_FIRST_EVAL_LOC
2546 mstore(BATCH_SCALAR_27_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2547 batched_evaluation :=
2548 addmod(batched_evaluation, mulmod(mload(LAGRANGE_FIRST_EVAL_LOC), batching_challenge, p), p)
2549 batching_challenge := mulmod(batching_challenge, rho, p)
2551 // 27: LAGRANGE_LAST_EVAL_LOC
2552 mstore(BATCH_SCALAR_28_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2553 batched_evaluation :=
2554 addmod(batched_evaluation, mulmod(mload(LAGRANGE_LAST_EVAL_LOC), batching_challenge, p), p)
2555 batching_challenge := mulmod(batching_challenge, rho, p)
2558 mstore(BATCH_SCALAR_29_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2559 batched_evaluation := addmod(batched_evaluation, mulmod(mload(W1_EVAL_LOC), batching_challenge, p), p)
2560 batching_challenge := mulmod(batching_challenge, rho, p)
2563 mstore(BATCH_SCALAR_30_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2564 batched_evaluation := addmod(batched_evaluation, mulmod(mload(W2_EVAL_LOC), batching_challenge, p), p)
2565 batching_challenge := mulmod(batching_challenge, rho, p)
2568 mstore(BATCH_SCALAR_31_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2569 batched_evaluation := addmod(batched_evaluation, mulmod(mload(W3_EVAL_LOC), batching_challenge, p), p)
2570 batching_challenge := mulmod(batching_challenge, rho, p)
2573 mstore(BATCH_SCALAR_32_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2574 batched_evaluation := addmod(batched_evaluation, mulmod(mload(W4_EVAL_LOC), batching_challenge, p), p)
2575 batching_challenge := mulmod(batching_challenge, rho, p)
2577 // 32: Z_PERM_EVAL_LOC
2578 mstore(BATCH_SCALAR_33_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2579 batched_evaluation := addmod(batched_evaluation, mulmod(mload(Z_PERM_EVAL_LOC), batching_challenge, p), p)
2580 batching_challenge := mulmod(batching_challenge, rho, p)
2582 // 33: LOOKUP_INVERSES_EVAL_LOC
2583 mstore(BATCH_SCALAR_34_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2584 batched_evaluation :=
2585 addmod(batched_evaluation, mulmod(mload(LOOKUP_INVERSES_EVAL_LOC), batching_challenge, p), p)
2586 batching_challenge := mulmod(batching_challenge, rho, p)
2588 // 34: LOOKUP_READ_COUNTS_EVAL_LOC
2589 mstore(BATCH_SCALAR_35_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2590 batched_evaluation :=
2591 addmod(batched_evaluation, mulmod(mload(LOOKUP_READ_COUNTS_EVAL_LOC), batching_challenge, p), p)
2592 batching_challenge := mulmod(batching_challenge, rho, p)
2594 // 35: LOOKUP_READ_TAGS_EVAL_LOC
2595 mstore(BATCH_SCALAR_36_LOC, mulmod(neg_unshifted_scalar, batching_challenge, p))
2596 batched_evaluation :=
2597 addmod(batched_evaluation, mulmod(mload(LOOKUP_READ_TAGS_EVAL_LOC), batching_challenge, p), p)
2598 batching_challenge := mulmod(batching_challenge, rho, p)
2600 // Unrolled for NUMBER_OF_SHIFTED_ENTITIES = 5
2601 // for (uint256 i = NUMBER_UNSHIFTED + 1; i <= NUMBER_OF_ENTITIES; ++i) {
2602 // scalars[i] = mem.shiftedScalar.neg() * mem.batchingChallenge;
2603 // mem.batchedEvaluation = mem.batchedEvaluation + (proof.sumcheckEvaluations[i - 1] * mem.batchingChallenge);
2604 // mem.batchingChallenge = mem.batchingChallenge * tp.rho;
2609 BATCH_SCALAR_29_LOC,
2610 addmod(mload(BATCH_SCALAR_29_LOC), mulmod(neg_shifted_scalar, batching_challenge, p), p)
2612 batched_evaluation := addmod(batched_evaluation, mulmod(mload(W1_SHIFT_EVAL_LOC), batching_challenge, p), p)
2613 batching_challenge := mulmod(batching_challenge, rho, p)
2617 BATCH_SCALAR_30_LOC,
2618 addmod(mload(BATCH_SCALAR_30_LOC), mulmod(neg_shifted_scalar, batching_challenge, p), p)
2620 batched_evaluation := addmod(batched_evaluation, mulmod(mload(W2_SHIFT_EVAL_LOC), batching_challenge, p), p)
2621 batching_challenge := mulmod(batching_challenge, rho, p)
2625 BATCH_SCALAR_31_LOC,
2626 addmod(mload(BATCH_SCALAR_31_LOC), mulmod(neg_shifted_scalar, batching_challenge, p), p)
2628 batched_evaluation := addmod(batched_evaluation, mulmod(mload(W3_SHIFT_EVAL_LOC), batching_challenge, p), p)
2629 batching_challenge := mulmod(batching_challenge, rho, p)
2633 BATCH_SCALAR_32_LOC,
2634 addmod(mload(BATCH_SCALAR_32_LOC), mulmod(neg_shifted_scalar, batching_challenge, p), p)
2636 batched_evaluation := addmod(batched_evaluation, mulmod(mload(W4_SHIFT_EVAL_LOC), batching_challenge, p), p)
2637 batching_challenge := mulmod(batching_challenge, rho, p)
2639 // 32: Z_PERM_EVAL_LOC
2641 BATCH_SCALAR_33_LOC,
2642 addmod(mload(BATCH_SCALAR_33_LOC), mulmod(neg_shifted_scalar, batching_challenge, p), p)
2644 batched_evaluation :=
2645 addmod(batched_evaluation, mulmod(mload(Z_PERM_SHIFT_EVAL_LOC), batching_challenge, p), p)
2646 batching_challenge := mulmod(batching_challenge, rho, p)
2648 mstore(BATCHED_EVALUATION_LOC, batched_evaluation)
2650 // Compute fold pos evaluations
2652 // TODO: work out the stack here
2653 mstore(CHALL_POW_LOC, POWERS_OF_EVALUATION_CHALLENGE_{{ LOG_N_MINUS_ONE }}_LOC)
2654 mstore(SUMCHECK_U_LOC, SUM_U_CHALLENGE_{{ LOG_N_MINUS_ONE }})
2655 mstore(GEMINI_A_LOC, GEMINI_A_EVAL_{{ LOG_N_MINUS_ONE }})
2656 // Inversion of this value was included in batch inversion above
2657 let inverted_chall_pow_minus_u_loc := INVERTED_CHALLENEGE_POW_MINUS_U_{{ LOG_N_MINUS_ONE }}_LOC
2658 let fold_pos_off := FOLD_POS_EVALUATIONS_{{ LOG_N_MINUS_ONE }}_LOC
2660 let batchedEvalAcc := batched_evaluation
2661 for { let i := LOG_N } gt(i, 0) { i := sub(i, 1) } {
2662 let chall_pow := mload(mload(CHALL_POW_LOC))
2663 let sum_check_u := mload(mload(SUMCHECK_U_LOC))
2665 // challengePower * batchedEvalAccumulator * 2
2666 let batchedEvalRoundAcc := mulmod(chall_pow, mulmod(batchedEvalAcc, 2, p), p)
2667 // (challengePower * (ONE - u) - u)
2668 let chall_pow_times_1_minus_u := mulmod(chall_pow, addmod(1, sub(p, sum_check_u), p), p)
2670 batchedEvalRoundAcc :=
2672 batchedEvalRoundAcc,
2676 mload(mload(GEMINI_A_LOC)), addmod(chall_pow_times_1_minus_u, sub(p, sum_check_u), p), p
2682 batchedEvalRoundAcc := mulmod(batchedEvalRoundAcc, mload(inverted_chall_pow_minus_u_loc), p)
2684 batchedEvalAcc := batchedEvalRoundAcc
2685 mstore(fold_pos_off, batchedEvalRoundAcc)
2687 mstore(CHALL_POW_LOC, sub(mload(CHALL_POW_LOC), 0x20))
2688 mstore(SUMCHECK_U_LOC, sub(mload(SUMCHECK_U_LOC), 0x20))
2689 mstore(GEMINI_A_LOC, sub(mload(GEMINI_A_LOC), 0x20))
2690 inverted_chall_pow_minus_u_loc := sub(inverted_chall_pow_minus_u_loc, 0x20)
2691 fold_pos_off := sub(fold_pos_off, 0x20)
2695 let constant_term_acc := mulmod(mload(FOLD_POS_EVALUATIONS_0_LOC), mload(POS_INVERTED_DENOM_0_LOC), p)
2697 let shplonk_nu := mload(SHPLONK_NU_CHALLENGE)
2699 constant_term_acc :=
2702 mulmod(mload(GEMINI_A_EVAL_0), mulmod(shplonk_nu, mload(NEG_INVERTED_DENOM_0_LOC), p), p),
2706 let shplonk_nu_sqr := mulmod(shplonk_nu, shplonk_nu, p)
2707 batching_challenge := shplonk_nu_sqr
2709 // TODO: improve scheduling
2710 mstore(SS_POS_INV_DENOM_LOC, POS_INVERTED_DENOM_1_LOC)
2711 mstore(SS_NEG_INV_DENOM_LOC, NEG_INVERTED_DENOM_1_LOC)
2713 mstore(SS_GEMINI_EVALS_LOC, GEMINI_A_EVAL_1)
2714 let fold_pos_evals_loc := FOLD_POS_EVALUATIONS_1_LOC
2716 let shplonk_z := mload(SHPLONK_Z_CHALLENGE)
2717 let scalars_loc := BATCH_SCALAR_37_LOC
2719 for { let i := 0 } lt(i, sub(LOG_N, 1)) { i := add(i, 1) } {
2720 let scaling_factor_pos := mulmod(batching_challenge, mload(mload(SS_POS_INV_DENOM_LOC)), p)
2721 let scaling_factor_neg :=
2722 mulmod(batching_challenge, mulmod(shplonk_nu, mload(mload(SS_NEG_INV_DENOM_LOC)), p), p)
2724 mstore(scalars_loc, addmod(sub(p, scaling_factor_neg), sub(p, scaling_factor_pos), p))
2726 let accum_contribution := mulmod(scaling_factor_neg, mload(mload(SS_GEMINI_EVALS_LOC)), p)
2727 accum_contribution :=
2728 addmod(accum_contribution, mulmod(scaling_factor_pos, mload(fold_pos_evals_loc), p), p)
2730 constant_term_acc := addmod(constant_term_acc, accum_contribution, p)
2732 batching_challenge := mulmod(batching_challenge, shplonk_nu_sqr, p)
2734 mstore(SS_POS_INV_DENOM_LOC, add(mload(SS_POS_INV_DENOM_LOC), 0x20))
2735 mstore(SS_NEG_INV_DENOM_LOC, add(mload(SS_NEG_INV_DENOM_LOC), 0x20))
2736 mstore(SS_GEMINI_EVALS_LOC, add(mload(SS_GEMINI_EVALS_LOC), 0x20))
2737 fold_pos_evals_loc := add(fold_pos_evals_loc, 0x20)
2738 scalars_loc := add(scalars_loc, 0x20)
2742 let precomp_success_flag := 1
2743 let q := Q // EC group order
2745 // The initial accumulator = 1 * shplonk_q
2746 // WORKTODO(md): we can ignore this accumulation as we are multiplying by 1,
2747 // Just set the accumulator instead.
2748 mstore(SCALAR_LOCATION, 0x1)
2750 let x := mload(SHPLONK_Q_X_LOC)
2751 let y := mload(SHPLONK_Q_Y_LOC)
2752 let xx := mulmod(x, x, q)
2753 // validate on curve
2754 precomp_success_flag :=
2755 and(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)), precomp_success_flag)
2757 mcopy(G1_LOCATION, SHPLONK_Q_X_LOC, 0x40)
2758 precomp_success_flag := staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR, 0x40)
2761 // Accumulate vk points
2764 // Acumulator = acumulator + scalar[1] * vk[0]
2765 mcopy(G1_LOCATION, Q_M_X_LOC, 0x40)
2766 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_1_LOC))
2767 precomp_success_flag :=
2768 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2769 precomp_success_flag :=
2770 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2772 // Accumulator = accumulator + scalar[2] * vk[1]
2773 mcopy(G1_LOCATION, Q_C_X_LOC, 0x40)
2774 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_2_LOC))
2775 precomp_success_flag :=
2776 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2777 precomp_success_flag :=
2778 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2780 // Accumulator = accumulator + scalar[3] * vk[2]
2781 mcopy(G1_LOCATION, Q_L_X_LOC, 0x40)
2782 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_3_LOC))
2783 precomp_success_flag :=
2784 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2785 precomp_success_flag :=
2786 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2788 // Accumulator = accumulator + scalar[4] * vk[3]
2789 mcopy(G1_LOCATION, Q_R_X_LOC, 0x40)
2790 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_4_LOC))
2791 precomp_success_flag :=
2792 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2793 precomp_success_flag :=
2794 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2796 // Accumulator = accumulator + scalar[5] * vk[4]
2797 mcopy(G1_LOCATION, Q_O_X_LOC, 0x40)
2798 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_5_LOC))
2799 precomp_success_flag :=
2800 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2801 precomp_success_flag :=
2802 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2804 // Accumulator = accumulator + scalar[6] * vk[5]
2805 mcopy(G1_LOCATION, Q_4_X_LOC, 0x40)
2806 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_6_LOC))
2807 precomp_success_flag :=
2808 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2809 precomp_success_flag :=
2810 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2812 // Accumulator = accumulator + scalar[7] * vk[6]
2813 mcopy(G1_LOCATION, Q_LOOKUP_X_LOC, 0x40)
2814 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_7_LOC))
2815 precomp_success_flag :=
2816 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2817 precomp_success_flag :=
2818 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2820 // Accumulator = accumulator + scalar[8] * vk[7]
2821 mcopy(G1_LOCATION, Q_ARITH_X_LOC, 0x40)
2822 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_8_LOC))
2823 precomp_success_flag :=
2824 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2825 precomp_success_flag :=
2826 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2828 // Accumulator = accumulator + scalar[9] * vk[8]
2829 mcopy(G1_LOCATION, Q_DELTA_RANGE_X_LOC, 0x40)
2830 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_9_LOC))
2831 precomp_success_flag :=
2832 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2833 precomp_success_flag :=
2834 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2836 // Accumulator = accumulator + scalar[10] * vk[9]
2837 mcopy(G1_LOCATION, Q_ELLIPTIC_X_LOC, 0x40)
2838 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_10_LOC))
2839 precomp_success_flag :=
2840 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2841 precomp_success_flag :=
2842 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2844 // Accumulator = accumulator + scalar[11] * vk[10]
2845 mcopy(G1_LOCATION, Q_MEMORY_X_LOC, 0x40)
2846 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_11_LOC))
2847 precomp_success_flag :=
2848 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2849 precomp_success_flag :=
2850 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2852 // Accumulator = accumulator + scalar[12] * vk[11]
2853 mcopy(G1_LOCATION, Q_NNF_X_LOC, 0x40)
2854 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_12_LOC))
2855 precomp_success_flag :=
2856 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2857 precomp_success_flag :=
2858 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2860 // Accumulator = accumulator + scalar[13] * vk[12]
2861 mcopy(G1_LOCATION, Q_POSEIDON_2_EXTERNAL_X_LOC, 0x40)
2862 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_13_LOC))
2863 precomp_success_flag :=
2864 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2865 precomp_success_flag :=
2866 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2868 // Accumulator = accumulator + scalar[14] * vk[13]
2869 mcopy(G1_LOCATION, Q_POSEIDON_2_INTERNAL_X_LOC, 0x40)
2870 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_14_LOC))
2871 precomp_success_flag :=
2872 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2873 precomp_success_flag :=
2874 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2876 // Accumulator = accumulator + scalar[15] * vk[14]
2877 mcopy(G1_LOCATION, SIGMA_1_X_LOC, 0x40)
2878 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_15_LOC))
2879 precomp_success_flag :=
2880 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2881 precomp_success_flag :=
2882 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2884 // Accumulator = accumulator + scalar[16] * vk[15]
2885 mcopy(G1_LOCATION, SIGMA_2_X_LOC, 0x40)
2886 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_16_LOC))
2887 precomp_success_flag :=
2888 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2889 precomp_success_flag :=
2890 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2892 // Accumulator = accumulator + scalar[17] * vk[16]
2893 mcopy(G1_LOCATION, SIGMA_3_X_LOC, 0x40)
2894 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_17_LOC))
2895 precomp_success_flag :=
2896 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2897 precomp_success_flag :=
2898 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2900 // Accumulator = accumulator + scalar[18] * vk[17]
2901 mcopy(G1_LOCATION, SIGMA_4_X_LOC, 0x40)
2902 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_18_LOC))
2903 precomp_success_flag :=
2904 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2905 precomp_success_flag :=
2906 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2908 // Accumulator = accumulator + scalar[19] * vk[18]
2909 mcopy(G1_LOCATION, ID_1_X_LOC, 0x40)
2910 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_19_LOC))
2911 precomp_success_flag :=
2912 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2913 precomp_success_flag :=
2914 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2916 // Accumulator = accumulator + scalar[20] * vk[19]
2917 mcopy(G1_LOCATION, ID_2_X_LOC, 0x40)
2918 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_20_LOC))
2919 precomp_success_flag :=
2920 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2921 precomp_success_flag :=
2922 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2924 // Accumulator = accumulator + scalar[21] * vk[20]
2925 mcopy(G1_LOCATION, ID_3_X_LOC, 0x40)
2926 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_21_LOC))
2927 precomp_success_flag :=
2928 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2929 precomp_success_flag :=
2930 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2932 // Accumulator = accumulator + scalar[22] * vk[21]
2933 mcopy(G1_LOCATION, ID_4_X_LOC, 0x40)
2934 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_22_LOC))
2935 precomp_success_flag :=
2936 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2937 precomp_success_flag :=
2938 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2940 // Accumulator = accumulator + scalar[23] * vk[22]
2941 mcopy(G1_LOCATION, TABLE_1_X_LOC, 0x40)
2942 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_23_LOC))
2943 precomp_success_flag :=
2944 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2945 precomp_success_flag :=
2946 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2948 // Accumulator = accumulator + scalar[24] * vk[23]
2949 mcopy(G1_LOCATION, TABLE_2_X_LOC, 0x40)
2950 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_24_LOC))
2951 precomp_success_flag :=
2952 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2953 precomp_success_flag :=
2954 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2956 // Accumulator = accumulator + scalar[25] * vk[24]
2957 mcopy(G1_LOCATION, TABLE_3_X_LOC, 0x40)
2958 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_25_LOC))
2959 precomp_success_flag :=
2960 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2961 precomp_success_flag :=
2962 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2964 // Accumulator = accumulator + scalar[26] * vk[25]
2965 mcopy(G1_LOCATION, TABLE_4_X_LOC, 0x40)
2966 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_26_LOC))
2967 precomp_success_flag :=
2968 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2969 precomp_success_flag :=
2970 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2972 // Accumulator = accumulator + scalar[27] * vk[26]
2973 mcopy(G1_LOCATION, LAGRANGE_FIRST_X_LOC, 0x40)
2974 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_27_LOC))
2975 precomp_success_flag :=
2976 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2977 precomp_success_flag :=
2978 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2980 // Accumulator = accumulator + scalar[28] * vk[27]
2981 mcopy(G1_LOCATION, LAGRANGE_LAST_X_LOC, 0x40)
2982 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_28_LOC))
2983 precomp_success_flag :=
2984 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
2985 precomp_success_flag :=
2986 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
2989 let x := mload(W_L_X_LOC)
2990 let y := mload(W_L_Y_LOC)
2991 let xx := mulmod(x, x, q)
2992 // validate on curve
2993 precomp_success_flag :=
2994 and(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)), precomp_success_flag)
2997 // Accumulate proof points
2998 // Accumulator = accumulator + scalar[29] * w_l
2999 mcopy(G1_LOCATION, W_L_X_LOC, 0x40)
3000 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_29_LOC))
3001 precomp_success_flag :=
3002 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
3003 precomp_success_flag :=
3004 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
3007 let x := mload(W_R_X_LOC)
3008 let y := mload(W_R_Y_LOC)
3009 let xx := mulmod(x, x, q)
3010 // validate on curve
3011 precomp_success_flag :=
3012 and(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)), precomp_success_flag)
3015 // Accumulator = accumulator + scalar[30] * w_r
3016 mcopy(G1_LOCATION, W_R_X_LOC, 0x40)
3017 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_30_LOC))
3018 precomp_success_flag :=
3019 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
3020 precomp_success_flag :=
3021 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
3024 let x := mload(W_O_X_LOC)
3025 let y := mload(W_O_Y_LOC)
3026 let xx := mulmod(x, x, q)
3027 // validate on curve
3028 precomp_success_flag :=
3029 and(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)), precomp_success_flag)
3032 // Accumulator = accumulator + scalar[31] * w_o
3033 mcopy(G1_LOCATION, W_O_X_LOC, 0x40)
3034 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_31_LOC))
3035 precomp_success_flag :=
3036 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
3037 precomp_success_flag :=
3038 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
3040 // Accumulator = accumulator + scalar[32] * w_4
3042 let x := mload(W_4_X_LOC)
3043 let y := mload(W_4_Y_LOC)
3044 let xx := mulmod(x, x, q)
3045 // validate on curve
3046 precomp_success_flag :=
3047 and(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)), precomp_success_flag)
3049 mcopy(G1_LOCATION, W_4_X_LOC, 0x40)
3050 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_32_LOC))
3051 precomp_success_flag :=
3052 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
3053 precomp_success_flag :=
3054 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
3057 let x := mload(Z_PERM_X_LOC)
3058 let y := mload(Z_PERM_Y_LOC)
3059 let xx := mulmod(x, x, q)
3060 // validate on curve
3061 precomp_success_flag :=
3062 and(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)), precomp_success_flag)
3064 // Accumulator = accumulator + scalar[33] * z_perm
3065 mcopy(G1_LOCATION, Z_PERM_X_LOC, 0x40)
3066 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_33_LOC))
3067 precomp_success_flag :=
3068 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
3069 precomp_success_flag :=
3070 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
3073 let x := mload(LOOKUP_INVERSES_X_LOC)
3074 let y := mload(LOOKUP_INVERSES_Y_LOC)
3075 let xx := mulmod(x, x, q)
3076 // validate on curve
3077 precomp_success_flag :=
3078 and(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)), precomp_success_flag)
3080 // Accumulator = accumulator + scalar[34] * lookup_inverses
3081 mcopy(G1_LOCATION, LOOKUP_INVERSES_X_LOC, 0x40)
3082 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_34_LOC))
3083 precomp_success_flag :=
3084 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
3085 precomp_success_flag :=
3086 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
3089 let x := mload(LOOKUP_READ_COUNTS_X_LOC)
3090 let y := mload(LOOKUP_READ_COUNTS_Y_LOC)
3091 let xx := mulmod(x, x, q)
3092 // validate on curve
3093 precomp_success_flag :=
3094 and(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)), precomp_success_flag)
3096 // Accumulator = accumulator + scalar[35] * lookup_read_counts
3097 mcopy(G1_LOCATION, LOOKUP_READ_COUNTS_X_LOC, 0x40)
3098 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_35_LOC))
3099 precomp_success_flag :=
3100 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
3101 precomp_success_flag :=
3102 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
3105 let x := mload(LOOKUP_READ_TAGS_X_LOC)
3106 let y := mload(LOOKUP_READ_TAGS_Y_LOC)
3107 let xx := mulmod(x, x, q)
3108 // validate on curve
3109 precomp_success_flag :=
3110 and(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)), precomp_success_flag)
3112 // Accumulator = accumulator + scalar[36] * lookup_read_tags
3113 mcopy(G1_LOCATION, LOOKUP_READ_TAGS_X_LOC, 0x40)
3114 mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_36_LOC))
3115 precomp_success_flag :=
3116 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
3117 precomp_success_flag :=
3118 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
3120 // Accumulate these LOG_N scalars with the gemini fold univariates
3129 // Accumulate the constant term accumulator
3130 // Accumulator = accumulator + 1 * costant term accumulator
3131 mstore(G1_LOCATION, 0x01)
3132 mstore(G1_Y_LOCATION, 0x02)
3133 mstore(SCALAR_LOCATION, constant_term_acc)
3134 precomp_success_flag :=
3135 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
3136 precomp_success_flag :=
3137 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
3139 // Accumlate final quotient commitment into shplonk check
3140 // Accumulator = accumulator + shplonkZ * quotient commitment
3142 let x := mload(KZG_QUOTIENT_X_LOC)
3143 let y := mload(KZG_QUOTIENT_Y_LOC)
3144 let xx := mulmod(x, x, q)
3145 // validate on curve
3146 precomp_success_flag :=
3147 and(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)), precomp_success_flag)
3149 mcopy(G1_LOCATION, KZG_QUOTIENT_X_LOC, 0x40)
3151 mstore(SCALAR_LOCATION, mload(SHPLONK_Z_CHALLENGE))
3152 precomp_success_flag :=
3153 and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, ACCUMULATOR_2, 0x40))
3154 precomp_success_flag :=
3155 and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, ACCUMULATOR, 0x40))
3158 if iszero(precomp_success_flag) {
3159 mstore(0x00, BATCH_ACCUMULATION_FAILED_SELECTOR)
3163 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
3164 /* SHPLEMINI - complete */
3165 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
3167 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
3169 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
3172 mstore(0xc0, mload(KZG_QUOTIENT_X_LOC))
3173 mstore(0xe0, sub(q, mload(KZG_QUOTIENT_Y_LOC)))
3178 mcopy(0x80, ACCUMULATOR, 0x40)
3180 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
3181 /* PAIRING AGGREGATION */
3182 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
3183 // Read the pairing encoded in the first 16 field elements of the proof
3184 let p0_other_x := mload(PAIRING_POINT_0)
3185 p0_other_x := or(shl(68, mload(PAIRING_POINT_1)), p0_other_x)
3186 p0_other_x := or(shl(136, mload(PAIRING_POINT_2)), p0_other_x)
3187 p0_other_x := or(shl(204, mload(PAIRING_POINT_3)), p0_other_x)
3189 let p0_other_y := mload(PAIRING_POINT_4)
3190 p0_other_y := or(shl(68, mload(PAIRING_POINT_5)), p0_other_y)
3191 p0_other_y := or(shl(136, mload(PAIRING_POINT_6)), p0_other_y)
3192 p0_other_y := or(shl(204, mload(PAIRING_POINT_7)), p0_other_y)
3194 let p1_other_x := mload(PAIRING_POINT_8)
3195 p1_other_x := or(shl(68, mload(PAIRING_POINT_9)), p1_other_x)
3196 p1_other_x := or(shl(136, mload(PAIRING_POINT_10)), p1_other_x)
3197 p1_other_x := or(shl(204, mload(PAIRING_POINT_11)), p1_other_x)
3199 let p1_other_y := mload(PAIRING_POINT_12)
3200 p1_other_y := or(shl(68, mload(PAIRING_POINT_13)), p1_other_y)
3201 p1_other_y := or(shl(136, mload(PAIRING_POINT_14)), p1_other_y)
3202 p1_other_y := or(shl(204, mload(PAIRING_POINT_15)), p1_other_y)
3204 // Validate p_0_other on curve
3205 let xx := mulmod(p0_other_x, p0_other_x, q)
3206 let xxx := mulmod(xx, p0_other_x, q)
3207 let yy := mulmod(p0_other_y, p0_other_y, q)
3209 let success := eq(yy, addmod(xxx, 3, q))
3211 // Validate p_1_other on curve
3212 xx := mulmod(p1_other_x, p1_other_x, q)
3213 xxx := mulmod(xx, p1_other_x, q)
3214 yy := mulmod(p1_other_y, p1_other_y, q)
3216 success := and(success, eq(yy, addmod(xxx, 3, q)))
3219 mstore(0x00, p0_other_x)
3220 mstore(0x20, p0_other_y)
3223 mstore(0x40, p1_other_x)
3224 mstore(0x60, p1_other_y)
3226 // p_1_agg is already in the correct location
3228 let recursion_separator := keccak256(0x00, 0x100)
3230 // Write separator back to scratch space
3231 mstore(0x00, p0_other_x)
3233 mstore(0x40, recursion_separator)
3234 // recursion_separator * p_0_other
3235 success := and(success, staticcall(gas(), 0x07, 0x00, 0x60, 0x00, 0x40))
3237 // (recursion_separator * p_0_other) + p_0_agg
3238 mcopy(0x40, 0x80, 0x40)
3239 // p_0 = (recursion_separator * p_0_other) + p_0_agg
3240 success := and(success, staticcall(gas(), 6, 0x00, 0x80, 0x00, 0x40))
3242 mstore(0x40, p1_other_x)
3243 mstore(0x60, p1_other_y)
3244 mstore(0x80, recursion_separator)
3246 success := and(success, staticcall(gas(), 7, 0x40, 0x60, 0x40, 0x40))
3248 // Write p_1_agg back to scratch space
3249 mcopy(0x80, 0xc0, 0x40)
3251 // 0xc0 - (recursion_separator * p_1_other) + p_1_agg
3252 success := and(success, staticcall(gas(), 6, 0x40, 0x80, 0xc0, 0x40))
3255 mstore(0x40, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2)
3256 mstore(0x60, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed)
3257 mstore(0x80, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b)
3258 mstore(0xa0, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa)
3261 mstore(0x100, 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1)
3262 mstore(0x120, 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0)
3263 mstore(0x140, 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4)
3264 mstore(0x160, 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55)
3266 let pairing_success := and(success, staticcall(gas(), 8, 0x00, 0x180, 0x00, 0x20))
3267 if iszero(and(pairing_success, mload(0x00))) {
3268 mstore(0x00, PAIRING_FAILED_SELECTOR)
3272 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
3273 /* PAIRING CHECK - Complete */
3274 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
3278 return(0x00, 0x20) // Proof succeeded!
3288 std::ostringstream os;
3295 std::ostringstream os;
3302 std::string template_str = HONK_CONTRACT_OPT_SOURCE;
3305 auto set_template_param = [&template_str](
const std::string&
key,
const std::string&
value) {
3306 std::string::size_type pos = 0;
3307 std::string pattern =
"{{ " +
key +
" }}";
3308 while ((pos = template_str.find(pattern, pos)) != std::string::npos) {
3309 template_str.replace(pos, pattern.length(),
value);
3310 pos +=
value.length();
3314 set_template_param(
"VK_HASH",
field_to_hex(verification_key->hash()));
3315 set_template_param(
"CIRCUIT_SIZE",
std::to_string(1 << verification_key->log_circuit_size));
3316 set_template_param(
"LOG_CIRCUIT_SIZE",
std::to_string(verification_key->log_circuit_size));
3317 set_template_param(
"NUM_PUBLIC_INPUTS",
std::to_string(verification_key->num_public_inputs));
3318 set_template_param(
"LOG_N_MINUS_ONE",
std::to_string(verification_key->log_circuit_size - 1));
3319 set_template_param(
"NUMBER_OF_BARYCENTRIC_INVERSES",
std::to_string(verification_key->log_circuit_size * 8));
3321 uint32_t gemini_fold_univariate_length =
static_cast<uint32_t
>((verification_key->log_circuit_size - 1) * 0x40);
3322 uint32_t gemini_fold_univariate_hash_length =
static_cast<uint32_t
>(gemini_fold_univariate_length + 0x20);
3323 uint32_t gemini_evals_length =
static_cast<uint32_t
>(verification_key->log_circuit_size * 0x20);
3324 uint32_t gemini_evals_hash_length =
static_cast<uint32_t
>(gemini_evals_length + 0x20);
3326 set_template_param(
"GEMINI_FOLD_UNIVARIATE_LENGTH",
int_to_hex(gemini_fold_univariate_length));
3327 set_template_param(
"GEMINI_FOLD_UNIVARIATE_HASH_LENGTH",
int_to_hex(gemini_fold_univariate_hash_length));
3328 set_template_param(
"GEMINI_EVALS_LENGTH",
int_to_hex(gemini_evals_length));
3329 set_template_param(
"GEMINI_EVALS_HASH_LENGTH",
int_to_hex(gemini_evals_hash_length));
3332 set_template_param(
"Q_L_X_LOC",
field_to_hex(verification_key->q_l.x));
3333 set_template_param(
"Q_L_Y_LOC",
field_to_hex(verification_key->q_l.y));
3334 set_template_param(
"Q_R_X_LOC",
field_to_hex(verification_key->q_r.x));
3335 set_template_param(
"Q_R_Y_LOC",
field_to_hex(verification_key->q_r.y));
3336 set_template_param(
"Q_O_X_LOC",
field_to_hex(verification_key->q_o.x));
3337 set_template_param(
"Q_O_Y_LOC",
field_to_hex(verification_key->q_o.y));
3338 set_template_param(
"Q_4_X_LOC",
field_to_hex(verification_key->q_4.x));
3339 set_template_param(
"Q_4_Y_LOC",
field_to_hex(verification_key->q_4.y));
3340 set_template_param(
"Q_M_X_LOC",
field_to_hex(verification_key->q_m.x));
3341 set_template_param(
"Q_M_Y_LOC",
field_to_hex(verification_key->q_m.y));
3342 set_template_param(
"Q_C_X_LOC",
field_to_hex(verification_key->q_c.x));
3343 set_template_param(
"Q_C_Y_LOC",
field_to_hex(verification_key->q_c.y));
3344 set_template_param(
"Q_LOOKUP_X_LOC",
field_to_hex(verification_key->q_lookup.x));
3345 set_template_param(
"Q_LOOKUP_Y_LOC",
field_to_hex(verification_key->q_lookup.y));
3346 set_template_param(
"Q_ARITH_X_LOC",
field_to_hex(verification_key->q_arith.x));
3347 set_template_param(
"Q_ARITH_Y_LOC",
field_to_hex(verification_key->q_arith.y));
3348 set_template_param(
"Q_DELTA_RANGE_X_LOC",
field_to_hex(verification_key->q_delta_range.x));
3349 set_template_param(
"Q_DELTA_RANGE_Y_LOC",
field_to_hex(verification_key->q_delta_range.y));
3350 set_template_param(
"Q_ELLIPTIC_X_LOC",
field_to_hex(verification_key->q_elliptic.x));
3351 set_template_param(
"Q_ELLIPTIC_Y_LOC",
field_to_hex(verification_key->q_elliptic.y));
3352 set_template_param(
"Q_MEMORY_X_LOC",
field_to_hex(verification_key->q_memory.x));
3353 set_template_param(
"Q_MEMORY_Y_LOC",
field_to_hex(verification_key->q_memory.y));
3354 set_template_param(
"Q_NNF_X_LOC",
field_to_hex(verification_key->q_nnf.x));
3355 set_template_param(
"Q_NNF_Y_LOC",
field_to_hex(verification_key->q_nnf.y));
3356 set_template_param(
"Q_POSEIDON_2_EXTERNAL_X_LOC",
field_to_hex(verification_key->q_poseidon2_external.x));
3357 set_template_param(
"Q_POSEIDON_2_EXTERNAL_Y_LOC",
field_to_hex(verification_key->q_poseidon2_external.y));
3358 set_template_param(
"Q_POSEIDON_2_INTERNAL_X_LOC",
field_to_hex(verification_key->q_poseidon2_internal.x));
3359 set_template_param(
"Q_POSEIDON_2_INTERNAL_Y_LOC",
field_to_hex(verification_key->q_poseidon2_internal.y));
3360 set_template_param(
"SIGMA_1_X_LOC",
field_to_hex(verification_key->sigma_1.x));
3361 set_template_param(
"SIGMA_1_Y_LOC",
field_to_hex(verification_key->sigma_1.y));
3362 set_template_param(
"SIGMA_2_X_LOC",
field_to_hex(verification_key->sigma_2.x));
3363 set_template_param(
"SIGMA_2_Y_LOC",
field_to_hex(verification_key->sigma_2.y));
3364 set_template_param(
"SIGMA_3_X_LOC",
field_to_hex(verification_key->sigma_3.x));
3365 set_template_param(
"SIGMA_3_Y_LOC",
field_to_hex(verification_key->sigma_3.y));
3366 set_template_param(
"SIGMA_4_X_LOC",
field_to_hex(verification_key->sigma_4.x));
3367 set_template_param(
"SIGMA_4_Y_LOC",
field_to_hex(verification_key->sigma_4.y));
3368 set_template_param(
"TABLE_1_X_LOC",
field_to_hex(verification_key->table_1.x));
3369 set_template_param(
"TABLE_1_Y_LOC",
field_to_hex(verification_key->table_1.y));
3370 set_template_param(
"TABLE_2_X_LOC",
field_to_hex(verification_key->table_2.x));
3371 set_template_param(
"TABLE_2_Y_LOC",
field_to_hex(verification_key->table_2.y));
3372 set_template_param(
"TABLE_3_X_LOC",
field_to_hex(verification_key->table_3.x));
3373 set_template_param(
"TABLE_3_Y_LOC",
field_to_hex(verification_key->table_3.y));
3374 set_template_param(
"TABLE_4_X_LOC",
field_to_hex(verification_key->table_4.x));
3375 set_template_param(
"TABLE_4_Y_LOC",
field_to_hex(verification_key->table_4.y));
3376 set_template_param(
"ID_1_X_LOC",
field_to_hex(verification_key->id_1.x));
3377 set_template_param(
"ID_1_Y_LOC",
field_to_hex(verification_key->id_1.y));
3378 set_template_param(
"ID_2_X_LOC",
field_to_hex(verification_key->id_2.x));
3379 set_template_param(
"ID_2_Y_LOC",
field_to_hex(verification_key->id_2.y));
3380 set_template_param(
"ID_3_X_LOC",
field_to_hex(verification_key->id_3.x));
3381 set_template_param(
"ID_3_Y_LOC",
field_to_hex(verification_key->id_3.y));
3382 set_template_param(
"ID_4_X_LOC",
field_to_hex(verification_key->id_4.x));
3383 set_template_param(
"ID_4_Y_LOC",
field_to_hex(verification_key->id_4.y));
3384 set_template_param(
"LAGRANGE_FIRST_X_LOC",
field_to_hex(verification_key->lagrange_first.x));
3385 set_template_param(
"LAGRANGE_FIRST_Y_LOC",
field_to_hex(verification_key->lagrange_first.y));
3386 set_template_param(
"LAGRANGE_LAST_X_LOC",
field_to_hex(verification_key->lagrange_last.x));
3387 set_template_param(
"LAGRANGE_LAST_Y_LOC",
field_to_hex(verification_key->lagrange_last.y));
3390 auto generate_unroll_section = [](
const std::string& section_name,
auto log_n) {
3391 std::ostringstream code;
3393 if (section_name ==
"ACCUMULATE_INVERSES") {
3395 for (
int i = 0; i < log_n; ++i) {
3396 code <<
" // i = " << i <<
"\n";
3397 code <<
" mstore(TEMP_" << i <<
"_LOC, accumulator)\n";
3398 code <<
" accumulator := mulmod(accumulator, mload(INVERTED_CHALLENEGE_POW_MINUS_U_" << i
3402 code <<
"\n // Accumulate pos inverted denom\n";
3403 int temp_idx = log_n;
3404 for (
int i = 0; i < log_n; ++i) {
3405 code <<
" // i = " << i <<
"\n";
3406 code <<
" mstore(TEMP_" << temp_idx <<
"_LOC, accumulator)\n";
3407 code <<
" accumulator := mulmod(accumulator, mload(POS_INVERTED_DENOM_" << i
3412 code <<
"\n // Accumulate neg inverted denom\n";
3413 for (
int i = 0; i < log_n; ++i) {
3414 code <<
" // i = " << i <<
"\n";
3415 code <<
" mstore(TEMP_" << temp_idx <<
"_LOC, accumulator)\n";
3416 code <<
" accumulator := mulmod(accumulator, mload(NEG_INVERTED_DENOM_" << i
3420 }
else if (section_name ==
"COLLECT_INVERSES") {
3421 int temp_idx = 3 * log_n - 1;
3424 code <<
" // i = " << log_n <<
"\n";
3425 for (
int i = log_n - 1; i >= 0; --i) {
3427 code <<
" let tmp := mulmod(accumulator, mload(TEMP_" << temp_idx <<
"_LOC), p)\n";
3428 code <<
" accumulator := mulmod(accumulator, mload(NEG_INVERTED_DENOM_" << i
3430 code <<
" mstore(NEG_INVERTED_DENOM_" << i <<
"_LOC, tmp)\n";
3433 code <<
" // i = " << i <<
"\n";
3438 code <<
"\n // Unrolled for LOG_N = " << log_n <<
"\n";
3439 code <<
" // i = " << log_n <<
"\n";
3442 for (
int i = log_n - 1; i >= 0; --i) {
3444 code <<
" let tmp := mulmod(accumulator, mload(TEMP_" << temp_idx <<
"_LOC), p)\n";
3445 code <<
" accumulator := mulmod(accumulator, mload(POS_INVERTED_DENOM_" << i
3447 code <<
" mstore(POS_INVERTED_DENOM_" << i <<
"_LOC, tmp)\n";
3450 code <<
" // i = " << i <<
"\n";
3455 code <<
"\n // i = " << log_n <<
"\n";
3458 for (
int i = log_n - 1; i >= 0; --i) {
3460 code <<
" let tmp := mulmod(accumulator, mload(TEMP_" << temp_idx <<
"_LOC), p)\n";
3461 code <<
" accumulator := mulmod(accumulator, mload(INVERTED_CHALLENEGE_POW_MINUS_U_" << i
3463 code <<
" mstore(INVERTED_CHALLENEGE_POW_MINUS_U_" << i <<
"_LOC, tmp)\n";
3466 code <<
" // i = " << i <<
"\n";
3470 }
else if (section_name ==
"ACCUMULATE_GEMINI_FOLD_UNIVARIATE") {
3473 for (
int i = 0; i < log_n - 1; ++i) {
3476 code <<
" let x := mload(GEMINI_FOLD_UNIVARIATE_" << i <<
"_X_LOC)\n";
3477 code <<
" let y := mload(GEMINI_FOLD_UNIVARIATE_" << i <<
"_Y_LOC)\n";
3478 code <<
" let xx := mulmod(x, x, q)\n";
3479 code <<
" // validate on curve\n";
3480 code <<
" precomp_success_flag := and(eq(mulmod(y, y, q), addmod(mulmod(x, "
3481 "xx, q), 3, q)), precomp_success_flag)\n";
3483 code <<
" mcopy(G1_LOCATION, GEMINI_FOLD_UNIVARIATE_" << i <<
"_X_LOC, 0x40)\n";
3484 code <<
" mstore(SCALAR_LOCATION, mload(BATCH_SCALAR_" << (37 + i) <<
"_LOC))\n";
3485 code <<
" precomp_success_flag :=\n";
3486 code <<
" and(precomp_success_flag, staticcall(gas(), 7, G1_LOCATION, 0x60, "
3487 "ACCUMULATOR_2, 0x40))\n";
3488 code <<
" precomp_success_flag :=\n";
3489 code <<
" and(precomp_success_flag, staticcall(gas(), 6, ACCUMULATOR, 0x80, "
3490 "ACCUMULATOR, 0x40))\n";
3491 if (i < log_n - 2) {
3495 }
else if (section_name ==
"GEMINI_FOLD_UNIVARIATE_ON_CURVE") {
3498 for (
int i = 0; i < log_n - 1; ++i) {
3499 code <<
" success_flag := and(success_flag, "
3500 "validateProofPointOnCurve(GEMINI_FOLD_UNIVARIATE_"
3501 << i <<
"_X_LOC, q))\n";
3509 int log_n =
static_cast<int>(verification_key->log_circuit_size);
3513 std::string::size_type start_pos = template_str.find(
"/// {{ UNROLL_SECTION_START ACCUMULATE_INVERSES }}");
3514 std::string::size_type end_pos = template_str.find(
"/// {{UNROLL_SECTION_END ACCUMULATE_INVERSES }}");
3515 if (start_pos != std::string::npos && end_pos != std::string::npos) {
3516 std::string::size_type start_line_end = template_str.find(
"\n", start_pos);
3517 std::string generated_code = generate_unroll_section(
"ACCUMULATE_INVERSES", log_n);
3518 template_str = template_str.substr(0, start_line_end + 1) + generated_code + template_str.substr(end_pos);
3524 std::string::size_type start_pos = template_str.find(
"// {{ UNROLL_SECTION_START COLLECT_INVERSES }}");
3525 std::string::size_type end_pos = template_str.find(
"// {{ UNROLL_SECTION_END COLLECT_INVERSES }}");
3526 if (start_pos != std::string::npos && end_pos != std::string::npos) {
3527 std::string::size_type start_line_end = template_str.find(
"\n", start_pos);
3528 std::string generated_code = generate_unroll_section(
"COLLECT_INVERSES", log_n);
3529 template_str = template_str.substr(0, start_line_end + 1) + generated_code + template_str.substr(end_pos);
3535 std::string::size_type start_pos =
3536 template_str.find(
"/// {{ UNROLL_SECTION_START ACCUMULATE_GEMINI_FOLD_UNIVARIATE }}");
3537 std::string::size_type end_pos =
3538 template_str.find(
"/// {{ UNROLL_SECTION_END ACCUMULATE_GEMINI_FOLD_UNIVARIATE }}");
3539 if (start_pos != std::string::npos && end_pos != std::string::npos) {
3540 std::string::size_type start_line_end = template_str.find(
"\n", start_pos);
3541 std::string generated_code = generate_unroll_section(
"ACCUMULATE_GEMINI_FOLD_UNIVARIATE", log_n);
3542 template_str = template_str.substr(0, start_line_end + 1) + generated_code + template_str.substr(end_pos);
3548 std::string::size_type start_pos =
3549 template_str.find(
"/// {{ UNROLL_SECTION_START GEMINI_FOLD_UNIVARIATE_ON_CURVE }}");
3550 std::string::size_type end_pos =
3551 template_str.find(
"/// {{ UNROLL_SECTION_END GEMINI_FOLD_UNIVARIATE_ON_CURVE }}");
3552 if (start_pos != std::string::npos && end_pos != std::string::npos) {
3553 std::string::size_type start_line_end = template_str.find(
"\n", start_pos);
3554 std::string generated_code = generate_unroll_section(
"GEMINI_FOLD_UNIVARIATE_ON_CURVE", log_n);
3555 template_str = template_str.substr(0, start_line_end + 1) + generated_code + template_str.substr(end_pos);
3561 std::string::size_type start_pos = template_str.find(
"// {{ SECTION_START MEMORY_LAYOUT }}");
3562 std::string::size_type end_pos = template_str.find(
"// {{ SECTION_END MEMORY_LAYOUT }}");
3563 if (start_pos != std::string::npos && end_pos != std::string::npos) {
3564 std::string::size_type start_line_end = template_str.find(
"\n", start_pos);
3566 template_str = template_str.substr(0, start_line_end + 1) + generated_code + template_str.substr(end_pos);
3570 return template_str;
std::string field_to_hex(const Field &f)
std::string get_optimized_honk_solidity_verifier(auto const &verification_key)
std::string generate_memory_offsets(int log_n)
std::string int_to_hex(size_t i)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
std::string to_string(bb::avm2::ValueTag tag)