diff --git a/cpp/src/barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.cpp b/cpp/src/barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.cpp index 8ff1782f1e..d49d1ec927 100644 --- a/cpp/src/barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.cpp +++ b/cpp/src/barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.cpp @@ -101,6 +101,10 @@ namespace barretenberg { namespace scalar_multiplication { +/** + * The pippppenger point table computes for each point P = (x,y), a point P' = (\beta * x, -y) which enables us + * to use the curve endomorphism for faster scalar multiplication. See below for more details. + */ void generate_pippenger_point_table(g1::affine_element* points, g1::affine_element* table, size_t num_points) { // iterate backwards, so that `points` and `table` can point to the same memory location @@ -916,14 +920,14 @@ g1::element pippenger(fr* scalars, * We use affine-addition formula in this method, which paradoxically is ~45% faster than the mixed addition formulae. * See `scalar_multiplication.cpp` for a more detailed description. * - * It's...unsafe, because we assume that the incomplete addition formula exceptions are not triggered. + * It's...unsafe, because we assume that the incomplete addition formula exceptions are not triggered i.e. that all the + * points provided as arguments to the msm are distinct. * We don't bother to check for this to avoid conditional branches in a critical section of our code. - * This is fine for situations where your bases are linearly independent (i.e. KZG10 polynomial commitments), - * because triggering the incomplete addition exceptions is about as hard as solving the disrete log problem. - * - * This is ok for the prover, but GIANT RED CLAXON WARNINGS FOR THE VERIFIER - * Don't use this in a verification algorithm! That would be a really bad idea. - * Unless you're a malicious adversary, then it would be a great idea! + * This is fine for situations where your bases are linearly independent (i.e. KZG10 polynomial commitments where + * there should be no equal points in the SRS), because triggering the incomplete addition exceptions is about as hard + *as solving the disrete log problem. This is ok for the prover, but GIANT RED CLAXON WARNINGS FOR THE VERIFIER Don't + *use this in a verification algorithm! That would be a really bad idea. Unless you're a malicious adversary, then it + *would be a great idea! * **/ g1::element pippenger_unsafe(fr* scalars, diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.cpp b/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.cpp index e55e6bdd5a..681c54e56e 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.cpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.cpp @@ -43,13 +43,11 @@ std::shared_ptr StandardHonkComposerHelp */ std::shared_ptr StandardHonkComposerHelper::compute_verification_key_base( - std::shared_ptr const& proving_key, - std::shared_ptr const& vrs) + std::shared_ptr const& proving_key) { auto key = std::make_shared( - proving_key->circuit_size, proving_key->num_public_inputs, vrs, proving_key->composer_type); - // TODO(kesha): Dirty hack for now. Need to actually make commitment-agnositc - auto commitment_key = pcs::kzg::CommitmentKey(proving_key->circuit_size, "../srs_db/ignition"); + proving_key->circuit_size, proving_key->num_public_inputs, proving_key->composer_type); + auto commitment_key = PCSParams::CommitmentKey(proving_key->circuit_size, "../srs_db/ignition"); // Compute and store commitments to all precomputed polynomials key->q_m = commitment_key.commit(proving_key->q_m); @@ -135,8 +133,7 @@ std::shared_ptr StandardHonkCompose compute_proving_key(circuit_constructor); } - verification_key = - StandardHonkComposerHelper::compute_verification_key_base(proving_key, crs_factory_->get_verifier_crs()); + verification_key = StandardHonkComposerHelper::compute_verification_key_base(proving_key); verification_key->composer_type = proving_key->composer_type; return verification_key; @@ -147,10 +144,10 @@ StandardVerifier StandardHonkComposerHelper::create_verifier(const CircuitConstr compute_verification_key(circuit_constructor); StandardVerifier output_state(verification_key); - // TODO(Cody): This should be more generic - auto kate_verification_key = std::make_unique("../srs_db/ignition"); + auto pcs_verification_key = + std::make_unique(verification_key->circuit_size, "../srs_db/ignition"); - output_state.kate_verification_key = std::move(kate_verification_key); + output_state.pcs_verification_key = std::move(pcs_verification_key); return output_state; } @@ -159,9 +156,13 @@ StandardProver StandardHonkComposerHelper::create_prover(const CircuitConstructo { compute_proving_key(circuit_constructor); compute_witness(circuit_constructor); - StandardProver output_state(proving_key); + auto pcs_commitment_key = + std::make_unique(proving_key->circuit_size, "../srs_db/ignition"); + + output_state.pcs_commitment_key = std::move(pcs_commitment_key); + return output_state; } } // namespace proof_system::honk diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.hpp b/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.hpp index e49e41882e..14bd534db0 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.hpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.hpp @@ -15,6 +15,7 @@ namespace proof_system::honk { class StandardHonkComposerHelper { public: using Flavor = flavor::Standard; + using PCSParams = Flavor::PCSParams; using CircuitConstructor = Flavor::CircuitConstructor; using ProvingKey = Flavor::ProvingKey; using VerificationKey = Flavor::VerificationKey; @@ -63,7 +64,7 @@ class StandardHonkComposerHelper { // This needs to be static as it may be used only to compute the selector commitments. static std::shared_ptr compute_verification_key_base( - std::shared_ptr const& proving_key, std::shared_ptr const& vrs); + std::shared_ptr const& proving_key); void compute_witness(const CircuitConstructor& circuit_constructor, const size_t minimum_circuit_size = 0); }; diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp index eb02bdca41..f5c5da1594 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp @@ -143,6 +143,11 @@ UltraProver UltraHonkComposerHelper::create_prover(CircuitConstructor& circuit_c UltraProver output_state(proving_key); + auto pcs_commitment_key = + std::make_unique(proving_key->circuit_size, "../srs_db/ignition"); + + output_state.pcs_commitment_key = std::move(pcs_commitment_key); + return output_state; } @@ -158,10 +163,10 @@ UltraVerifier UltraHonkComposerHelper::create_verifier(const CircuitConstructor& UltraVerifier output_state(verification_key); - // TODO(Cody): This should be more generic - auto kate_verification_key = std::make_unique("../srs_db/ignition"); + auto pcs_verification_key = + std::make_unique(verification_key->circuit_size, "../srs_db/ignition"); - output_state.kate_verification_key = std::move(kate_verification_key); + output_state.pcs_verification_key = std::move(pcs_verification_key); return output_state; } @@ -310,13 +315,10 @@ std::shared_ptr UltraHonkComposerHelpe compute_proving_key(circuit_constructor); } - verification_key = std::make_shared(proving_key->circuit_size, - proving_key->num_public_inputs, - crs_factory_->get_verifier_crs(), - proving_key->composer_type); + verification_key = std::make_shared( + proving_key->circuit_size, proving_key->num_public_inputs, proving_key->composer_type); - // TODO(kesha): Dirty hack for now. Need to actually make commitment-agnositc - auto commitment_key = pcs::kzg::CommitmentKey(proving_key->circuit_size, "../srs_db/ignition"); + auto commitment_key = PCSCommitmentKey(proving_key->circuit_size, "../srs_db/ignition"); // Compute and store commitments to all precomputed polynomials verification_key->q_m = commitment_key.commit(proving_key->q_m); diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp index 7e426d7b4d..5a13a92f33 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp @@ -19,6 +19,10 @@ class UltraHonkComposerHelper { using CircuitConstructor = Flavor::CircuitConstructor; using ProvingKey = Flavor::ProvingKey; using VerificationKey = Flavor::VerificationKey; + using PCSParams = Flavor::PCSParams; + using PCS = Flavor::PCS; + using PCSCommitmentKey = PCSParams::CommitmentKey; + using PCSVerificationKey = PCSParams::VerificationKey; static constexpr size_t NUM_RESERVED_GATES = 4; // equal to the number of multilinear evaluations leaked static constexpr size_t NUM_WIRES = CircuitConstructor::NUM_WIRES; diff --git a/cpp/src/barretenberg/honk/flavor/standard.hpp b/cpp/src/barretenberg/honk/flavor/standard.hpp index 29fed767c0..a083a0d79e 100644 --- a/cpp/src/barretenberg/honk/flavor/standard.hpp +++ b/cpp/src/barretenberg/honk/flavor/standard.hpp @@ -7,6 +7,7 @@ #include #include "barretenberg/honk/pcs/commitment_key.hpp" #include "barretenberg/honk/sumcheck/polynomials/barycentric_data.hpp" +#include "barretenberg/honk/pcs/kzg/kzg.hpp" #include "barretenberg/honk/sumcheck/polynomials/univariate.hpp" #include "barretenberg/ecc/curves/bn254/g1.hpp" #include "barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp" @@ -40,6 +41,7 @@ class Standard { using Commitment = G1::affine_element; using CommitmentHandle = G1::affine_element; using PCSParams = pcs::kzg::Params; + using PCS = pcs::kzg::KZG; static constexpr size_t NUM_WIRES = CircuitConstructor::NUM_WIRES; // The number of multivariate polynomials on which a sumcheck prover sumcheck operates (including shifts). We often diff --git a/cpp/src/barretenberg/honk/flavor/ultra.hpp b/cpp/src/barretenberg/honk/flavor/ultra.hpp index b1670666db..26ba270b4f 100644 --- a/cpp/src/barretenberg/honk/flavor/ultra.hpp +++ b/cpp/src/barretenberg/honk/flavor/ultra.hpp @@ -7,6 +7,7 @@ #include #include "barretenberg/honk/pcs/commitment_key.hpp" #include "barretenberg/honk/sumcheck/polynomials/barycentric_data.hpp" +#include "barretenberg/honk/pcs/ipa/ipa.hpp" #include "barretenberg/honk/sumcheck/polynomials/univariate.hpp" #include "barretenberg/ecc/curves/bn254/g1.hpp" #include "barretenberg/honk/transcript/transcript.hpp" @@ -35,7 +36,11 @@ class Ultra { using GroupElement = G1::element; using Commitment = G1::affine_element; using CommitmentHandle = G1::affine_element; - using PCSParams = pcs::kzg::Params; + // UltraHonk will be run with KZG by default but temporarily we set the commitment to IPA to + // be able to do e2e tests with this pcs as well + // TODO: instantiate this with but IPA and KZG when the templating work is finished + using PCSParams = pcs::ipa::Params; + using PCS = pcs::ipa::IPA; static constexpr size_t NUM_WIRES = CircuitConstructor::NUM_WIRES; // The number of multivariate polynomials on which a sumcheck prover sumcheck operates (including shifts). We often diff --git a/cpp/src/barretenberg/honk/pcs/claim.hpp b/cpp/src/barretenberg/honk/pcs/claim.hpp index d009edc0d3..a07a070656 100644 --- a/cpp/src/barretenberg/honk/pcs/claim.hpp +++ b/cpp/src/barretenberg/honk/pcs/claim.hpp @@ -26,15 +26,15 @@ template class OpeningPair { * @tparam Params for the given commitment scheme */ template class OpeningClaim { - using CK = typename Params::CK; - using CommitmentAffine = typename Params::C; + using CK = typename Params::CommitmentKey; + using Commitment = typename Params::Commitment; using Fr = typename Params::Fr; public: // (challenge r, evaluation v = p(r)) OpeningPair opening_pair; // commitment to univariate polynomial p(X) - CommitmentAffine commitment; + Commitment commitment; /** * @brief inefficiently check that the claim is correct by recomputing the commitment @@ -44,7 +44,7 @@ template class OpeningClaim { * @param polynomial the claimed witness polynomial p(X) * @return C = Commit(p(X)) && p(r) = v */ - bool verify(CK* ck, const barretenberg::Polynomial& polynomial) const + bool verify(std::shared_ptr ck, const barretenberg::Polynomial& polynomial) const { Fr real_eval = polynomial.evaluate(opening_pair.challenge); if (real_eval != opening_pair.evaluation) { @@ -78,14 +78,14 @@ template class OpeningClaim { * @tparam CommitmentKey */ template class MLEOpeningClaim { - using CommitmentAffine = typename Params::C; + using Commitment = typename Params::Commitment; using Fr = typename Params::Fr; public: // commitment to a univariate polynomial // whose coefficients are the multi-linear evaluations // of C = [f] - CommitmentAffine commitment; + Commitment commitment; // v = f(u) = ∑ᵢ aᵢ⋅Lᵢ(u) // v↺ = g(u) = a₁⋅L₀(u) + … + aₙ₋₁⋅Lₙ₋₂(u) Fr evaluation; diff --git a/cpp/src/barretenberg/honk/pcs/commitment_key.hpp b/cpp/src/barretenberg/honk/pcs/commitment_key.hpp index 5d4e32c80d..432fa17bfb 100644 --- a/cpp/src/barretenberg/honk/pcs/commitment_key.hpp +++ b/cpp/src/barretenberg/honk/pcs/commitment_key.hpp @@ -3,6 +3,8 @@ /** * @brief Provides interfaces for different 'CommitmentKey' classes. * + * TODO(#218)(Adrian / Mara): This class should take ownership of the SRS, and handle reading the file from disk as well + * as carrying out any modification to the SRS (e.g compute pippenger point table) to simplify the codebase. */ #include "barretenberg/polynomials/polynomial_arithmetic.hpp" @@ -20,107 +22,94 @@ namespace proof_system::honk::pcs { namespace kzg { -/** - * @brief CommitmentKey object over a pairing group 𝔾₁, using a structured reference string (SRS). - * The SRS is given as a list of 𝔾₁ points - * { [xʲ]₁ }ⱼ where 'x' is unknown. - * - * TODO(#218)(Adrian): This class should take ownership of the SRS, and handle reading the file from disk. - */ -class CommitmentKey { +struct Params { using Fr = typename barretenberg::g1::Fr; - // C is a "raw commitment" resulting to be fed to the transcript. - using C = typename barretenberg::g1::affine_element; - // Commitment represent's a homomorphically computed group element. - using Commitment = barretenberg::g1::element; + using Commitment = typename barretenberg::g1::affine_element; + using GroupElement = barretenberg::g1::element; using Polynomial = barretenberg::Polynomial; - public: - CommitmentKey() = delete; - + class CommitmentKey; + class VerificationKey; /** - * @brief Construct a new Kate Commitment Key object from existing SRS + * @brief CommitmentKey object over a pairing group 𝔾₁, using a structured reference string (SRS). + * The SRS is given as a list of 𝔾₁ points { [xʲ]₁ }ⱼ where 'x' is unknown. The SRS stored in the commitment key is + * after applying the pippenger_point_table thus being double the size of what is loaded from path. * - * @param n - * @param path * */ - CommitmentKey(const size_t num_points, std::string_view path) - : pippenger_runtime_state(num_points) - , srs(num_points, std::string(path)) - {} - - /** - * @brief Uses the ProverSRS to create a commitment to p(X) - * - * @param polynomial a univariate polynomial p(X) = ∑ᵢ aᵢ⋅Xⁱ () - * @return Commitment computed as C = [p(x)] = ∑ᵢ aᵢ⋅[xⁱ]₁ - */ - C commit(std::span polynomial) - { - const size_t degree = polynomial.size(); - ASSERT(degree <= srs.get_monomial_size()); - return barretenberg::scalar_multiplication::pippenger_unsafe( - const_cast(polynomial.data()), srs.get_monomial_points(), degree, pippenger_runtime_state); + class CommitmentKey { + + public: + CommitmentKey() = delete; + + /** + * @brief Construct a new Kate Commitment Key object from existing SRS + * + * @param n + * @param path + * + */ + CommitmentKey(const size_t num_points, std::string_view path) + : pippenger_runtime_state(num_points) + , srs(num_points, std::string(path)) + {} + + /** + * @brief Uses the ProverSRS to create a commitment to p(X) + * + * @param polynomial a univariate polynomial p(X) = ∑ᵢ aᵢ⋅Xⁱ () + * @return Commitment computed as C = [p(x)] = ∑ᵢ aᵢ⋅[xⁱ]₁ where x is the secret trapdoor + */ + Commitment commit(std::span polynomial) + { + const size_t degree = polynomial.size(); + ASSERT(degree <= srs.get_monomial_size()); + return barretenberg::scalar_multiplication::pippenger_unsafe( + const_cast(polynomial.data()), srs.get_monomial_points(), degree, pippenger_runtime_state); + }; + + barretenberg::scalar_multiplication::pippenger_runtime_state pippenger_runtime_state; + proof_system::FileReferenceString srs; }; - private: - barretenberg::scalar_multiplication::pippenger_runtime_state pippenger_runtime_state; - proof_system::FileReferenceString srs; -}; - -class VerificationKey { - using Fr = typename barretenberg::g1::Fr; - using C = typename barretenberg::g1::affine_element; - - using Commitment = barretenberg::g1::element; - using Polynomial = barretenberg::Polynomial; - - public: - VerificationKey() = delete; - - /** - * @brief Construct a new Kate Commitment Key object from existing SRS - * - * - * @param verifier_srs verifier G2 point - */ - VerificationKey(std::string_view path) - : verifier_srs(std::string(path)) - {} - - /** - * @brief verifies a pairing equation over 2 points using the verifier SRS - * - * @param p0 = P₀ - * @param p1 = P₁ - * @return e(P₀,[1]₁)e(P₁,[x]₂) ≡ [1]ₜ - */ - bool pairing_check(const Commitment& p0, const Commitment& p1) - { - C pairing_points[2]{ p0, p1 }; - // The final pairing check of step 12. - // TODO(Adrian): try to template parametrise the pairing + fq12 output :/ - barretenberg::fq12 result = barretenberg::pairing::reduced_ate_pairing_batch_precomputed( - pairing_points, verifier_srs.get_precomputed_g2_lines(), 2); - - return (result == barretenberg::fq12::one()); - } - - private: - proof_system::VerifierFileReferenceString verifier_srs; -}; - -struct Params { - using Fr = typename barretenberg::g1::Fr; - using C = typename barretenberg::g1::affine_element; - - using Commitment = barretenberg::g1::element; - using Polynomial = barretenberg::Polynomial; - - using CK = CommitmentKey; - using VK = VerificationKey; + class VerificationKey { + + public: + VerificationKey() = delete; + + /** + * @brief Construct a new Kate Verification Key object from existing SRS + * + * @param num_points + * @param verifier_srs verifier G2 point + */ + VerificationKey(size_t num_points, std::string_view path) + : pippenger_runtime_state(num_points) + , verifier_srs(std::string(path)) + {} + + /** + * @brief verifies a pairing equation over 2 points using the verifier SRS + * + * @param p0 = P₀ + * @param p1 = P₁ + * @return e(P₀,[1]₁)e(P₁,[x]₂) ≡ [1]ₜ + */ + bool pairing_check(const GroupElement& p0, const GroupElement& p1) + { + Commitment pairing_points[2]{ p0, p1 }; + // The final pairing check of step 12. + // TODO(Adrian): try to template parametrise the pairing + fq12 output :/ + barretenberg::fq12 result = barretenberg::pairing::reduced_ate_pairing_batch_precomputed( + pairing_points, verifier_srs.get_precomputed_g2_lines(), 2); + + return (result == barretenberg::fq12::one()); + } + + barretenberg::scalar_multiplication::pippenger_runtime_state pippenger_runtime_state; + proof_system::VerifierFileReferenceString verifier_srs; + }; }; } // namespace kzg @@ -132,155 +121,125 @@ namespace { template constexpr typename G::Fr trapdoor(5); } -/** - * @brief Simulates a KZG CommitmentKey, but where we know the secret trapdoor - * which allows us to commit to polynomials using a single group multiplication. - * - * @tparam G the commitment group - */ -template class CommitmentKey { +template struct Params { using Fr = typename G::Fr; - using C = typename G::affine_element; + using Commitment = typename G::affine_element; + using GroupElement = typename G::element; - using Commitment = typename G::element; using Polynomial = barretenberg::Polynomial; - public: - /** - * @brief efficiently create a KZG commitment to p(X) using the trapdoor 'secret' - * Uses only 1 group scalar multiplication, and 1 polynomial evaluation - * - * - * @param polynomial a univariate polynomial p(X) - * @return Commitment computed as C = p(secret)•[1]_1 . - */ - C commit(std::span polynomial) - { - const Fr eval_secret = barretenberg::polynomial_arithmetic::evaluate(polynomial, trapdoor); - return C::one() * eval_secret; - }; -}; - -template class VerificationKey { - using Fr = typename G::Fr; - using C = typename G::affine_element; + template class CommitmentKey; + template class VerificationKey; - using Commitment = typename G::element; - using Polynomial = barretenberg::Polynomial; - - public: /** - * @brief verifies a pairing equation over 2 points using the trapdoor + * @brief Simulates a KZG CommitmentKey, but where we know the secret trapdoor + * which allows us to commit to polynomials using a single group multiplication. * - * @param p0 = P₀ - * @param p1 = P₁ - * @return P₀ - x⋅P₁ ≡ [1] + * @tparam G the commitment group */ - bool pairing_check(const Commitment& p0, const Commitment& p1) - { - Commitment result = p0 + p1 * trapdoor; - return result.is_point_at_infinity(); - } -}; - -template struct Params { - using Fr = typename G::Fr; - using C = typename G::affine_element; - - using Commitment = typename G::element; - using Polynomial = barretenberg::Polynomial; + template class CommitmentKey { + + public: + /** + * @brief efficiently create a KZG commitment to p(X) using the trapdoor 'secret' + * Uses only 1 group scalar multiplication, and 1 polynomial evaluation + * + * + * @param polynomial a univariate polynomial p(X) + * @return Commitment computed as C = p(secret)•[1]_1 . + */ + Commitment commit(std::span polynomial) + { + const Fr eval_secret = barretenberg::polynomial_arithmetic::evaluate(polynomial, trapdoor); + return Commitment::one() * eval_secret; + }; + }; - using CK = CommitmentKey; - using VK = VerificationKey; + template class VerificationKey { + + public: + /** + * @brief verifies a pairing equation over 2 points using the trapdoor + * + * @param p0 = P₀ + * @param p1 = P₁ + * @return P₀ - x⋅P₁ ≡ [1] + */ + bool pairing_check(const Commitment& p0, const Commitment& p1) + { + Commitment result = p0 + p1 * trapdoor; + return result.is_point_at_infinity(); + } + }; }; } // namespace fake namespace ipa { -/** - * @brief CommitmentKey object over a group 𝔾₁, using a structured reference string (SRS). - * The SRS is given as a list of 𝔾₁ points - * { [xʲ]₁ }ⱼ where 'x' is unknown. - * - * @todo This class should take ownership of the SRS, and handle reading the file from disk. - */ -class CommitmentKey { +struct Params { using Fr = typename barretenberg::g1::Fr; - // C is a "raw commitment" resulting to be fed to the transcript. - using C = typename barretenberg::g1::affine_element; - // Commitment represent's a homomorphically computed group element. - using Commitment = barretenberg::g1::element; + using Commitment = typename barretenberg::g1::affine_element; + using GroupElement = barretenberg::g1::element; using Polynomial = barretenberg::Polynomial; - public: - CommitmentKey() = delete; - - /** - * @brief Construct a new Kate Commitment Key object from existing SRS - * - * @param n - * @param path - * - * @todo change path to string_view - */ - CommitmentKey(const size_t num_points, std::string_view path) - : pippenger_runtime_state(num_points) - , srs(num_points, std::string(path)) - {} - - /** - * @brief Uses the ProverSRS to create a commitment to p(X) - * - * @param polynomial a univariate polynomial p(X) = ∑ᵢ aᵢ⋅Xⁱ () - * @return Commitment computed as C = [p(x)] = ∑ᵢ aᵢ⋅[xⁱ]₁ - */ - C commit(std::span polynomial) - { - const size_t degree = polynomial.size(); - ASSERT(degree <= srs.get_monomial_size()); - return barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( - const_cast(polynomial.data()), srs.get_monomial_points(), degree, pippenger_runtime_state); + class CommitmentKey; + class VerificationKey; + + class CommitmentKey { + + public: + CommitmentKey() = delete; + + /** + * @brief Construct a new IPA Commitment Key object from existing SRS.. + * + * @param num_points + * @param path + * + */ + CommitmentKey(const size_t num_points, std::string_view path) + : pippenger_runtime_state(num_points) + , srs(num_points, std::string(path)) + {} + + /** + * @brief Uses the ProverSRS to create an unblinded commitment to p(X) + * + * @param polynomial a univariate polynomial p(X) = ∑ᵢ aᵢ⋅Xⁱ () + * @return Commitment computed as C = [p(x)] = ∑ᵢ aᵢ⋅Gᵢ where Gᵢ is the i-th element of the SRS + */ + Commitment commit(std::span polynomial) + { + const size_t degree = polynomial.size(); + ASSERT(degree <= srs.get_monomial_size()); + return barretenberg::scalar_multiplication::pippenger_unsafe( + const_cast(polynomial.data()), srs.get_monomial_points(), degree, pippenger_runtime_state); + }; + + barretenberg::scalar_multiplication::pippenger_runtime_state pippenger_runtime_state; + proof_system::FileReferenceString srs; }; - barretenberg::scalar_multiplication::pippenger_runtime_state pippenger_runtime_state; - proof_system::FileReferenceString srs; -}; - -class VerificationKey { - using Fr = typename barretenberg::g1::Fr; - using C = typename barretenberg::g1::affine_element; - - using Commitment = barretenberg::g1::element; - using Polynomial = barretenberg::Polynomial; - - public: - VerificationKey() = delete; - - /** - * @brief Construct a new Kate Commitment Key object from existing SRS - * - * - * @param verifier_srs verifier G2 point - */ - VerificationKey(const size_t num_points, std::string_view path) - : pippenger_runtime_state(num_points) - , srs(num_points, std::string(path)) - {} - - barretenberg::scalar_multiplication::pippenger_runtime_state pippenger_runtime_state; - proof_system::FileReferenceString srs; -}; - -struct Params { - using Fr = typename barretenberg::g1::Fr; - using C = typename barretenberg::g1::affine_element; - - using Commitment = barretenberg::g1::element; - using Polynomial = barretenberg::Polynomial; - - using CK = CommitmentKey; - using VK = VerificationKey; + class VerificationKey { + public: + VerificationKey() = delete; + + /** + * @brief Construct a new IPA Verification Key object from existing SRS + * + * + * @param num_points specifies the length of the SRS + * @param path is the location to the SRS file + */ + VerificationKey(const size_t num_points, std::string_view path) + : pippenger_runtime_state(num_points) + , srs(num_points, std::string(path)) + {} + + barretenberg::scalar_multiplication::pippenger_runtime_state pippenger_runtime_state; + proof_system::FileReferenceString srs; + }; }; } // namespace ipa diff --git a/cpp/src/barretenberg/honk/pcs/commitment_key.test.hpp b/cpp/src/barretenberg/honk/pcs/commitment_key.test.hpp index 991bc98386..97f9ad98be 100644 --- a/cpp/src/barretenberg/honk/pcs/commitment_key.test.hpp +++ b/cpp/src/barretenberg/honk/pcs/commitment_key.test.hpp @@ -25,16 +25,16 @@ constexpr std::string_view kzg_srs_path = "../srs_db/ignition"; template inline std::shared_ptr CreateCommitmentKey(); -template <> inline std::shared_ptr CreateCommitmentKey() +template <> inline std::shared_ptr CreateCommitmentKey() { const size_t n = 128; - return std::make_shared(n, kzg_srs_path); + return std::make_shared(n, kzg_srs_path); } // For IPA -template <> inline std::shared_ptr CreateCommitmentKey() +template <> inline std::shared_ptr CreateCommitmentKey() { const size_t n = 128; - return std::make_shared(n, kzg_srs_path); + return std::make_shared(n, kzg_srs_path); } template inline std::shared_ptr CreateCommitmentKey() @@ -45,15 +45,17 @@ template inline std::shared_ptr CreateCommitmentKey() template inline std::shared_ptr CreateVerificationKey(); -template <> inline std::shared_ptr CreateVerificationKey() +template <> inline std::shared_ptr CreateVerificationKey() { - return std::make_shared(kzg_srs_path); + const size_t n = 128; + return std::make_shared(n, kzg_srs_path); } // For IPA -template <> inline std::shared_ptr CreateVerificationKey() +template <> inline std::shared_ptr CreateVerificationKey() { const size_t n = 128; - return std::make_shared(n, kzg_srs_path); + // + return std::make_shared(n, kzg_srs_path); } template inline std::shared_ptr CreateVerificationKey() // requires std::default_initializable @@ -61,23 +63,23 @@ template inline std::shared_ptr CreateVerificationKey() return std::make_shared(); } template class CommitmentTest : public ::testing::Test { - using CK = typename Params::CK; - using VK = typename Params::VK; + using CK = typename Params::CommitmentKey; + using VK = typename Params::VerificationKey; using Fr = typename Params::Fr; - using CommitmentAffine = typename Params::C; + using Commitment = typename Params::Commitment; using Polynomial = typename Params::Polynomial; using Transcript = transcript::StandardTranscript; public: CommitmentTest() - : engine{ &numeric::random::get_debug_engine() } + : engine{ &numeric::random::get_engine() } {} std::shared_ptr ck() { return commitment_key; } std::shared_ptr vk() { return verification_key; } - CommitmentAffine commit(const Polynomial& polynomial) { return commitment_key->commit(polynomial); } + Commitment commit(const Polynomial& polynomial) { return commitment_key->commit(polynomial); } Polynomial random_polynomial(const size_t n) { @@ -121,7 +123,7 @@ template class CommitmentTest : public ::testing::Test { auto& [x, y] = claim.opening_pair; Fr y_expected = witness.evaluate(x); EXPECT_EQ(y, y_expected) << "OpeningClaim: evaluations mismatch"; - CommitmentAffine commitment_expected = commit(witness); + Commitment commitment_expected = commit(witness); EXPECT_EQ(commitment, commitment_expected) << "OpeningClaim: commitment mismatch"; } @@ -186,14 +188,14 @@ template class CommitmentTest : public ::testing::Test { // Can be omitted if not needed. static void TearDownTestSuite() {} - static typename std::shared_ptr commitment_key; - static typename std::shared_ptr verification_key; + static typename std::shared_ptr commitment_key; + static typename std::shared_ptr verification_key; }; template -typename std::shared_ptr CommitmentTest::commitment_key = nullptr; +typename std::shared_ptr CommitmentTest::commitment_key = nullptr; template -typename std::shared_ptr CommitmentTest::verification_key = nullptr; +typename std::shared_ptr CommitmentTest::verification_key = nullptr; using CommitmentSchemeParams = ::testing::Types; using IpaCommitmentSchemeParams = ::testing::Types; diff --git a/cpp/src/barretenberg/honk/pcs/gemini/gemini.hpp b/cpp/src/barretenberg/honk/pcs/gemini/gemini.hpp index 6e2cd50fe7..56e73ab4c0 100644 --- a/cpp/src/barretenberg/honk/pcs/gemini/gemini.hpp +++ b/cpp/src/barretenberg/honk/pcs/gemini/gemini.hpp @@ -67,11 +67,11 @@ template struct ProverOutput { }; template class MultilinearReductionScheme { - using CK = typename Params::CK; + using CK = typename Params::CommitmentKey; using Fr = typename Params::Fr; + using GroupElement = typename Params::GroupElement; using Commitment = typename Params::Commitment; - using CommitmentAffine = typename Params::C; using Polynomial = barretenberg::Polynomial; public: @@ -212,18 +212,18 @@ template class MultilinearReductionScheme { */ static std::vector> reduce_verify(std::span mle_opening_point, /* u */ const Fr batched_evaluation, /* all */ - Commitment& batched_f, /* unshifted */ - Commitment& batched_g, /* to-be-shifted */ + GroupElement& batched_f, /* unshifted */ + GroupElement& batched_g, /* to-be-shifted */ VerifierTranscript& transcript) { const size_t num_variables = mle_opening_point.size(); // Get polynomials Fold_i, i = 1,...,m-1 from transcript - std::vector commitments; + std::vector commitments; commitments.reserve(num_variables - 1); for (size_t i = 0; i < num_variables - 1; ++i) { auto commitment = - transcript.template receive_from_prover("Gemini:FOLD_" + std::to_string(i + 1)); + transcript.template receive_from_prover("Gemini:FOLD_" + std::to_string(i + 1)); commitments.emplace_back(commitment); } @@ -329,14 +329,14 @@ template class MultilinearReductionScheme { * @param r evaluation point at which we have partially evaluated A₀ at r and -r. * @return std::pair c0_r_pos, c0_r_neg */ - static std::pair compute_simulated_commitments(Commitment& batched_f, - Commitment& batched_g, - Fr r) + static std::pair compute_simulated_commitments(GroupElement& batched_f, + GroupElement& batched_g, + Fr r) { // C₀ᵣ₊ = [F] + r⁻¹⋅[G] - Commitment C0_r_pos = batched_f; + GroupElement C0_r_pos = batched_f; // C₀ᵣ₋ = [F] - r⁻¹⋅[G] - Commitment C0_r_neg = batched_f; + GroupElement C0_r_neg = batched_f; Fr r_inv = r.invert(); if (!batched_g.is_point_at_infinity()) { batched_g *= r_inv; diff --git a/cpp/src/barretenberg/honk/pcs/gemini/gemini.test.cpp b/cpp/src/barretenberg/honk/pcs/gemini/gemini.test.cpp index cf2e0549cf..69a28eb032 100644 --- a/cpp/src/barretenberg/honk/pcs/gemini/gemini.test.cpp +++ b/cpp/src/barretenberg/honk/pcs/gemini/gemini.test.cpp @@ -12,7 +12,7 @@ namespace proof_system::honk::pcs::gemini { template class GeminiTest : public CommitmentTest { using Gemini = MultilinearReductionScheme; using Fr = typename Params::Fr; - using Commitment = typename Params::Commitment; + using GroupElement = typename Params::GroupElement; using Polynomial = typename barretenberg::Polynomial; public: @@ -21,8 +21,8 @@ template class GeminiTest : public CommitmentTest { std::vector multilinear_evaluations, std::vector> multilinear_polynomials, std::vector> multilinear_polynomials_to_be_shifted, - std::vector multilinear_commitments, - std::vector multilinear_commitments_to_be_shifted) + std::vector multilinear_commitments, + std::vector multilinear_commitments_to_be_shifted) { auto prover_transcript = ProverTranscript::init_empty(); @@ -38,8 +38,8 @@ template class GeminiTest : public CommitmentTest { Polynomial batched_unshifted(1 << log_n); Polynomial batched_to_be_shifted(1 << log_n); - Commitment batched_commitment_unshifted = Commitment::zero(); - Commitment batched_commitment_to_be_shifted = Commitment::zero(); + GroupElement batched_commitment_unshifted = GroupElement::zero(); + GroupElement batched_commitment_to_be_shifted = GroupElement::zero(); const size_t num_unshifted = multilinear_polynomials.size(); const size_t num_shifted = multilinear_polynomials_to_be_shifted.size(); for (size_t i = 0; i < num_unshifted; ++i) { @@ -105,7 +105,7 @@ TYPED_TEST_SUITE(GeminiTest, CommitmentSchemeParams); TYPED_TEST(GeminiTest, Single) { using Fr = typename TypeParam::Fr; - using Commitment = typename TypeParam::Commitment; + using GroupElement = typename TypeParam::GroupElement; const size_t n = 16; const size_t log_n = 4; @@ -119,8 +119,8 @@ TYPED_TEST(GeminiTest, Single) std::vector multilinear_evaluations = { eval }; std::vector> multilinear_polynomials = { poly }; std::vector> multilinear_polynomials_to_be_shifted = {}; - std::vector multilinear_commitments = { commitment }; - std::vector multilinear_commitments_to_be_shifted = {}; + std::vector multilinear_commitments = { commitment }; + std::vector multilinear_commitments_to_be_shifted = {}; this->execute_gemini_and_verify_claims(log_n, u, @@ -134,7 +134,7 @@ TYPED_TEST(GeminiTest, Single) TYPED_TEST(GeminiTest, SingleShift) { using Fr = typename TypeParam::Fr; - using Commitment = typename TypeParam::Commitment; + using GroupElement = typename TypeParam::GroupElement; const size_t n = 16; const size_t log_n = 4; @@ -152,8 +152,8 @@ TYPED_TEST(GeminiTest, SingleShift) std::vector multilinear_evaluations = { eval_shift }; std::vector> multilinear_polynomials = {}; std::vector> multilinear_polynomials_to_be_shifted = { poly }; - std::vector multilinear_commitments = {}; - std::vector multilinear_commitments_to_be_shifted = { commitment }; + std::vector multilinear_commitments = {}; + std::vector multilinear_commitments_to_be_shifted = { commitment }; this->execute_gemini_and_verify_claims(log_n, u, @@ -167,7 +167,7 @@ TYPED_TEST(GeminiTest, SingleShift) TYPED_TEST(GeminiTest, Double) { using Fr = typename TypeParam::Fr; - using Commitment = typename TypeParam::Commitment; + using GroupElement = typename TypeParam::GroupElement; const size_t n = 16; const size_t log_n = 4; @@ -187,8 +187,8 @@ TYPED_TEST(GeminiTest, Double) std::vector multilinear_evaluations = { eval1, eval2 }; std::vector> multilinear_polynomials = { poly1, poly2 }; std::vector> multilinear_polynomials_to_be_shifted = {}; - std::vector multilinear_commitments = { commitment1, commitment2 }; - std::vector multilinear_commitments_to_be_shifted = {}; + std::vector multilinear_commitments = { commitment1, commitment2 }; + std::vector multilinear_commitments_to_be_shifted = {}; this->execute_gemini_and_verify_claims(log_n, u, @@ -203,7 +203,7 @@ TYPED_TEST(GeminiTest, DoubleWithShift) { // using Gemini = MultilinearReductionScheme; using Fr = typename TypeParam::Fr; - using Commitment = typename TypeParam::Commitment; + using GroupElement = typename TypeParam::GroupElement; const size_t n = 16; const size_t log_n = 4; @@ -225,8 +225,8 @@ TYPED_TEST(GeminiTest, DoubleWithShift) std::vector multilinear_evaluations = { eval1, eval2, eval2_shift }; std::vector> multilinear_polynomials = { poly1, poly2 }; std::vector> multilinear_polynomials_to_be_shifted = { poly2 }; - std::vector multilinear_commitments = { commitment1, commitment2 }; - std::vector multilinear_commitments_to_be_shifted = { commitment2 }; + std::vector multilinear_commitments = { commitment1, commitment2 }; + std::vector multilinear_commitments_to_be_shifted = { commitment2 }; this->execute_gemini_and_verify_claims(log_n, u, diff --git a/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp b/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp index a7eaf54f91..edbec05a24 100644 --- a/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp +++ b/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp @@ -2,18 +2,12 @@ #include #include #include +#include +#include "barretenberg/common/assert.hpp" #include "barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.hpp" +#include "barretenberg/honk/pcs/claim.hpp" #include "barretenberg/honk/pcs/commitment_key.hpp" -#include "barretenberg/stdlib/primitives/curves/bn254.hpp" - -// Suggested by Zac: Future optimisations -// 1: write a program that generates a large set of generator points (2^23?) and writes to a file on disk -// 2: create a SRS class for IPA similar to existing SRS class, that loads these points from disk -// and stores in struct *and* applies the pippenger point table endomorphism transforation -// 3: when constructing a InnerProductArgument class, pass std::shared_ptr as input param and store as member -// variable -// 4: (SRS class should contain a `pippenger_runtime_state` object so it does not need to be repeatedly -// generated) +#include "barretenberg/honk/transcript/transcript.hpp" /** * @brief IPA (inner-product argument) commitment scheme class. Conforms to the specification @@ -21,63 +15,65 @@ * */ namespace proof_system::honk::pcs::ipa { -template class InnerProductArgument { + +template class IPA { using Fr = typename Params::Fr; + using GroupElement = typename Params::GroupElement; using Commitment = typename Params::Commitment; - using CommitmentAffine = typename Params::C; - using CK = typename Params::CK; - using VK = typename Params::VK; + using CK = typename Params::CommitmentKey; + using VK = typename Params::VerificationKey; using Polynomial = barretenberg::Polynomial; public: /** - * @brief Compute a proof for opening a single polynomial at a single evaluation point + * @brief Compute an inner product argument proof for opening a single polynomial at a single evaluation point * * @param ck The commitment key containing srs and pippenger_runtime_state for computing MSM * @param opening_pair (challenge, evaluation) * @param polynomial The witness polynomial whose opening proof needs to be computed * @param transcript Prover transcript */ - static void reduce_prove(std::shared_ptr ck, - const OpeningPair& opening_pair, - const Polynomial& polynomial, - ProverTranscript& transcript) + static void compute_opening_proof(std::shared_ptr ck, + const OpeningPair& opening_pair, + const Polynomial& polynomial, + ProverTranscript& transcript) { + ASSERT(opening_pair.challenge != 0 && "The challenge point should not be zero"); + auto poly_degree = static_cast(polynomial.size()); + transcript.send_to_verifier("IPA:poly_degree", static_cast(poly_degree)); Fr generator_challenge = transcript.get_challenge("IPA:generator_challenge"); - auto aux_generator = CommitmentAffine::one() * generator_challenge; + auto aux_generator = Commitment::one() * generator_challenge; - ASSERT(opening_pair.challenge != 0 && "The challenge point should not be zero"); - const size_t poly_degree = polynomial.size(); - // To check poly_degree is greater than zero and a power of two - // TODO(#220)(Arijit): To accomodate non power of two poly_degree + // Checks poly_degree is greater than zero and a power of two + // In the future, we might want to consider if non-powers of two are needed ASSERT((poly_degree > 0) && (!(poly_degree & (poly_degree - 1))) && "The poly_degree should be positive and a power of two"); auto a_vec = polynomial; - // TODO(#220)(Arijit): to make it more efficient by directly using G_vector for the input points when i = 0 and - // write the output points to G_vec_local. Then use G_vec_local for rounds where i>0, this can be done after we - // use SRS instead of G_vector. auto srs_elements = ck->srs.get_monomial_points(); - std::vector G_vec_local(poly_degree); - for (size_t i = 0; i < poly_degree; i++) { - G_vec_local[i] = srs_elements[i]; + std::vector G_vec_local(poly_degree); + // The SRS stored in the commitment key is the result after applying the pippenger point table so the + // values at odd indices contain the point {srs[i-1].x * beta, srs[i-1].y}, where beta is the endomorphism + // G_vec_local should use only the original SRS thus we extract only the even indices. + for (size_t i = 0; i < poly_degree * 2; i += 2) { + G_vec_local[i >> 1] = srs_elements[i]; } - // Construct b vector - // TODO(#220)(Arijit): For round i=0, b_vec can be derived in-place. - // This means that the size of b_vec can be 50% of the current size (i.e. we only write values to b_vec at the - // end of round 0) std::vector b_vec(poly_degree); Fr b_power = 1; for (size_t i = 0; i < poly_degree; i++) { b_vec[i] = b_power; b_power *= opening_pair.challenge; } - // Iterate for log_2(poly_degree) rounds to compute the round commitments. - const size_t log_poly_degree = static_cast(numeric::get_msb(poly_degree)); - std::vector L_elements(log_poly_degree); - std::vector R_elements(log_poly_degree); - size_t round_size = poly_degree; - + // Iterate for log(poly_degree) rounds to compute the round commitments. + auto log_poly_degree = static_cast(numeric::get_msb(poly_degree)); + std::vector L_elements(log_poly_degree); + std::vector R_elements(log_poly_degree); + std::size_t round_size = poly_degree; + + // TODO(#479): restructure IPA so it can be integrated with the pthread alternative to work queue (or even the + // work queue itself). Investigate whether parallelising parts of each rounds of IPA rounds brings significant + // improvements and see if reducing the size of G_vec_local and b_vec by taking the first iteration out of the + // loop can also be integrated. for (size_t i = 0; i < log_poly_degree; i++) { round_size >>= 1; // Compute inner_prod_L := < a_vec_lo, b_vec_hi > and inner_prod_R := < a_vec_hi, b_vec_lo > @@ -98,13 +94,18 @@ template class InnerProductArgument { R_elements[i] += aux_generator * inner_prod_R; std::string index = std::to_string(i); - transcript.send_to_verifier("IPA:L_" + index, CommitmentAffine(L_elements[i])); - transcript.send_to_verifier("IPA:R_" + index, CommitmentAffine(R_elements[i])); + transcript.send_to_verifier("IPA:L_" + index, Commitment(L_elements[i])); + transcript.send_to_verifier("IPA:R_" + index, Commitment(R_elements[i])); // Generate the round challenge. const Fr round_challenge = transcript.get_challenge("IPA:round_challenge_" + index); const Fr round_challenge_inv = round_challenge.invert(); + std::vector G_lo(G_vec_local.begin(), G_vec_local.begin() + static_cast(round_size)); + std::vector G_hi(G_vec_local.begin() + static_cast(round_size), G_vec_local.end()); + G_lo = GroupElement::batch_mul_with_endomorphism(G_lo, round_challenge_inv); + G_hi = GroupElement::batch_mul_with_endomorphism(G_hi, round_challenge); + // Update the vectors a_vec, b_vec and G_vec. // a_vec_next = a_vec_lo * round_challenge + a_vec_hi * round_challenge_inv // b_vec_next = b_vec_lo * round_challenge_inv + b_vec_hi * round_challenge @@ -115,21 +116,7 @@ template class InnerProductArgument { b_vec[j] *= round_challenge_inv; b_vec[j] += round_challenge * b_vec[round_size + j]; - /* - TODO(#220)(Arijit): (performance improvement suggested by Zac): We can improve performance here by using - element::batch_mul_with_endomorphism. This method takes a vector of input points points and a scalar x - and outputs a vector containing points[i]*x. It's 30% faster than a basic mul operation due to - performing group additions in 2D affine coordinates instead of 3D projective coordinates (affine point - additions are usually more expensive than projective additions due to the need to compute a modular - inverse. However we get around this by computing a single batch inverse. This only works if you are - adding a lot of independent point pairs so you can amortise the cost of the single batch inversion - across multiple points). - */ - - auto G_lo = Commitment(G_vec_local[j]) * round_challenge_inv; - auto G_hi = Commitment(G_vec_local[round_size + j]) * round_challenge; - auto temp = G_lo + G_hi; - G_vec_local[j] = temp.normalize(); + G_vec_local[j] = G_lo[j] + G_hi[j]; } } @@ -145,31 +132,29 @@ template class InnerProductArgument { * * @return true/false depending on if the proof verifies */ - static bool reduce_verify(std::shared_ptr vk, - const OpeningPair& opening_pair, - size_t poly_degree, - VerifierTranscript& transcript) + static bool verify(std::shared_ptr vk, + const OpeningClaim& opening_claim, + VerifierTranscript& transcript) { - auto commitment = transcript.template receive_from_prover("IPA:C"); - + auto poly_degree = static_cast(transcript.template receive_from_prover("IPA:poly_degree")); Fr generator_challenge = transcript.get_challenge("IPA:generator_challenge"); - auto aux_generator = CommitmentAffine::one() * generator_challenge; + auto aux_generator = Commitment::one() * generator_challenge; - size_t log_poly_degree = numeric::get_msb(poly_degree); + auto log_poly_degree = static_cast(numeric::get_msb(poly_degree)); // Compute C_prime - Commitment C_prime = commitment + (aux_generator * opening_pair.evaluation); + GroupElement C_prime = opening_claim.commitment + (aux_generator * opening_claim.opening_pair.evaluation); // Compute C_zero = C_prime + ∑_{j ∈ [k]} u_j^2L_j + ∑_{j ∈ [k]} u_j^{-2}R_j - const size_t pippenger_size = 2 * log_poly_degree; + auto pippenger_size = 2 * log_poly_degree; std::vector round_challenges(log_poly_degree); std::vector round_challenges_inv(log_poly_degree); - std::vector msm_elements(pippenger_size); + std::vector msm_elements(pippenger_size); std::vector msm_scalars(pippenger_size); for (size_t i = 0; i < log_poly_degree; i++) { std::string index = std::to_string(i); - auto element_L = transcript.template receive_from_prover("IPA:L_" + index); - auto element_R = transcript.template receive_from_prover("IPA:R_" + index); + auto element_L = transcript.template receive_from_prover("IPA:L_" + index); + auto element_R = transcript.template receive_from_prover("IPA:R_" + index); round_challenges[i] = transcript.get_challenge("IPA:round_challenge_" + index); round_challenges_inv[i] = round_challenges[i].invert(); @@ -178,9 +163,9 @@ template class InnerProductArgument { msm_scalars[2 * i] = round_challenges[i].sqr(); msm_scalars[2 * i + 1] = round_challenges_inv[i].sqr(); } - Commitment LR_sums = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( + GroupElement LR_sums = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( &msm_scalars[0], &msm_elements[0], pippenger_size, vk->pippenger_runtime_state); - Commitment C_zero = C_prime + LR_sums; + GroupElement C_zero = C_prime + LR_sums; /** * Compute b_zero where b_zero can be computed using the polynomial: @@ -193,7 +178,7 @@ template class InnerProductArgument { for (size_t i = 0; i < log_poly_degree; i++) { auto exponent = static_cast(Fr(2).pow(i)); b_zero *= round_challenges_inv[log_poly_degree - 1 - i] + - (round_challenges[log_poly_degree - 1 - i] * opening_pair.challenge.pow(exponent)); + (round_challenges[log_poly_degree - 1 - i] * opening_claim.opening_pair.challenge.pow(exponent)); } // Compute G_zero @@ -214,16 +199,19 @@ template class InnerProductArgument { } auto srs_elements = vk->srs.get_monomial_points(); // Copy the G_vector to local memory. - std::vector G_vec_local(poly_degree); - for (size_t i = 0; i < poly_degree; i++) { - G_vec_local[i] = srs_elements[i]; + std::vector G_vec_local(poly_degree); + // The SRS stored in the commitment key is the result after applying the pippenger point table so the + // values at odd indices contain the point {srs[i-1].x * beta, srs[i-1].y}, where beta is the endomorphism + // G_vec_local should use only the original SRS thus we extract only the even indices. + for (size_t i = 0; i < poly_degree * 2; i += 2) { + G_vec_local[i >> 1] = srs_elements[i]; } auto G_zero = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( &s_vec[0], &G_vec_local[0], poly_degree, vk->pippenger_runtime_state); auto a_zero = transcript.template receive_from_prover("IPA:a_0"); - Commitment right_hand_side = G_zero * a_zero + aux_generator * a_zero * b_zero; + GroupElement right_hand_side = G_zero * a_zero + aux_generator * a_zero * b_zero; return (C_zero.normalize() == right_hand_side.normalize()); } diff --git a/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp b/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp index 2a9c704401..63f038e895 100644 --- a/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp +++ b/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp @@ -1,61 +1,81 @@ #include "ipa.hpp" #include "barretenberg/common/mem.hpp" #include +#include "barretenberg/ecc/curves/types.hpp" #include "barretenberg/polynomials/polynomial_arithmetic.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/ecc/curves/bn254/fq12.hpp" #include "barretenberg/honk/pcs/commitment_key.hpp" #include "barretenberg/honk/pcs/commitment_key.test.hpp" using namespace barretenberg; -namespace proof_system::honk::pcs { +namespace proof_system::honk::pcs::ipa { -class IPATests : public CommitmentTest { +class IPATest : public CommitmentTest { public: - using Params = ipa::Params; using Fr = typename Params::Fr; - using element = typename Params::Commitment; - using affine_element = typename Params::C; - using CK = typename Params::CK; - using VK = typename Params::VK; + using GroupElement = typename Params::GroupElement; + using CK = typename Params::CommitmentKey; + using VK = typename Params::VerificationKey; using Polynomial = barretenberg::Polynomial; }; -TEST_F(IPATests, Commit) +TEST_F(IPATest, CommitOnManyZeroCoeffPolyWorks) +{ + constexpr size_t n = 4; + Polynomial p(n); + for (size_t i = 0; i < n - 1; i++) { + p[i] = Fr::zero(); + } + p[3] = Fr::one(); + GroupElement commitment = this->commit(p); + auto srs_elements = this->ck()->srs.get_monomial_points(); + GroupElement expected = srs_elements[0] * p[0]; + // The SRS stored in the commitment key is the result after applying the pippenger point table so the + // values at odd indices contain the point {srs[i-1].x * beta, srs[i-1].y}, where beta is the endomorphism + // G_vec_local should use only the original SRS thus we extract only the even indices. + for (size_t i = 2; i < 2 * n; i += 2) { + expected += srs_elements[i] * p[i >> 1]; + } + EXPECT_EQ(expected.normalize(), commitment.normalize()); +} + +TEST_F(IPATest, Commit) { constexpr size_t n = 128; auto poly = this->random_polynomial(n); - barretenberg::g1::element commitment = this->commit(poly); + GroupElement commitment = this->commit(poly); auto srs_elements = this->ck()->srs.get_monomial_points(); - barretenberg::g1::element expected = srs_elements[0] * poly[0]; - for (size_t i = 1; i < n; i++) { - expected += srs_elements[i] * poly[i]; + GroupElement expected = srs_elements[0] * poly[0]; + // The SRS stored in the commitment key is the result after applying the pippenger point table so the + // values at odd indices contain the point {srs[i-1].x * beta, srs[i-1].y}, where beta is the endomorphism + // G_vec_local should use only the original SRS thus we extract only the even indices. + for (size_t i = 2; i < 2 * n; i += 2) { + expected += srs_elements[i] * poly[i >> 1]; } EXPECT_EQ(expected.normalize(), commitment.normalize()); } -TEST_F(IPATests, Open) +TEST_F(IPATest, Open) { - using IPA = ipa::InnerProductArgument; + using IPA = IPA; // generate a random polynomial, degree needs to be a power of two size_t n = 128; auto poly = this->random_polynomial(n); auto [x, eval] = this->random_eval(poly); auto commitment = this->commit(poly); - const OpeningPair opening_pair{ x, eval }; + const OpeningPair opening_pair = { x, eval }; + const OpeningClaim opening_claim{ opening_pair, commitment }; // initialize empty prover transcript ProverTranscript prover_transcript; - - prover_transcript.send_to_verifier("IPA:C", commitment); - - IPA::reduce_prove(this->ck(), opening_pair, poly, prover_transcript); + IPA::compute_opening_proof(this->ck(), opening_pair, poly, prover_transcript); // initialize verifier transcript from proof data VerifierTranscript verifier_transcript{ prover_transcript.proof_data }; - auto result = IPA::reduce_verify(this->vk(), opening_pair, n, verifier_transcript); + auto result = IPA::verify(this->vk(), opening_claim, verifier_transcript); EXPECT_TRUE(result); EXPECT_EQ(prover_transcript.get_manifest(), verifier_transcript.get_manifest()); } -} // namespace proof_system::honk::pcs +} // namespace proof_system::honk::pcs::ipa diff --git a/cpp/src/barretenberg/honk/pcs/kzg/kzg.hpp b/cpp/src/barretenberg/honk/pcs/kzg/kzg.hpp index 7160339cf2..fb69278dee 100644 --- a/cpp/src/barretenberg/honk/pcs/kzg/kzg.hpp +++ b/cpp/src/barretenberg/honk/pcs/kzg/kzg.hpp @@ -1,6 +1,7 @@ #pragma once #include "../claim.hpp" +#include "barretenberg/honk/pcs/commitment_key.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/honk/transcript/transcript.hpp" @@ -8,86 +9,60 @@ #include namespace proof_system::honk::pcs::kzg { -/** - * @brief A transformed polynomial commitment opening claim of the form (P₀, P₁) ∈ 𝔾₁ - * which should satisfy e(P₀, [1]₂) ⋅ e(P₁, [x]₂)=1. - * - * @tparam Params CommitmentScheme parameters, where the verification key VK has a - * `pairing_check` function. - */ -template class BilinearAccumulator { - using VK = typename Params::VK; - using Fr = typename Params::Fr; - using CommitmentAffine = typename Params::C; - using Commitment = typename Params::Commitment; - - public: - /** - * @brief Construct a new Bilinear Accumulator object given a claim (C,r,v) and proof π. - * - P₀ = C − v⋅[1]₁ + r⋅[x]₁ - * - P₁ = −π - * @param claim an OpeningClaim (C,r,v) - * @param proof a Commitment π - */ - BilinearAccumulator(const OpeningClaim& claim, const Commitment& proof) - : lhs(claim.commitment - (Commitment::one() * claim.opening_pair.evaluation) + - (proof * claim.opening_pair.challenge)) - , rhs(-proof) - {} - - /** - * @brief verifies the accumulator with a pairing check - * - * @param vk VerificationKey - * @return e(P₀,[1]₁)e(P₁,[x]₂)≡ [1]ₜ - */ - bool verify(std::shared_ptr vk) const { return vk->pairing_check(lhs, rhs); }; - - bool operator==(const BilinearAccumulator& other) const = default; - - CommitmentAffine lhs, rhs; -}; - -template class UnivariateOpeningScheme { - using CK = typename Params::CK; +template class KZG { + using CK = typename Params::CommitmentKey; + using VK = typename Params::VerificationKey; using Fr = typename Params::Fr; using Commitment = typename Params::Commitment; - using CommitmentAffine = typename Params::C; + using GroupElement = typename Params::GroupElement; using Polynomial = barretenberg::Polynomial; - public: - using Accumulator = BilinearAccumulator; - /** - * @brief Compute KZG opening proof polynomial + * @brief Computes the KZG commitment to an opening proof polynomial at a single evaluation point * - * @param opening_pair OpeningPair = {r, v = polynomial(r)} - * @param polynomial the witness polynomial being opened - * @return KZG quotient polynomial of the form (p(X) - v) / (X - r) + * @param ck The commitment key which has a commit function, the srs and pippenger_runtime_state + * @param opening_pair OpeningPair = {r, v = p(r)} + * @param polynomial The witness whose opening proof needs to be computed + * @param prover_transcript Prover transcript */ - static Polynomial compute_opening_proof_polynomial(const OpeningPair& opening_pair, - const Polynomial& polynomial) + public: + static void compute_opening_proof(std::shared_ptr ck, + const OpeningPair& opening_pair, + const Polynomial& polynomial, + ProverTranscript& prover_trancript) { Polynomial quotient(polynomial); quotient[0] -= opening_pair.evaluation; + // Computes the coefficients for the quotient polynomial q(X) = (p(X) - v) / (X - r) through an FFT quotient.factor_roots(opening_pair.challenge); - - return quotient; + auto quotient_commitment = ck->commit(quotient); + // TODO(#479): for now we compute the KZG commitment directly to unify the KZG and IPA interfaces but in the + // future we might need to adjust this to use the incoming alternative to work queue (i.e. variation of + // pthreads) or even the work queue itself + prover_trancript.send_to_verifier("KZG:W", quotient_commitment); }; /** - * @brief Computes the accumulator for a single polynomial commitment opening claim + * @brief Computes the KZG verification for an opening claim of a single polynomial commitment * This reduction is non-interactive and always succeeds. * + * @param vk is the verification key which has a pairing check function * @param claim OpeningClaim ({r, v}, C) - * @param proof π, a commitment to Q(X) = ( P(X) - v )/( X - r) - * @return Accumulator {C − v⋅[1]₁ + r⋅π, −π} + * @return e(P₀,[1]₁)e(P₁,[x]₂)≡ [1]ₜ where + * - P₀ = C − v⋅[1]₁ + r⋅[x]₁ + * - P₁ = [Q(x)]₁ */ - static Accumulator reduce_verify(const OpeningClaim& claim, VerifierTranscript& verifier_transcript) + static bool verify(std::shared_ptr vk, + const OpeningClaim& claim, + VerifierTranscript& verifier_transcript) { - auto quotient_commitment = verifier_transcript.template receive_from_prover("KZG:W"); - return Accumulator(claim, quotient_commitment); + auto quotient_commitment = verifier_transcript.template receive_from_prover("KZG:W"); + auto lhs = claim.commitment - (GroupElement::one() * claim.opening_pair.evaluation) + + (quotient_commitment * claim.opening_pair.challenge); + auto rhs = -quotient_commitment; + + return vk->pairing_check(lhs, rhs); }; }; } // namespace proof_system::honk::pcs::kzg diff --git a/cpp/src/barretenberg/honk/pcs/kzg/kzg.test.cpp b/cpp/src/barretenberg/honk/pcs/kzg/kzg.test.cpp index e618dc0141..439b33cc9f 100644 --- a/cpp/src/barretenberg/honk/pcs/kzg/kzg.test.cpp +++ b/cpp/src/barretenberg/honk/pcs/kzg/kzg.test.cpp @@ -15,24 +15,26 @@ namespace proof_system::honk::pcs::kzg { -template class BilinearAccumulationTest : public CommitmentTest { +template class KZGTest : public CommitmentTest { public: using Fr = typename Params::Fr; using Commitment = typename Params::Commitment; + using GroupElement = typename Params::GroupElement; using Polynomial = barretenberg::Polynomial; }; -TYPED_TEST_SUITE(BilinearAccumulationTest, CommitmentSchemeParams); +TYPED_TEST_SUITE(KZGTest, CommitmentSchemeParams); -TYPED_TEST(BilinearAccumulationTest, single) +TYPED_TEST(KZGTest, single) { const size_t n = 16; - using KZG = UnivariateOpeningScheme; + using KZG = KZG; using Fr = typename TypeParam::Fr; auto witness = this->random_polynomial(n); - auto commitment = this->commit(witness); + barretenberg::g1::element commitment = this->commit(witness); + auto challenge = Fr::random_element(); auto evaluation = witness.evaluate(challenge); auto opening_pair = OpeningPair{ challenge, evaluation }; @@ -40,13 +42,10 @@ TYPED_TEST(BilinearAccumulationTest, single) auto prover_transcript = ProverTranscript::init_empty(); - auto quotient_W = KZG::compute_opening_proof_polynomial(opening_pair, witness); - prover_transcript.send_to_verifier("KZG:W", this->commit(quotient_W)); + KZG::compute_opening_proof(this->ck(), opening_pair, witness, prover_transcript); auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); - auto kzg_claim = KZG::reduce_verify(opening_claim, verifier_transcript); - - bool verified = kzg_claim.verify(this->vk()); + bool verified = KZG::verify(this->vk(), opening_claim, verifier_transcript); EXPECT_EQ(verified, true); } @@ -57,13 +56,13 @@ TYPED_TEST(BilinearAccumulationTest, single) * of a single Honk proof. (Expository comments included throughout). * */ -TYPED_TEST(BilinearAccumulationTest, GeminiShplonkKzgWithShift) +TYPED_TEST(KZGTest, GeminiShplonkKzgWithShift) { using Shplonk = shplonk::SingleBatchOpeningScheme; using Gemini = gemini::MultilinearReductionScheme; - using KZG = UnivariateOpeningScheme; + using KZG = KZG; using Fr = typename TypeParam::Fr; - using Commitment = typename TypeParam::Commitment; + using GroupElement = typename TypeParam::GroupElement; using Polynomial = typename barretenberg::Polynomial; const size_t n = 16; @@ -78,8 +77,8 @@ TYPED_TEST(BilinearAccumulationTest, GeminiShplonkKzgWithShift) auto poly2 = this->random_polynomial(n); poly2[0] = Fr::zero(); // this property is required of polynomials whose shift is used - Commitment commitment1 = this->commit(poly1); - Commitment commitment2 = this->commit(poly2); + GroupElement commitment1 = this->commit(poly1); + GroupElement commitment2 = this->commit(poly2); auto eval1 = poly1.evaluate_mle(mle_opening_point); auto eval2 = poly2.evaluate_mle(mle_opening_point); @@ -104,8 +103,8 @@ TYPED_TEST(BilinearAccumulationTest, GeminiShplonkKzgWithShift) batched_to_be_shifted.add_scaled(poly2, rhos[2]); // Compute batched commitments - Commitment batched_commitment_unshifted = Commitment::zero(); - Commitment batched_commitment_to_be_shifted = Commitment::zero(); + GroupElement batched_commitment_unshifted = GroupElement::zero(); + GroupElement batched_commitment_to_be_shifted = GroupElement::zero(); batched_commitment_unshifted = commitment1 * rhos[0] + commitment2 * rhos[1]; batched_commitment_to_be_shifted = commitment2 * rhos[2]; @@ -149,8 +148,7 @@ TYPED_TEST(BilinearAccumulationTest, GeminiShplonkKzgWithShift) // KZG prover: // - Adds commitment [W] to transcript - auto quotient_W = KZG::compute_opening_proof_polynomial(shplonk_opening_pair, shplonk_witness); - prover_transcript.send_to_verifier("KZG:W", this->commit(quotient_W)); + KZG::compute_opening_proof(this->ck(), shplonk_opening_pair, shplonk_witness, prover_transcript); // Run the full verifier PCS protocol with genuine opening claims (genuine commitment, genuine evaluation) @@ -169,10 +167,9 @@ TYPED_TEST(BilinearAccumulationTest, GeminiShplonkKzgWithShift) // KZG verifier: // aggregates inputs [Q] - [Q_z] and [W] into an 'accumulator' (can perform pairing check on result) - auto kzg_claim = KZG::reduce_verify(shplonk_verifier_claim, verifier_transcript); + bool verified = KZG::verify(this->vk(), shplonk_verifier_claim, verifier_transcript); // Final pairing check: e([Q] - [Q_z] + z[W], [1]_2) = e([W], [x]_2) - bool verified = kzg_claim.verify(this->vk()); EXPECT_EQ(verified, true); } diff --git a/cpp/src/barretenberg/honk/pcs/shplonk/shplonk_single.hpp b/cpp/src/barretenberg/honk/pcs/shplonk/shplonk_single.hpp index 36c3567185..95190804b9 100644 --- a/cpp/src/barretenberg/honk/pcs/shplonk/shplonk_single.hpp +++ b/cpp/src/barretenberg/honk/pcs/shplonk/shplonk_single.hpp @@ -8,16 +8,17 @@ namespace proof_system::honk::pcs::shplonk { /** * @brief Protocol for opening several polynomials, each in a single different point. - * It is a simplification of the MultiBatchOpeningScheme. + * It is a simplification of the MultiBatchOpeningScheme (several polynomials on several + * different points, protocol not implemented). * * @tparam Params for the given commitment scheme */ template class SingleBatchOpeningScheme { - using CK = typename Params::CK; + using CK = typename Params::CommitmentKey; using Fr = typename Params::Fr; + using GroupElement = typename Params::GroupElement; using Commitment = typename Params::Commitment; - using CommitmentAffine = typename Params::C; using Polynomial = barretenberg::Polynomial; public: @@ -129,7 +130,7 @@ template class SingleBatchOpeningScheme { const Fr nu = transcript.get_challenge("Shplonk:nu"); - auto Q_commitment = transcript.template receive_from_prover("Shplonk:Q"); + auto Q_commitment = transcript.template receive_from_prover("Shplonk:Q"); const Fr z_challenge = transcript.get_challenge("Shplonk:z"); @@ -143,7 +144,7 @@ template class SingleBatchOpeningScheme { // [G] = [Q] - ∑ⱼ ρʲ / ( r − xⱼ )⋅[fⱼ] + G₀⋅[1] // = [Q] - [∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ )] - Commitment G_commitment = Q_commitment; + GroupElement G_commitment = Q_commitment; // {ẑⱼ(r)}ⱼ , where ẑⱼ(r) = 1/zⱼ(r) = 1/(r - xⱼ) std::vector inverse_vanishing_evals; @@ -168,7 +169,7 @@ template class SingleBatchOpeningScheme { current_nu *= nu; } // [G] += G₀⋅[1] = [G] + (∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ ))⋅[1] - G_commitment += Commitment::one() * G_commitment_constant; + G_commitment += GroupElement::one() * G_commitment_constant; // Return opening pair (z, 0) and commitment [G] return { { z_challenge, Fr::zero() }, G_commitment }; diff --git a/cpp/src/barretenberg/honk/proof_system/composer_helper.lib.hpp b/cpp/src/barretenberg/honk/proof_system/composer_helper.lib.hpp index 24c89a3a06..58d515019e 100644 --- a/cpp/src/barretenberg/honk/proof_system/composer_helper.lib.hpp +++ b/cpp/src/barretenberg/honk/proof_system/composer_helper.lib.hpp @@ -23,7 +23,7 @@ std::shared_ptr compute_verification_key_commo auto verification_key = std::make_shared( proving_key->circuit_size, proving_key->num_public_inputs, vrs, proving_key->composer_type); - auto commitment_key = typename Flavor::PCSParams::CK(proving_key->circuit_size, "../srs_db/ignition"); + auto commitment_key = typename Flavor::PCSParams::CommitmentKey(proving_key->circuit_size, "../srs_db/ignition"); size_t poly_idx = 0; // TODO(#391) zip for (auto& polynomial : proving_key) { diff --git a/cpp/src/barretenberg/honk/proof_system/prover.cpp b/cpp/src/barretenberg/honk/proof_system/prover.cpp index 6747fc0bee..39ac5684b0 100644 --- a/cpp/src/barretenberg/honk/proof_system/prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/prover.cpp @@ -217,13 +217,13 @@ template void StandardProver_::execute_shplonk_p } /** - * - Compute KZG quotient commitment [W]_1. - * + * - Compute final PCS opening proof: + * - For KZG, this is the quotient commitment [W]_1 + * - For IPA, the vectors L and R * */ -template void StandardProver_::execute_kzg_round() +template void StandardProver_::execute_final_pcs_round() { - quotient_W = KZG::compute_opening_proof_polynomial(shplonk_output.opening_pair, shplonk_output.witness); - queue.add_commitment(quotient_W, "KZG:W"); + PCS::compute_opening_proof(pcs_commitment_key, shplonk_output.opening_pair, shplonk_output.witness, transcript); } template plonk::proof& StandardProver_::export_proof() @@ -275,9 +275,9 @@ template plonk::proof& StandardProver_::construc execute_shplonk_partial_evaluation_round(); // Fiat-Shamir: z - // Compute KZG quotient commitment - execute_kzg_round(); - queue.process_queue(); + // Compute final PCS opening proof (this is KZG quotient commitment or IPA opening proof) + execute_final_pcs_round(); + // TODO(#479): queue.process_queue after the work_queue has been (re)added to KZG/IPA return export_proof(); } diff --git a/cpp/src/barretenberg/honk/proof_system/prover.hpp b/cpp/src/barretenberg/honk/proof_system/prover.hpp index 7c7d1d0bb8..80b577c767 100644 --- a/cpp/src/barretenberg/honk/proof_system/prover.hpp +++ b/cpp/src/barretenberg/honk/proof_system/prover.hpp @@ -3,7 +3,6 @@ #include "barretenberg/plonk/proof_system/types/proof.hpp" #include "barretenberg/honk/pcs/gemini/gemini.hpp" #include "barretenberg/honk/pcs/shplonk/shplonk_single.hpp" -#include "barretenberg/honk/pcs/kzg/kzg.hpp" #include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/honk/sumcheck/sumcheck.hpp" #include "barretenberg/honk/sumcheck/sumcheck_output.hpp" @@ -20,11 +19,13 @@ template concept StandardFlavor = IsAnyOf class StandardProver_ { using FF = typename Flavor::FF; - using PCSParams = typename Flavor::PCSParams; using ProvingKey = typename Flavor::ProvingKey; using Polynomial = typename Flavor::Polynomial; using ProverPolynomials = typename Flavor::ProverPolynomials; using CommitmentLabels = typename Flavor::CommitmentLabels; + using PCSParams = typename Flavor::PCSParams; + using PCSCommitmentKey = typename Flavor::PCSParams::CommitmentKey; + using PCS = typename Flavor::PCS; public: explicit StandardProver_(std::shared_ptr input_key = nullptr); @@ -38,7 +39,8 @@ template class StandardProver_ { void execute_pcs_evaluation_round(); void execute_shplonk_batched_quotient_round(); void execute_shplonk_partial_evaluation_round(); - void execute_kzg_round(); + + void execute_final_pcs_round(); void compute_wire_commitments(); @@ -73,10 +75,10 @@ template class StandardProver_ { sumcheck::SumcheckOutput sumcheck_output; pcs::gemini::ProverOutput gemini_output; pcs::shplonk::ProverOutput shplonk_output; + std::shared_ptr pcs_commitment_key; using Gemini = pcs::gemini::MultilinearReductionScheme; using Shplonk = pcs::shplonk::SingleBatchOpeningScheme; - using KZG = pcs::kzg::UnivariateOpeningScheme; private: plonk::proof proof; diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index f0d7d26089..0081cef985 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -271,15 +271,15 @@ template void UltraProver_::execute_shplonk_partial shplonk_output = Shplonk::compute_partially_evaluated_batched_quotient( gemini_output.opening_pairs, gemini_output.witnesses, std::move(batched_quotient_Q), nu_challenge, z_challenge); } - /** - * - Compute KZG quotient commitment [W]_1. - * + * - Compute final PCS opening proof: + * - For KZG, this is the quotient commitment [W]_1 + * - For IPA, the vectors L and R * */ -template void UltraProver_::execute_kzg_round() +template void UltraProver_::execute_final_pcs_round() { - quotient_W = KZG::compute_opening_proof_polynomial(shplonk_output.opening_pair, shplonk_output.witness); - queue.add_commitment(quotient_W, "KZG:W"); + PCS::compute_opening_proof(pcs_commitment_key, shplonk_output.opening_pair, shplonk_output.witness, transcript); + // queue.add_commitment(quotient_W, "KZG:W"); } template plonk::proof& UltraProver_::export_proof() @@ -329,9 +329,8 @@ template plonk::proof& UltraProver_::construct_proo execute_shplonk_partial_evaluation_round(); // Fiat-Shamir: z - // Compute KZG quotient commitment - execute_kzg_round(); - queue.process_queue(); + // Compute PCS opening proof (either KZG quotient commitment or IPA opening proof) + execute_final_pcs_round(); return export_proof(); } diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp index 5b42bbd150..f225e831f1 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp @@ -3,7 +3,6 @@ #include "barretenberg/plonk/proof_system/types/proof.hpp" #include "barretenberg/honk/pcs/gemini/gemini.hpp" #include "barretenberg/honk/pcs/shplonk/shplonk_single.hpp" -#include "barretenberg/honk/pcs/kzg/kzg.hpp" #include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/honk/flavor/ultra.hpp" #include "barretenberg/honk/sumcheck/relations/relation_parameters.hpp" @@ -18,6 +17,8 @@ template class UltraProver_ { using FF = typename Flavor::FF; using PCSParams = typename Flavor::PCSParams; + using PCS = typename Flavor::PCS; + using PCSCommitmentKey = typename Flavor::PCSParams::CommitmentKey; using ProvingKey = typename Flavor::ProvingKey; using Polynomial = typename Flavor::Polynomial; using ProverPolynomials = typename Flavor::ProverPolynomials; @@ -35,7 +36,7 @@ template class UltraProver_ { void execute_pcs_evaluation_round(); void execute_shplonk_batched_quotient_round(); void execute_shplonk_partial_evaluation_round(); - void execute_kzg_round(); + void execute_final_pcs_round(); void compute_wire_commitments(); @@ -63,15 +64,15 @@ template class UltraProver_ { Polynomial quotient_W; - work_queue queue; + work_queue queue; sumcheck::SumcheckOutput sumcheck_output; pcs::gemini::ProverOutput gemini_output; pcs::shplonk::ProverOutput shplonk_output; + std::shared_ptr pcs_commitment_key; using Gemini = pcs::gemini::MultilinearReductionScheme; using Shplonk = pcs::shplonk::SingleBatchOpeningScheme; - using KZG = pcs::kzg::UnivariateOpeningScheme; private: plonk::proof proof; diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index 628a969d26..c54f7065b1 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -19,15 +19,15 @@ UltraVerifier_::UltraVerifier_(std::shared_ptr UltraVerifier_::UltraVerifier_(UltraVerifier_&& other) : key(std::move(other.key)) - , kate_verification_key(std::move(other.kate_verification_key)) + , pcs_verification_key(std::move(other.pcs_verification_key)) {} template UltraVerifier_& UltraVerifier_::operator=(UltraVerifier_&& other) { key = other.key; - kate_verification_key = (std::move(other.kate_verification_key)); - kate_g1_elements.clear(); - kate_fr_elements.clear(); + pcs_verification_key = (std::move(other.pcs_verification_key)); + commitments.clear(); + pcs_fr_elements.clear(); return *this; } @@ -40,9 +40,10 @@ template bool UltraVerifier_::verify_proof(const plonk using FF = typename Flavor::FF; using GroupElement = typename Flavor::GroupElement; using Commitment = typename Flavor::Commitment; - using Gemini = pcs::gemini::MultilinearReductionScheme; - using Shplonk = pcs::shplonk::SingleBatchOpeningScheme; - using KZG = pcs::kzg::UnivariateOpeningScheme; + using PCSParams = typename Flavor::PCSParams; + using PCS = typename Flavor::PCS; + using Gemini = pcs::gemini::MultilinearReductionScheme; + using Shplonk = pcs::shplonk::SingleBatchOpeningScheme; using VerifierCommitments = typename Flavor::VerifierCommitments; using CommitmentLabels = typename Flavor::CommitmentLabels; @@ -155,11 +156,8 @@ template bool UltraVerifier_::verify_proof(const plonk // Produce a Shplonk claim: commitment [Q] - [Q_z], evaluation zero (at random challenge z) auto shplonk_claim = Shplonk::reduce_verify(gemini_claim, transcript); - // Aggregate inputs [Q] - [Q_z] and [W] into an 'accumulator' (can perform pairing check on result) - auto kzg_claim = KZG::reduce_verify(shplonk_claim, transcript); - - // Return result of final pairing check - return kzg_claim.verify(kate_verification_key); + // // Verify the Shplonk claim with KZG or IPA + return PCS::verify(pcs_verification_key, shplonk_claim, transcript); } template class UltraVerifier_; diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.hpp b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.hpp index 2aa06d2244..a5456f5a0d 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.hpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.hpp @@ -9,7 +9,7 @@ template class UltraVerifier_ { using FF = typename Flavor::FF; using Commitment = typename Flavor::Commitment; using VerificationKey = typename Flavor::VerificationKey; - using PCSVerificationKey = typename Flavor::PCSParams::VK; + using PCSVerificationKey = typename Flavor::PCSParams::VerificationKey; public: explicit UltraVerifier_(std::shared_ptr verifier_key = nullptr); @@ -21,9 +21,9 @@ template class UltraVerifier_ { bool verify_proof(const plonk::proof& proof); std::shared_ptr key; - std::map kate_g1_elements; - std::map kate_fr_elements; - std::shared_ptr kate_verification_key; + std::map commitments; + std::map pcs_fr_elements; + std::shared_ptr pcs_verification_key; VerifierTranscript transcript; }; diff --git a/cpp/src/barretenberg/honk/proof_system/verifier.cpp b/cpp/src/barretenberg/honk/proof_system/verifier.cpp index 3506f15aaa..87fbb3fe95 100644 --- a/cpp/src/barretenberg/honk/proof_system/verifier.cpp +++ b/cpp/src/barretenberg/honk/proof_system/verifier.cpp @@ -17,15 +17,15 @@ StandardVerifier_::StandardVerifier_(std::shared_ptr StandardVerifier_::StandardVerifier_(StandardVerifier_&& other) : key(other.key) - , kate_verification_key(std::move(other.kate_verification_key)) + , pcs_verification_key(std::move(other.pcs_verification_key)) {} template StandardVerifier_& StandardVerifier_::operator=(StandardVerifier_&& other) { key = other.key; - kate_verification_key = (std::move(other.kate_verification_key)); - kate_g1_elements.clear(); - kate_fr_elements.clear(); + pcs_verification_key = (std::move(other.pcs_verification_key)); + commitments.clear(); + pcs_fr_elements.clear(); return *this; } @@ -60,9 +60,10 @@ template bool StandardVerifier_::verify_proof(const pl using FF = typename Flavor::FF; using GroupElement = typename Flavor::GroupElement; using Commitment = typename Flavor::Commitment; - using Gemini = pcs::gemini::MultilinearReductionScheme; - using Shplonk = pcs::shplonk::SingleBatchOpeningScheme; - using KZG = pcs::kzg::UnivariateOpeningScheme; + using PCSParams = typename Flavor::PCSParams; + using Gemini = pcs::gemini::MultilinearReductionScheme; + using Shplonk = pcs::shplonk::SingleBatchOpeningScheme; + using PCS = typename Flavor::PCS; using VerifierCommitments = typename Flavor::VerifierCommitments; using CommitmentLabels = typename Flavor::CommitmentLabels; @@ -163,11 +164,8 @@ template bool StandardVerifier_::verify_proof(const pl // Produce a Shplonk claim: commitment [Q] - [Q_z], evaluation zero (at random challenge z) auto shplonk_claim = Shplonk::reduce_verify(gemini_claim, transcript); - // Aggregate inputs [Q] - [Q_z] and [W] into an 'accumulator' (can perform pairing check on result) - auto kzg_claim = KZG::reduce_verify(shplonk_claim, transcript); - - // Return result of final pairing check - return kzg_claim.verify(kate_verification_key); + // Verify the Shplonk claim with KZG or IPA + return PCS::verify(pcs_verification_key, shplonk_claim, transcript); } template class StandardVerifier_; diff --git a/cpp/src/barretenberg/honk/proof_system/verifier.hpp b/cpp/src/barretenberg/honk/proof_system/verifier.hpp index c62f4c3a27..7034adf3d6 100644 --- a/cpp/src/barretenberg/honk/proof_system/verifier.hpp +++ b/cpp/src/barretenberg/honk/proof_system/verifier.hpp @@ -8,7 +8,7 @@ template class StandardVerifier_ { using FF = typename Flavor::FF; using Commitment = typename Flavor::Commitment; using VerificationKey = typename Flavor::VerificationKey; - using PCSVerificationKey = typename Flavor::PCSParams::VK; + using PCSVerificationKey = typename Flavor::PCSParams::VerificationKey; public: StandardVerifier_(std::shared_ptr verifier_key = nullptr); @@ -20,9 +20,9 @@ template class StandardVerifier_ { bool verify_proof(const plonk::proof& proof); std::shared_ptr key; - std::map kate_g1_elements; - std::map kate_fr_elements; - std::shared_ptr kate_verification_key; + std::map commitments; + std::map pcs_fr_elements; + std::shared_ptr pcs_verification_key; VerifierTranscript transcript; }; diff --git a/cpp/src/barretenberg/honk/proof_system/work_queue.hpp b/cpp/src/barretenberg/honk/proof_system/work_queue.hpp index bbb6867b79..f8402bfde8 100644 --- a/cpp/src/barretenberg/honk/proof_system/work_queue.hpp +++ b/cpp/src/barretenberg/honk/proof_system/work_queue.hpp @@ -14,9 +14,9 @@ enum WorkType { SCALAR_MULTIPLICATION }; // at the same time as the similar patterns in Gemini etc. template class work_queue { - using CommitmentKey = typename Params::CK; + using CommitmentKey = typename Params::CommitmentKey; using FF = typename Params::Fr; - using Commitment = typename Params::C; + using Commitment = typename Params::Commitment; struct work_item_info { uint32_t num_scalar_multiplications; diff --git a/cpp/src/barretenberg/honk/transcript/transcript.test.cpp b/cpp/src/barretenberg/honk/transcript/transcript.test.cpp index 6f82adc460..a3269dac47 100644 --- a/cpp/src/barretenberg/honk/transcript/transcript.test.cpp +++ b/cpp/src/barretenberg/honk/transcript/transcript.test.cpp @@ -27,7 +27,7 @@ template class TranscriptTest : public testing::Test { { TranscriptManifest manifest_expected; - size_t log_n(numeric::get_msb(circuit_size)); + auto log_n = numeric::get_msb(circuit_size); size_t max_relation_length = 5; size_t size_FF = sizeof(FF); @@ -79,7 +79,25 @@ template class TranscriptTest : public testing::Test { manifest_expected.add_challenge(round, "Shplonk:z"); round++; + // TODO(Mara): Make testing more flavor agnostic so we can test this with all flavors manifest_expected.add_entry(round, "KZG:W", size_G); + + // For IPA + // manifest_expected.add_entry(round, "IPA:poly_degree", circuit_size); + // manifest_expected.add_challenge(round, "IPA:generator_challenge"); + + // for (size_t i = 0; i < log_n; i++) { + // round++; + // std::string idx = std::to_string(i); + // manifest_expected.add_entry(round, "IPA:L_" + idx, size_G); + // manifest_expected.add_entry(round, "IPA:R_" + idx, size_G); + // std::string label = "IPA:round_challenge_" + idx; + // manifest_expected.add_challenge(round, label); + // } + + // round++; + // manifest_expected.add_entry(round, "IPA:a_0", size_FF); + manifest_expected.add_challenge(round); // no challenge return manifest_expected; @@ -108,7 +126,6 @@ TYPED_TEST(TranscriptTest, ProverManifestConsistency) // Check that the prover generated manifest agrees with the manifest hard coded in this suite auto manifest_expected = TestFixture::construct_standard_honk_manifest(prover.key->circuit_size); auto prover_manifest = prover.transcript.get_manifest(); - // Note: a manifest can be printed using manifest.print() for (size_t round = 0; round < manifest_expected.size(); ++round) { ASSERT_EQ(prover_manifest[round], manifest_expected[round]) << "Prover manifest discrepency in round " << round; diff --git a/cpp/src/barretenberg/plonk/composer/composer_helper/composer_helper_lib.cpp b/cpp/src/barretenberg/plonk/composer/composer_helper/composer_helper_lib.cpp index a51cc7bc9b..286cdea17b 100644 --- a/cpp/src/barretenberg/plonk/composer/composer_helper/composer_helper_lib.cpp +++ b/cpp/src/barretenberg/plonk/composer/composer_helper/composer_helper_lib.cpp @@ -51,7 +51,7 @@ std::shared_ptr compute_verification_key_common( auto circuit_verification_key = std::make_shared( proving_key->circuit_size, proving_key->num_public_inputs, vrs, proving_key->composer_type); // TODO(kesha): Dirty hack for now. Need to actually make commitment-agnositc - auto commitment_key = proof_system::honk::pcs::kzg::CommitmentKey(proving_key->circuit_size, srs_path); + auto commitment_key = proof_system::honk::pcs::kzg::Params::CommitmentKey(proving_key->circuit_size, srs_path); for (size_t i = 0; i < proving_key->polynomial_manifest.size(); ++i) { const auto& poly_info = proving_key->polynomial_manifest[i]; diff --git a/cpp/src/barretenberg/proof_system/flavor/flavor.hpp b/cpp/src/barretenberg/proof_system/flavor/flavor.hpp index f150a277a2..a476c362ed 100644 --- a/cpp/src/barretenberg/proof_system/flavor/flavor.hpp +++ b/cpp/src/barretenberg/proof_system/flavor/flavor.hpp @@ -176,18 +176,12 @@ class ProvingKey_ : public PrecomputedPolynomials, public WitnessPolynomials { */ template class VerificationKey_ : public PrecomputedCommitments { public: - std::shared_ptr vrs; - VerificationKey_() = default; - VerificationKey_(const size_t circuit_size, - const size_t num_public_inputs, - std::shared_ptr const& vrs, - ComposerType composer_type) + VerificationKey_(const size_t circuit_size, const size_t num_public_inputs, ComposerType composer_type) { this->circuit_size = circuit_size; this->log_circuit_size = numeric::get_msb(circuit_size); this->num_public_inputs = num_public_inputs; - this->vrs = vrs; this->composer_type = composer_type; }; };