Skip to content

Commit

Permalink
feat(avm): enable zeromorph in AVM verification (#8111)
Browse files Browse the repository at this point in the history
Resolves #4944
  • Loading branch information
jeanmon authored Aug 22, 2024
1 parent 8a1032e commit b1f9fb6
Show file tree
Hide file tree
Showing 13 changed files with 158 additions and 87 deletions.
53 changes: 42 additions & 11 deletions barretenberg/cpp/src/barretenberg/bb/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,13 @@ std::string to_json(std::vector<bb::fr>& data)
return format("[", join(map(data, [](auto fr) { return format("\"", fr, "\""); })), "]");
}

std::string vk_to_json(std::vector<bb::fr>& data)
std::string vk_to_json(std::vector<bb::fr> const& data)
{
// We need to move vk_hash to the front...
std::rotate(data.begin(), data.end() - 1, data.end());
std::vector<bb::fr> rotated(data.begin(), data.end() - 1);
rotated.insert(rotated.begin(), data.at(data.size() - 1));

return format("[", join(map(data, [](auto fr) { return format("\"", fr, "\""); })), "]");
return format("[", join(map(rotated, [](auto fr) { return format("\"", fr, "\""); })), "]");
}

std::string honk_vk_to_json(std::vector<bb::fr>& data)
Expand Down Expand Up @@ -950,18 +951,25 @@ void avm_prove(const std::filesystem::path& bytecode_path,
auto const [verification_key, proof] =
AVM_TRACK_TIME_V("prove/all", avm_trace::Execution::prove(bytecode, calldata, public_inputs_vec, avm_hints));

// TODO(ilyas): <#4887>: Currently we only need these two parts of the vk, look into pcs_verification key reqs
std::vector<uint64_t> vk_vector = { verification_key.circuit_size, verification_key.num_public_inputs };
std::vector<fr> vk_as_fields = { verification_key.circuit_size, verification_key.num_public_inputs };
std::string vk_json = vk_to_json(vk_as_fields);
std::vector<fr> vk_as_fields = { fr(verification_key.circuit_size), fr(verification_key.num_public_inputs) };

for (auto const& comm : verification_key.get_all()) {
std::vector<fr> comm_as_fields = field_conversion::convert_to_bn254_frs(comm);
vk_as_fields.insert(vk_as_fields.end(), comm_as_fields.begin(), comm_as_fields.end());
}

vinfo("vk fields size: ", vk_as_fields.size());
vinfo("circuit size: ", vk_as_fields[0]);
vinfo("num of pub inputs: ", vk_as_fields[1]);

std::string vk_json = to_json(vk_as_fields);
const auto proof_path = output_path / "proof";
const auto vk_path = output_path / "vk";
const auto vk_fields_path = output_path / "vk_fields.json";

write_file(proof_path, to_buffer(proof));
vinfo("proof written to: ", proof_path);
write_file(vk_path, to_buffer(vk_vector));
write_file(vk_path, to_buffer(vk_as_fields));
vinfo("vk written to: ", vk_path);
write_file(vk_fields_path, { vk_json.begin(), vk_json.end() });
vinfo("vk as fields written to: ", vk_fields_path);
Expand All @@ -988,11 +996,34 @@ void avm_prove(const std::filesystem::path& bytecode_path,
*/
bool avm_verify(const std::filesystem::path& proof_path, const std::filesystem::path& vk_path)
{
using Commitment = AvmFlavorSettings::Commitment;
std::vector<fr> const proof = many_from_buffer<fr>(read_file(proof_path));
std::vector<uint8_t> vk_bytes = read_file(vk_path);
auto circuit_size = from_buffer<size_t>(vk_bytes, 0);
auto num_public_inputs = from_buffer<size_t>(vk_bytes, sizeof(size_t));
auto vk = AvmFlavor::VerificationKey(circuit_size, num_public_inputs);
std::vector<fr> vk_as_fields = many_from_buffer<fr>(vk_bytes);

vinfo("initializing crs with size: ", 1);
init_bn254_crs(1);

auto circuit_size = uint64_t(vk_as_fields[0]);
auto num_public_inputs = uint64_t(vk_as_fields[1]);
std::span vk_span(vk_as_fields);

vinfo("vk fields size: ", vk_as_fields.size());
vinfo("circuit size: ", circuit_size);
vinfo("num of pub inputs: ", num_public_inputs);

// Each commitment (precomputed entity) is represented as 2 Fq field elements.
// Each Fq element is split into two limbs of Fr elements.
// We therefore need 2 (circuit_size, num_public_inputs) + 4 * NUM_PRECOMPUTED_ENTITIES fr elements.
ASSERT(vk_as_fields.size() == 4 * AvmFlavor::NUM_PRECOMPUTED_ENTITIES + 2);

std::array<Commitment, AvmFlavor::NUM_PRECOMPUTED_ENTITIES> precomputed_cmts;
for (size_t i = 0; i < AvmFlavor::NUM_PRECOMPUTED_ENTITIES; i++) {
// Start at offset 2 and adds 4 fr elements per commitment. Therefore, index = 4 * i + 2.
precomputed_cmts[i] = field_conversion::convert_from_bn254_frs<Commitment>(vk_span.subspan(4 * i + 2, 4));
}

auto vk = AvmFlavor::VerificationKey(circuit_size, num_public_inputs, precomputed_cmts);

const bool verified = AVM_TRACK_TIME_V("verify/all", avm_trace::Execution::verify(vk, proof));
vinfo("verified: ", verified);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ using namespace bb::srs::factories;

class MemVerifierCrs : public VerifierCrs<curve::BN254> {
public:
MemVerifierCrs(g2::affine_element const& g2_point)
: g2_x(g2_point)
MemVerifierCrs(g2::affine_element g2_point, g1::affine_element const& g1_identity)
: g1_identityx(g1_identity)
, g2_x(std::move(g2_point))
, precomputed_g2_lines(
static_cast<pairing::miller_lines*>(aligned_alloc(64, sizeof(bb::pairing::miller_lines) * 2)))
{

bb::pairing::precompute_miller_lines(bb::g2::one, precomputed_g2_lines[0]);
bb::pairing::precompute_miller_lines(g2_x, precomputed_g2_lines[1]);
}
Expand All @@ -43,8 +43,14 @@ namespace bb::srs::factories {
MemBn254CrsFactory::MemBn254CrsFactory(std::vector<g1::affine_element> const& points,
g2::affine_element const& g2_point)
: prover_crs_(std::make_shared<MemProverCrs<curve::BN254>>(points))
, verifier_crs_(std::make_shared<MemVerifierCrs>(g2_point))
{}
{
auto g1_identity = g1::affine_element();
if (!points.empty()) {
g1_identity = points[0];
}

verifier_crs_ = std::make_shared<MemVerifierCrs>(g2_point, g1_identity);
}

std::shared_ptr<bb::srs::factories::ProverCrs<curve::BN254>> MemBn254CrsFactory::get_prover_crs(size_t)
{
Expand Down
6 changes: 5 additions & 1 deletion barretenberg/cpp/src/barretenberg/srs/io.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,11 @@ template <typename Curve> class IO {
size_t num_read = 0;
std::string path = get_transcript_path(dir, num);

while (is_file_exist(path) && num_read < degree) {
if (!is_file_exist(path)) {
throw_or_abort(format("File path for transcript g1 ", path, " is invalid."));
}

while (num_read < degree) {
Manifest manifest;
read_manifest(path, manifest);

Expand Down
12 changes: 2 additions & 10 deletions barretenberg/cpp/src/barretenberg/vm/avm/generated/composer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,7 @@ AvmProver AvmComposer::create_prover(CircuitConstructor& circuit_constructor)
AvmVerifier AvmComposer::create_verifier(CircuitConstructor& circuit_constructor)
{
auto verification_key = compute_verification_key(circuit_constructor);

AvmVerifier output_state(verification_key);

auto pcs_verification_key = std::make_unique<VerifierCommitmentKey>();

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

return output_state;
return AvmVerifier(std::move(verification_key));
}

std::shared_ptr<Flavor::ProvingKey> AvmComposer::compute_proving_key(CircuitConstructor& circuit_constructor)
Expand Down Expand Up @@ -76,8 +69,7 @@ std::shared_ptr<Flavor::VerificationKey> AvmComposer::compute_verification_key(C
compute_proving_key(circuit_constructor);
}

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

return verification_key;
}
Expand Down
25 changes: 24 additions & 1 deletion barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,30 @@ class AvmFlavor {
auto get_to_be_shifted() { return AvmFlavor::get_to_be_shifted<DataType>(*this); }
};

using VerificationKey = VerificationKey_<PrecomputedEntities<Commitment>, VerifierCommitmentKey>;
// Note(md): required for instantiation from the proving key - im sure there are other ways to construct this
class VerificationKey : public VerificationKey_<PrecomputedEntities<Commitment>, VerifierCommitmentKey> {
public:
VerificationKey() = default;

VerificationKey(const std::shared_ptr<ProvingKey>& proving_key)
: VerificationKey_(proving_key->circuit_size, proving_key->num_public_inputs)
{
for (auto [polynomial, commitment] :
zip_view(proving_key->get_precomputed_polynomials(), this->get_all())) {
commitment = proving_key->commitment_key->commit(polynomial);
}
}

VerificationKey(const size_t circuit_size,
const size_t num_public_inputs,
std::array<Commitment, NUM_PRECOMPUTED_ENTITIES> const& precomputed_cmts)
: VerificationKey_(circuit_size, num_public_inputs)
{
for (auto [vk_cmt, cmt] : zip_view(this->get_all(), precomputed_cmts)) {
vk_cmt = cmt;
}
}
};

class AllValues : public AllEntities<FF> {
public:
Expand Down
37 changes: 18 additions & 19 deletions barretenberg/cpp/src/barretenberg/vm/avm/generated/verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace bb {

AvmVerifier::AvmVerifier(std::shared_ptr<Flavor::VerificationKey> verifier_key)
: key(verifier_key)
: key(std::move(verifier_key))
{}

AvmVerifier::AvmVerifier(AvmVerifier&& other) noexcept
Expand All @@ -21,7 +21,7 @@ AvmVerifier::AvmVerifier(AvmVerifier&& other) noexcept
AvmVerifier& AvmVerifier::operator=(AvmVerifier&& other) noexcept
{
key = other.key;
pcs_verification_key = (std::move(other.pcs_verification_key));
pcs_verification_key = other.pcs_verification_key;
commitments.clear();
return *this;
}
Expand Down Expand Up @@ -53,9 +53,9 @@ bool AvmVerifier::verify_proof(const HonkProof& proof,
using Flavor = AvmFlavor;
using FF = Flavor::FF;
using Commitment = Flavor::Commitment;
// using PCS = Flavor::PCS;
// using Curve = Flavor::Curve;
// using ZeroMorph = ZeroMorphVerifier_<Curve>;
using PCS = Flavor::PCS;
using Curve = Flavor::Curve;
using ZeroMorph = ZeroMorphVerifier_<Curve>;
using VerifierCommitments = Flavor::VerifierCommitments;
using CommitmentLabels = Flavor::CommitmentLabels;

Expand Down Expand Up @@ -138,20 +138,19 @@ bool AvmVerifier::verify_proof(const HonkProof& proof,

// Execute ZeroMorph rounds. See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the
// unrolled protocol.
// NOTE: temporarily disabled - facing integration issues
// auto opening_claim = ZeroMorph::verify(circuit_size,
// commitments.get_unshifted(),
// commitments.get_to_be_shifted(),
// claimed_evaluations.get_unshifted(),
// claimed_evaluations.get_shifted(),
// multivariate_challenge,
// pcs_verification_key->get_g1_identity(),
// transcript);

// auto pairing_points = PCS::reduce_verify(opening_claim, transcript);
// auto verified = pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]);
// return sumcheck_verified.value() && verified;
return sumcheck_verified.value();

auto opening_claim = ZeroMorph::verify(circuit_size,
commitments.get_unshifted(),
commitments.get_to_be_shifted(),
claimed_evaluations.get_unshifted(),
claimed_evaluations.get_shifted(),
multivariate_challenge,
pcs_verification_key.get_g1_identity(),
transcript);

auto pairing_points = PCS::reduce_verify(opening_claim, transcript);
auto verified = pcs_verification_key.pairing_check(pairing_points[0], pairing_points[1]);
return sumcheck_verified.value() && verified;
}

} // namespace bb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class AvmVerifier {

std::shared_ptr<VerificationKey> key;
std::map<std::string, Commitment> commitments;
std::shared_ptr<VerifierCommitmentKey> pcs_verification_key;
VerifierCommitmentKey pcs_verification_key;
std::shared_ptr<Transcript> transcript;
};

Expand Down
8 changes: 1 addition & 7 deletions barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,13 +325,7 @@ VmPublicInputs Execution::convert_public_inputs(std::vector<FF> const& public_in

bool Execution::verify(AvmFlavor::VerificationKey vk, HonkProof const& proof)
{
auto verification_key = std::make_shared<AvmFlavor::VerificationKey>(vk);
AvmVerifier verifier(verification_key);

// todo: not needed for now until we verify the PCS/pairing of the proof
// auto pcs_verification_key = std::make_unique<VerifierCommitmentKey>(verification_key->circuit_size,
// crs_factory_);
// output_state.pcs_verification_key = std::move(pcs_verification_key);
AvmVerifier verifier(std::make_shared<AvmFlavor::VerificationKey>(vk));

// Proof structure: public_inputs | calldata_size | calldata | returndata_size | returndata | raw proof
std::vector<FF> public_inputs_vec;
Expand Down
12 changes: 2 additions & 10 deletions bb-pilcom/bb-pil-backend/templates/composer.cpp.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,7 @@ void {{name}}Composer::compute_witness(CircuitConstructor& circuit)
{{name}}Verifier {{name}}Composer::create_verifier(CircuitConstructor& circuit_constructor)
{
auto verification_key = compute_verification_key(circuit_constructor);

{{name}}Verifier output_state(verification_key);

auto pcs_verification_key = std::make_unique<VerifierCommitmentKey>();

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

return output_state;
return {{name}}Verifier(std::move(verification_key));
}

std::shared_ptr<Flavor::ProvingKey> {{name}}Composer::compute_proving_key(CircuitConstructor& circuit_constructor)
Expand Down Expand Up @@ -76,8 +69,7 @@ std::shared_ptr<Flavor::VerificationKey> {{name}}Composer::compute_verification_
compute_proving_key(circuit_constructor);
}

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

return verification_key;
}
Expand Down
25 changes: 24 additions & 1 deletion bb-pilcom/bb-pil-backend/templates/flavor.hpp.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,30 @@ class {{name}}Flavor {
}
};

using VerificationKey = VerificationKey_<PrecomputedEntities<Commitment>, VerifierCommitmentKey>;
// Note(md): required for instantiation from the proving key - im sure there are other ways to construct this
class VerificationKey : public VerificationKey_<PrecomputedEntities<Commitment>, VerifierCommitmentKey> {
public:
VerificationKey() = default;

VerificationKey(const std::shared_ptr<ProvingKey>& proving_key)
: VerificationKey_(proving_key->circuit_size, proving_key->num_public_inputs)
{
for (auto [polynomial, commitment] :
zip_view(proving_key->get_precomputed_polynomials(), this->get_all())) {
commitment = proving_key->commitment_key->commit(polynomial);
}
}

VerificationKey(const size_t circuit_size,
const size_t num_public_inputs,
std::array<Commitment, NUM_PRECOMPUTED_ENTITIES> const& precomputed_cmts)
: VerificationKey_(circuit_size, num_public_inputs)
{
for (auto [vk_cmt, cmt] : zip_view(this->get_all(), precomputed_cmts)) {
vk_cmt = cmt;
}
}
};

{{!-- Used by sumcheck --}}
class AllValues : public AllEntities<FF> {
Expand Down
Loading

0 comments on commit b1f9fb6

Please sign in to comment.