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(avm): enable zeromorph in AVM verification #8111

Merged
merged 3 commits into from
Aug 22, 2024
Merged
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
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);
Copy link
Contributor

Choose a reason for hiding this comment

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

just curious: why is this initialised with size 1?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My understanding of the verification code for Zeromorph is that it only uses the identity point for g1 and a single g2 point to initialize the SRS. I saw that value "1" was also used for "verify_client_ivc".
My thought was to not read unnecessarily data as my assumption is that it would be safe.
Is there any security risk to initialize the CRS with a too small amount of data? Otherwise, I am happy to put it back to the same constant as in the avm_prover.
Thanks for the feedback @maramihali

Copy link
Contributor

Choose a reason for hiding this comment

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

just looked back on what verify client_ivc_verify, makes sense


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));
jeanmon marked this conversation as resolved.
Show resolved Hide resolved
}

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)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This assumes implicitly that the order of get_all() matches that of precomputed_cmts. I don't think we can do much about it...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, you are right. I am relying on codegen for this.

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
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
Loading