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

test: more vk tests to compare circuit/native/vk_data #310

Merged
merged 13 commits into from
Apr 5, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -5,150 +5,149 @@

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

using namespace barretenberg;
using namespace bonk;

/**
* @brief generated a random vk data for use in tests
* @brief generate a random vk data for use in tests
*
* @return verification_key_data randomly generated
*/
verification_key_data rand_vk_data()
{
verification_key_data key_data;
key_data.composer_type = static_cast<uint32_t>(plonk::ComposerType::STANDARD);
key_data.circuit_size = 1024; // not random - must be power of 2
key_data.num_public_inputs = engine.get_random_uint32();
key_data.commitments["test1"] = g1::element::random_element();
key_data.commitments["test2"] = g1::element::random_element();
key_data.commitments["foo1"] = g1::element::random_element();
key_data.commitments["foo2"] = g1::element::random_element();
return key_data;
verification_key_data rand_vk_data() {
verification_key_data vk_data;
vk_data.composer_type = static_cast<uint32_t>(plonk::ComposerType::STANDARD);
vk_data.circuit_size = 1024; // not random - must be power of 2
vk_data.num_public_inputs = engine.get_random_uint32();
vk_data.commitments["test1"] = g1::element::random_element();
vk_data.commitments["test2"] = g1::element::random_element();
vk_data.commitments["foo1"] = g1::element::random_element();
vk_data.commitments["foo2"] = g1::element::random_element();
return vk_data;
}

/**
* @brief expect that two vk data compressions are equal for a few different hash indices
*
* @param key0_data
* @param key1_data
* @param vk0_data
* @param vk1_data
*/
void expect_compressions_eq(verification_key_data key0_data, verification_key_data key1_data)
void expect_compressions_eq(verification_key_data vk0_data, verification_key_data vk1_data)
{
// 0 hash index
EXPECT_EQ(key0_data.compress_native(0), key1_data.compress_native(0));
EXPECT_EQ(vk0_data.compress_native(0), vk1_data.compress_native(0));
// nonzero hash index
EXPECT_EQ(key0_data.compress_native(15), key1_data.compress_native(15));
EXPECT_EQ(vk0_data.compress_native(15), vk1_data.compress_native(15));
}

/**
* @brief expect that two vk data compressions are not-equal for a few different hash indices
*
* @param key0_data
* @param key1_data
* @param vk0_data
* @param vk1_data
*/
void expect_compressions_ne(verification_key_data key0_data, verification_key_data key1_data)
void expect_compressions_ne(verification_key_data vk0_data, verification_key_data vk1_data)
{
EXPECT_NE(key0_data.compress_native(0), key1_data.compress_native(0));
EXPECT_NE(key0_data.compress_native(15), key1_data.compress_native(15));
// ne hash indeces still lead to ne compressions
EXPECT_NE(key0_data.compress_native(0), key1_data.compress_native(15));
EXPECT_NE(key0_data.compress_native(14), key1_data.compress_native(15));
EXPECT_NE(vk0_data.compress_native(0), vk1_data.compress_native(0));
EXPECT_NE(vk0_data.compress_native(15), vk1_data.compress_native(15));
// ne hash indices still lead to ne compressions
EXPECT_NE(vk0_data.compress_native(0), vk1_data.compress_native(15));
EXPECT_NE(vk0_data.compress_native(14), vk1_data.compress_native(15));
}

TEST(verification_key, buffer_serialization)
{
verification_key_data key_data = rand_vk_data();
verification_key_data vk_data = rand_vk_data();

auto buf = to_buffer(key_data);
auto buf = to_buffer(vk_data);
auto result = from_buffer<verification_key_data>(buf);

EXPECT_EQ(key_data, result);
EXPECT_EQ(vk_data, result);
}

TEST(verification_key, stream_serialization)
{
verification_key_data key_data = rand_vk_data();
verification_key_data vk_data = rand_vk_data();

std::stringstream s;
write(s, key_data);
write(s, vk_data);

verification_key_data result;
read(static_cast<std::istream&>(s), result);

EXPECT_EQ(key_data, result);
EXPECT_EQ(vk_data, result);
}

TEST(verification_key, basic_compression_equality)
{
verification_key_data key0_data = rand_vk_data();
verification_key_data key1_data = key0_data; // copy
expect_compressions_eq(key0_data, key1_data);
verification_key_data vk0_data = rand_vk_data();
verification_key_data vk1_data = vk0_data; // copy
expect_compressions_eq(vk0_data, vk1_data);
}

TEST(verification_key, compression_inequality_index_mismatch)
{
verification_key_data key0_data = rand_vk_data();
verification_key_data key1_data = key0_data; // copy
verification_key_data vk0_data = rand_vk_data();
verification_key_data vk1_data = vk0_data; // copy
// inquality on hash index mismatch
EXPECT_NE(key0_data.compress_native(0), key1_data.compress_native(15));
EXPECT_NE(key0_data.compress_native(14), key1_data.compress_native(15));
EXPECT_NE(vk0_data.compress_native(0), vk1_data.compress_native(15));
EXPECT_NE(vk0_data.compress_native(14), vk1_data.compress_native(15));
}

TEST(verification_key, compression_inequality_composer_type)
{
verification_key_data key0_data = rand_vk_data();
verification_key_data key1_data = key0_data; // copy
key0_data.composer_type = static_cast<uint32_t>(plonk::ComposerType::PLOOKUP);
expect_compressions_ne(key0_data, key1_data);
verification_key_data vk0_data = rand_vk_data();
verification_key_data vk1_data = vk0_data; // copy
vk0_data.composer_type = static_cast<uint32_t>(plonk::ComposerType::PLOOKUP);
expect_compressions_ne(vk0_data, vk1_data);
}

TEST(verification_key, compression_inequality_different_circuit_size)
TEST(verification_key, compression_inequality_different_circuit_size) \
{
verification_key_data key0_data = rand_vk_data();
verification_key_data key1_data = key0_data;
key0_data.circuit_size = 4096;
expect_compressions_ne(key0_data, key1_data);
verification_key_data vk0_data = rand_vk_data();
verification_key_data vk1_data = vk0_data;
vk0_data.circuit_size = 4096;
expect_compressions_ne(vk0_data, vk1_data);
}

TEST(verification_key, compression_inequality_different_num_public_inputs)
TEST(verification_key, compression_inequality_different_num_public_inputs) \
{
verification_key_data key0_data = rand_vk_data();
verification_key_data key1_data = key0_data;
key0_data.num_public_inputs = 42;
expect_compressions_ne(key0_data, key1_data);
verification_key_data vk0_data = rand_vk_data();
verification_key_data vk1_data = vk0_data;
vk0_data.num_public_inputs = 42;
expect_compressions_ne(vk0_data, vk1_data);
}

TEST(verification_key, compression_inequality_different_commitments)
TEST(verification_key, compression_inequality_different_commitments) \
{
verification_key_data key0_data = rand_vk_data();
verification_key_data key1_data = key0_data;
key0_data.commitments["test1"] = g1::element::random_element();
expect_compressions_ne(key0_data, key1_data);
verification_key_data vk0_data = rand_vk_data();
verification_key_data vk1_data = vk0_data;
vk0_data.commitments["test1"] = g1::element::random_element();
expect_compressions_ne(vk0_data, vk1_data);
}

TEST(verification_key, compression_inequality_different_num_commitments)
TEST(verification_key, compression_inequality_different_num_commitments) \
{
verification_key_data key0_data = rand_vk_data();
verification_key_data key1_data = key0_data;
key0_data.commitments["new"] = g1::element::random_element();
expect_compressions_ne(key0_data, key1_data);
verification_key_data vk0_data = rand_vk_data();
verification_key_data vk1_data = vk0_data;
vk0_data.commitments["new"] = g1::element::random_element();
expect_compressions_ne(vk0_data, vk1_data);
}

TEST(verification_key, compression_equality_different_contains_recursive_proof)
TEST(verification_key, compression_equality_different_contains_recursive_proof) \
{
verification_key_data key0_data = rand_vk_data();
verification_key_data key1_data = key0_data;
key0_data.contains_recursive_proof = false;
key1_data.contains_recursive_proof = true;
expect_compressions_eq(key0_data, key1_data);
verification_key_data vk0_data = rand_vk_data();
verification_key_data vk1_data = vk0_data;
vk0_data.contains_recursive_proof = false;
vk1_data.contains_recursive_proof = true;
expect_compressions_eq(vk0_data, vk1_data);
}

TEST(verification_key, compression_equality_different_recursive_proof_public_input_indices)
TEST(verification_key, compression_equality_different_recursive_proof_public_input_indices) \
{
verification_key_data key0_data = rand_vk_data();
verification_key_data key1_data = key0_data;
key1_data.recursive_proof_public_input_indices.push_back(42);
expect_compressions_eq(key0_data, key1_data);
verification_key_data vk0_data = rand_vk_data();
verification_key_data vk1_data = vk0_data;
vk1_data.recursive_proof_public_input_indices.push_back(42);
expect_compressions_eq(vk0_data, vk1_data);
}
Original file line number Diff line number Diff line change
@@ -1,42 +1,100 @@
#include "verification_key.hpp"
#include <gtest/gtest.h>

#include "barretenberg/ecc/curves/bn254/fr.hpp"
#include "barretenberg/ecc/curves/bn254/g1.hpp"
#include "barretenberg/common/test.hpp"
#include "barretenberg/proof_system/verification_key/verification_key.hpp"
#include "barretenberg/plonk/proof_system/constants.hpp"
#include "barretenberg/stdlib/types/types.hpp"

using namespace plonk;
#include "barretenberg/plonk/composer/standard_composer.hpp"
#include "barretenberg/plonk/composer/turbo_composer.hpp"
#include "barretenberg/plonk/composer/ultra_composer.hpp"
#include "verification_key.hpp"

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

/**
* @brief A test fixture that will let us generate VK data and run tests
* for all composer types
*
* @tparam Composer
*/
template <typename Composer> class VerificationKeyFixture : public testing::Test {
public:
using Curve = stdlib::bn254<Composer>;
using RecursVk = plonk::stdlib::recursion::verification_key<Curve>;

static Composer init_composer() {
return Composer("../srs_db/ignition");
}

/**
* @brief generate a random vk data for use in tests
*
* @return verification_key_data randomly generated
*/
static verification_key_data rand_vk_data() {
verification_key_data vk_data;
vk_data.composer_type = static_cast<uint32_t>(Composer::type);
vk_data.circuit_size = 1024; // not random - must be power of 2
vk_data.num_public_inputs = engine.get_random_uint32();
vk_data.commitments["test1"] = g1::element::random_element();
vk_data.commitments["test2"] = g1::element::random_element();
vk_data.commitments["foo1"] = g1::element::random_element();
vk_data.commitments["foo2"] = g1::element::random_element();
return vk_data;
}
};

// Each test will run for all composer types
using ComposerTypes = testing::Types<plonk::StandardComposer, plonk::TurboComposer, plonk::UltraComposer, honk::StandardHonkComposer>;
TYPED_TEST_SUITE(VerificationKeyFixture, ComposerTypes);

verification_key_data rand_vk_data(plonk::ComposerType composer_type)
TYPED_TEST(VerificationKeyFixture, vk_data_vs_recursion_compress_native)
{
verification_key_data key_data;
key_data.composer_type = static_cast<uint32_t>(composer_type);
key_data.circuit_size = 1024; // not random - must be power of 2
key_data.num_public_inputs = engine.get_random_uint16();
key_data.commitments["test1"] = g1::element::random_element();
key_data.commitments["test2"] = g1::element::random_element();
key_data.commitments["foo1"] = g1::element::random_element();
key_data.commitments["foo2"] = g1::element::random_element();
return key_data;
using RecursVk = typename TestFixture::RecursVk;
auto composer = TestFixture::init_composer();

verification_key_data vk_data = TestFixture::rand_vk_data();
verification_key_data vk_data_copy = vk_data;

auto file_crs = std::make_unique<bonk::FileReferenceStringFactory>("../srs_db/ignition");
auto file_verifier = file_crs->get_verifier_crs();

auto native_vk = std::make_shared<bonk::verification_key>(std::move(vk_data_copy), file_verifier);
auto recurs_vk = RecursVk::from_witness(&composer, native_vk);

EXPECT_EQ(vk_data.compress_native(0), RecursVk::compress_native(native_vk, 0));
EXPECT_EQ(vk_data.compress_native(15), RecursVk::compress_native(native_vk, 15));
// ne hash indeces still lead to ne compressions
EXPECT_NE(vk_data.compress_native(0), RecursVk::compress_native(native_vk, 15));
EXPECT_NE(vk_data.compress_native(14), RecursVk::compress_native(native_vk, 15));
}

TEST(stdlib_verification_key, compress_native_comparison)
TYPED_TEST(VerificationKeyFixture, compress_vs_compress_native)
{
// Compute compression of native verification key (i.e. vk_data)
auto crs = std::make_unique<bonk::FileReferenceStringFactory>("../srs_db/ignition");
verification_key_data vk_data = rand_vk_data(stdlib::types::Composer::type);
const size_t hash_idx = 10;
auto native_vk_compression = vk_data.compress_native(hash_idx);

// Compute compression of recursive verification key
auto verification_key = std::make_shared<bonk::verification_key>(std::move(vk_data), crs->get_verifier_crs());
auto recursive_vk_compression =
stdlib::recursion::verification_key<stdlib::types::bn254>::compress_native(verification_key, hash_idx);
EXPECT_EQ(native_vk_compression, recursive_vk_compression);
}
using RecursVk = typename TestFixture::RecursVk;
auto composer = TestFixture::init_composer();

verification_key_data vk_data = TestFixture::rand_vk_data();

auto file_crs = std::make_unique<bonk::FileReferenceStringFactory>("../srs_db/ignition");
auto file_verifier = file_crs->get_verifier_crs();

auto native_vk = std::make_shared<bonk::verification_key>(std::move(vk_data), file_verifier);
auto recurs_vk = RecursVk::from_witness(&composer, native_vk);

EXPECT_EQ(
recurs_vk->compress(0).get_value(),
RecursVk::compress_native(native_vk, 0)
);
EXPECT_EQ(
recurs_vk->compress(15).get_value(),
RecursVk::compress_native(native_vk, 15)
);
// ne hash indeces still lead to ne compressions
EXPECT_NE(
recurs_vk->compress(0).get_value(),
RecursVk::compress_native(native_vk, 15)
);
EXPECT_NE(
recurs_vk->compress(14).get_value(),
RecursVk::compress_native(native_vk, 15)
);
}