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: goblin op queue transcript aggregation #2257

Merged
merged 48 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
eed0ec5
initial agg protocol in prover and verifier
ledwards2225 Sep 6, 2023
9c6c0ba
set ultra ops in op queue plus test
ledwards2225 Sep 6, 2023
75b568c
prover has a pointer to op queue
ledwards2225 Sep 6, 2023
485fd84
infra for getting prev agg transcript from op queue
ledwards2225 Sep 6, 2023
afe3a07
tests passing with only shifted t claims
ledwards2225 Sep 7, 2023
08bf084
op codes constrained to constant variables
ledwards2225 Sep 7, 2023
0f76d3b
passing with claims on t and T
ledwards2225 Sep 7, 2023
f29901d
verifier checks identity plus cleanup
ledwards2225 Sep 7, 2023
3ccc711
basic prover functionality in place
ledwards2225 Sep 8, 2023
1138b7d
full protocol passing with mock prev op queue data
ledwards2225 Sep 10, 2023
ce0e92e
test improvement, new right shift, cleanup
ledwards2225 Sep 11, 2023
81fbe06
resolve some todos in the builder
ledwards2225 Sep 11, 2023
9bb5889
fix build error
ledwards2225 Sep 11, 2023
61cae4a
splitting goblin builder into its own class
ledwards2225 Sep 12, 2023
578a646
chore: remove bb symlink
ludamad Sep 13, 2023
efebc27
chore: circuits/bb => bb
ludamad Sep 13, 2023
11a3ae6
chore: Prepare for build system changes
ludamad Sep 13, 2023
a6ff45c
Merge remote-tracking branch 'origin/master' into lde/transcript_agg_new
ludamad Sep 13, 2023
0f59546
Merge fixup
ludamad Sep 13, 2023
e281742
formatting
ledwards2225 Sep 13, 2023
6947053
Merge branch 'master' into lde/transcript_aggregation_redux
ledwards2225 Sep 13, 2023
51964dd
recursive flavor is templated by builder
ledwards2225 Sep 13, 2023
f1e3508
Merge branch 'master' into lde/transcript_aggregation_redux
ledwards2225 Sep 13, 2023
d04a518
more formatting
ledwards2225 Sep 13, 2023
97f5815
improve right shift fctn and add test
ledwards2225 Sep 13, 2023
7fe7291
Merge branch 'master' into lde/transcript_aggregation_redux
ledwards2225 Sep 13, 2023
24d8f47
clean up recursive verifier circuit tests
ledwards2225 Sep 14, 2023
d15c6fb
all 4 recursive vers working w op queue agg
ledwards2225 Sep 15, 2023
b8bfb1c
Merge branch 'master' into lde/transcript_aggregation_redux
ledwards2225 Sep 15, 2023
ebac0cc
fix ECCVM build error
ledwards2225 Sep 15, 2023
9e42d7e
format
ledwards2225 Sep 15, 2023
b1f18a4
comments and cleanup
ledwards2225 Sep 15, 2023
91589e6
brutal master merge
ledwards2225 Sep 17, 2023
18857dd
format
ledwards2225 Sep 17, 2023
98042d0
fpormatt
ledwards2225 Sep 17, 2023
9ad0e48
formewnt
ledwards2225 Sep 17, 2023
dd780a0
add todo for sumcheck
ledwards2225 Sep 18, 2023
7a4c584
Merge branch 'master' into lde/transcript_aggregation_redux
ledwards2225 Sep 18, 2023
e35d19a
cleanup
ledwards2225 Sep 18, 2023
be50dda
Merge branch 'master' into lde/transcript_aggregation_redux
ledwards2225 Sep 18, 2023
c0156af
initial version of simple full goblin test
ledwards2225 Sep 19, 2023
8af1b00
Merge branch 'master' into lde/transcript_aggregation_redux
ledwards2225 Sep 19, 2023
1e2d734
fix
ledwards2225 Sep 19, 2023
517ccba
Merge branch 'master' into lde/transcript_aggregation_redux
ledwards2225 Sep 21, 2023
9cfbaf9
Updates based on Keshas comments
ledwards2225 Sep 21, 2023
b46982f
Merge branch 'master' into lde/transcript_aggregation_redux
ledwards2225 Sep 21, 2023
2b476a1
add todo with issue for avoiding new challenge
ledwards2225 Sep 21, 2023
782cace
Merge branch 'master' into lde/transcript_aggregation_redux
ledwards2225 Sep 22, 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
@@ -0,0 +1,197 @@
#include <cstddef>
#include <cstdint>
#include <gtest/gtest.h>

#include "barretenberg/common/log.hpp"
#include "barretenberg/honk/composer/eccvm_composer.hpp"
#include "barretenberg/honk/composer/ultra_composer.hpp"
#include "barretenberg/honk/proof_system/ultra_prover.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"

namespace test_full_goblin_composer {

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

class FullGoblinComposerTests : public ::testing::Test {
protected:
static void SetUpTestSuite()
{
barretenberg::srs::init_crs_factory("../srs_db/ignition");
barretenberg::srs::init_grumpkin_crs_factory("../srs_db/grumpkin");
}

using Curve = curve::BN254;
using FF = Curve::ScalarField;
using Point = Curve::AffineElement;
using CommitmentKey = proof_system::honk::pcs::CommitmentKey<Curve>;
using GoblinUltraBuilder = proof_system::GoblinUltraCircuitBuilder;
using GoblinUltraComposer = proof_system::honk::GoblinUltraComposer;
using ECCVMFlavor = proof_system::honk::flavor::ECCVMGrumpkin;
using ECCVMBuilder = proof_system::ECCVMCircuitBuilder<ECCVMFlavor>;
using ECCVMComposer = proof_system::honk::ECCVMComposer_<ECCVMFlavor>;
using VMOp = proof_system_eccvm::VMOperation<ECCVMFlavor::CycleGroup>;
static constexpr size_t NUM_OP_QUEUE_COLUMNS = proof_system::honk::flavor::GoblinUltra::NUM_WIRES;

/**
* @brief Generate a simple test circuit with some ECC op gates and conventional arithmetic gates
*
* @param builder
*/
void generate_test_circuit(auto& 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);
}
builder.queue_ecc_eq();

// 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.
*
* @param op_queue
*/
static void perform_op_queue_interactions_for_mock_first_circuit(
std::shared_ptr<proof_system::ECCOpQueue>& op_queue)
{
auto builder = GoblinUltraBuilder(op_queue);

// Add a mul accum op and an equality op
auto point = Point::one() * FF::random_element();
Rumata888 marked this conversation as resolved.
Show resolved Hide resolved
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 Test proof construction/verification for a circuit with ECC op gates, public inputs, and basic arithmetic
* gates
* @note We simulate op queue interactions with a previous circuit so the actual circuit under test utilizes an op queue
* with non-empty 'previous' data. This avoid complications with zero-commitments etc.
*
*/
TEST_F(FullGoblinComposerTests, SimpleCircuit)
{
auto op_queue = std::make_shared<proof_system::ECCOpQueue>();

// Add mock data to op queue to simulate interaction with a "first" circuit
perform_op_queue_interactions_for_mock_first_circuit(op_queue);

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

generate_test_circuit(builder);

auto composer = GoblinUltraComposer();
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);
EXPECT_EQ(verified, true);
}

// Construct an ECCVM circuit then generate and verify its proof
{
// Instantiate an ECCVM builder with the vm ops stored in the op queue
auto builder = ECCVMBuilder(op_queue->raw_ops);

// // Can fiddle with one of the operands to trigger a failure
// builder.vm_operations[0].z1 *= 2;
Rumata888 marked this conversation as resolved.
Show resolved Hide resolved

auto composer = ECCVMComposer();
auto prover = composer.create_prover(builder);
auto proof = prover.construct_proof();
auto verifier = composer.create_verifier(builder);
bool verified = verifier.verify_proof(proof);
ASSERT_TRUE(verified);
}
}

/**
* @brief Check that ECCVM verification fails if ECC op queue operands are tampered with
*
*/
TEST_F(FullGoblinComposerTests, SimpleCircuitFailureCase)
{
auto op_queue = std::make_shared<proof_system::ECCOpQueue>();

// Add mock data to op queue to simulate interaction with a "first" circuit
perform_op_queue_interactions_for_mock_first_circuit(op_queue);

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

generate_test_circuit(builder);

auto composer = GoblinUltraComposer();
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);
EXPECT_EQ(verified, true);
}

// Construct an ECCVM circuit then generate and verify its proof
{
// Instantiate an ECCVM builder with the vm ops stored in the op queue
auto builder = ECCVMBuilder(op_queue->raw_ops);

// Fiddle with one of the operands to trigger a failure
builder.vm_operations[0].z1 += 1;

auto composer = ECCVMComposer();
auto prover = composer.create_prover(builder);
auto proof = prover.construct_proof();
auto verifier = composer.create_verifier(builder);
bool verified = verifier.verify_proof(proof);
EXPECT_EQ(verified, false);
}
}

} // namespace test_full_goblin_composer
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "barretenberg/common/log.hpp"
#include "barretenberg/honk/composer/ultra_composer.hpp"
#include "barretenberg/honk/proof_system/ultra_prover.hpp"
#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp"
#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp"

using namespace proof_system::honk;
Expand All @@ -18,51 +19,114 @@ auto& engine = numeric::random::get_debug_engine();
class GoblinUltraHonkComposerTests : public ::testing::Test {
protected:
static void SetUpTestSuite() { barretenberg::srs::init_crs_factory("../srs_db/ignition"); }

using Curve = curve::BN254;
using FF = Curve::ScalarField;
using Point = Curve::AffineElement;
using CommitmentKey = pcs::CommitmentKey<Curve>;

/**
* @brief Generate a simple test circuit with some ECC op gates and conventional arithmetic gates
*
* @param builder
*/
void generate_test_circuit(auto& builder)
{
// Add some ecc op gates
for (size_t i = 0; i < 3; ++i) {
auto point = Point::one() * FF::random_element();
auto scalar = FF::random_element();
builder.queue_ecc_mul_accum(point, scalar);
}
builder.queue_ecc_eq();

// 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 Construct a goblin ultra circuit then generate a verify its proof
*
* @param op_queue
* @return auto
*/
bool construct_test_circuit_then_generate_and_verify_proof(auto& op_queue)
{
auto builder = proof_system::GoblinUltraCircuitBuilder(op_queue);

generate_test_circuit(builder);

auto composer = GoblinUltraComposer();
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 Test proof construction/verification for a circuit with ECC op gates, public inputs, and basic arithmetic
* gates
* @note We simulate op queue interactions with a previous circuit so the actual circuit under test utilizes an op queue
* with non-empty 'previous' data. This avoid complications with zero-commitments etc.
*
*/
TEST_F(GoblinUltraHonkComposerTests, SimpleCircuit)
TEST_F(GoblinUltraHonkComposerTests, SingleCircuit)
{
using fr = barretenberg::fr;
using g1 = barretenberg::g1;
auto builder = proof_system::UltraCircuitBuilder();

// Define an arbitrary number of operations/gates
size_t num_ecc_ops = 3;
size_t num_conventional_gates = 10;

// Add some ecc op gates
for (size_t i = 0; i < num_ecc_ops; ++i) {
auto point = g1::affine_one * fr::random_element();
auto scalar = fr::random_element();
builder.queue_ecc_mul_accum(point, scalar);
}
auto op_queue = std::make_shared<proof_system::ECCOpQueue>();

// Add some conventional gates that utlize public inputs
for (size_t i = 0; i < num_conventional_gates; ++i) {
fr a = fr::random_element();
fr b = fr::random_element();
fr c = fr::random_element();
fr 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, fr(1), fr(1), fr(1), fr(-1), fr(0) });
}
// Add mock data to op queue to simulate interaction with a previous circuit
op_queue->populate_with_mock_initital_data();

// Construct a test circuit then generate and verify its proof
auto verified = construct_test_circuit_then_generate_and_verify_proof(op_queue);

auto composer = GoblinUltraComposer();
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);
EXPECT_EQ(verified, true);
}

/**
* @brief Test proof construction/verification for a circuit with ECC op gates, public inputs, and basic arithmetic
* gates
*
*/
TEST_F(GoblinUltraHonkComposerTests, MultipleCircuits)
{
// Instantiate EccOpQueue. This will be shared across all circuits in the series
auto op_queue = std::make_shared<proof_system::ECCOpQueue>();

// Add mock data to op queue to simulate interaction with a previous circuit
op_queue->populate_with_mock_initital_data();

// Construct multiple test circuits that share an ECC op queue. Generate and verify a proof for each.
size_t NUM_CIRCUITS = 3;
for (size_t i = 0; i < NUM_CIRCUITS; ++i) {
construct_test_circuit_then_generate_and_verify_proof(op_queue);
}

// Compute the commitments to the aggregate op queue directly and check that they match those that were computed
// iteratively during transcript aggregation by the provers and stored in the op queue.
size_t aggregate_op_queue_size = op_queue->current_ultra_ops_size;
auto crs_factory = std::make_shared<barretenberg::srs::factories::FileCrsFactory<Curve>>("../srs_db/ignition");
auto commitment_key = std::make_shared<CommitmentKey>(aggregate_op_queue_size, crs_factory);
size_t idx = 0;
for (auto& result : op_queue->ultra_ops_commitments) {
auto expected = commitment_key->commit(op_queue->ultra_ops[idx++]);
EXPECT_EQ(result, expected);
}
}

} // namespace test_ultra_honk_composer
2 changes: 1 addition & 1 deletion barretenberg/cpp/src/barretenberg/honk/flavor/ecc_vm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ template <typename CycleGroup_T, typename Curve_T, typename PCS_T> class ECCVMBa
};
};

class ECCVM : public ECCVMBase<grumpkin::g1, curve::BN254, pcs::kzg::KZG<curve::BN254, true>> {};
class ECCVM : public ECCVMBase<grumpkin::g1, curve::BN254, pcs::kzg::KZG<curve::BN254>> {};
class ECCVMGrumpkin : public ECCVMBase<barretenberg::g1, curve::Grumpkin, pcs::ipa::IPA<curve::Grumpkin>> {};

// NOLINTEND(cppcoreguidelines-avoid-const-or-ref-data-members)
Expand Down
10 changes: 6 additions & 4 deletions barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include "barretenberg/honk/pcs/kzg/kzg.hpp"
#include "barretenberg/honk/transcript/transcript.hpp"
#include "barretenberg/polynomials/univariate.hpp"
#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp"
#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp"
#include "barretenberg/proof_system/flavor/flavor.hpp"
#include "barretenberg/proof_system/relations/auxiliary_relation.hpp"
#include "barretenberg/proof_system/relations/ecc_op_queue_relation.hpp"
Expand All @@ -16,13 +16,13 @@ namespace proof_system::honk::flavor {

class GoblinUltra {
public:
using CircuitBuilder = UltraCircuitBuilder;
using CircuitBuilder = GoblinUltraCircuitBuilder;
using Curve = curve::BN254;
using PCS = pcs::kzg::KZG<Curve>;
using FF = Curve::ScalarField;
using GroupElement = Curve::Element;
using Commitment = Curve::AffineElement;
using CommitmentHandle = Curve::AffineElement;
using FF = Curve::ScalarField;
using PCS = pcs::kzg::KZG<Curve>;
using Polynomial = barretenberg::Polynomial<FF>;
using PolynomialHandle = std::span<FF>;
using CommitmentKey = pcs::CommitmentKey<Curve>;
Expand Down Expand Up @@ -288,6 +288,8 @@ class GoblinUltra {

size_t num_ecc_op_gates; // needed to determine public input offset

std::shared_ptr<ECCOpQueue> op_queue;

// The plookup wires that store plookup read data.
std::array<PolynomialHandle, 3> get_table_column_wires() { return { w_l, w_r, w_o }; };
};
Expand Down
Loading