Skip to content

Commit

Permalink
feat: Goblin translator opcode constraint and accumulator transfer re…
Browse files Browse the repository at this point in the history
…lations (Goblin Translator part 5)
  • Loading branch information
Rumata888 committed Oct 11, 2023
1 parent 6bf12dd commit 2cad52f
Show file tree
Hide file tree
Showing 3 changed files with 279 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
#pragma once
#include "barretenberg/numeric/uint256/uint256.hpp"
#include "relation_parameters.hpp"
#include "relation_types.hpp"

namespace proof_system {

template <typename FF_> class GoblinTranslatorOpcodeConstraintRelationImpl {
public:
using FF = FF_;

// 1 + polynomial degree of this relation
static constexpr size_t RELATION_LENGTH = 7; // degree(op(op - 1)(op - 2)(op - 3)(op - 4)(op - 8)) = 6
static constexpr size_t LEN_1 = 7;

template <template <size_t...> typename SubrelationAccumulatorsTemplate>
using GetAccumulatorTypes = SubrelationAccumulatorsTemplate<LEN_1>;

/**
* @brief Expression for enforcing the value of the Opcode to be {0,1,2,3,4,8}
* @details This relation enforces the opcode to be one of described values. Since we don't care about even values
* in the opcode wire and usually just set them to zero, we don't use a lagrange polynomial to specify the relation
* to be enforced just at odd indices, which brings the degree down by 1.
*
* @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor`
* @param extended_edges an std::array containing the fully extended Univariate edges.
* @param parameters contains beta, gamma, and public_input_delta, ....
* @param scaling_factor optional term to scale the evaluation before adding to evals.
*/
template <typename AccumulatorTypes>
void static accumulate(typename AccumulatorTypes::Accumulators& accumulators,
const auto& extended_edges,
const RelationParameters<FF>&,
const FF& scaling_factor)
{

using View = typename std::tuple_element<0, typename AccumulatorTypes::AccumulatorViews>::type;
auto op = View(extended_edges.op);
static const FF minus_one = FF(-1);
static const FF minus_two = FF(-2);
static const FF minus_three = FF(-3);
static const FF minus_four = FF(-4);
static const FF minus_eight = FF(-8);

// Contribution (1) (op(op-1)(op-2)(op-3)(op-4)(op-8))
auto tmp_1 = op * (op + minus_one);
tmp_1 *= (op + minus_two);
tmp_1 *= (op + minus_three);
tmp_1 *= (op + minus_four);
tmp_1 *= (op + minus_eight);
tmp_1 *= scaling_factor;
std::get<0>(accumulators) += tmp_1;
};
};

template <typename FF_> class GoblinTranslatorAccumulatorTransferRelationImpl {
public:
using FF = FF_;

// 1 + polynomial degree of this relation
static constexpr size_t RELATION_LENGTH = 3; // degree((SOME_LAGRANGE)(A-B)) = 2
static constexpr size_t LEN_1 = 3;
static constexpr size_t LEN_2 = 3;
static constexpr size_t LEN_3 = 3;
static constexpr size_t LEN_4 = 3;
static constexpr size_t LEN_5 = 3;
static constexpr size_t LEN_6 = 3;
static constexpr size_t LEN_7 = 3;
static constexpr size_t LEN_8 = 3;
static constexpr size_t LEN_9 = 3;
static constexpr size_t LEN_10 = 3;
static constexpr size_t LEN_11 = 3;
static constexpr size_t LEN_12 = 3;
template <template <size_t...> typename SubrelationAccumulatorsTemplate>
using GetAccumulatorTypes = SubrelationAccumulatorsTemplate<LEN_1,
LEN_2,
LEN_3,
LEN_4,
LEN_5,
LEN_6,
LEN_7,
LEN_8,
LEN_9,
LEN_10,
LEN_11,
LEN_12>;

/**
* @brief Relation enforcing non-arithmetic transitions of accumulator (value that is tracking the batched
* evaluation of polynomials in non-native field)
* @details This relation enforces three pieces of logic:
* 1) Accumulator starts as zero before we start accumulating stuff
* 2) Bet
* 3)
*
* @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor`
* @param extended_edges an std::array containing the fully extended Univariate edges.
* @param parameters contains beta, gamma, and public_input_delta, ....
* @param scaling_factor optional term to scale the evaluation before adding to evals.
*/
template <typename AccumulatorTypes>
void static accumulate(typename AccumulatorTypes::Accumulators& accumulators,
const auto& extended_edges,
const RelationParameters<FF>& relation_parameters,
const FF& scaling_factor)
{
using View = typename std::tuple_element<0, typename AccumulatorTypes::AccumulatorViews>::type;

// We use combination of lagrange polynomials at even indices in the minicircuit for copying the accumulator
auto lagrange_even = View(extended_edges.lagrange_even);

// Lagrange at index 1 is used to confirm the accumulator result
auto lagrange_second = View(extended_edges.lagrange_second);

// Lagrange at index (size of minicircuit - 2) is used to enforce that it starts with zero
auto lagrange_second_to_last_in_minicircuit = View(extended_edges.lagrange_second_to_last_in_minicircuit);

auto accumulators_binary_limbs_0 = View(extended_edges.accumulators_binary_limbs_0);
auto accumulators_binary_limbs_1 = View(extended_edges.accumulators_binary_limbs_1);
auto accumulators_binary_limbs_2 = View(extended_edges.accumulators_binary_limbs_2);
auto accumulators_binary_limbs_3 = View(extended_edges.accumulators_binary_limbs_3);
auto accumulators_binary_limbs_0_shift = View(extended_edges.accumulators_binary_limbs_0_shift);
auto accumulators_binary_limbs_1_shift = View(extended_edges.accumulators_binary_limbs_1_shift);
auto accumulators_binary_limbs_2_shift = View(extended_edges.accumulators_binary_limbs_2_shift);
auto accumulators_binary_limbs_3_shift = View(extended_edges.accumulators_binary_limbs_3_shift);

// Contribution (1) (1-4 ensure transfer of accumulator limbs at even indices of the minicircuit)
auto tmp_1 = accumulators_binary_limbs_0 - accumulators_binary_limbs_0_shift;
tmp_1 *= lagrange_even;
tmp_1 *= scaling_factor;
std::get<0>(accumulators) += tmp_1;

// Contribution (2)
auto tmp_2 = accumulators_binary_limbs_1 - accumulators_binary_limbs_1_shift;
tmp_2 *= lagrange_even;
tmp_2 *= scaling_factor;
std::get<1>(accumulators) += tmp_2;
// Contribution (3)
auto tmp_3 = accumulators_binary_limbs_2 - accumulators_binary_limbs_2_shift;
tmp_3 *= lagrange_even;
tmp_3 *= scaling_factor;
std::get<2>(accumulators) += tmp_3;
// Contribution (4)
auto tmp_4 = accumulators_binary_limbs_3 - accumulators_binary_limbs_3_shift;
tmp_4 *= lagrange_even;
tmp_4 *= scaling_factor;
std::get<3>(accumulators) += tmp_4;

// Contribution (5) (5-9 ensure that accumulator starts with zeroed-out limbs)
auto tmp_5 = accumulators_binary_limbs_0 * lagrange_second_to_last_in_minicircuit;
tmp_5 *= scaling_factor;
std::get<4>(accumulators) += tmp_5;

// Contribution (6)
auto tmp_6 = accumulators_binary_limbs_1 * lagrange_second_to_last_in_minicircuit;
tmp_6 *= scaling_factor;
std::get<5>(accumulators) += tmp_6;

// Contribution (7)
auto tmp_7 = accumulators_binary_limbs_2 * lagrange_second_to_last_in_minicircuit;
tmp_7 *= scaling_factor;
std::get<6>(accumulators) += tmp_7;

// Contribution (8)
auto tmp_8 = accumulators_binary_limbs_3 * lagrange_second_to_last_in_minicircuit;
tmp_8 *= scaling_factor;
std::get<7>(accumulators) += tmp_8;

// Contribution (9) (9-12 ensure the output is as stated, we basically use this to get the result out of the
// proof)
auto tmp_9 = (accumulators_binary_limbs_0 - relation_parameters.accumulated_result[0]) * lagrange_second;
tmp_9 *= scaling_factor;
std::get<8>(accumulators) += tmp_9;

// Contribution (10)
auto tmp_10 = (accumulators_binary_limbs_1 - relation_parameters.accumulated_result[1]) * lagrange_second;
tmp_10 *= scaling_factor;
std::get<9>(accumulators) += tmp_10;

// Contribution (11)
auto tmp_11 = (accumulators_binary_limbs_2 - relation_parameters.accumulated_result[2]) * lagrange_second;
tmp_11 *= scaling_factor;
std::get<10>(accumulators) += tmp_11;

// Contribution (12)
auto tmp_12 = (accumulators_binary_limbs_3 - relation_parameters.accumulated_result[3]) * lagrange_second;
tmp_12 *= scaling_factor;
std::get<11>(accumulators) += tmp_12;
};
};
template <typename FF>
using GoblinTranslatorOpcodeConstraintRelation = Relation<GoblinTranslatorOpcodeConstraintRelationImpl<FF>>;

template <typename FF>
using GoblinTranslatorAccumulatorTransferRelation = Relation<GoblinTranslatorAccumulatorTransferRelationImpl<FF>>;

} // namespace proof_system
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
*/
#include "barretenberg/ecc/curves/bn254/fr.hpp"
#include "barretenberg/proof_system/relations/decomposition_relation.hpp"
#include "barretenberg/proof_system/relations/extra_relations.hpp"
#include "barretenberg/proof_system/relations/gen_perm_sort_relation.hpp"
#include "barretenberg/proof_system/relations/permutation_relation.hpp"
#include "decomposition_relation.hpp"
#include "extra_relations.hpp"
#include <gtest/gtest.h>

using namespace proof_system;
Expand Down Expand Up @@ -905,4 +907,77 @@ TEST_F(GoblinTranslatorRelationConsistency, DecompositionRelation)
run_test(/*random_inputs=*/true);
};

TEST_F(GoblinTranslatorRelationConsistency, OpcodeConstraintRelation)
{
const auto run_test = [](bool random_inputs) {
using Relation = GoblinTranslatorOpcodeConstraintRelation<FF>;
using RelationValues = typename Relation::RelationValues;

const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
const auto& op = input_elements.op;

RelationValues expected_values;

const auto parameters = RelationParameters<FF>::get_random();

// (Contribution 1)
auto contribution_1 = op * (op - FF(1)) * (op - FF(2)) * (op - FF(3)) * (op - FF(4)) * (op - FF(8));
expected_values[0] = contribution_1;

validate_relation_execution<Relation>(expected_values, input_elements, parameters);
};
run_test(/*random_inputs=*/false);
run_test(/*random_inputs=*/true);
};

TEST_F(GoblinTranslatorRelationConsistency, AccumulatorTransferRelation)
{
const auto run_test = [](bool random_inputs) {
using Relation = GoblinTranslatorAccumulatorTransferRelation<FF>;
using RelationValues = typename Relation::RelationValues;

const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();

const auto& lagrange_even = input_elements.lagrange_even;
const auto& lagrange_second = input_elements.lagrange_second;
const auto& lagrange_second_to_last_in_minicircuit = input_elements.lagrange_second_to_last_in_minicircuit;
const auto& accumulators_binary_limbs_0 = input_elements.accumulators_binary_limbs_0;
const auto& accumulators_binary_limbs_0_shift = input_elements.accumulators_binary_limbs_0_shift;
const auto& accumulators_binary_limbs_1 = input_elements.accumulators_binary_limbs_1;
const auto& accumulators_binary_limbs_1_shift = input_elements.accumulators_binary_limbs_1_shift;
const auto& accumulators_binary_limbs_2 = input_elements.accumulators_binary_limbs_2;
const auto& accumulators_binary_limbs_2_shift = input_elements.accumulators_binary_limbs_2_shift;
const auto& accumulators_binary_limbs_3 = input_elements.accumulators_binary_limbs_3;
const auto& accumulators_binary_limbs_3_shift = input_elements.accumulators_binary_limbs_3_shift;

RelationValues expected_values;

const auto parameters = RelationParameters<FF>::get_random();

const auto [accumulated_result_0, accumulated_result_1, accumulated_result_2, accumulated_result_3] =
parameters.accumulated_result;

// Check transfer of accumulator at even indices
expected_values[0] = lagrange_even * (accumulators_binary_limbs_0 - accumulators_binary_limbs_0_shift);
expected_values[1] = lagrange_even * (accumulators_binary_limbs_1 - accumulators_binary_limbs_1_shift);
expected_values[2] = lagrange_even * (accumulators_binary_limbs_2 - accumulators_binary_limbs_2_shift);
expected_values[3] = lagrange_even * (accumulators_binary_limbs_3 - accumulators_binary_limbs_3_shift);

// Check the accumulator starts as zero
expected_values[4] = accumulators_binary_limbs_0 * lagrange_second_to_last_in_minicircuit;
expected_values[5] = accumulators_binary_limbs_1 * lagrange_second_to_last_in_minicircuit;
expected_values[6] = accumulators_binary_limbs_2 * lagrange_second_to_last_in_minicircuit;
expected_values[7] = accumulators_binary_limbs_3 * lagrange_second_to_last_in_minicircuit;

// Check the accumulator results in submitted value
expected_values[8] = (accumulators_binary_limbs_0 - accumulated_result_0) * lagrange_second;
expected_values[9] = (accumulators_binary_limbs_1 - accumulated_result_1) * lagrange_second;
expected_values[10] = (accumulators_binary_limbs_2 - accumulated_result_2) * lagrange_second;
expected_values[11] = (accumulators_binary_limbs_3 - accumulated_result_3) * lagrange_second;
validate_relation_execution<Relation>(expected_values, input_elements, parameters);
};
run_test(/*random_inputs=*/false);
run_test(/*random_inputs=*/true);
};

} // namespace proof_system::ultra_relation_consistency_tests
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#pragma once

#include <array>
namespace proof_system {

/**
Expand All @@ -8,6 +8,7 @@ namespace proof_system {
* @tparam FF
*/
template <typename FF> struct RelationParameters {
static const int NUM_BINARY_LIMBS_IN_GOBLIN_TRANSLATOR = 4;
FF eta = FF(0); // Lookup
FF beta = FF(0); // Permutation + Lookup
FF gamma = FF(0); // Permutation + Lookup
Expand All @@ -18,6 +19,7 @@ template <typename FF> struct RelationParameters {
// eccvm_set_permutation_delta is used in the set membership gadget in eccvm/ecc_set_relation.hpp
// We can remove this by modifying the relation, but increases complexity
FF eccvm_set_permutation_delta = 0;
std::array<FF, NUM_BINARY_LIMBS_IN_GOBLIN_TRANSLATOR> accumulated_result = { FF(0) }; // Goblin Translator

static RelationParameters get_random()
{
Expand All @@ -32,6 +34,10 @@ template <typename FF> struct RelationParameters {
result.eccvm_set_permutation_delta = result.gamma * (result.gamma + result.beta_sqr) *
(result.gamma + result.beta_sqr + result.beta_sqr) *
(result.gamma + result.beta_sqr + result.beta_sqr + result.beta_sqr);
result.accumulated_result = {
FF::random_element(), FF::random_element(), FF::random_element(), FF::random_element()
};

return result;
}
};
Expand Down

0 comments on commit 2cad52f

Please sign in to comment.