Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Encapsulated Goblin #3524

Merged
merged 26 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
7950c3c
codys baseline changes
ledwards2225 Nov 27, 2023
d0314a5
updates to test structure; passing; no recursion
ledwards2225 Nov 30, 2023
2e8ced6
construct recursive ver directly from native vkey
ledwards2225 Nov 30, 2023
3ebd005
new test suite; passes with 2 layers of recusion
ledwards2225 Nov 30, 2023
cfdbc3b
full test with recursion is passing through trans
ledwards2225 Dec 1, 2023
178f646
remove pseudo from composer tests
ledwards2225 Dec 1, 2023
fa68496
Merge branch 'master' into lde-cg/full_test_rework
codygunton Dec 4, 2023
6ef21ac
const&
codygunton Dec 4, 2023
91f3b8c
const&
codygunton Dec 4, 2023
466cbf0
basic goblin prove and verify structure
ledwards2225 Dec 4, 2023
616fd40
Merge branch 'master' into lde-cg/full_test_rework
ledwards2225 Dec 4, 2023
d2db965
It works!
codygunton Dec 4, 2023
385edee
VM verification split out
codygunton Dec 4, 2023
b1df3ae
Bring tests in line w/ e/o
codygunton Dec 5, 2023
4e332f4
WIP
codygunton Dec 5, 2023
c02db5a
Fix Translator test
codygunton Dec 6, 2023
a4b5e2f
Share testing code
codygunton Dec 6, 2023
4f5d1ea
Cleanup
codygunton Dec 6, 2023
ba98a33
Cleanup
codygunton Dec 6, 2023
55ec020
Spawn todos.
codygunton Dec 6, 2023
e075d93
Remove comment
codygunton Dec 6, 2023
9d9f735
Remove stupid alias.
codygunton Dec 6, 2023
c90e3bf
Adjust comments per review.
codygunton Dec 6, 2023
60d7f56
Better modeling of kernel
codygunton Dec 6, 2023
977021e
Merge remote-tracking branch 'origin/master' into lde-cg/full_test_re…
codygunton Dec 6, 2023
791ff7d
Rename utils.hpp
codygunton Dec 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ void construct_proof_with_specified_num_iterations(
Composer composer;

for (auto _ : state) {
// Constuct circuit and prover; don't include this part in measurement
// Construct circuit and prover; don't include this part in measurement
state.PauseTiming();
auto prover = get_prover(composer, test_circuit_function, num_iterations);
state.ResumeTiming();
Expand Down
11 changes: 7 additions & 4 deletions barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,31 +345,34 @@ template <ECCVMFlavor Flavor> void ECCVMProver_<Flavor>::execute_transcript_cons
transcript->send_to_verifier("Translation:hack_evaluation", hack.evaluate(evaluation_challenge_x));

// Get another challenge for batching the univariate claims
FF batching_challenge = transcript->get_challenge("Translation:batching_challenge");
FF ipa_batching_challenge = transcript->get_challenge("Translation:ipa_batching_challenge");

// Collect the polynomials and evaluations to be batched
RefArray univariate_polynomials{ key->transcript_op, key->transcript_Px, key->transcript_Py,
key->transcript_z1, key->transcript_z2, hack };
std::array<FF, univariate_polynomials.size()> univariate_evaluations;

// Constuct the batched polynomial and batched evaluation
// Construct the batched polynomial and batched evaluation
Polynomial batched_univariate{ key->circuit_size };
FF batched_evaluation{ 0 };
auto batching_scalar = FF(1);
for (auto [polynomial, eval] : zip_view(univariate_polynomials, univariate_evaluations)) {
batched_univariate.add_scaled(polynomial, batching_scalar);
batched_evaluation += eval * batching_scalar;
batching_scalar *= batching_challenge;
batching_scalar *= ipa_batching_challenge;
}

// Compute a proof for the batched univariate opening
PCS::compute_opening_proof(
commitment_key, { evaluation_challenge_x, batched_evaluation }, batched_univariate, transcript);

// Get another challenge for batching the univariate claims
translation_batching_challenge_v = transcript->get_challenge("Translation:batching_challenge");
}

template <ECCVMFlavor Flavor> plonk::proof& ECCVMProver_<Flavor>::export_proof()
{
proof.proof_data = transcript->proof_data;
proof.proof_data = transcript->export_proof();
return proof;
}

Expand Down
1 change: 1 addition & 0 deletions barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ template <ECCVMFlavor Flavor> class ECCVMProver_ {
Polynomial quotient_W;

FF evaluation_challenge_x;
FF translation_batching_challenge_v; // to be rederived by the translator verifier

sumcheck::SumcheckOutput<Flavor> sumcheck_output;
pcs::gemini::ProverOutput<Curve> gemini_output;
Expand Down
9 changes: 5 additions & 4 deletions barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,16 +253,17 @@ template <typename Flavor> bool ECCVMVerifier_<Flavor>::verify_proof(const plonk
transcript->template receive_from_prover<FF>("Translation:hack_evaluation")
};

FF batching_challenge = transcript->get_challenge("Translation:batching_challenge");
// Get another challenge for batching the univariate claims
FF ipa_batching_challenge = transcript->get_challenge("Translation:ipa_batching_challenge");

// Constuct batched commitment and batched evaluation
// Construct batched commitment and batched evaluation
auto batched_commitment = transcript_commitments[0];
auto batched_transcript_eval = transcript_evaluations[0];
auto batching_scalar = batching_challenge;
auto batching_scalar = ipa_batching_challenge;
for (size_t idx = 1; idx < transcript_commitments.size(); ++idx) {
batched_commitment = batched_commitment + transcript_commitments[idx] * batching_scalar;
batched_transcript_eval += batching_scalar * transcript_evaluations[idx];
batching_scalar *= batching_challenge;
batching_scalar *= ipa_batching_challenge;
}

// Construct and verify batched opening claim
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ template <typename BuilderType> class GoblinUltraRecursive_ {
* @param builder
* @param native_key Native verification key from which to extract the precomputed commitments
*/
VerificationKey(CircuitBuilder* builder, std::shared_ptr<NativeVerificationKey> native_key)
VerificationKey(CircuitBuilder* builder, const std::shared_ptr<NativeVerificationKey>& native_key)
: VerificationKey_<GoblinUltra::PrecomputedEntities<Commitment>>(native_key->circuit_size,
native_key->num_public_inputs)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ template <typename BuilderType> class UltraRecursive_ {
* @param builder
* @param native_key Native verification key from which to extract the precomputed commitments
*/
VerificationKey(CircuitBuilder* builder, std::shared_ptr<NativeVerificationKey> native_key)
VerificationKey(CircuitBuilder* builder, const std::shared_ptr<NativeVerificationKey>& native_key)
: VerificationKey_<PrecomputedEntities<Commitment>>(native_key->circuit_size, native_key->num_public_inputs)
{
this->q_m = Commitment::from_witness(builder, native_key->q_m);
Expand Down
2 changes: 1 addition & 1 deletion barretenberg/cpp/src/barretenberg/goblin/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
barretenberg_module(goblin ultra_honk eccvm translator_vm)
barretenberg_module(goblin ultra_honk eccvm translator_vm transcript)
165 changes: 22 additions & 143 deletions barretenberg/cpp/src/barretenberg/goblin/full_goblin_composer.test.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "barretenberg/eccvm/eccvm_composer.hpp"
#include "barretenberg/goblin/goblin.hpp"
#include "barretenberg/goblin/translation_evaluations.hpp"
#include "barretenberg/goblin/utils.hpp"
#include "barretenberg/proof_system/circuit_builder/eccvm/eccvm_circuit_builder.hpp"
#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp"
#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp"
Expand All @@ -8,14 +10,11 @@

#include <gtest/gtest.h>

using namespace barretenberg;
using namespace proof_system::honk;

namespace test_full_goblin_composer {

namespace {
auto& engine = numeric::random::get_debug_engine();
}

class FullGoblinComposerTests : public ::testing::Test {
protected:
static void SetUpTestSuite()
Expand All @@ -30,110 +29,11 @@ class FullGoblinComposerTests : public ::testing::Test {
using Point = Curve::AffineElement;
using CommitmentKey = pcs::CommitmentKey<Curve>;
using OpQueue = proof_system::ECCOpQueue;
using GoblinUltraBuilder = proof_system::GoblinUltraCircuitBuilder;
using ECCVMFlavor = flavor::ECCVM;
using ECCVMBuilder = proof_system::ECCVMCircuitBuilder<ECCVMFlavor>;
using ECCVMComposer = ECCVMComposer_<ECCVMFlavor>;

static constexpr size_t NUM_OP_QUEUE_COLUMNS = flavor::GoblinUltra::NUM_WIRES;

/**
* @brief Generate a simple test circuit with some ECC op gates and conventional arithmetic gates
*
* @param builder
*/
static void generate_test_circuit(proof_system::GoblinUltraCircuitBuilder& builder)
{
// Add some arbitrary ecc op gates
for (size_t i = 0; i < 3; ++i) {
auto point = Point::random_element();
auto scalar = FF::random_element();
builder.queue_ecc_add_accum(point);
builder.queue_ecc_mul_accum(point, scalar);
}
// queues the result of the preceding ECC
builder.queue_ecc_eq(); // should be eq and reset

// Add some conventional gates that utilize public inputs
for (size_t i = 0; i < 10; ++i) {
FF a = FF::random_element();
FF b = FF::random_element();
FF c = FF::random_element();
FF d = a + b + c;
uint32_t a_idx = builder.add_public_variable(a);
uint32_t b_idx = builder.add_variable(b);
uint32_t c_idx = builder.add_variable(c);
uint32_t d_idx = builder.add_variable(d);

builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, FF(1), FF(1), FF(1), FF(-1), FF(0) });
}
}

/**
* @brief Mock the interactions of a simple curcuit with the op_queue
* @details The transcript aggregation protocol in the Goblin proof system can not yet support an empty "previous
* transcript" (see issue #723). This function mocks the interactions with the op queue of a fictional "first"
* circuit. This way, when we go to generate a proof over our first "real" circuit, the transcript aggregation
* protocol can proceed nominally. The mock data is valid in the sense that it can be processed by all stages of
* Goblin as if it came from a genuine circuit.
*
* @todo WOKTODO: this is a zero commitments issue
*
* @param op_queue
*/
static void perform_op_queue_interactions_for_mock_first_circuit(
std::shared_ptr<proof_system::ECCOpQueue>& op_queue)
{
proof_system::GoblinUltraCircuitBuilder builder{ op_queue };

// Add a mul accum op and an equality op
auto point = Point::one() * FF::random_element();
auto scalar = FF::random_element();
builder.queue_ecc_mul_accum(point, scalar);
builder.queue_ecc_eq();

op_queue->set_size_data();

// Manually compute the op queue transcript commitments (which would normally be done by the prover)
auto crs_factory_ = barretenberg::srs::get_crs_factory();
auto commitment_key = CommitmentKey(op_queue->get_current_size(), crs_factory_);
std::array<Point, NUM_OP_QUEUE_COLUMNS> op_queue_commitments;
size_t idx = 0;
for (auto& entry : op_queue->get_aggregate_transcript()) {
op_queue_commitments[idx++] = commitment_key.commit(entry);
}
// Store the commitment data for use by the prover of the next circuit
op_queue->set_commitment_data(op_queue_commitments);
}

/**
* @brief Construct and a verify a Honk proof
*
*/
static bool construct_and_verify_honk_proof(GoblinUltraComposer& composer,
proof_system::GoblinUltraCircuitBuilder& builder)
{
auto instance = composer.create_instance(builder);
auto prover = composer.create_prover(instance);
auto verifier = composer.create_verifier(instance);
auto proof = prover.construct_proof();
bool verified = verifier.verify_proof(proof);

return verified;
}

/**
* @brief Construct and verify a Goblin ECC op queue merge proof
*
*/
static bool construct_and_verify_merge_proof(GoblinUltraComposer& composer, std::shared_ptr<OpQueue>& op_queue)
{
auto merge_prover = composer.create_merge_prover(op_queue);
auto merge_verifier = composer.create_merge_verifier(/*srs_size=*/10);
auto merge_proof = merge_prover.construct_proof();
bool verified = merge_verifier.verify_proof(merge_proof);

return verified;
}
using KernelInput = Goblin::AccumulationOutput;
};

/**
Expand All @@ -145,52 +45,31 @@ class FullGoblinComposerTests : public ::testing::Test {
*/
TEST_F(FullGoblinComposerTests, SimpleCircuit)
{
auto op_queue = std::make_shared<proof_system::ECCOpQueue>();
barretenberg::Goblin goblin;

// Add mock data to op queue to simulate interaction with a "first" circuit
perform_op_queue_interactions_for_mock_first_circuit(op_queue);
// Construct an initial circuit; its proof will be recursively verified by the first kernel
info("Initial circuit.");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I never intended these prints to stick around but no strong feelings

GoblinUltraBuilder initial_circuit{ goblin.op_queue };
GoblinTestingUtils::construct_simple_initial_circuit(initial_circuit);
KernelInput kernel_input = goblin.accumulate(initial_circuit);

// Construct a series of simple Goblin circuits; generate and verify their proofs
size_t NUM_CIRCUITS = 3;
size_t NUM_CIRCUITS = 2;
for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) {
proof_system::GoblinUltraCircuitBuilder builder{ op_queue };

generate_test_circuit(builder);

// The same composer is used to manage Honk and Merge prover/verifier
proof_system::honk::GoblinUltraComposer composer;
// Construct a circuit with logic resembling that of the "kernel circuit"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its a bit misleading to use the kernel terminology here since the point of this test is that there's no recursion. Not a big deal

info("\nKernel circuit ", circuit_idx);
GoblinUltraBuilder circuit_builder{ goblin.op_queue };
GoblinTestingUtils::construct_arithmetic_circuit(circuit_builder);

// Construct and verify Ultra Goblin Honk proof
bool honk_verified = construct_and_verify_honk_proof(composer, builder);
EXPECT_TRUE(honk_verified);

// Construct and verify op queue merge proof
bool merge_verified = construct_and_verify_merge_proof(composer, op_queue);
EXPECT_TRUE(merge_verified);
// Construct proof of the current kernel circuit to be recursively verified by the next one
kernel_input = goblin.accumulate(circuit_builder);
}

// Execute the ECCVM
// TODO(https://github.com/AztecProtocol/barretenberg/issues/785) Properly initialize transcript
auto eccvm_builder = ECCVMBuilder(op_queue);
auto eccvm_composer = ECCVMComposer();
auto eccvm_prover = eccvm_composer.create_prover(eccvm_builder);
auto eccvm_verifier = eccvm_composer.create_verifier(eccvm_builder);
auto eccvm_proof = eccvm_prover.construct_proof();
bool eccvm_verified = eccvm_verifier.verify_proof(eccvm_proof);
EXPECT_TRUE(eccvm_verified);

// Execute the Translator
// TODO(https://github.com/AztecProtocol/barretenberg/issues/786) Properly derive batching_challenge
auto batching_challenge = Fbase::random_element();
auto evaluation_input = eccvm_prover.evaluation_challenge_x;
proof_system::GoblinTranslatorCircuitBuilder translator_builder{ batching_challenge, evaluation_input, op_queue };
GoblinTranslatorComposer translator_composer;
GoblinTranslatorProver translator_prover = translator_composer.create_prover(translator_builder);
GoblinTranslatorVerifier translator_verifier = translator_composer.create_verifier(translator_builder);
proof_system::plonk::proof translator_proof = translator_prover.construct_proof();
bool accumulator_construction_verified = translator_verifier.verify_proof(translator_proof);
bool translation_verified = translator_verifier.verify_translation(eccvm_prover.translation_evaluations);
EXPECT_TRUE(accumulator_construction_verified && translation_verified);
Goblin::Proof proof = goblin.prove();
bool verified = goblin.verify(proof);
EXPECT_TRUE(verified);
}

// TODO(https://github.com/AztecProtocol/barretenberg/issues/787) Expand these tests.
} // namespace test_full_goblin_composer
Loading