diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/pcs/gemini/gemini.hpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/pcs/gemini/gemini.hpp index e30d8fa840e5..27a49973990c 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/pcs/gemini/gemini.hpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/pcs/gemini/gemini.hpp @@ -237,7 +237,8 @@ template class GeminiVerifier_ { GroupElement C0_r_neg = batched_f; Fr r_inv = r.invert(); - // WORKTODO: reinstate some kind of !batched_g.is_point_at_infinity() check for stdlib? This is mostly relevant for Gemini unit tests since in practice batched_g will not be zero + // WORKTODO: reinstate some kind of !batched_g.is_point_at_infinity() check for stdlib? This is mostly relevant + // for Gemini unit tests since in practice batched_g will not be zero bool batched_g_is_point_at_infinity = false; if constexpr (!Curve::is_stdlib_type) { batched_g_is_point_at_infinity = batched_g.is_point_at_infinity(); @@ -247,7 +248,7 @@ template class GeminiVerifier_ { C0_r_pos += batched_g; C0_r_neg -= batched_g; } - + return { C0_r_pos, C0_r_neg }; } diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.hpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.hpp index 37bb0c98b627..fd9e4a5853fa 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.hpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.hpp @@ -186,18 +186,25 @@ template class ShplonkVerifier_ { GroupElement G_commitment = Q_commitment; // Compute {ẑⱼ(r)}ⱼ , where ẑⱼ(r) = 1/zⱼ(r) = 1/(r - xⱼ) - // WORKTODO: doing innefficient inversion for now since batch inversion is not implemented for field_t std::vector vanishing_evals; vanishing_evals.reserve(num_claims); for (const auto& claim : claims) { vanishing_evals.emplace_back(z_challenge - claim.opening_pair.challenge); } + // If recursion, invert elements individually, otherwise batch invert std::vector inverse_vanishing_evals; - for (const auto& val : vanishing_evals) { - inverse_vanishing_evals.emplace_back(val.invert()); + if constexpr (Curve::is_stdlib_type) { + for (const auto& val : vanishing_evals) { + inverse_vanishing_evals.emplace_back(val.invert()); + } + } else { + Fr::batch_invert(vanishing_evals); + inverse_vanishing_evals = vanishing_evals; } auto current_nu = Fr(1); + std::vector commitments; // used in recursion setting only + std::vector scalars; for (size_t j = 0; j < num_claims; ++j) { // (Cⱼ, xⱼ, vⱼ) const auto& [opening_pair, commitment] = claims[j]; @@ -206,18 +213,30 @@ template class ShplonkVerifier_ { // G₀ += ρʲ / ( r − xⱼ ) ⋅ vⱼ G_commitment_constant += scaling_factor * opening_pair.evaluation; - // [G] -= ρʲ / ( r − xⱼ )⋅[fⱼ] - G_commitment -= commitment * scaling_factor; + + // If recursion, store MSM inputs for batch mul, otherwise perform mul and add directly + if constexpr (Curve::is_stdlib_type) { + commitments.emplace_back(commitment); + scalars.emplace_back(scaling_factor); + } else { + // [G] -= ρʲ / ( r − xⱼ )⋅[fⱼ] + G_commitment -= commitment * scaling_factor; + } current_nu *= nu; } - // [G] += G₀⋅[1] = [G] + (∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ ))⋅[1] - // GroupElement sort_of_one{ x, y }; + // If recursion, perform [G] -= ∑ⱼ ρʲ / ( r − xⱼ )⋅[fⱼ] via batch_mul + if constexpr (Curve::is_stdlib_type) { + G_commitment -= GroupElement::batch_mul(commitments, scalars); + } + + // [G] += G₀⋅[1] = [G] + (∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ ))⋅[1] if constexpr (Curve::is_stdlib_type) { auto ctx = nu.get_context(); G_commitment += GroupElement::one(ctx) * G_commitment_constant; } else { + // GroupElement sort_of_one{ x, y }; G_commitment += vk->srs->get_first_g1() * G_commitment_constant; } diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp index 72c564ea3f9b..21c975dfe175 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp @@ -66,7 +66,7 @@ template bool UltraRecursiveVerifier_::verify_proof(co auto public_input_size_native = static_cast(public_input_size.get_value()); auto pub_inputs_offset_native = static_cast(pub_inputs_offset.get_value()); - info("1. num gates = 0", builder->get_num_gates()); + info("1. num gates = ", builder->get_num_gates()); if (circuit_size_native != key->circuit_size) { return false; @@ -109,14 +109,14 @@ template bool UltraRecursiveVerifier_::verify_proof(co // Get permutation challenges auto [beta, gamma] = transcript.get_challenges("beta", "gamma"); - info("2. num gates = 0", builder->get_num_gates()); + info("2. num gates = ", builder->get_num_gates()); const FF public_input_delta = proof_system::honk::compute_public_input_delta( public_inputs, beta, gamma, circuit_size, pub_inputs_offset_native); const FF lookup_grand_product_delta = proof_system::honk::compute_lookup_grand_product_delta(beta, gamma, circuit_size); - info("3. num gates = 0", builder->get_num_gates()); + info("3. num gates = ", builder->get_num_gates()); relation_parameters.beta = beta; relation_parameters.gamma = gamma; @@ -132,7 +132,7 @@ template bool UltraRecursiveVerifier_::verify_proof(co std::optional sumcheck_output = sumcheck.verify(relation_parameters, transcript); - info("4. num gates = 0", builder->get_num_gates()); + info("4. num gates = ", builder->get_num_gates()); // // Note(luke): Temporary. Done only to complete manifest through sumcheck. Delete once we proceed to Gemini. // [[maybe_unused]] FF rho = transcript.get_challenge("rho"); @@ -157,7 +157,7 @@ template bool UltraRecursiveVerifier_::verify_proof(co ++evaluation_idx; } - info("5. num gates = 0", builder->get_num_gates()); + info("5. num gates = ", builder->get_num_gates()); // Construct vectors of scalars for batched unshifted and to-be-shifted commitments const size_t NUM_UNSHIFTED = commitments.get_unshifted().size(); @@ -177,10 +177,10 @@ template bool UltraRecursiveVerifier_::verify_proof(co // Batch the commitments to the unshifted and to-be-shifted polynomials using powers of rho auto batched_commitment_unshifted = GroupElement::batch_mul(commitments.get_unshifted(), scalars_unshifted); - info("6. num gates = 0", builder->get_num_gates()); + info("6. num gates = ", builder->get_num_gates()); auto batched_commitment_to_be_shifted = GroupElement::batch_mul(commitments.get_to_be_shifted(), scalars_to_be_shifted); - info("7. num gates = 0", builder->get_num_gates()); + info("7. num gates = ", builder->get_num_gates()); // Produce a Gemini claim consisting of: // - d+1 commitments [Fold_{r}^(0)], [Fold_{-r}^(0)], and [Fold^(l)], l = 1:d-1 @@ -191,14 +191,14 @@ template bool UltraRecursiveVerifier_::verify_proof(co batched_commitment_to_be_shifted, transcript); - info("8. num gates = 0", builder->get_num_gates()); + info("8. num gates = ", builder->get_num_gates()); // // Note(luke): Temporary. Done only to complete manifest through Gemini. Delete once we proceed to Shplonk. // [[maybe_unused]] FF nu = transcript.get_challenge("Shplonk:nu"); // Produce a Shplonk claim: commitment [Q] - [Q_z], evaluation zero (at random challenge z) auto shplonk_claim = Shplonk::reduce_verification(pcs_verification_key, gemini_claim, transcript); (void)shplonk_claim; - info("9. num gates = 0", builder->get_num_gates()); + info("9. num gates = ", builder->get_num_gates()); // DEBUG! return true; diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp index 17507b2d6dcd..271c06c4258e 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp @@ -61,6 +61,21 @@ template class RecursiveVerifierTest : public testing:: inner_scalar_field_ct(witness_ct(&builder, 0))); big_a* big_b; + + // const size_t num_gates = 1 << 17; + // for (size_t i = 0; i < num_gates; ++i) { + // fr a = fr::random_element(); + // uint32_t a_idx = builder.add_variable(a); + + // fr b = fr::random_element(); + // fr c = fr::random_element(); + // fr d = a + b + c; + // uint32_t b_idx = builder.add_variable(b); + // uint32_t c_idx = builder.add_variable(c); + // uint32_t d_idx = builder.add_variable(d); + + // builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, fr(1), fr(1), fr(1), fr(-1), fr(0) }); + // } }; static void create_outer_circuit(InnerBuilder& inner_circuit, OuterBuilder& outer_builder)