190 const std::string& section_name,
194 std::string start_marker =
"/// {{ UNROLL_SECTION_START " + section_name +
" }}";
195 std::string end_marker =
"/// {{ UNROLL_SECTION_END " + section_name +
" }}";
196 std::string::size_type start_pos = template_str.find(start_marker);
197 std::string::size_type end_pos = template_str.find(end_marker);
200 if (start_pos == std::string::npos || end_pos == std::string::npos) {
201 info(
"Missing unroll markers for section: " + section_name);
205 if (start_pos != std::string::npos && end_pos != std::string::npos) {
206 std::string::size_type start_line_end = template_str.find(
"\n", start_pos);
208 template_str = template_str.substr(0, start_line_end + 1) + generated_code + template_str.substr(end_pos);
224 const int NUMBER_OF_SUBRELATIONS = 31;
225 const int NUMBER_OF_ALPHAS = NUMBER_OF_SUBRELATIONS - 1;
226 const int START_POINTER = 0x1000;
228 std::ostringstream
out;
231 auto print_header_centered = [&](
const std::string& text) {
232 const std::string top =
"/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/";
233 const std::string bottom =
"/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/";
234 size_t width =
static_cast<size_t>(top.length()) - 4;
235 std::string centered =
236 "/*" + std::string(
static_cast<size_t>((width - text.length()) / 2),
' ') + text +
237 std::string(
static_cast<size_t>(width - text.length() - (width - text.length()) / 2),
' ') +
"*/";
238 out <<
"\n" << top <<
"\n" << centered <<
"\n" << bottom <<
"\n";
241 auto print_loc = [&](
int pointer,
const std::string&
name) {
245 auto print_fr = print_loc;
247 auto print_g1 = [&](
int pointer,
const std::string&
name) {
248 print_loc(pointer,
name +
"_X_LOC");
249 print_loc(pointer + 32,
name +
"_Y_LOC");
253 const std::vector<std::string> vk_fr = {
"VK_CIRCUIT_SIZE_LOC",
254 "VK_NUM_PUBLIC_INPUTS_LOC",
255 "VK_PUB_INPUTS_OFFSET_LOC" };
257 const std::vector<std::string> vk_g1 = {
"Q_M",
283 "Q_POSEIDON_2_EXTERNAL",
284 "Q_POSEIDON_2_INTERNAL" };
286 const std::vector<std::string> pairing_points = {
"PAIRING_POINT_0_X_0_LOC",
"PAIRING_POINT_0_X_1_LOC",
287 "PAIRING_POINT_0_Y_0_LOC",
"PAIRING_POINT_0_Y_1_LOC",
288 "PAIRING_POINT_1_X_0_LOC",
"PAIRING_POINT_1_X_1_LOC",
289 "PAIRING_POINT_1_Y_0_LOC",
"PAIRING_POINT_1_Y_1_LOC" };
291 const std::vector<std::string> proof_g1 = {
292 "W_L",
"W_R",
"W_O",
"LOOKUP_READ_COUNTS",
"LOOKUP_READ_TAGS",
"W_4",
"LOOKUP_INVERSES",
"Z_PERM"
295 const std::vector<std::string> entities = {
"SIGMA1",
321 "QPOSEIDON2_EXTERNAL",
322 "QPOSEIDON2_INTERNAL",
329 "LOOKUP_READ_COUNTS",
337 const std::vector<std::string> challenges = {
"ETA",
347 "PUBLIC_INPUTS_DELTA_NUMERATOR",
348 "PUBLIC_INPUTS_DELTA_DENOMINATOR" };
350 const std::vector<std::string> subrelation_intermediates = {
"AUX_NON_NATIVE_FIELD_IDENTITY",
351 "AUX_LIMB_ACCUMULATOR_IDENTITY",
352 "AUX_RAM_CONSISTENCY_CHECK_IDENTITY",
353 "AUX_ROM_CONSISTENCY_CHECK_IDENTITY",
354 "AUX_MEMORY_CHECK_IDENTITY" };
356 const std::vector<std::string> general_intermediates = {
"FINAL_ROUND_TARGET_LOC",
"POW_PARTIAL_EVALUATION_LOC" };
358 int pointer = START_POINTER;
361 print_header_centered(
"VK INDICIES");
362 for (
const auto& item : vk_fr) {
363 print_fr(pointer, item);
366 for (
const auto& item : vk_g1) {
367 print_g1(pointer, item);
372 print_header_centered(
"PROOF INDICIES");
373 for (
const auto& item : pairing_points) {
374 print_fr(pointer, item);
380 print_g1(pointer,
"GEMINI_MASKING_POLY");
384 for (
const auto& item : proof_g1) {
385 print_g1(pointer, item);
391 print_g1(pointer,
"LIBRA_CONCAT");
393 print_fr(pointer,
"LIBRA_SUM_LOC");
398 print_header_centered(
"PROOF INDICIES - SUMCHECK UNIVARIATES");
399 for (
int size = 0; size < log_n; ++size) {
403 print_fr(pointer,
name);
409 print_header_centered(
"PROOF INDICIES - SUMCHECK EVALUATIONS");
413 print_fr(pointer,
"GEMINI_MASKING_EVAL_LOC");
417 for (
const auto& entity : entities) {
418 print_fr(pointer, entity +
"_EVAL_LOC");
424 print_fr(pointer,
"LIBRA_EVALUATION_LOC");
426 print_g1(pointer,
"LIBRA_GRAND_PRODUCT");
428 print_g1(pointer,
"LIBRA_QUOTIENT");
433 print_header_centered(
"PROOF INDICIES - GEMINI FOLDING COMMS");
434 for (
int size = 0; size < log_n - 1; ++size) {
435 print_g1(pointer,
"GEMINI_FOLD_UNIVARIATE_" +
std::to_string(size));
440 print_header_centered(
"PROOF INDICIES - GEMINI FOLDING EVALUATIONS");
441 for (
int size = 0; size < log_n; ++size) {
448 print_header_centered(
"PROOF INDICIES - LIBRA POLY EVALUATIONS");
449 for (
int i = 0; i < 4; ++i) {
450 print_fr(pointer,
"LIBRA_POLY_EVAL_" +
std::to_string(i) +
"_LOC");
455 print_g1(pointer,
"SHPLONK_Q");
457 print_g1(pointer,
"KZG_QUOTIENT");
460 print_header_centered(
"PROOF INDICIES - COMPLETE");
463 print_header_centered(
"CHALLENGES");
464 for (
const auto& chall : challenges) {
465 print_fr(pointer, chall +
"_CHALLENGE");
468 for (
int alpha = 0; alpha < NUMBER_OF_ALPHAS; ++alpha) {
472 for (
int gate = 0; gate < log_n; ++gate) {
479 print_fr(pointer,
"LIBRA_CHALLENGE");
483 for (
int sum_u = 0; sum_u < log_n; ++sum_u) {
487 print_header_centered(
"CHALLENGES - COMPLETE");
490 print_header_centered(
"SUMCHECK - RUNTIME MEMORY");
491 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - BARYCENTRIC");
495 print_fr(pointer,
"BARYCENTRIC_LAGRANGE_DENOMINATOR_" +
std::to_string(i) +
"_LOC");
498 for (
int i = 0; i < log_n; ++i) {
505 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - BARYCENTRIC COMPLETE");
508 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - SUBRELATION EVALUATIONS");
509 for (
int i = 0; i < NUMBER_OF_SUBRELATIONS; ++i) {
510 print_fr(pointer,
"SUBRELATION_EVAL_" +
std::to_string(i) +
"_LOC");
513 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - SUBRELATION EVALUATIONS COMPLETE");
516 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - SUBRELATION INTERMEDIATES");
517 for (
const auto& item : general_intermediates) {
518 print_fr(pointer, item);
521 for (
const auto& item : subrelation_intermediates) {
522 print_fr(pointer, item);
525 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - COMPLETE");
528 print_header_centered(
"SHPLEMINI - RUNTIME MEMORY");
529 print_header_centered(
"SHPLEMINI - POWERS OF EVALUATION CHALLENGE");
530 out <<
"/// {{ UNROLL_SECTION_START POWERS_OF_EVALUATION_CHALLENGE }}\n";
531 for (
int i = 0; i < log_n; ++i) {
532 print_fr(pointer,
"POWERS_OF_EVALUATION_CHALLENGE_" +
std::to_string(i) +
"_LOC");
535 out <<
"/// {{ UNROLL_SECTION_END POWERS_OF_EVALUATION_CHALLENGE }}\n";
536 print_header_centered(
"SHPLEMINI - POWERS OF EVALUATION CHALLENGE COMPLETE");
539 print_header_centered(
"SHPLEMINI - RUNTIME MEMORY - BATCH SCALARS");
540 const int BATCH_SIZE = 69;
541 for (
int i = 1; i < BATCH_SIZE; ++i) {
545 print_header_centered(
"SHPLEMINI - RUNTIME MEMORY - BATCH SCALARS COMPLETE");
548 print_header_centered(
"SHPLEMINI - RUNTIME MEMORY - INVERSIONS");
550 print_fr(pointer,
"GEMINI_R_INV_LOC");
555 print_fr(pointer,
"LIBRA_SUBGROUP_DENOM_LOC");
560 for (
int i = 0; i < log_n; ++i) {
561 print_fr(pointer,
"BATCH_EVALUATION_ACCUMULATOR_INVERSION_" +
std::to_string(i) +
"_LOC");
566 print_fr(pointer,
"CONSTANT_TERM_ACCUMULATOR_LOC");
570 print_fr(pointer,
"POS_INVERTED_DENOMINATOR");
572 print_fr(pointer,
"NEG_INVERTED_DENOMINATOR");
576 out <<
"// LOG_N challenge pow minus u\n";
577 for (
int i = 0; i < log_n; ++i) {
578 print_fr(pointer,
"INVERTED_CHALLENGE_POW_MINUS_U_" +
std::to_string(i) +
"_LOC");
583 out <<
"// LOG_N pos_inverted_off\n";
584 for (
int i = 0; i < log_n; ++i) {
585 print_fr(pointer,
"POS_INVERTED_DENOM_" +
std::to_string(i) +
"_LOC");
590 out <<
"// LOG_N neg_inverted_off\n";
591 for (
int i = 0; i < log_n; ++i) {
592 print_fr(pointer,
"NEG_INVERTED_DENOM_" +
std::to_string(i) +
"_LOC");
597 for (
int i = 0; i < log_n; ++i) {
598 print_fr(pointer,
"FOLD_POS_EVALUATIONS_" +
std::to_string(i) +
"_LOC");
602 print_header_centered(
"SHPLEMINI RUNTIME MEMORY - INVERSIONS - COMPLETE");
603 print_header_centered(
"SHPLEMINI RUNTIME MEMORY - COMPLETE");
608 print_fr(pointer,
"BARYCENTRIC_TEMP_" +
std::to_string(i) +
"_LOC");
612 print_fr(pointer,
"PUBLIC_INPUTS_DENOM_TEMP_LOC");
614 print_fr(pointer,
"GEMINI_R_INV_TEMP_LOC");
618 print_fr(pointer,
"LIBRA_SUBGROUP_DENOM_TEMP_LOC");
621 print_fr(pointer,
"BATCH_PRODUCT_TEMP_LOC");
625 print_header_centered(
"Temporary space");
626 for (
int i = 0; i < 3 * log_n; ++i) {
634 const int consistency_scratch_length = active_challenge_poly_length + 1;
635 print_header_centered(
"Small subgroup IPA");
636 out <<
"// Allocate only the active challenge-poly prefix and the extra denominator/product slot\n";
637 for (
int i = 0; i < active_challenge_poly_length; ++i) {
638 print_fr(pointer,
"CHALLENGE_POLY_LAGRANGE_BASE_" +
std::to_string(i));
643 for (
int i = 0; i < consistency_scratch_length; ++i) {
644 print_fr(pointer,
"CONSISTENCY_DENOMINATORS_BASE_" +
std::to_string(i));
649 for (
int i = 0; i < consistency_scratch_length; ++i) {
650 print_fr(pointer,
"CONSISTENCY_PRODUCTS_BASE_" +
std::to_string(i));
655 out <<
"// LIBRA_UNIVARIATES_LENGTH = BATCHED_RELATION_PARTIAL_LENGTH = " <<
std::dec
661 out <<
"// 1/SUBGROUP_SIZE mod p (precomputed constant)\n";
663 out <<
"// 1/256 mod p, computed as pow(256, p-2, p) where p = BN254 scalar field modulus\n";
664 out <<
"// 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001\n";
665 out <<
"uint256 internal constant INV_SUBGROUP_SIZE = "
666 "0x3033ea246e506e898e97f570caffd704cb0bb460313fb720b29e139e5c100001;\n";
669 print_fr(pointer,
"LATER_SCRATCH_SPACE");
671 print_header_centered(
"Temporary space - COMPLETE");
675 out <<
"// Aliases for scratch space\n";
676 out <<
"// Scratch space aliases at 0x00-0x40\n";
677 out <<
"// Phase 1 (sumcheck rounds): CHALL_POW_LOC, SUMCHECK_U_LOC, GEMINI_A_LOC\n";
678 out <<
"// Phase 2 (shplemini batch scalars): SS_POS_INV_DENOM_LOC, SS_NEG_INV_DENOM_LOC, SS_GEMINI_EVALS_LOC\n";
679 out <<
"// These phases do not overlap in execution time.\n";
681 print_fr(0x00,
"CHALL_POW_LOC");
682 print_fr(0x20,
"SUMCHECK_U_LOC");
683 print_fr(0x40,
"GEMINI_A_LOC");
685 print_fr(0x00,
"SS_POS_INV_DENOM_LOC");
686 print_fr(0x20,
"SS_NEG_INV_DENOM_LOC");
687 print_fr(0x40,
"SS_GEMINI_EVALS_LOC");
691 print_header_centered(
"SUMCHECK - MEMORY ALIASES");
716 auto set_template_param = [&template_str](
const std::string&
key,
const std::string&
value) {
717 std::string::size_type pos = 0;
718 std::string pattern =
"{{ " +
key +
" }}";
719 while ((pos = template_str.find(pattern, pos)) != std::string::npos) {
720 template_str.replace(pos, pattern.length(),
value);
721 pos +=
value.length();
725 auto log_circuit_size = verification_key->log_circuit_size;
728 if (log_circuit_size > 31 || log_circuit_size < 1) {
729 info(
"log_circuit_size out of bounds | 0 < x < 31 | x = " +
std::to_string(log_circuit_size));
733 if (verification_key->num_public_inputs < bb::PAIRING_POINTS_SIZE) {
734 info(
"invariant broken: public input points are smaller than pairing points (they are usually appended)");
738 set_template_param(
"VK_HASH",
field_to_hex(verification_key->hash()));
739 set_template_param(
"CIRCUIT_SIZE",
std::to_string(1 << log_circuit_size));
740 set_template_param(
"LOG_CIRCUIT_SIZE",
std::to_string(log_circuit_size));
741 set_template_param(
"NUM_PUBLIC_INPUTS",
std::to_string(verification_key->num_public_inputs));
743 set_template_param(
"REAL_NUM_PUBLIC_INPUTS",
744 std::to_string(verification_key->num_public_inputs - bb::PAIRING_POINTS_SIZE));
745 set_template_param(
"LOG_N_MINUS_ONE",
std::to_string(log_circuit_size - 1));
749 set_template_param(
"BATCHED_RELATION_PARTIAL_LENGTH_MINUS_ONE",
"8");
750 set_template_param(
"NUMBER_OF_LAGRANGE_BASES",
std::to_string(log_circuit_size * 9));
751 set_template_param(
"NUMBER_OF_LAGRANGE_BASES_PLUS_ONE",
std::to_string(log_circuit_size * 9 + 1));
753 set_template_param(
"LIBRA_BATCH_SCALAR_0",
std::to_string(37 + log_circuit_size));
754 set_template_param(
"LIBRA_BATCH_SCALAR_1",
std::to_string(38 + log_circuit_size));
755 set_template_param(
"LIBRA_BATCH_SCALAR_2",
std::to_string(39 + log_circuit_size));
758 uint32_t gemini_fold_univariate_length =
static_cast<uint32_t
>((log_circuit_size - 1) * 0x40);
759 uint32_t gemini_fold_univariate_hash_length =
static_cast<uint32_t
>(gemini_fold_univariate_length + 0x20);
761 uint32_t gemini_evals_length =
762 is_zk ?
static_cast<uint32_t
>((log_circuit_size + 4) * 0x20) :
static_cast<uint32_t
>(log_circuit_size * 0x20);
763 uint32_t gemini_evals_hash_length =
static_cast<uint32_t
>(gemini_evals_length + 0x20);
765 set_template_param(
"GEMINI_FOLD_UNIVARIATE_LENGTH",
int_to_hex(gemini_fold_univariate_length));
766 set_template_param(
"GEMINI_FOLD_UNIVARIATE_HASH_LENGTH",
int_to_hex(gemini_fold_univariate_hash_length));
767 set_template_param(
"GEMINI_EVALS_LENGTH",
int_to_hex(gemini_evals_length));
768 set_template_param(
"GEMINI_EVALS_HASH_LENGTH",
int_to_hex(gemini_evals_hash_length));
774 auto set_g1_template_param = [&](
const std::string& name_prefix,
const auto& point) {
776 set_template_param(name_prefix +
"_X_LOC", x_hex);
777 set_template_param(name_prefix +
"_Y_LOC", y_hex);
779 set_g1_template_param(
"Q_L", verification_key->q_l());
780 set_g1_template_param(
"Q_R", verification_key->q_r());
781 set_g1_template_param(
"Q_O", verification_key->q_o());
782 set_g1_template_param(
"Q_4", verification_key->q_4());
783 set_g1_template_param(
"Q_M", verification_key->q_m());
784 set_g1_template_param(
"Q_C", verification_key->q_c());
785 set_g1_template_param(
"Q_LOOKUP", verification_key->q_lookup());
786 set_g1_template_param(
"Q_ARITH", verification_key->q_arith());
787 set_g1_template_param(
"Q_DELTA_RANGE", verification_key->q_delta_range());
788 set_g1_template_param(
"Q_ELLIPTIC", verification_key->q_elliptic());
789 set_g1_template_param(
"Q_MEMORY", verification_key->q_memory());
790 set_g1_template_param(
"Q_NNF", verification_key->q_nnf());
791 set_g1_template_param(
"Q_POSEIDON_2_EXTERNAL", verification_key->q_poseidon2_external());
792 set_g1_template_param(
"Q_POSEIDON_2_INTERNAL", verification_key->q_poseidon2_internal());
793 set_g1_template_param(
"SIGMA_1", verification_key->sigma_1());
794 set_g1_template_param(
"SIGMA_2", verification_key->sigma_2());
795 set_g1_template_param(
"SIGMA_3", verification_key->sigma_3());
796 set_g1_template_param(
"SIGMA_4", verification_key->sigma_4());
797 set_g1_template_param(
"TABLE_1", verification_key->table_1());
798 set_g1_template_param(
"TABLE_2", verification_key->table_2());
799 set_g1_template_param(
"TABLE_3", verification_key->table_3());
800 set_g1_template_param(
"TABLE_4", verification_key->table_4());
801 set_g1_template_param(
"ID_1", verification_key->id_1());
802 set_g1_template_param(
"ID_2", verification_key->id_2());
803 set_g1_template_param(
"ID_3", verification_key->id_3());
804 set_g1_template_param(
"ID_4", verification_key->id_4());
805 set_g1_template_param(
"LAGRANGE_FIRST", verification_key->lagrange_first());
806 set_g1_template_param(
"LAGRANGE_LAST", verification_key->lagrange_last());