Skip to content

Commit

Permalink
chore: Random polynomial is now applied on a per-relation term by the…
Browse files Browse the repository at this point in the history
  • Loading branch information
zac-williamson authored Jun 27, 2023
1 parent 0452563 commit 3ad1f7e
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 44 deletions.
6 changes: 5 additions & 1 deletion barretenberg/cpp/src/barretenberg/honk/flavor/standard.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,14 @@ class Standard {
using Relations = std::tuple<sumcheck::ArithmeticRelation<FF>, sumcheck::PermutationRelation<FF>>;

static constexpr size_t MAX_RELATION_LENGTH = get_max_relation_length<Relations>();

// MAX_RANDOM_RELATION_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta` random
// polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation length = 3
static constexpr size_t MAX_RANDOM_RELATION_LENGTH = MAX_RELATION_LENGTH + 1;
static constexpr size_t NUM_RELATIONS = std::tuple_size<Relations>::value;

// Instantiate the BarycentricData needed to extend each Relation Univariate
static_assert(instantiate_barycentric_utils<FF, MAX_RELATION_LENGTH>());
static_assert(instantiate_barycentric_utils<FF, MAX_RANDOM_RELATION_LENGTH>());

// define the containers for storing the contributions from each relation in Sumcheck
using RelationUnivariates = decltype(create_relation_univariates_container<FF, Relations>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,14 @@ class StandardGrumpkin {
using Relations = std::tuple<sumcheck::ArithmeticRelation<FF>, sumcheck::PermutationRelation<FF>>;

static constexpr size_t MAX_RELATION_LENGTH = get_max_relation_length<Relations>();

// MAX_RANDOM_RELATION_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta` random
// polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation length = 3
static constexpr size_t MAX_RANDOM_RELATION_LENGTH = MAX_RELATION_LENGTH + 1;
static constexpr size_t NUM_RELATIONS = std::tuple_size<Relations>::value;

// Instantiate the BarycentricData needed to extend each Relation Univariate
static_assert(instantiate_barycentric_utils<FF, MAX_RELATION_LENGTH>());
static_assert(instantiate_barycentric_utils<FF, MAX_RANDOM_RELATION_LENGTH>());

// define the containers for storing the contributions from each relation in Sumcheck
using RelationUnivariates = decltype(create_relation_univariates_container<FF, Relations>());
Expand Down
6 changes: 5 additions & 1 deletion barretenberg/cpp/src/barretenberg/honk/flavor/ultra.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,14 @@ class Ultra {
sumcheck::AuxiliaryRelation<FF>>;

static constexpr size_t MAX_RELATION_LENGTH = get_max_relation_length<Relations>();

// MAX_RANDOM_RELATION_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta` random
// polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation length = 3
static constexpr size_t MAX_RANDOM_RELATION_LENGTH = MAX_RELATION_LENGTH + 1;
static constexpr size_t NUM_RELATIONS = std::tuple_size<Relations>::value;

// Instantiate the BarycentricData needed to extend each Relation Univariate
static_assert(instantiate_barycentric_utils<FF, MAX_RELATION_LENGTH>());
static_assert(instantiate_barycentric_utils<FF, MAX_RANDOM_RELATION_LENGTH>());

// define the container for storing the univariate contribution from each relation in Sumcheck
using RelationUnivariates = decltype(create_relation_univariates_container<FF, Relations>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,14 @@ class UltraGrumpkin {
sumcheck::AuxiliaryRelation<FF>>;

static constexpr size_t MAX_RELATION_LENGTH = get_max_relation_length<Relations>();

// MAX_RANDOM_RELATION_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta` random
// polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation length = 3
static constexpr size_t MAX_RANDOM_RELATION_LENGTH = MAX_RELATION_LENGTH + 1;
static constexpr size_t NUM_RELATIONS = std::tuple_size<Relations>::value;

// Instantiate the BarycentricData needed to extend each Relation Univariate
static_assert(instantiate_barycentric_utils<FF, MAX_RELATION_LENGTH>());
static_assert(instantiate_barycentric_utils<FF, MAX_RANDOM_RELATION_LENGTH>());

// define the container for storing the univariate contribution from each relation in Sumcheck
using RelationUnivariates = decltype(create_relation_univariates_container<FF, Relations>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
#include "relation_parameters.hpp"

namespace proof_system::honk::sumcheck {

template <typename T>
concept HasSubrelationLinearlyIndependentMember = requires(T) { T::Relation::SUBRELATION_LINEARLY_INDEPENDENT; };
/**
* @brief The templates defined herein facilitate sharing the relation arithmetic between the prover and the verifier.
*
Expand Down Expand Up @@ -66,6 +67,31 @@ template <typename FF, template <typename> typename RelationBase> class Relation
Relation::template add_edge_contribution_impl<ValueAccumTypes>(
accumulator, input, relation_parameters, scaling_factor);
}

/**
* @brief Check is subrelation is linearly independent
* Method always returns true if relation has no SUBRELATION_LINEARLY_INDEPENDENT std::array
* (i.e. default is to make linearly independent)
* @tparam size_t
*/
template <size_t>
static constexpr bool is_subrelation_linearly_independent()
requires(!HasSubrelationLinearlyIndependentMember<Relation>)
{
return true;
}

/**
* @brief Check is subrelation is linearly independent
* Method is active if relation has SUBRELATION_LINEARLY_INDEPENDENT array defined
* @tparam size_t
*/
template <size_t subrelation_index>
static constexpr bool is_subrelation_linearly_independent()
requires(HasSubrelationLinearlyIndependentMember<Relation>)
{
return std::get<subrelation_index>(Relation::SUBRELATION_LINEARLY_INDEPENDENT);
}
};

} // namespace proof_system::honk::sumcheck
7 changes: 4 additions & 3 deletions barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ template <typename Flavor, class Transcript> class Sumcheck {
using ClaimedEvaluations = typename Flavor::ClaimedEvaluations;

static constexpr size_t MAX_RELATION_LENGTH = Flavor::MAX_RELATION_LENGTH;
static constexpr size_t MAX_RANDOM_RELATION_LENGTH = Flavor::MAX_RANDOM_RELATION_LENGTH;
static constexpr size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES;

Transcript& transcript;
Expand Down Expand Up @@ -161,15 +162,15 @@ template <typename Flavor, class Transcript> class Sumcheck {
for (size_t round_idx = 0; round_idx < multivariate_d; round_idx++) {
// Obtain the round univariate from the transcript
std::string round_univariate_label = "Sumcheck:univariate_" + std::to_string(round_idx);
auto round_univariate =
transcript.template receive_from_prover<Univariate<FF, MAX_RELATION_LENGTH>>(round_univariate_label);
auto round_univariate = transcript.template receive_from_prover<Univariate<FF, MAX_RANDOM_RELATION_LENGTH>>(
round_univariate_label);

bool checked = round.check_sum(round_univariate, pow_univariate);
verified = verified && checked;
FF round_challenge = transcript.get_challenge("Sumcheck:u_" + std::to_string(round_idx));
multivariate_challenge.emplace_back(round_challenge);

round.compute_next_target_sum(round_univariate, round_challenge, pow_univariate);
round.compute_next_target_sum(round_univariate, round_challenge);
pow_univariate.partially_evaluate(round_challenge);

if (!verified) {
Expand Down
84 changes: 51 additions & 33 deletions barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ template <typename Flavor> class SumcheckRound {
Relations relations;
static constexpr size_t NUM_RELATIONS = Flavor::NUM_RELATIONS;
static constexpr size_t MAX_RELATION_LENGTH = Flavor::MAX_RELATION_LENGTH;
static constexpr size_t MAX_RANDOM_RELATION_LENGTH = Flavor::MAX_RANDOM_RELATION_LENGTH;

FF target_total_sum = 0;

Expand All @@ -99,13 +100,14 @@ template <typename Flavor> class SumcheckRound {
*
* @tparam T : In practice, this is a Univariate<FF, MAX_NUM_RELATIONS>.
*/
Univariate<FF, MAX_RELATION_LENGTH> batch_over_relations(FF challenge)
Univariate<FF, MAX_RANDOM_RELATION_LENGTH> batch_over_relations(FF challenge,
const PowUnivariate<FF>& pow_univariate)
{
FF running_challenge = 1;
scale_univariates(univariate_accumulators, challenge, running_challenge);

auto result = Univariate<FF, MAX_RELATION_LENGTH>();
extend_and_batch_univariates(univariate_accumulators, result);
auto result = Univariate<FF, MAX_RANDOM_RELATION_LENGTH>(0);
extend_and_batch_univariates(univariate_accumulators, pow_univariate, result);

// Reset all univariate accumulators to 0 before beginning accumulation in the next round
zero_univariates(univariate_accumulators);
Expand Down Expand Up @@ -134,10 +136,10 @@ template <typename Flavor> class SumcheckRound {
* values. Most likely this will end up being S_l(0), ... , S_l(t-1) where t is around 12. At the end, reset all
* univariate accumulators to be zero.
*/
Univariate<FF, MAX_RELATION_LENGTH> compute_univariate(auto& polynomials,
const RelationParameters<FF>& relation_parameters,
const PowUnivariate<FF>& pow_univariate,
const FF alpha)
Univariate<FF, MAX_RANDOM_RELATION_LENGTH> compute_univariate(auto& polynomials,
const RelationParameters<FF>& relation_parameters,
const PowUnivariate<FF>& pow_univariate,
const FF alpha)
{
// Precompute the vector of required powers of zeta
// TODO(luke): Parallelize this
Expand Down Expand Up @@ -196,7 +198,7 @@ template <typename Flavor> class SumcheckRound {
add_nested_tuples(univariate_accumulators, accumulators);
}
// Batch the univariate contributions from each sub-relation to obtain the round univariate
return batch_over_relations(alpha);
return batch_over_relations(alpha, pow_univariate);
}

/**
Expand All @@ -212,14 +214,12 @@ template <typename Flavor> class SumcheckRound {
const PowUnivariate<FF>& pow_univariate,
const FF alpha)
{
accumulate_relation_evaluations<>(purported_evaluations, relation_parameters);
accumulate_relation_evaluations<>(
purported_evaluations, relation_parameters, pow_univariate.partial_evaluation_constant);

auto running_challenge = FF(1);
auto output = FF(0);
scale_and_batch_elements(relation_evaluations, alpha, running_challenge, output);

output *= pow_univariate.partial_evaluation_constant;

return output;
}

Expand All @@ -228,11 +228,11 @@ template <typename Flavor> class SumcheckRound {
*
* @param univariate T^{l}(X), the round univariate that is equal to S^{l}(X)/( (1−X) + X⋅ζ^{ 2^l } )
*/
bool check_sum(Univariate<FF, MAX_RELATION_LENGTH>& univariate, const PowUnivariate<FF>& pow_univariate)
bool check_sum(Univariate<FF, MAX_RANDOM_RELATION_LENGTH>& univariate, const PowUnivariate<FF>& pow_univariate)
{
// S^{l}(0) = ( (1−0) + 0⋅ζ^{ 2^l } ) ⋅ T^{l}(0) = T^{l}(0)
// S^{l}(1) = ( (1−1) + 1⋅ζ^{ 2^l } ) ⋅ T^{l}(1) = ζ^{ 2^l } ⋅ T^{l}(1)
FF total_sum = univariate.value_at(0) + (pow_univariate.zeta_pow * univariate.value_at(1));
FF total_sum = univariate.value_at(0) + univariate.value_at(1);
// target_total_sum = sigma_{l} =
bool sumcheck_round_failed = (target_total_sum != total_sum);
round_failed = round_failed || sumcheck_round_failed;
Expand All @@ -247,19 +247,13 @@ template <typename Flavor> class SumcheckRound {
* @param round_challenge u_l
* @return FF sigma_{l+1} = S^l(u_l)
*/
FF compute_next_target_sum(Univariate<FF, MAX_RELATION_LENGTH>& univariate,
FF& round_challenge,
const PowUnivariate<FF>& pow_univariate)
FF compute_next_target_sum(Univariate<FF, MAX_RANDOM_RELATION_LENGTH>& univariate, FF& round_challenge)
{
// IMPROVEMENT(Cody): Use barycentric static method, maybe implement evaluation as member
// function on Univariate.
auto barycentric = BarycentricData<FF, MAX_RELATION_LENGTH, MAX_RELATION_LENGTH>();
auto barycentric = BarycentricData<FF, MAX_RANDOM_RELATION_LENGTH, MAX_RANDOM_RELATION_LENGTH>();
// Evaluate T^{l}(u_{l})
target_total_sum = barycentric.evaluate(univariate, round_challenge);
// Evaluate (1−u_l) + u_l ⋅ ζ^{2^l} )
FF pow_monomial_eval = pow_univariate.univariate_eval(round_challenge);
// sigma_{l+1} = S^l(u_l) = (1−u_l) + u_l⋅ζ^{2^l} ) ⋅ T^{l}(u_l)
target_total_sum *= pow_monomial_eval;
return target_total_sum;
}

Expand Down Expand Up @@ -307,14 +301,19 @@ template <typename Flavor> class SumcheckRound {
template <size_t relation_idx = 0>
// TODO(#224)(Cody): Input should be an array?
void accumulate_relation_evaluations(ClaimedEvaluations purported_evaluations,
const RelationParameters<FF>& relation_parameters)
const RelationParameters<FF>& relation_parameters,
const FF& partial_evaluation_constant)
{
std::get<relation_idx>(relations).add_full_relation_value_contribution(
std::get<relation_idx>(relation_evaluations), purported_evaluations, relation_parameters);
std::get<relation_idx>(relation_evaluations),
purported_evaluations,
relation_parameters,
partial_evaluation_constant);

// Repeat for the next relation.
if constexpr (relation_idx + 1 < NUM_RELATIONS) {
accumulate_relation_evaluations<relation_idx + 1>(purported_evaluations, relation_parameters);
accumulate_relation_evaluations<relation_idx + 1>(
purported_evaluations, relation_parameters, partial_evaluation_constant);
}
}

Expand All @@ -334,13 +333,32 @@ template <typename Flavor> class SumcheckRound {
* @param result A Univariate of length extended_size
*/
template <size_t extended_size>
static void extend_and_batch_univariates(auto& tuple, Univariate<FF, extended_size>& result)
static void extend_and_batch_univariates(auto& tuple,
const PowUnivariate<FF>& pow_univariate,
Univariate<FF, extended_size>& result)
{
auto extend_and_sum = [&](auto& element) {
using Element = std::remove_reference_t<decltype(element)>;
// Random poly R(X) = (1-X) + X.zeta_pow
auto random_poly_edge = Univariate<FF, 2>({ 1, pow_univariate.zeta_pow });
BarycentricData<FF, 2, extended_size> pow_zeta_univariate_extender = BarycentricData<FF, 2, extended_size>();
Univariate<FF, extended_size> extended_random_polynomial_edge =
pow_zeta_univariate_extender.extend(random_poly_edge);

auto extend_and_sum = [&]<size_t relation_idx, size_t subrelation_idx, typename Element>(Element& element) {
using Relation = typename std::tuple_element<relation_idx, Relations>::type;

// TODO(#224)(Cody): this barycentric stuff should be more built-in?
BarycentricData<FF, Element::LENGTH, extended_size> barycentric_utils;
result += barycentric_utils.extend(element);
auto extended = barycentric_utils.extend(element);

const bool is_subrelation_linearly_independent =
Relation::template is_subrelation_linearly_independent<subrelation_idx>();
if (is_subrelation_linearly_independent) {
// if subrelation is linearly independent, multiply by random polynomial
result += extended * extended_random_polynomial_edge;
} else {
// if subrelation is pure sum over hypercube, don't multiply by random polynomial
result += extended;
}
};
apply_to_tuple_of_tuples(tuple, extend_and_sum);
}
Expand All @@ -352,7 +370,7 @@ template <typename Flavor> class SumcheckRound {
*/
static void zero_univariates(auto& tuple)
{
auto set_to_zero = [](auto& element) {
auto set_to_zero = []<size_t, size_t>(auto& element) {
std::fill(element.evaluations.begin(), element.evaluations.end(), FF(0));
};
apply_to_tuple_of_tuples(tuple, set_to_zero);
Expand All @@ -367,7 +385,7 @@ template <typename Flavor> class SumcheckRound {
*/
static void scale_univariates(auto& tuple, const FF& challenge, FF current_scalar)
{
auto scale_by_consecutive_powers_of_challenge = [&](auto& element) {
auto scale_by_consecutive_powers_of_challenge = [&]<size_t, size_t>(auto& element) {
element *= current_scalar;
current_scalar *= challenge;
};
Expand All @@ -383,14 +401,14 @@ template <typename Flavor> class SumcheckRound {
* @param tuple A Tuple of tuples of Univariates
* @param operation Operation to apply to Univariates
*/
template <typename Operation, size_t outer_idx = 0, size_t inner_idx = 0>
template <class Operation, size_t outer_idx = 0, size_t inner_idx = 0>
static void apply_to_tuple_of_tuples(auto& tuple, Operation&& operation)
{
auto& inner_tuple = std::get<outer_idx>(tuple);
auto& univariate = std::get<inner_idx>(inner_tuple);

// Apply the specified operation to each Univariate
std::invoke(std::forward<Operation>(operation), univariate);
operation.template operator()<outer_idx, inner_idx>(univariate);

const size_t inner_size = std::tuple_size_v<std::decay_t<decltype(std::get<outer_idx>(tuple))>>;
const size_t outer_size = std::tuple_size_v<std::decay_t<decltype(tuple)>>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ using ProverPolynomials = typename Flavor::ProverPolynomials;
using ClaimedEvaluations = typename Flavor::ClaimedEvaluations;

const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES;
const size_t max_relation_length = 5;
const size_t max_relation_length = Flavor::MAX_RANDOM_RELATION_LENGTH;
const size_t input_polynomial_length = 2;

namespace test_sumcheck_round {
Expand Down Expand Up @@ -301,8 +301,9 @@ TEST(SumcheckRound, TupleOfTuplesOfUnivariates)
SumcheckRound<Flavor>::scale_univariates(tuple_of_tuples, challenge, running_challenge);

// Use extend_and_batch_univariates to extend to MAX_LENGTH then accumulate
PowUnivariate<FF> pow_univariate(1);
auto result = Univariate<FF, MAX_LENGTH>();
SumcheckRound<Flavor>::extend_and_batch_univariates(tuple_of_tuples, result);
SumcheckRound<Flavor>::extend_and_batch_univariates(tuple_of_tuples, pow_univariate, result);

// Repeat the batching process manually
auto result_expected = barycentric_util_1.extend(univariate_1) * 1 +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ template <typename Flavor> class TranscriptTests : public testing::Test {

auto log_n = numeric::get_msb(circuit_size);

size_t max_relation_length = 5;
size_t max_relation_length = Flavor::MAX_RANDOM_RELATION_LENGTH;
size_t size_FF = sizeof(FF);
size_t size_G = 2 * size_FF;
size_t size_uni = max_relation_length * size_FF;
Expand Down

0 comments on commit 3ad1f7e

Please sign in to comment.