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 = 29;
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) {
242 out <<
"uint256 internal constant " << name <<
" = " <<
std::showbase <<
std::hex << pointer <<
";\n";
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",
269 "Q_POSEIDON_2_EXTERNAL",
270 "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 = {
"QM",
307 "QPOSEIDON2_EXTERNAL",
308 "QPOSEIDON2_INTERNAL",
329 "LOOKUP_READ_COUNTS",
337 const std::vector<std::string> challenges = {
"ETA",
346 "PUBLIC_INPUTS_DELTA_NUMERATOR",
347 "PUBLIC_INPUTS_DELTA_DENOMINATOR" };
349 const std::vector<std::string> subrelation_intermediates = {
"AUX_NON_NATIVE_FIELD_IDENTITY",
350 "AUX_LIMB_ACCUMULATOR_IDENTITY",
351 "AUX_RAM_CONSISTENCY_CHECK_IDENTITY",
352 "AUX_ROM_CONSISTENCY_CHECK_IDENTITY",
353 "AUX_MEMORY_CHECK_IDENTITY" };
355 const std::vector<std::string> general_intermediates = {
"FINAL_ROUND_TARGET_LOC",
"POW_PARTIAL_EVALUATION_LOC" };
357 int pointer = START_POINTER;
360 print_header_centered(
"VK INDICIES");
361 for (
const auto& item : vk_fr) {
362 print_fr(pointer, item);
365 for (
const auto& item : vk_g1) {
366 print_g1(pointer, item);
371 print_header_centered(
"PROOF INDICIES");
372 for (
const auto& item : pairing_points) {
373 print_fr(pointer, item);
379 print_g1(pointer,
"GEMINI_MASKING_POLY");
383 for (
const auto& item : proof_g1) {
384 print_g1(pointer, item);
390 print_g1(pointer,
"LIBRA_CONCAT");
392 print_fr(pointer,
"LIBRA_SUM_LOC");
397 print_header_centered(
"PROOF INDICIES - SUMCHECK UNIVARIATES");
398 for (
int size = 0; size < log_n; ++size) {
402 print_fr(pointer, name);
408 print_header_centered(
"PROOF INDICIES - SUMCHECK EVALUATIONS");
412 print_fr(pointer,
"GEMINI_MASKING_EVAL_LOC");
416 for (
const auto& entity : entities) {
417 print_fr(pointer, entity +
"_EVAL_LOC");
423 print_fr(pointer,
"LIBRA_EVALUATION_LOC");
425 print_g1(pointer,
"LIBRA_GRAND_PRODUCT");
427 print_g1(pointer,
"LIBRA_QUOTIENT");
432 print_header_centered(
"PROOF INDICIES - GEMINI FOLDING COMMS");
433 for (
int size = 0; size < log_n - 1; ++size) {
434 print_g1(pointer,
"GEMINI_FOLD_UNIVARIATE_" +
std::to_string(size));
439 print_header_centered(
"PROOF INDICIES - GEMINI FOLDING EVALUATIONS");
440 for (
int size = 0; size < log_n; ++size) {
447 print_header_centered(
"PROOF INDICIES - LIBRA POLY EVALUATIONS");
448 for (
int i = 0; i < 4; ++i) {
449 print_fr(pointer,
"LIBRA_POLY_EVAL_" +
std::to_string(i) +
"_LOC");
454 print_g1(pointer,
"SHPLONK_Q");
456 print_g1(pointer,
"KZG_QUOTIENT");
459 print_header_centered(
"PROOF INDICIES - COMPLETE");
462 print_header_centered(
"CHALLENGES");
463 for (
const auto& chall : challenges) {
464 print_fr(pointer, chall +
"_CHALLENGE");
467 for (
int alpha = 0; alpha < NUMBER_OF_ALPHAS; ++alpha) {
471 for (
int gate = 0; gate < log_n; ++gate) {
478 print_fr(pointer,
"LIBRA_CHALLENGE");
482 for (
int sum_u = 0; sum_u < log_n; ++sum_u) {
486 print_header_centered(
"CHALLENGES - COMPLETE");
489 print_header_centered(
"SUMCHECK - RUNTIME MEMORY");
490 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - BARYCENTRIC");
494 print_fr(pointer,
"BARYCENTRIC_LAGRANGE_DENOMINATOR_" +
std::to_string(i) +
"_LOC");
497 for (
int i = 0; i < log_n; ++i) {
504 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - BARYCENTRIC COMPLETE");
507 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - SUBRELATION EVALUATIONS");
508 for (
int i = 0; i < NUMBER_OF_SUBRELATIONS; ++i) {
509 print_fr(pointer,
"SUBRELATION_EVAL_" +
std::to_string(i) +
"_LOC");
512 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - SUBRELATION EVALUATIONS COMPLETE");
515 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - SUBRELATION INTERMEDIATES");
516 for (
const auto& item : general_intermediates) {
517 print_fr(pointer, item);
520 for (
const auto& item : subrelation_intermediates) {
521 print_fr(pointer, item);
524 print_header_centered(
"SUMCHECK - RUNTIME MEMORY - COMPLETE");
527 print_header_centered(
"SHPLEMINI - RUNTIME MEMORY");
528 print_header_centered(
"SHPLEMINI - POWERS OF EVALUATION CHALLENGE");
529 out <<
"/// {{ UNROLL_SECTION_START POWERS_OF_EVALUATION_CHALLENGE }}\n";
530 for (
int i = 0; i < log_n; ++i) {
531 print_fr(pointer,
"POWERS_OF_EVALUATION_CHALLENGE_" +
std::to_string(i) +
"_LOC");
534 out <<
"/// {{ UNROLL_SECTION_END POWERS_OF_EVALUATION_CHALLENGE }}\n";
535 print_header_centered(
"SHPLEMINI - POWERS OF EVALUATION CHALLENGE COMPLETE");
538 print_header_centered(
"SHPLEMINI - RUNTIME MEMORY - BATCH SCALARS");
539 const int BATCH_SIZE = 69;
540 for (
int i = 1; i < BATCH_SIZE; ++i) {
544 print_header_centered(
"SHPLEMINI - RUNTIME MEMORY - BATCH SCALARS COMPLETE");
547 print_header_centered(
"SHPLEMINI - RUNTIME MEMORY - INVERSIONS");
549 print_fr(pointer,
"GEMINI_R_INV_LOC");
554 print_fr(pointer,
"LIBRA_SUBGROUP_DENOM_LOC");
559 for (
int i = 0; i < log_n; ++i) {
560 print_fr(pointer,
"BATCH_EVALUATION_ACCUMULATOR_INVERSION_" +
std::to_string(i) +
"_LOC");
565 print_fr(pointer,
"CONSTANT_TERM_ACCUMULATOR_LOC");
569 print_fr(pointer,
"POS_INVERTED_DENOMINATOR");
571 print_fr(pointer,
"NEG_INVERTED_DENOMINATOR");
575 out <<
"// LOG_N challenge pow minus u\n";
576 for (
int i = 0; i < log_n; ++i) {
577 print_fr(pointer,
"INVERTED_CHALLENGE_POW_MINUS_U_" +
std::to_string(i) +
"_LOC");
582 out <<
"// LOG_N pos_inverted_off\n";
583 for (
int i = 0; i < log_n; ++i) {
584 print_fr(pointer,
"POS_INVERTED_DENOM_" +
std::to_string(i) +
"_LOC");
589 out <<
"// LOG_N neg_inverted_off\n";
590 for (
int i = 0; i < log_n; ++i) {
591 print_fr(pointer,
"NEG_INVERTED_DENOM_" +
std::to_string(i) +
"_LOC");
596 for (
int i = 0; i < log_n; ++i) {
597 print_fr(pointer,
"FOLD_POS_EVALUATIONS_" +
std::to_string(i) +
"_LOC");
601 print_header_centered(
"SHPLEMINI RUNTIME MEMORY - INVERSIONS - COMPLETE");
602 print_header_centered(
"SHPLEMINI RUNTIME MEMORY - COMPLETE");
607 print_fr(pointer,
"BARYCENTRIC_TEMP_" +
std::to_string(i) +
"_LOC");
611 print_fr(pointer,
"PUBLIC_INPUTS_DENOM_TEMP_LOC");
613 print_fr(pointer,
"GEMINI_R_INV_TEMP_LOC");
617 print_fr(pointer,
"LIBRA_SUBGROUP_DENOM_TEMP_LOC");
620 print_fr(pointer,
"BATCH_PRODUCT_TEMP_LOC");
624 print_header_centered(
"Temporary space");
625 for (
int i = 0; i < 3 * log_n; ++i) {
633 const int consistency_scratch_length = active_challenge_poly_length + 1;
634 print_header_centered(
"Small subgroup IPA");
635 out <<
"// Allocate only the active challenge-poly prefix and the extra denominator/product slot\n";
636 for (
int i = 0; i < active_challenge_poly_length; ++i) {
637 print_fr(pointer,
"CHALLENGE_POLY_LAGRANGE_BASE_" +
std::to_string(i));
642 for (
int i = 0; i < consistency_scratch_length; ++i) {
643 print_fr(pointer,
"CONSISTENCY_DENOMINATORS_BASE_" +
std::to_string(i));
648 for (
int i = 0; i < consistency_scratch_length; ++i) {
649 print_fr(pointer,
"CONSISTENCY_PRODUCTS_BASE_" +
std::to_string(i));
654 out <<
"// LIBRA_UNIVARIATES_LENGTH = BATCHED_RELATION_PARTIAL_LENGTH = " <<
std::dec
658 out <<
"uint256 internal constant LIBRA_UNIVARIATES_LENGTH_MINUS_ONE = " <<
std::showbase <<
std::hex
660 out <<
"// 1/SUBGROUP_SIZE mod p (precomputed constant)\n";
662 out <<
"// 1/256 mod p, computed as pow(256, p-2, p) where p = BN254 scalar field modulus\n";
663 out <<
"// 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001\n";
664 out <<
"uint256 internal constant INV_SUBGROUP_SIZE = "
665 "0x3033ea246e506e898e97f570caffd704cb0bb460313fb720b29e139e5c100001;\n";
668 print_fr(pointer,
"LATER_SCRATCH_SPACE");
670 print_header_centered(
"Temporary space - COMPLETE");
674 out <<
"// Aliases for scratch space\n";
675 out <<
"// Scratch space aliases at 0x00-0x40\n";
676 out <<
"// Phase 1 (sumcheck rounds): CHALL_POW_LOC, SUMCHECK_U_LOC, GEMINI_A_LOC\n";
677 out <<
"// Phase 2 (shplemini batch scalars): SS_POS_INV_DENOM_LOC, SS_NEG_INV_DENOM_LOC, SS_GEMINI_EVALS_LOC\n";
678 out <<
"// These phases do not overlap in execution time.\n";
680 print_fr(0x00,
"CHALL_POW_LOC");
681 print_fr(0x20,
"SUMCHECK_U_LOC");
682 print_fr(0x40,
"GEMINI_A_LOC");
684 print_fr(0x00,
"SS_POS_INV_DENOM_LOC");
685 print_fr(0x20,
"SS_NEG_INV_DENOM_LOC");
686 print_fr(0x40,
"SS_GEMINI_EVALS_LOC");
690 print_header_centered(
"SUMCHECK - MEMORY ALIASES");
715 auto set_template_param = [&template_str](
const std::string&
key,
const std::string&
value) {
716 std::string::size_type pos = 0;
717 std::string pattern =
"{{ " +
key +
" }}";
718 while ((pos = template_str.find(pattern, pos)) != std::string::npos) {
719 template_str.replace(pos, pattern.length(),
value);
720 pos +=
value.length();
724 auto log_circuit_size = verification_key->log_circuit_size;
727 if (log_circuit_size > 31 || log_circuit_size < 1) {
728 info(
"log_circuit_size out of bounds | 0 < x < 31 | x = " +
std::to_string(log_circuit_size));
732 if (verification_key->num_public_inputs < bb::PAIRING_POINTS_SIZE) {
733 info(
"invariant broken: public input points are smaller than pairing points (they are usually appended)");
737 set_template_param(
"VK_HASH",
field_to_hex(verification_key->hash()));
738 set_template_param(
"CIRCUIT_SIZE",
std::to_string(1 << log_circuit_size));
739 set_template_param(
"LOG_CIRCUIT_SIZE",
std::to_string(log_circuit_size));
740 set_template_param(
"NUM_PUBLIC_INPUTS",
std::to_string(verification_key->num_public_inputs));
742 set_template_param(
"REAL_NUM_PUBLIC_INPUTS",
743 std::to_string(verification_key->num_public_inputs - bb::PAIRING_POINTS_SIZE));
744 set_template_param(
"LOG_N_MINUS_ONE",
std::to_string(log_circuit_size - 1));
748 set_template_param(
"BATCHED_RELATION_PARTIAL_LENGTH_MINUS_ONE",
"8");
749 set_template_param(
"NUMBER_OF_LAGRANGE_BASES",
std::to_string(log_circuit_size * 9));
750 set_template_param(
"NUMBER_OF_LAGRANGE_BASES_PLUS_ONE",
std::to_string(log_circuit_size * 9 + 1));
752 set_template_param(
"LIBRA_BATCH_SCALAR_0",
std::to_string(37 + log_circuit_size));
753 set_template_param(
"LIBRA_BATCH_SCALAR_1",
std::to_string(38 + log_circuit_size));
754 set_template_param(
"LIBRA_BATCH_SCALAR_2",
std::to_string(39 + log_circuit_size));
757 uint32_t gemini_fold_univariate_length =
static_cast<uint32_t
>((log_circuit_size - 1) * 0x40);
758 uint32_t gemini_fold_univariate_hash_length =
static_cast<uint32_t
>(gemini_fold_univariate_length + 0x20);
760 uint32_t gemini_evals_length =
761 is_zk ?
static_cast<uint32_t
>((log_circuit_size + 4) * 0x20) :
static_cast<uint32_t
>(log_circuit_size * 0x20);
762 uint32_t gemini_evals_hash_length =
static_cast<uint32_t
>(gemini_evals_length + 0x20);
764 set_template_param(
"GEMINI_FOLD_UNIVARIATE_LENGTH",
int_to_hex(gemini_fold_univariate_length));
765 set_template_param(
"GEMINI_FOLD_UNIVARIATE_HASH_LENGTH",
int_to_hex(gemini_fold_univariate_hash_length));
766 set_template_param(
"GEMINI_EVALS_LENGTH",
int_to_hex(gemini_evals_length));
767 set_template_param(
"GEMINI_EVALS_HASH_LENGTH",
int_to_hex(gemini_evals_hash_length));
773 auto set_g1_template_param = [&](
const std::string& name_prefix,
const auto& point) {
775 set_template_param(name_prefix +
"_X_LOC", x_hex);
776 set_template_param(name_prefix +
"_Y_LOC", y_hex);
778 set_g1_template_param(
"Q_L", verification_key->q_l);
779 set_g1_template_param(
"Q_R", verification_key->q_r);
780 set_g1_template_param(
"Q_O", verification_key->q_o);
781 set_g1_template_param(
"Q_4", verification_key->q_4);
782 set_g1_template_param(
"Q_M", verification_key->q_m);
783 set_g1_template_param(
"Q_C", verification_key->q_c);
784 set_g1_template_param(
"Q_LOOKUP", verification_key->q_lookup);
785 set_g1_template_param(
"Q_ARITH", verification_key->q_arith);
786 set_g1_template_param(
"Q_DELTA_RANGE", verification_key->q_delta_range);
787 set_g1_template_param(
"Q_ELLIPTIC", verification_key->q_elliptic);
788 set_g1_template_param(
"Q_MEMORY", verification_key->q_memory);
789 set_g1_template_param(
"Q_NNF", verification_key->q_nnf);
790 set_g1_template_param(
"Q_POSEIDON_2_EXTERNAL", verification_key->q_poseidon2_external);
791 set_g1_template_param(
"Q_POSEIDON_2_INTERNAL", verification_key->q_poseidon2_internal);
792 set_g1_template_param(
"SIGMA_1", verification_key->sigma_1);
793 set_g1_template_param(
"SIGMA_2", verification_key->sigma_2);
794 set_g1_template_param(
"SIGMA_3", verification_key->sigma_3);
795 set_g1_template_param(
"SIGMA_4", verification_key->sigma_4);
796 set_g1_template_param(
"TABLE_1", verification_key->table_1);
797 set_g1_template_param(
"TABLE_2", verification_key->table_2);
798 set_g1_template_param(
"TABLE_3", verification_key->table_3);
799 set_g1_template_param(
"TABLE_4", verification_key->table_4);
800 set_g1_template_param(
"ID_1", verification_key->id_1);
801 set_g1_template_param(
"ID_2", verification_key->id_2);
802 set_g1_template_param(
"ID_3", verification_key->id_3);
803 set_g1_template_param(
"ID_4", verification_key->id_4);
804 set_g1_template_param(
"LAGRANGE_FIRST", verification_key->lagrange_first);
805 set_g1_template_param(
"LAGRANGE_LAST", verification_key->lagrange_last);