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: Elliptic Curve Virtual Machine Circuit #644

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
126 changes: 126 additions & 0 deletions cpp/src/barretenberg/honk/composer/eccvm_composer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#include "./eccvm_composer.hpp"
#include "barretenberg/honk/proof_system/ultra_prover.hpp"
#include "barretenberg/proof_system/composer/composer_lib.hpp"
#include "barretenberg/proof_system/composer/permutation_lib.hpp"

namespace proof_system::honk {

/**
* @brief Compute witness polynomials
*
*/
template <ECCVMFlavor Flavor>
void ECCVMComposerHelper_<Flavor>::compute_witness(CircuitConstructor& circuit_constructor)
{
if (computed_witness) {
return;
}

auto polynomials = circuit_constructor.compute_full_polynomials();

auto key_wires = proving_key->get_wires();
auto poly_wires = polynomials.get_wires();

for (size_t i = 0; i < key_wires.size(); ++i) {
std::copy(poly_wires[i].begin(), poly_wires[i].end(), key_wires[i].begin());
}

computed_witness = true;
}

template <ECCVMFlavor Flavor>
ECCVMProver_<Flavor> ECCVMComposerHelper_<Flavor>::create_prover(CircuitConstructor& circuit_constructor)
{
compute_proving_key(circuit_constructor);
compute_witness(circuit_constructor);
compute_commitment_key(proving_key->circuit_size);

ECCVMProver_<Flavor> output_state(proving_key, commitment_key);

return output_state;
}

/**
* Create verifier: compute verification key,
* initialize verifier with it and an initial manifest and initialize commitment_scheme.
*
* @return The verifier.
* */
template <ECCVMFlavor Flavor>
ECCVMVerifier_<Flavor> ECCVMComposerHelper_<Flavor>::create_verifier(CircuitConstructor& circuit_constructor)
{
auto verification_key = compute_verification_key(circuit_constructor);

ECCVMVerifier_<Flavor> output_state(verification_key);

auto pcs_verification_key = std::make_unique<PCSVerificationKey>(verification_key->circuit_size, crs_factory_);

output_state.pcs_verification_key = std::move(pcs_verification_key);

return output_state;
}

template <ECCVMFlavor Flavor>
std::shared_ptr<typename Flavor::ProvingKey> ECCVMComposerHelper_<Flavor>::compute_proving_key(
CircuitConstructor& circuit_constructor)
{
if (proving_key) {
return proving_key;
}

// Initialize proving_key
// TODO(#392)(Kesha): replace composer types.
{
// TODO: get num gates in a more efficient way
const auto rows = circuit_constructor.compute_full_polynomials();
const size_t subgroup_size = rows.lagrange_first.size();
// Differentiate between Honk and Plonk here since Plonk pkey requires crs whereas Honk pkey does not
proving_key = std::make_shared<typename Flavor::ProvingKey>(subgroup_size, 0);
}

// construct_selector_polynomials<Flavor>(circuit_constructor, proving_key.get());

// TODO(@zac-williamson): We don't enforce nonzero selectors atm. Will create problems in recursive setting. Needs
// fix enforce_nonzero_polynomial_selectors(circuit_constructor, proving_key.get());

compute_first_and_last_lagrange_polynomials<Flavor>(proving_key.get());
{
const size_t n = proving_key->circuit_size;
typename Flavor::Polynomial lagrange_polynomial_second(n);
lagrange_polynomial_second[1] = 1;
proving_key->lagrange_second = lagrange_polynomial_second;
}

proving_key->contains_recursive_proof = false;

return proving_key;
}

/**
* Compute verification key consisting of selector precommitments.
*
* @return Pointer to created circuit verification key.
* */
template <ECCVMFlavor Flavor>
std::shared_ptr<typename Flavor::VerificationKey> ECCVMComposerHelper_<Flavor>::compute_verification_key(
CircuitConstructor& circuit_constructor)
{
if (verification_key) {
return verification_key;
}

if (!proving_key) {
compute_proving_key(circuit_constructor);
}

verification_key =
std::make_shared<typename Flavor::VerificationKey>(proving_key->circuit_size, proving_key->num_public_inputs);

verification_key->lagrange_first = commitment_key->commit(proving_key->lagrange_first);
verification_key->lagrange_second = commitment_key->commit(proving_key->lagrange_second);
verification_key->lagrange_last = commitment_key->commit(proving_key->lagrange_last);
return verification_key;
}
template class ECCVMComposerHelper_<honk::flavor::ECCVM>;

} // namespace proof_system::honk
72 changes: 72 additions & 0 deletions cpp/src/barretenberg/honk/composer/eccvm_composer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#pragma once

#include "barretenberg/honk/proof_system/eccvm_prover.hpp"
#include "barretenberg/honk/proof_system/eccvm_verifier.hpp"
#include "barretenberg/proof_system/circuit_builder/eccvm/eccvm_circuit_builder.hpp"
#include "barretenberg/proof_system/composer/composer_lib.hpp"
#include "barretenberg/srs/factories/file_crs_factory.hpp"

namespace proof_system::honk {
template <ECCVMFlavor Flavor> class ECCVMComposerHelper_ {
public:
using CircuitConstructor = ECCVMCircuitConstructor<Flavor>;
using ProvingKey = typename Flavor::ProvingKey;
using VerificationKey = typename Flavor::VerificationKey;
using PCSParams = typename Flavor::PCSParams;
using PCS = typename Flavor::PCS;
using PCSCommitmentKey = typename PCSParams::CommitmentKey;
using PCSVerificationKey = typename PCSParams::VerificationKey;

static constexpr std::string_view NAME_STRING = "ECCVM";
static constexpr size_t NUM_RESERVED_GATES = 0; // equal to the number of multilinear evaluations leaked
static constexpr size_t NUM_WIRES = CircuitConstructor::NUM_WIRES;
std::shared_ptr<ProvingKey> proving_key;
std::shared_ptr<VerificationKey> verification_key;

// The crs_factory holds the path to the srs and exposes methods to extract the srs elements
std::shared_ptr<srs::factories::CrsFactory> crs_factory_;

// The commitment key is passed to the prover but also used herein to compute the verfication key commitments
std::shared_ptr<PCSCommitmentKey> commitment_key;

std::vector<uint32_t> recursive_proof_public_input_indices;
bool contains_recursive_proof = false;
bool computed_witness = false;

ECCVMComposerHelper_()
: crs_factory_(barretenberg::srs::get_crs_factory()){};

explicit ECCVMComposerHelper_(std::shared_ptr<srs::factories::CrsFactory> crs_factory)
: crs_factory_(std::move(crs_factory))
{}

ECCVMComposerHelper_(std::shared_ptr<ProvingKey> p_key, std::shared_ptr<VerificationKey> v_key)
: proving_key(std::move(p_key))
, verification_key(std::move(v_key))
{}

ECCVMComposerHelper_(ECCVMComposerHelper_&& other) noexcept = default;
ECCVMComposerHelper_(ECCVMComposerHelper_ const& other) noexcept = default;
ECCVMComposerHelper_& operator=(ECCVMComposerHelper_&& other) noexcept = default;
ECCVMComposerHelper_& operator=(ECCVMComposerHelper_ const& other) noexcept = default;
~ECCVMComposerHelper_() = default;

std::shared_ptr<ProvingKey> compute_proving_key(CircuitConstructor& circuit_constructor);
std::shared_ptr<VerificationKey> compute_verification_key(CircuitConstructor& circuit_constructor);

void compute_witness(CircuitConstructor& circuit_constructor);

ECCVMProver_<Flavor> create_prover(CircuitConstructor& circuit_constructor);
ECCVMVerifier_<Flavor> create_verifier(CircuitConstructor& circuit_constructor);

void add_table_column_selector_poly_to_proving_key(polynomial& small, const std::string& tag);

void compute_commitment_key(size_t circuit_size)
{
commitment_key = std::make_shared<typename PCSParams::CommitmentKey>(circuit_size, crs_factory_);
};
};
extern template class ECCVMComposerHelper_<honk::flavor::ECCVM>;
// TODO(#532): this pattern is weird; is this not instantiating the templates?
using ECCVMComposerHelper = ECCVMComposerHelper_<honk::flavor::ECCVM>;
} // namespace proof_system::honk
93 changes: 93 additions & 0 deletions cpp/src/barretenberg/honk/composer/eccvm_composer.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#include <cstddef>
#include <cstdint>
#include <gtest/gtest.h>
#include <vector>

#include "barretenberg/honk/composer/eccvm_composer.hpp"
#include "barretenberg/honk/proof_system/prover.hpp"
#include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp"
#include "barretenberg/honk/sumcheck/relations/relation_parameters.hpp"
#include "barretenberg/honk/sumcheck/sumcheck_round.hpp"
#include "barretenberg/honk/utils/grand_product_delta.hpp"
#include "barretenberg/numeric/uint256/uint256.hpp"
#include "barretenberg/polynomials/polynomial.hpp"
#include "barretenberg/proof_system/circuit_builder/eccvm/eccvm_circuit_builder.hpp"

using namespace proof_system::honk;

namespace test_standard_honk_composer {

class ECCVMComposerTests : public ::testing::Test {
protected:
static void SetUpTestSuite() { barretenberg::srs::init_crs_factory("../srs_db/ignition"); }
};
namespace {
auto& engine = numeric::random::get_debug_engine();
}
proof_system::ECCVMCircuitConstructor<flavor::ECCVM> generate_trace(numeric::random::Engine* engine = nullptr)
{
proof_system::ECCVMCircuitConstructor<flavor::ECCVM> result;

grumpkin::g1::element a = grumpkin::get_generator(0);
grumpkin::g1::element b = grumpkin::get_generator(1);
grumpkin::g1::element c = grumpkin::get_generator(2);
grumpkin::fr x = grumpkin::fr::random_element(engine);
grumpkin::fr y = grumpkin::fr::random_element(engine);

grumpkin::g1::element expected_1 = (a * x) + a + a + (b * y) + (b * x) + (b * x);
grumpkin::g1::element expected_2 = (a * x) + c + (b * x);

result.add_accumulate(a);
result.mul_accumulate(a, x);
result.mul_accumulate(b, x);
result.mul_accumulate(b, y);
result.add_accumulate(a);
result.mul_accumulate(b, x);
result.eq(expected_1);
result.add_accumulate(c);
result.mul_accumulate(a, x);
result.mul_accumulate(b, x);
result.eq(expected_2);
result.mul_accumulate(a, x);
result.mul_accumulate(b, x);
result.mul_accumulate(c, x);

return result;
}

TEST_F(ECCVMComposerTests, BaseCase)
{
auto circuit_constructor = generate_trace(&engine);

auto composer = ECCVMComposerHelper();
auto prover = composer.create_prover(circuit_constructor);

// / size_t pidx = 0;
// for (auto& p : prover.prover_polynomials) {
// size_t count = 0;
// for (auto& x : p) {
// std::cout << "poly[" << pidx << "][" << count << "] = " << x << std::endl;
// count++;
// }
// pidx++;
// }
auto proof = prover.construct_proof();
auto verifier = composer.create_verifier(circuit_constructor);
bool verified = verifier.verify_proof(proof);
ASSERT_TRUE(verified);
}

TEST_F(ECCVMComposerTests, EqFails)
{
auto circuit_constructor = generate_trace(&engine);
// create an eq opcode that is not satisfied
circuit_constructor.eq(grumpkin::g1::affine_one);
auto composer = ECCVMComposerHelper();
auto prover = composer.create_prover(circuit_constructor);

auto proof = prover.construct_proof();
auto verifier = composer.create_verifier(circuit_constructor);
bool verified = verifier.verify_proof(proof);
ASSERT_FALSE(verified);
}
} // namespace test_standard_honk_composer
Loading