17TEST(SumcheckRound, SumcheckTupleOfTuplesOfUnivariates)
22 using SubrelationSeparators =
typename Utils::SubrelationSeparators;
29 const size_t MAX_LENGTH = 5;
38 SubrelationSeparators challenge{};
41 Utils::scale_univariates(tuple_of_tuples, challenge);
49 auto result_expected = univariate_1.template extend_to<MAX_LENGTH>() +
50 univariate_2.template extend_to<MAX_LENGTH>() * challenge[0] +
51 univariate_3.template extend_to<MAX_LENGTH>() * challenge[1];
54 EXPECT_EQ(result, result_expected);
72TEST(SumcheckRound, TuplesOfEvaluationArrays)
77 using SubrelationSeparators =
typename Utils::SubrelationSeparators;
89 SubrelationSeparators challenge{ 5, 25 };
91 FF result = Utils::scale_and_batch_elements(tuple_of_arrays, challenge);
94 auto result_expected = evaluations_arithmetic[0] +
95 evaluations_arithmetic[1] * challenge[0] +
96 evaluations_dependent[0] * challenge[1];
99 EXPECT_EQ(result, result_expected);
102 Utils::zero_elements(tuple_of_arrays);
114TEST(SumcheckRound, AddTuplesOfTuplesOfUnivariates)
150TEST(SumcheckRound, ComputeEffectiveRoundSize)
158 const size_t full_size = 32;
159 const size_t round_size = full_size;
164 for (
auto& poly : random_polynomials) {
169 for (
auto [prover_poly, random_poly] :
zip_view(prover_polynomials.get_all(), random_polynomials)) {
170 prover_poly = random_poly.share();
174 EXPECT_EQ(effective_size, round_size);
179 const size_t full_size = 64;
180 const size_t active_size = 20;
181 const size_t round_size = full_size;
188 for (
auto& poly : random_polynomials) {
201 for (
auto [prover_poly, random_poly] :
zip_view(prover_polynomials.get_all(), random_polynomials)) {
202 prover_poly = random_poly.share();
207 EXPECT_EQ(effective_size, active_size);
208 EXPECT_LE(effective_size, round_size);
213 const size_t full_size = 64;
214 const size_t active_size = 23;
215 const size_t expected_effective_size = 24;
216 const size_t round_size = full_size;
221 for (
auto& poly : random_polynomials) {
232 for (
auto [prover_poly, random_poly] :
zip_view(prover_polynomials.get_all(), random_polynomials)) {
233 prover_poly = random_poly.share();
237 EXPECT_EQ(effective_size, expected_effective_size);
243 const size_t full_size = 64;
244 const size_t round_size = full_size;
249 size_t witness_idx = 0;
250 for (
auto& poly : random_polynomials) {
254 if (witness_idx == 0) {
256 }
else if (witness_idx == 1) {
258 }
else if (witness_idx == 2) {
271 for (
auto [prover_poly, random_poly] :
zip_view(prover_polynomials.get_all(), random_polynomials)) {
272 prover_poly = random_poly.share();
277 EXPECT_EQ(effective_size, 30);
282 const size_t full_size = 128;
283 const size_t active_size = 2;
284 const size_t round_size = full_size;
289 for (
auto& poly : random_polynomials) {
300 for (
auto [prover_poly, random_poly] :
zip_view(prover_polynomials.get_all(), random_polynomials)) {
301 prover_poly = random_poly.share();
305 EXPECT_EQ(effective_size, active_size);
306 EXPECT_GE(effective_size, 2);
348TEST(SumcheckRound, ExtendEdgesShortMonomial)
354 using ExtendedEdges =
typename SumcheckRound::ExtendedEdges;
356 const size_t multivariate_d = 3;
357 const size_t multivariate_n = 1 << multivariate_d;
362 for (
auto& poly : test_polynomials) {
364 for (
size_t i = 0; i < multivariate_n; ++i) {
370 for (
auto [prover_poly, test_poly] :
zip_view(prover_polynomials.get_all(), test_polynomials)) {
371 prover_poly = test_poly.share();
374 SumcheckRound round(multivariate_n);
380 const size_t edge_idx = 2;
381 ExtendedEdges extended_edges;
383 round.extend_edges(extended_edges, prover_polynomials, edge_idx);
386 auto& first_edge = extended_edges.get_all()[0];
389 FF val_at_0 = first_edge.value_at(0);
390 FF val_at_1 = first_edge.value_at(1);
392 EXPECT_EQ(val_at_0,
FF(2)) <<
"Extended univariate should evaluate to 2 at X=0";
393 EXPECT_EQ(val_at_1,
FF(3)) <<
"Extended univariate should evaluate to 3 at X=1";
396 EXPECT_EQ(first_edge.evaluations.size(), 2) <<
"UltraFlavor uses short monomials (length 2)";
398 info(
"Extended edges create correct degree-1 univariates for USE_SHORT_MONOMIALS flavors");
407TEST(SumcheckRound, ExtendEdges)
414 using ExtendedEdges =
typename SumcheckRound::ExtendedEdges;
416 const size_t multivariate_d = 3;
417 const size_t multivariate_n = 1 << multivariate_d;
422 for (
auto& poly : test_polynomials) {
424 for (
size_t i = 0; i < multivariate_n; ++i) {
430 for (
auto [prover_poly, test_poly] :
zip_view(prover_polynomials.get_all(), test_polynomials)) {
431 prover_poly = test_poly.share();
434 SumcheckRound round(multivariate_n);
440 const size_t edge_idx = 2;
441 ExtendedEdges extended_edges;
443 round.extend_edges(extended_edges, prover_polynomials, edge_idx);
446 auto& first_edge = extended_edges.get_all()[0];
449 EXPECT_EQ(first_edge.value_at(0),
FF(2)) <<
"U(0) should be 2";
450 EXPECT_EQ(first_edge.value_at(1),
FF(3)) <<
"U(1) should be 3";
454 <<
"Non-short-monomial flavor should extend to MAX_PARTIAL_RELATION_LENGTH";
458 for (
size_t x = 2; x < std::min(static_cast<size_t>(7), first_edge.evaluations.size()); ++x) {
459 FF expected =
FF(2 + x);
460 EXPECT_EQ(first_edge.value_at(x), expected)
461 <<
"Extended univariate U(X) = 2 + X should evaluate to " << (2 + x) <<
" at X=" << x
462 <<
" (barycentric extension should preserve linear form)";
465 info(
"Extended edges correctly perform full barycentric extension to MAX_PARTIAL_RELATION_LENGTH=",
477TEST(SumcheckRound, AccumulateRelationUnivariatesSumcheckTestFlavor)
484 const size_t multivariate_d = 2;
485 const size_t multivariate_n = 1 << multivariate_d;
490 info(
"Test 1: Arithmetic relation accumulation");
518 for (
auto& poly : prover_polynomials.get_all()) {
519 if (poly.size() == 0) {
525 SumcheckRound round(multivariate_n);
526 typename SumcheckRound::ExtendedEdges extended_edges;
527 round.extend_edges(extended_edges, prover_polynomials, 0);
530 typename SumcheckRound::SumcheckTupleOfTuplesOfUnivariates accumulator{};
535 round.accumulate_relation_univariates_public(accumulator, extended_edges, relation_parameters,
FF(1));
543 EXPECT_EQ(arith_univariate.value_at(0),
FF(0)) <<
"Relation should be satisfied at edge 0";
544 EXPECT_EQ(arith_univariate.value_at(1),
FF(0)) <<
"Relation should be satisfied at edge 1";
546 info(
"Arithmetic relation: verified relation is satisfied for valid circuit");
551 info(
"Test 2: Scaling factor application");
563 for (
auto& poly : prover_polynomials.get_all()) {
564 if (poly.size() == 0) {
569 SumcheckRound round(multivariate_n);
570 typename SumcheckRound::ExtendedEdges extended_edges;
571 round.extend_edges(extended_edges, prover_polynomials, 0);
573 typename SumcheckRound::SumcheckTupleOfTuplesOfUnivariates acc1{};
574 typename SumcheckRound::SumcheckTupleOfTuplesOfUnivariates acc2{};
579 round.accumulate_relation_univariates_public(acc1, extended_edges, relation_parameters,
FF(1));
580 round.accumulate_relation_univariates_public(acc2, extended_edges, relation_parameters,
FF(2));
586 EXPECT_EQ(arith2.value_at(0), arith1.value_at(0) *
FF(2)) <<
"Scaling should multiply contribution";
587 EXPECT_EQ(arith2.value_at(1), arith1.value_at(1) *
FF(2)) <<
"Scaling should multiply contribution";
589 info(
"Scaling factor: verified 2x scaling produces 2x contribution");
594 info(
"Test 3: Multiple accumulation calls");
605 for (
auto& poly : prover_polynomials.get_all()) {
606 if (poly.size() == 0) {
611 SumcheckRound round(multivariate_n);
612 typename SumcheckRound::ExtendedEdges extended_edges;
613 round.extend_edges(extended_edges, prover_polynomials, 0);
615 typename SumcheckRound::SumcheckTupleOfTuplesOfUnivariates accumulator{};
620 round.accumulate_relation_univariates_public(accumulator, extended_edges, relation_parameters,
FF(1));
622 FF value_after_first = arith.value_at(0);
625 round.accumulate_relation_univariates_public(accumulator, extended_edges, relation_parameters,
FF(1));
626 FF value_after_second = arith.value_at(0);
629 EXPECT_EQ(value_after_second, value_after_first *
FF(2)) <<
"Second accumulation should add to first";
631 info(
"Multiple accumulations: verified contributions are summed");
635 info(
"Test 4: DependentTestRelation (linearly dependent) is not scaled");
645 for (
auto& poly : prover_polynomials.get_all()) {
646 if (poly.size() == 0) {
651 SumcheckRound round(multivariate_n);
652 typename SumcheckRound::ExtendedEdges extended_edges;
653 round.extend_edges(extended_edges, prover_polynomials, 0);
655 typename SumcheckRound::SumcheckTupleOfTuplesOfUnivariates acc1{}, acc2{};
662 round.accumulate_relation_univariates_public(acc1, extended_edges, relation_parameters,
FF(1));
663 round.accumulate_relation_univariates_public(acc2, extended_edges, relation_parameters,
FF(2));
672 EXPECT_EQ(dependent_test_acc2.value_at(0), dependent_test_acc1.value_at(0))
673 <<
"DependentTestRelation (linearly dependent) should NOT be scaled";
674 EXPECT_EQ(dependent_test_acc2.value_at(1), dependent_test_acc1.value_at(1))
675 <<
"DependentTestRelation (linearly dependent) should NOT be scaled";
677 info(
"DependentTestRelation: verified that linearly dependent relation is NOT scaled");
752TEST(SumcheckRound, CheckSumRoundFailurePersistence)
759 info(
"Test: round_failed flag persistence across multiple checks");
763 info(
"Test 1: Single failed check sets round_failed flag");
765 FF wrong_target =
FF(999);
772 EXPECT_FALSE(verifier_round.
round_failed) <<
"round_failed should initially be false";
777 EXPECT_FALSE(result) <<
"check_sum should return false for wrong target";
778 EXPECT_TRUE(verifier_round.
round_failed) <<
"round_failed flag should be set after failed check";
780 info(
"Single failure: round_failed flag correctly set");
785 info(
"Test 2: Multiple passing checks keep round_failed false");
799 EXPECT_TRUE(result1) <<
"First check should pass";
800 EXPECT_FALSE(verifier_round.
round_failed) <<
"round_failed should be false after first pass";
805 EXPECT_TRUE(result2) <<
"Second check should pass";
806 EXPECT_FALSE(verifier_round.
round_failed) <<
"round_failed should remain false after second pass";
808 info(
"Multiple passes: round_failed correctly remains false");
817TEST(SumcheckRound, CheckSumRecursiveUnsatisfiableWitness)
821 using FF =
typename RecursiveFlavor::FF;
823 constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = RecursiveFlavor::BATCHED_RELATION_PARTIAL_LENGTH;
825 info(
"Test: Recursive check_sum with unsatisfiable witness");
829 info(
"Test 1: Unsatisfiable witness where target != S(0) + S(1)");
834 auto native_val_0 =
bb::fr(10);
835 auto native_val_1 =
bb::fr(20);
836 auto native_wrong_target =
bb::fr(100);
839 FF val_0 = FF::from_witness(&
builder, native_val_0);
840 FF val_1 = FF::from_witness(&
builder, native_val_1);
841 FF wrong_target = FF::from_witness(&
builder, native_wrong_target);
857 EXPECT_FALSE(check_result) <<
"check_sum should return false for mismatched values";
860 EXPECT_TRUE(
builder.failed()) <<
"Builder should detect constraint violation (unsatisfiable witness)";
862 info(
"Unsatisfiable witness: Builder correctly detects constraint violation");
867 info(
"Test 2: Satisfiable witness where target == S(0) + S(1)");
872 auto native_val_0 =
bb::fr(10);
873 auto native_val_1 =
bb::fr(20);
874 auto native_correct_target = native_val_0 + native_val_1;
877 FF val_0 = FF::from_witness(&
builder, native_val_0);
878 FF val_1 = FF::from_witness(&
builder, native_val_1);
879 FF correct_target = FF::from_witness(&
builder, native_correct_target);
894 EXPECT_TRUE(check_result) <<
"check_sum should return true for matching values";
897 EXPECT_FALSE(
builder.failed()) <<
"Builder should not fail for satisfiable witness";
902 info(
"Satisfiable witness: Builder correctly validates constraint satisfaction");
907 info(
"Test 4: Multiple rounds where one has unsatisfiable witness");
917 univariate_1.
value_at(0) = val_0_round1;
918 univariate_1.
value_at(1) = val_1_round1;
924 EXPECT_TRUE(result_1);
925 EXPECT_FALSE(
builder.failed()) <<
"First round should not fail";
933 univariate_2.
value_at(0) = val_0_round2;
934 univariate_2.
value_at(1) = val_1_round2;
938 EXPECT_FALSE(result_2) <<
"Second round should fail";
941 EXPECT_TRUE(
builder.failed()) <<
"Builder should detect failure in second round";
943 info(
"Multiple rounds: Builder correctly detects failure in one of multiple rounds");