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: Added correctness tests for several small relations in Goblin Translator (Goblin Translator part 8) #2963

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
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,9 @@ template <size_t mini_circuit_size> class GoblinTranslator_ {
// define the tuple of Relations that comprise the Sumcheck relation
using Relations = std::tuple<GoblinTranslatorPermutationRelation<FF>,
GoblinTranslatorGenPermSortRelation<FF>,
GoblinTranslatorDecompositionRelation<FF>,
GoblinTranslatorOpcodeConstraintRelation<FF>,
GoblinTranslatorAccumulatorTransferRelation<FF>,
GoblinTranslatorDecompositionRelation<FF>,
GoblinTranslatorNonNativeFieldRelation<FF>>;

static constexpr size_t MAX_RELATION_LENGTH = get_max_relation_length<Relations>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -450,4 +450,190 @@ TEST_F(RelationCorrectnessTests, GoblinTranslatorPermutationRelationCorrectness)
check_relation<Flavor, std::tuple_element_t<0, Relations>>(circuit_size, prover_polynomials, params);
}

TEST_F(RelationCorrectnessTests, GoblinTranslatorGenPermSortRelationCorrectness)
{
using Flavor = flavor::GoblinTranslatorBasic;
using FF = typename Flavor::FF;
using ProverPolynomials = typename Flavor::ProverPolynomials;
using Polynomial = barretenberg::Polynomial<FF>;
auto& engine = numeric::random::get_debug_engine();

const auto circuit_size = Flavor::FULL_CIRCUIT_SIZE;
const auto sort_step = Flavor::SORT_STEP;
const auto max_value = (1 << Flavor::MICRO_LIMB_BITS) - 1;

// No relation parameters are used in this relation
proof_system::RelationParameters<FF> params;

ProverPolynomials prover_polynomials;
std::vector<Polynomial> polynomial_container;

// Allocate polynomials
for (size_t i = 0; i < prover_polynomials.size(); i++) {
Polynomial temporary_polynomial(circuit_size);
polynomial_container.push_back(temporary_polynomial);
prover_polynomials[i] = polynomial_container[i];
}

// Construct lagrange polynomials that are needed for Goblin Translator's GenPermSort Relation
prover_polynomials.lagrange_first[0] = 1;
prover_polynomials.lagrange_last[circuit_size - 1] = 1;

// Create a vector and fill with necessary steps for the GenPermSort relation
auto sorted_elements_count = (max_value / sort_step) + 1;
std::vector<uint64_t> vector_for_sorting(circuit_size);
for (size_t i = 0; i < sorted_elements_count - 1; i++) {
vector_for_sorting[i] = i * sort_step;
}
vector_for_sorting[sorted_elements_count - 1] = max_value;

// Add random values to fill the leftover space
for (size_t i = sorted_elements_count; i < circuit_size; i++) {
vector_for_sorting[i] = engine.get_random_uint16() & ((1 << Flavor::MICRO_LIMB_BITS) - 1);
}

// Get ordered polynomials
auto polynomial_pointers = std::vector{ &prover_polynomials.ordered_range_constraints_0,
&prover_polynomials.ordered_range_constraints_1,
&prover_polynomials.ordered_range_constraints_2,
&prover_polynomials.ordered_range_constraints_3,
&prover_polynomials.ordered_range_constraints_4 };

// Sort the vector
std::sort(vector_for_sorting.begin(), vector_for_sorting.end());

// Copy values, transforming them into Finite Field elements
std::transform(vector_for_sorting.cbegin(),
vector_for_sorting.cend(),
prover_polynomials.ordered_range_constraints_0.begin(),
[](uint64_t in) { return FF(in); });

// Copy the same polynomial into the 4 other ordered polynomials (they are not the same in an actual proof, but we
// only need to check the correctness of the relation and it acts independently on each polynomial)
parallel_for(4, [&](size_t i) {
std::copy(prover_polynomials.ordered_range_constraints_0.begin(),
prover_polynomials.ordered_range_constraints_0.end(),
polynomial_pointers[i + 1]->begin());
});

// Get shifted polynomials
prover_polynomials.ordered_range_constraints_0_shift =
polynomial_container[Flavor::ORDERED_RANGE_CONSTRAINTS_0].shifted();
prover_polynomials.ordered_range_constraints_1_shift =
polynomial_container[Flavor::ORDERED_RANGE_CONSTRAINTS_1].shifted();
prover_polynomials.ordered_range_constraints_2_shift =
polynomial_container[Flavor::ORDERED_RANGE_CONSTRAINTS_2].shifted();
prover_polynomials.ordered_range_constraints_3_shift =
polynomial_container[Flavor::ORDERED_RANGE_CONSTRAINTS_3].shifted();
prover_polynomials.ordered_range_constraints_4_shift =
polynomial_container[Flavor::ORDERED_RANGE_CONSTRAINTS_4].shifted();

using Relations = typename Flavor::Relations;

// Check that GenPermSort relation is satisfied across each row of the prover polynomials
check_relation<Flavor, std::tuple_element_t<1, Relations>>(circuit_size, prover_polynomials, params);
}

/**
* @brief Test the correctness of GoblinTranslator's extra relations (GoblinTranslatorOpcodeConstraintRelation and
* GoblinTranslatorAccumulatorTransferRelation)
*
*/
TEST_F(RelationCorrectnessTests, GoblinTranslatorExtraRelationsCorrectness)
{
using Flavor = flavor::GoblinTranslatorBasic;
using FF = typename Flavor::FF;
using ProverPolynomials = typename Flavor::ProverPolynomials;
using ProverPolynomialIds = typename Flavor::ProverPolynomialIds;
using Polynomial = barretenberg::Polynomial<FF>;

auto& engine = numeric::random::get_debug_engine();

auto circuit_size = Flavor::FULL_CIRCUIT_SIZE;
auto mini_circuit_size = Flavor::MINI_CIRCUIT_SIZE;

// We only use accumulated_result from relation parameters in this relation
proof_system::RelationParameters<FF> params;
params.accumulated_result = {
FF::random_element(), FF::random_element(), FF::random_element(), FF::random_element()
};

// Create storage for polynomials
ProverPolynomials prover_polynomials;
// We use polynomial ids to make shifting the polynomials easier
ProverPolynomialIds prover_polynomial_ids;
std::vector<Polynomial> polynomial_container;
std::vector<size_t> polynomial_ids;
for (size_t i = 0; i < prover_polynomials.size(); i++) {
Polynomial temporary_polynomial(circuit_size);
// Allocate polynomials
polynomial_container.push_back(temporary_polynomial);
// Push sequential ids to polynomial ids
polynomial_ids.push_back(i);
prover_polynomial_ids[i] = polynomial_ids[i];
}
// Get ids of shifted polynomials and put them in a set
auto shifted_ids = prover_polynomial_ids.get_shifted();
std::unordered_set<size_t> shifted_id_set;
for (auto& id : shifted_ids) {
shifted_id_set.emplace(id);
}
// Assign spans to non-shifted prover polynomials
for (size_t i = 0; i < prover_polynomials.size(); i++) {
if (!shifted_id_set.contains(i)) {
prover_polynomials[i] = polynomial_container[i];
}
}

// Assign shifted spans to shifted prover polynomials using ids
for (size_t i = 0; i < shifted_ids.size(); i++) {
auto shifted_id = shifted_ids[i];
auto to_be_shifted_id = prover_polynomial_ids.get_to_be_shifted()[i];
prover_polynomials[shifted_id] = polynomial_container[to_be_shifted_id].shifted();
}

// Fill in lagrange even polynomial
for (size_t i = 2; i < mini_circuit_size; i += 2) {
prover_polynomials.lagrange_even_in_minicircuit[i] = 1;
}
constexpr size_t NUMBER_OF_POSSIBLE_OPCODES = 6;
constexpr std::array<uint64_t, NUMBER_OF_POSSIBLE_OPCODES> possible_opcode_values = { 0, 1, 2, 3, 4, 8 };

// Assign random opcode values
for (size_t i = 1; i < mini_circuit_size - 1; i += 2) {
prover_polynomials.op[i] =
possible_opcode_values[static_cast<size_t>(engine.get_random_uint8() % NUMBER_OF_POSSIBLE_OPCODES)];
}

// Initialize used lagrange polynomials
prover_polynomials.lagrange_second[1] = 1;
prover_polynomials.lagrange_second_to_last_in_minicircuit[mini_circuit_size - 2] = 1;

// Put random values in accumulator binary limbs (values should be preserved across even->next odd shift)
for (size_t i = 2; i < mini_circuit_size - 2; i += 2) {
prover_polynomials.accumulators_binary_limbs_0[i] = FF ::random_element();
prover_polynomials.accumulators_binary_limbs_1[i] = FF ::random_element();
prover_polynomials.accumulators_binary_limbs_2[i] = FF ::random_element();
prover_polynomials.accumulators_binary_limbs_3[i] = FF ::random_element();
prover_polynomials.accumulators_binary_limbs_0[i + 1] = prover_polynomials.accumulators_binary_limbs_0[i];
prover_polynomials.accumulators_binary_limbs_1[i + 1] = prover_polynomials.accumulators_binary_limbs_1[i];
prover_polynomials.accumulators_binary_limbs_2[i + 1] = prover_polynomials.accumulators_binary_limbs_2[i];
prover_polynomials.accumulators_binary_limbs_3[i + 1] = prover_polynomials.accumulators_binary_limbs_3[i];
}

// The values of accumulator binary limbs at index 1 should equal the accumulated result from relation parameters
prover_polynomials.accumulators_binary_limbs_0[1] = params.accumulated_result[0];
prover_polynomials.accumulators_binary_limbs_1[1] = params.accumulated_result[1];
prover_polynomials.accumulators_binary_limbs_2[1] = params.accumulated_result[2];
prover_polynomials.accumulators_binary_limbs_3[1] = params.accumulated_result[3];

using Relations = typename Flavor::Relations;

// Check that Opcode Constraint relation is satisfied across each row of the prover polynomials
check_relation<Flavor, std::tuple_element_t<2, Relations>>(circuit_size, prover_polynomials, params);

// Check that Accumulator Transfer relation is satisfied across each row of the prover polynomials
check_relation<Flavor, std::tuple_element_t<3, Relations>>(circuit_size, prover_polynomials, params);
}

} // namespace test_honk_relations