Skip to content

Commit

Permalink
chore: extract merge from UC and simplify (AztecProtocol#4343)
Browse files Browse the repository at this point in the history
Removes `create_merge_prover`/`verifier` from `UltraComposer`. They are
now constructed directly from their respective class constructors. This
PR also simplifies the merge classes and removes the templating on
Flavor which was unnecessary.

closes AztecProtocol/barretenberg#804
  • Loading branch information
ledwards2225 authored Feb 2, 2024
1 parent 3391e2d commit 5300d00
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 117 deletions.
9 changes: 6 additions & 3 deletions barretenberg/cpp/src/barretenberg/goblin/goblin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "barretenberg/proof_system/instance_inspector.hpp"
#include "barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.hpp"
#include "barretenberg/translator_vm/goblin_translator_composer.hpp"
#include "barretenberg/ultra_honk/merge_prover.hpp"
#include "barretenberg/ultra_honk/merge_verifier.hpp"
#include "barretenberg/ultra_honk/ultra_composer.hpp"

namespace bb {
Expand All @@ -33,7 +35,8 @@ class Goblin {
using TranslatorBuilder = bb::GoblinTranslatorCircuitBuilder;
using TranslatorComposer = bb::GoblinTranslatorComposer;
using RecursiveMergeVerifier = bb::stdlib::recursion::goblin::MergeRecursiveVerifier_<GoblinUltraCircuitBuilder>;
using MergeVerifier = bb::MergeVerifier_<GoblinUltraFlavor>;
using MergeProver = bb::MergeProver;
using MergeVerifier = bb::MergeVerifier;
/**
* @brief Output of goblin::accumulate; an Ultra proof and the corresponding verification key
*
Expand Down Expand Up @@ -107,7 +110,7 @@ class Goblin {
auto ultra_proof = prover.construct_proof();

// Construct and store the merge proof to be recursively verified on the next call to accumulate
auto merge_prover = composer.create_merge_prover(op_queue);
MergeProver merge_prover{ op_queue };
merge_proof = merge_prover.construct_proof();

if (!merge_proof_exists) {
Expand Down Expand Up @@ -211,7 +214,7 @@ class Goblin {
// TODO(https://github.com/AztecProtocol/barretenberg/issues/811): no merge prover for now since we're not
// mocking the first set of ecc ops
// // Construct and store the merge proof to be recursively verified on the next call to accumulate
// auto merge_prover = composer.create_merge_prover(op_queue);
// MergeProver merge_prover{ op_queue };
// merge_proof = merge_prover.construct_proof();

// if (!merge_proof_exists) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class RecursiveMergeVerifierTest : public testing::Test {

// Generate a proof over the inner circuit
InnerComposer inner_composer;
auto merge_prover = inner_composer.create_merge_prover(op_queue);
MergeProver merge_prover{ op_queue };
auto merge_proof = merge_prover.construct_proof();

// Create a recursive merge verification circuit for the merge proof
Expand All @@ -61,7 +61,7 @@ class RecursiveMergeVerifierTest : public testing::Test {

// Check 1: Perform native merge verification then perform the pairing on the outputs of the recursive merge
// verifier and check that the result agrees.
auto native_verifier = inner_composer.create_merge_verifier();
MergeVerifier native_verifier;
bool verified_native = native_verifier.verify_proof(merge_proof);
VerifierCommitmentKey pcs_verification_key(0, srs::get_crs_factory());
auto verified_recursive =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "barretenberg/common/log.hpp"
#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp"
#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp"
#include "barretenberg/ultra_honk/merge_prover.hpp"
#include "barretenberg/ultra_honk/merge_verifier.hpp"
#include "barretenberg/ultra_honk/ultra_composer.hpp"
#include "barretenberg/ultra_honk/ultra_prover.hpp"

Expand Down Expand Up @@ -71,10 +73,10 @@ class GoblinUltraHonkComposerTests : public ::testing::Test {
* @brief Construct and verify a Goblin ECC op queue merge proof
*
*/
bool construct_and_verify_merge_proof(auto& composer, auto& op_queue)
bool construct_and_verify_merge_proof(auto& op_queue)
{
auto merge_prover = composer.create_merge_prover(op_queue);
auto merge_verifier = composer.create_merge_verifier();
MergeProver merge_prover{ op_queue };
MergeVerifier merge_verifier;
auto merge_proof = merge_prover.construct_proof();
bool verified = merge_verifier.verify_proof(merge_proof);

Expand Down Expand Up @@ -108,7 +110,7 @@ TEST_F(GoblinUltraHonkComposerTests, SingleCircuit)
EXPECT_TRUE(honk_verified);

// Construct and verify Goblin ECC op queue Merge proof
auto merge_verified = construct_and_verify_merge_proof(composer, op_queue);
auto merge_verified = construct_and_verify_merge_proof(op_queue);
EXPECT_TRUE(merge_verified);
}

Expand All @@ -135,7 +137,7 @@ TEST_F(GoblinUltraHonkComposerTests, MultipleCircuitsMergeOnly)
auto composer = GoblinUltraComposer();

// Construct and verify Goblin ECC op queue Merge proof
auto merge_verified = construct_and_verify_merge_proof(composer, op_queue);
auto merge_verified = construct_and_verify_merge_proof(op_queue);
EXPECT_TRUE(merge_verified);
}
}
Expand Down Expand Up @@ -195,7 +197,7 @@ TEST_F(GoblinUltraHonkComposerTests, MultipleCircuitsHonkAndMerge)
EXPECT_TRUE(honk_verified);

// Construct and verify Goblin ECC op queue Merge proof
auto merge_verified = construct_and_verify_merge_proof(composer, op_queue);
auto merge_verified = construct_and_verify_merge_proof(op_queue);
EXPECT_TRUE(merge_verified);
}

Expand Down
46 changes: 22 additions & 24 deletions barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
namespace bb {

/**
* Create MergeProver_
* @brief Create MergeProver
* @details We require an SRS at least as large as the current op queue size in order to commit to the shifted
* per-circuit contribution t_i^{shift}
*
*/
template <typename Flavor>
MergeProver_<Flavor>::MergeProver_(const std::shared_ptr<CommitmentKey>& commitment_key,
const std::shared_ptr<ECCOpQueue>& op_queue,
const std::shared_ptr<Transcript>& transcript)
: transcript(transcript)
, op_queue(op_queue)
, pcs_commitment_key(commitment_key)
{}
MergeProver::MergeProver(const std::shared_ptr<ECCOpQueue>& op_queue)
: op_queue(op_queue)
, pcs_commitment_key(std::make_shared<CommitmentKey>(op_queue->ultra_ops[0].size()))
{
// Update internal size data in the op queue that allows for extraction of e.g. previous aggregate transcript
op_queue->set_size_data();
}

/**
* @brief Prove proper construction of the aggregate Goblin ECC op queue polynomials T_i^(j), j = 1,2,3,4.
Expand All @@ -26,11 +27,12 @@ MergeProver_<Flavor>::MergeProver_(const std::shared_ptr<CommitmentKey>& commitm
* TODO(#746): Prove connection between t_i^{shift}, committed to herein, and t_i, used in the main protocol. See issue
* for details (https://github.com/AztecProtocol/barretenberg/issues/746).
*
* @tparam Flavor
* @return HonkProof&
* @return honk::proof
*/
template <typename Flavor> HonkProof& MergeProver_<Flavor>::construct_proof()
HonkProof MergeProver::construct_proof()
{
transcript = std::make_shared<Transcript>();

size_t N = op_queue->get_current_size();

// Extract T_i, T_{i-1}
Expand All @@ -40,14 +42,14 @@ template <typename Flavor> HonkProof& MergeProver_<Flavor>::construct_proof()
ASSERT(T_prev[0].size() > 0);

// Construct t_i^{shift} as T_i - T_{i-1}
std::array<Polynomial, Flavor::NUM_WIRES> t_shift;
for (size_t i = 0; i < Flavor::NUM_WIRES; ++i) {
std::array<Polynomial, NUM_WIRES> t_shift;
for (size_t i = 0; i < NUM_WIRES; ++i) {
t_shift[i] = Polynomial(T_current[i]);
t_shift[i] -= T_prev[i];
}

// Compute/get commitments [t_i^{shift}], [T_{i-1}], and [T_i] and add to transcript
std::array<Commitment, Flavor::NUM_WIRES> C_T_current;
std::array<Commitment, NUM_WIRES> C_T_current;
for (size_t idx = 0; idx < t_shift.size(); ++idx) {
// Get previous transcript commitment [T_{i-1}] from op queue
auto C_T_prev = op_queue->ultra_ops_commitments[idx];
Expand All @@ -72,20 +74,20 @@ template <typename Flavor> HonkProof& MergeProver_<Flavor>::construct_proof()
// Add univariate opening claims for each polynomial.
std::vector<OpeningClaim> opening_claims;
// Compute evaluation T_{i-1}(\kappa)
for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) {
for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
auto polynomial = Polynomial(T_prev[idx]);
auto evaluation = polynomial.evaluate(kappa);
transcript->send_to_verifier("T_prev_eval_" + std::to_string(idx + 1), evaluation);
opening_claims.emplace_back(OpeningClaim{ polynomial, { kappa, evaluation } });
}
// Compute evaluation t_i^{shift}(\kappa)
for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) {
for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
auto evaluation = t_shift[idx].evaluate(kappa);
transcript->send_to_verifier("t_shift_eval_" + std::to_string(idx + 1), evaluation);
opening_claims.emplace_back(OpeningClaim{ t_shift[idx], { kappa, evaluation } });
}
// Compute evaluation T_i(\kappa)
for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) {
for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
auto polynomial = Polynomial(T_current[idx]);
auto evaluation = polynomial.evaluate(kappa);
transcript->send_to_verifier("T_current_eval_" + std::to_string(idx + 1), evaluation);
Expand All @@ -112,11 +114,7 @@ template <typename Flavor> HonkProof& MergeProver_<Flavor>::construct_proof()
auto quotient_commitment = pcs_commitment_key->commit(quotient);
transcript->send_to_verifier("KZG:W", quotient_commitment);

proof = transcript->proof_data;
return proof;
return transcript->proof_data;
}

template class MergeProver_<UltraFlavor>;
template class MergeProver_<GoblinUltraFlavor>;

} // namespace bb
} // namespace bb
31 changes: 14 additions & 17 deletions barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,28 @@ namespace bb {
/**
* @brief Prover class for the Goblin ECC op queue transcript merge protocol
*
* @tparam Flavor
*/
template <typename Flavor> class MergeProver_ {
using FF = typename Flavor::FF;
using Polynomial = typename Flavor::Polynomial;
using CommitmentKey = typename Flavor::CommitmentKey;
using Commitment = typename Flavor::Commitment;
using PCS = typename Flavor::PCS;
using Curve = typename Flavor::Curve;
using OpeningClaim = ProverOpeningClaim<Curve>;
using OpeningPair = bb::OpeningPair<Curve>;
class MergeProver {
using Curve = curve::BN254;
using FF = Curve::ScalarField;
using Polynomial = polynomial;
using CommitmentKey = bb::CommitmentKey<Curve>;
using Commitment = Curve::AffineElement;
using PCS = bb::KZG<Curve>;
using OpeningClaim = typename bb::ProverOpeningClaim<Curve>;
using Transcript = BaseTranscript;

public:
std::shared_ptr<Transcript> transcript;
std::shared_ptr<ECCOpQueue> op_queue;
std::shared_ptr<CommitmentKey> pcs_commitment_key;

explicit MergeProver_(const std::shared_ptr<CommitmentKey>&,
const std::shared_ptr<ECCOpQueue>&,
const std::shared_ptr<Transcript>& transcript = std::make_shared<Transcript>());
BBERG_PROFILE HonkProof& construct_proof();
explicit MergeProver(const std::shared_ptr<ECCOpQueue>&);

BBERG_PROFILE HonkProof construct_proof();

private:
HonkProof proof;
std::shared_ptr<ECCOpQueue> op_queue;
std::shared_ptr<CommitmentKey> pcs_commitment_key;
static constexpr size_t NUM_WIRES = GoblinUltraFlavor::NUM_WIRES;
};

} // namespace bb
36 changes: 15 additions & 21 deletions barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

namespace bb {

template <typename Flavor>
MergeVerifier_<Flavor>::MergeVerifier_()
: transcript(std::make_shared<Transcript>())
, pcs_verification_key(std::make_unique<VerifierCommitmentKey>(0, bb::srs::get_crs_factory())){};
MergeVerifier::MergeVerifier()
: pcs_verification_key(std::make_unique<VerifierCommitmentKey>(0, bb::srs::get_crs_factory())){};

/**
* @brief Verify proper construction of the aggregate Goblin ECC op queue polynomials T_i^(j), j = 1,2,3,4.
Expand All @@ -15,18 +13,17 @@ MergeVerifier_<Flavor>::MergeVerifier_()
* M_{i-1}), where the shift magnitude M_{i-1} is the length of T_{i-1}. This protocol verfies that the aggregate op
* queue has been constructed correctly via a simple Schwartz-Zippel check. Evaluations are checked via batched KZG.
*
* @tparam Flavor
* @return HonkProof&
*/
template <typename Flavor> bool MergeVerifier_<Flavor>::verify_proof(const HonkProof& proof)
bool MergeVerifier::verify_proof(const HonkProof& proof)
{
transcript = std::make_shared<Transcript>(proof);

// Receive commitments [t_i^{shift}], [T_{i-1}], and [T_i]
std::array<Commitment, Flavor::NUM_WIRES> C_T_prev;
std::array<Commitment, Flavor::NUM_WIRES> C_t_shift;
std::array<Commitment, Flavor::NUM_WIRES> C_T_current;
for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) {
std::array<Commitment, NUM_WIRES> C_T_prev;
std::array<Commitment, NUM_WIRES> C_t_shift;
std::array<Commitment, NUM_WIRES> C_T_current;
for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
C_T_prev[idx] = transcript->template receive_from_prover<Commitment>("T_PREV_" + std::to_string(idx + 1));
C_t_shift[idx] = transcript->template receive_from_prover<Commitment>("t_SHIFT_" + std::to_string(idx + 1));
C_T_current[idx] = transcript->template receive_from_prover<Commitment>("T_CURRENT_" + std::to_string(idx + 1));
Expand All @@ -35,27 +32,27 @@ template <typename Flavor> bool MergeVerifier_<Flavor>::verify_proof(const HonkP
FF kappa = transcript->get_challenge("kappa");

// Receive transcript poly evaluations and add corresponding univariate opening claims {(\kappa, p(\kappa), [p(X)]}
std::array<FF, Flavor::NUM_WIRES> T_prev_evals;
std::array<FF, Flavor::NUM_WIRES> t_shift_evals;
std::array<FF, Flavor::NUM_WIRES> T_current_evals;
std::array<FF, NUM_WIRES> T_prev_evals;
std::array<FF, NUM_WIRES> t_shift_evals;
std::array<FF, NUM_WIRES> T_current_evals;
std::vector<OpeningClaim> opening_claims;
for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) {
for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
T_prev_evals[idx] = transcript->template receive_from_prover<FF>("T_prev_eval_" + std::to_string(idx + 1));
opening_claims.emplace_back(OpeningClaim{ { kappa, T_prev_evals[idx] }, C_T_prev[idx] });
}
for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) {
for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
t_shift_evals[idx] = transcript->template receive_from_prover<FF>("t_shift_eval_" + std::to_string(idx + 1));
opening_claims.emplace_back(OpeningClaim{ { kappa, t_shift_evals[idx] }, C_t_shift[idx] });
}
for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) {
for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
T_current_evals[idx] =
transcript->template receive_from_prover<FF>("T_current_eval_" + std::to_string(idx + 1));
opening_claims.emplace_back(OpeningClaim{ { kappa, T_current_evals[idx] }, C_T_current[idx] });
}

// Check the identity T_i(\kappa) = T_{i-1}(\kappa) + t_i^{shift}(\kappa). If it fails, return false
bool identity_checked = true;
for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) {
for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
identity_checked = identity_checked && (T_current_evals[idx] == T_prev_evals[idx] + t_shift_evals[idx]);
}

Expand All @@ -79,7 +76,4 @@ template <typename Flavor> bool MergeVerifier_<Flavor>::verify_proof(const HonkP
return identity_checked && verified;
}

template class MergeVerifier_<UltraFlavor>;
template class MergeVerifier_<GoblinUltraFlavor>;

} // namespace bb
} // namespace bb
28 changes: 13 additions & 15 deletions barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,25 @@ namespace bb {
/**
* @brief Verifier class for the Goblin ECC op queue transcript merge protocol
*
* @tparam Flavor
*/
template <typename Flavor> class MergeVerifier_ {
using FF = typename Flavor::FF;
using Polynomial = typename Flavor::Polynomial;
using CommitmentKey = typename Flavor::CommitmentKey;
using Commitment = typename Flavor::Commitment;
using PCS = typename Flavor::PCS;
using Curve = typename Flavor::Curve;
using OpeningClaim = typename bb::OpeningClaim<Curve>;
using VerificationKey = typename Flavor::VerificationKey;
using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey;
using Transcript = typename Flavor::Transcript;
class MergeVerifier {
using Curve = curve::BN254;
using FF = typename Curve::ScalarField;
using Commitment = typename Curve::AffineElement;
using PCS = bb::KZG<Curve>;
using OpeningClaim = bb::OpeningClaim<Curve>;
using VerifierCommitmentKey = bb::VerifierCommitmentKey<Curve>;
using Transcript = BaseTranscript;

public:
std::shared_ptr<Transcript> transcript;
std::shared_ptr<ECCOpQueue> op_queue;
std::shared_ptr<VerifierCommitmentKey> pcs_verification_key;

explicit MergeVerifier_();
explicit MergeVerifier();
bool verify_proof(const HonkProof& proof);

private:
std::shared_ptr<VerifierCommitmentKey> pcs_verification_key;
static constexpr size_t NUM_WIRES = GoblinUltraFlavor::NUM_WIRES;
};

} // namespace bb
Loading

0 comments on commit 5300d00

Please sign in to comment.