Skip to content
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 @@ -49,7 +49,7 @@ template <typename Flavor, typename Relation> void execute_relation_for_univaria
}

// Ultra relations (Sumcheck prover work)
BENCHMARK(execute_relation_for_univariates<UltraFlavor, UltraArithmeticRelation<Fr>>);
BENCHMARK(execute_relation_for_univariates<UltraFlavor, ArithmeticRelation<Fr>>);
BENCHMARK(execute_relation_for_univariates<UltraFlavor, DeltaRangeConstraintRelation<Fr>>);
BENCHMARK(execute_relation_for_univariates<UltraFlavor, EllipticRelation<Fr>>);
BENCHMARK(execute_relation_for_univariates<UltraFlavor, MemoryRelation<Fr>>);
Expand All @@ -64,7 +64,7 @@ BENCHMARK(execute_relation_for_univariates<MegaFlavor, Poseidon2ExternalRelation
BENCHMARK(execute_relation_for_univariates<MegaFlavor, Poseidon2InternalRelation<Fr>>);

// Ultra relations (verifier work)
BENCHMARK(execute_relation_for_values<UltraFlavor, UltraArithmeticRelation<Fr>>);
BENCHMARK(execute_relation_for_values<UltraFlavor, ArithmeticRelation<Fr>>);
BENCHMARK(execute_relation_for_values<UltraFlavor, DeltaRangeConstraintRelation<Fr>>);
BENCHMARK(execute_relation_for_values<UltraFlavor, EllipticRelation<Fr>>);
BENCHMARK(execute_relation_for_values<UltraFlavor, MemoryRelation<Fr>>);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace bb {
class UltraCircuitChecker {
public:
using FF = bb::fr;
using Arithmetic = UltraArithmeticRelation<FF>;
using Arithmetic = ArithmeticRelation<FF>;
using Elliptic = EllipticRelation<FF>;
using Memory = MemoryRelation<FF>;
using NonNativeField = NonNativeFieldRelation<FF>;
Expand Down
2 changes: 1 addition & 1 deletion barretenberg/cpp/src/barretenberg/flavor/flavor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ template <typename RelationsTuple> constexpr auto create_sumcheck_tuple_of_tuple
*
* @example if RelationsTuple = UltraFlavor::Relations_, then the tuple returned by the function is a tuple of length 9,
* where the first element of the tuple is an array of length 2 (as the first relation in UltraFlavor::Relations_ is the
* UltraArithmeticRelation, which is made up by two subrelations).
* ArithmeticRelation, which is made up by two subrelations).
*
* @tparam RelationsTuple
*/
Expand Down
2 changes: 1 addition & 1 deletion barretenberg/cpp/src/barretenberg/flavor/mega_flavor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class MegaFlavor {
// define the tuple of Relations that comprise the Sumcheck relation
// Note: made generic for use in MegaRecursive.
template <typename FF>
using Relations_ = std::tuple<bb::UltraArithmeticRelation<FF>,
using Relations_ = std::tuple<bb::ArithmeticRelation<FF>,
bb::UltraPermutationRelation<FF>,
bb::LogDerivLookupRelation<FF>,
bb::DeltaRangeConstraintRelation<FF>,
Expand Down
2 changes: 1 addition & 1 deletion barretenberg/cpp/src/barretenberg/flavor/ultra_flavor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class UltraFlavor {
// List of relations reflecting the Ultra arithmetisation. WARNING: As UltraKeccak flavor inherits from
// Ultra flavor any change of ordering in this tuple needs to be reflected in the smart contract, otherwise
// relation accumulation will not match.
using Relations_ = std::tuple<bb::UltraArithmeticRelation<FF>,
using Relations_ = std::tuple<bb::ArithmeticRelation<FF>,
bb::UltraPermutationRelation<FF>,
bb::LogDerivLookupRelation<FF>,
bb::DeltaRangeConstraintRelation<FF>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ template <> class RelationChecker<bb::UltraFlavor> : public RelationChecker<void
using FF = UltraFlavor::FF;

// Linearly independent relations (must be satisfied at each row)
Base::check<UltraArithmeticRelation<FF>>(polynomials, params, "UltraArithmetic");
Base::check<ArithmeticRelation<FF>>(polynomials, params, "UltraArithmetic");
Base::check<UltraPermutationRelation<FF>>(polynomials, params, "UltraPermutation");
Base::check<DeltaRangeConstraintRelation<FF>>(polynomials, params, "DeltaRangeConstraint");
Base::check<EllipticRelation<FF>>(polynomials, params, "Elliptic");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace bb {

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

Expand All @@ -25,60 +25,45 @@ template <typename FF_> class UltraArithmeticRelationImpl {
template <typename AllEntities> inline static bool skip(const AllEntities& in) { return in.q_arith.is_zero(); }

/**
* @brief Expression for the Ultra Arithmetic gate.
* @details This relation encapsulates several idenitities, toggled by the value of q_arith in [0, 1, 2, 3, ...].
* @brief Expression for the Ultra (width-4) Arithmetic gate.
* @details This relation contains two subrelations and encapsulates several identities, toggled by the value of
* q_arith in [0, 1, 2, 3].
*
* The whole formula is:
* Subrelation 1:
* q_arith *
* [ (-1/2) * (q_arith - 3) * (q_m * w_1 * w_2) + \sum_{i=1..4} q_i * w_i + q_c + (q_arith - 1) * w_4_shift]
*
* q_arith * ( ( (-1/2) * (q_arith - 3) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c ) +
* (q_arith - 1)*( α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m) + w_4_omega) ) = 0
* Subrelation 2:
* q_arith * (q_arith - 1) * (q_arith - 2) * (w_1 + w_4 - w_1_shift + q_m)
*
* This formula results in several cases depending on q_arith:
* 1. q_arith == 0: Arithmetic gate is completely disabled
* These formulas result in several cases depending on q_arith:
*
* 2. q_arith == 1: Everything in the minigate on the right is disabled. The equation is just a standard plonk
* equation with extra wires: q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c = 0
* CASE q_arith == 0: Arithmetic gate is completely disabled
*
* 3. q_arith == 2: The (w_1 + w_4 - ...) term is disabled. The equation is:
* (1/2) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + w_4_omega = 0
* It allows defining w_4 at next index (w_4_omega) in terms of current wire values
* CASE q_arith == 1: Conventional 4-wire Ultra arithmetic relation
* Subrelation 1: q_m * w_1 * w_2 + \sum_{i=1..4} q_i * w_i + q_c
* Subrelation 2: Disabled
*
* 4. q_arith == 3: The product of w_1 and w_2 is disabled, but a mini addition gate is enabled. α² allows us to
* split the equation into two:
* CASE q_arith == 2: Same as above but with an additional linear term: +w_4_shift
* Subrelation 1: q_m * w_1 * w_2 + [ \sum_{i=1..4} q_i * w_i + q_c + w_4_shift ] * 2
* Subrelation 2: Disabled
* Note: Factor of 2 on the linear term must be accounted for when constructing inputs to the relation.
*
* q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + 2 * w_4_omega = 0
*
* w_1 + w_4 - w_1_omega + q_m = 0 (we are reusing q_m here)
*
* 5. q_arith > 3: The product of w_1 and w_2 is scaled by (q_arith - 3), while the w_4_omega term is scaled by
* (q_arith
* - 1). The equation can be split into two:
*
* (q_arith - 3)* q_m * w_1 * w_ 2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + (q_arith - 1) * w_4_omega
* = 0
*
* w_1 + w_4 - w_1_omega + q_m = 0
*
* The problem that q_m is used both in both equations can be dealt with by appropriately changing selector values
* at the next gate. Then we can treat (q_arith - 1) as a simulated q_6 selector and scale q_m to handle (q_arith -
* 3) at product.
*
* The relation is
* defined as C(in(X)...) = q_arith * [ -1/2(q_arith - 3)(q_m * w_r * w_l) + (q_l * w_l) + (q_r * w_r) +
* (q_o * w_o) + (q_4 * w_4) + q_c + (q_arith - 1)w_4_shift ]
*
* q_arith *
* (q_arith - 2) * (q_arith - 1) * (w_l + w_4 - w_l_shift + q_m)
* CASE q_arith == 3:
* Subrelation 1: [ \sum_{i=1..4} q_i * w_i + q_c + (2 * w_4_shift) ] * 3
* Subrelation 2: [ w_1 + w_4 - w_1_shift + q_m ] * 6
* Note: We are repurposing q_m here as an additive term in the second subrelation.
* Note: Factor of 2 on the w_4_shift term must be accounted for when constructing inputs to the relation.
*
* @param evals transformed to `evals + C(in(X)...)*scaling_factor`
* @param in an std::array containing the fully extended Univariate edges.
* @param parameters contains beta, gamma, and public_input_delta, ....
* @param in Inputs to the relation algebra
* @param parameters Unused in this relation
* @param scaling_factor optional term to scale the evaluation before adding to evals.
*/
template <typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
inline static void accumulate(ContainerOverSubrelations& evals,
const AllEntities& in,
const Parameters&,
BB_UNUSED const Parameters& params,
const FF& scaling_factor)
{
using Accumulator = std::tuple_element_t<0, ContainerOverSubrelations>;
Expand All @@ -91,6 +76,7 @@ template <typename FF_> class UltraArithmeticRelationImpl {

auto q_arith_sub_1 = q_arith_m - FF(1);
auto scaled_q_arith = q_arith_m * scaling_factor;
// Subrelation 1
{
using Accumulator = std::tuple_element_t<0, ContainerOverSubrelations>;

Expand All @@ -111,6 +97,7 @@ template <typename FF_> class UltraArithmeticRelationImpl {

std::get<0>(evals) += (tmp0 + Accumulator(tmp1)) * Accumulator(scaled_q_arith);
}
// Subrelation 2
{
using ShortAccumulator = std::tuple_element_t<1, ContainerOverSubrelations>;

Expand All @@ -124,5 +111,5 @@ template <typename FF_> class UltraArithmeticRelationImpl {
};
};

template <typename FF> using UltraArithmeticRelation = Relation<UltraArithmeticRelationImpl<FF>>;
template <typename FF> using ArithmeticRelation = Relation<ArithmeticRelationImpl<FF>>;
} // namespace bb
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,13 @@ class UltraRelationConsistency : public testing::Test {
};
};

TEST_F(UltraRelationConsistency, UltraArithmeticRelation)
TEST_F(UltraRelationConsistency, ArithmeticRelation)
{
const auto run_test = [](bool random_inputs) {
using Relation = UltraArithmeticRelation<FF>;
const auto run_test = [](bool random_inputs, const FF& q_arith_value = FF::random_element()) {
using Relation = ArithmeticRelation<FF>;
using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;

const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
const auto& w_1 = input_elements.w_l;
const auto& w_1_shift = input_elements.w_l_shift;
const auto& w_2 = input_elements.w_r;
Expand All @@ -127,21 +127,48 @@ TEST_F(UltraRelationConsistency, UltraArithmeticRelation)
const auto& q_o = input_elements.q_o;
const auto& q_4 = input_elements.q_4;
const auto& q_c = input_elements.q_c;

// Set specific q_arith value to enable testing different modes of the arithmetic relation
input_elements.q_arith = q_arith_value;
const auto& q_arith = input_elements.q_arith;

SumcheckArrayOfValuesOverSubrelations expected_values;
static const FF neg_half = FF(-2).invert();

// Contribution 1
auto contribution_1 = (q_arith - 3) * (q_m * w_2 * w_1) * neg_half;
contribution_1 += (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c;
contribution_1 += (q_arith - 1) * w_4_shift;
contribution_1 *= q_arith;
expected_values[0] = contribution_1;
FF contribution_1 = FF(0);
FF contribution_2 = FF(0);
if (q_arith == FF(1)) {
// Contribution 1
contribution_1 = (q_m * w_2 * w_1) + (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c;

// Contribution 2: None
} else if (q_arith == FF(2)) {
// Contribution 1
contribution_1 = (q_m * w_2 * w_1);
contribution_1 += ((q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + w_4_shift + q_c) * FF(2);

// Contribution 2: None
} else if (q_arith == FF(3)) {
// Contribution 1
contribution_1 = (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c;
contribution_1 += w_4_shift * FF(2);
contribution_1 *= FF(3);

// Contribution 2
contribution_2 = (w_1 + w_4 - w_1_shift + q_m) * FF(6);
} else {
// Contribution 1
contribution_1 = (q_arith - 3) * (q_m * w_2 * w_1) * neg_half;
contribution_1 += (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c;
contribution_1 += (q_arith - 1) * w_4_shift;
contribution_1 *= q_arith;

// Contribution 2
contribution_2 = (w_1 + w_4 - w_1_shift + q_m);
contribution_2 *= (q_arith - 2) * (q_arith - 1) * q_arith;
}

// Contribution 2
auto contribution_2 = (w_1 + w_4 - w_1_shift + q_m);
contribution_2 *= (q_arith - 2) * (q_arith - 1) * q_arith;
expected_values[0] = contribution_1;
expected_values[1] = contribution_2;

const auto parameters = RelationParameters<FF>::get_random();
Expand All @@ -150,6 +177,9 @@ TEST_F(UltraRelationConsistency, UltraArithmeticRelation)
};
run_test(/*random_inputs=*/false);
run_test(/*random_inputs=*/true);
run_test(/*random_inputs=*/true, /*q_arith_value=*/FF(1));
run_test(/*random_inputs=*/true, /*q_arith_value=*/FF(2));
run_test(/*random_inputs=*/true, /*q_arith_value=*/FF(3));
};

TEST_F(UltraRelationConsistency, UltraPermutationRelation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,11 @@ void UltraCircuitBuilder_<ExecutionTrace>::create_big_mul_add_gate(const mul_qua
{
this->assert_valid_variables({ in.a, in.b, in.c, in.d });
blocks.arithmetic.populate_wires(in.a, in.b, in.c, in.d);
blocks.arithmetic.q_m().emplace_back(include_next_gate_w_4 ? in.mul_scaling * FF(2) : in.mul_scaling);
// If include_next_gate_w_4 is true then we set q_arith = 2. In this case, the linear term in the ArithmeticRelation
Copy link
Contributor

Choose a reason for hiding this comment

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

easier to understand!

// is scaled by a factor of 2. We compensate here by scaling the quadratic term by 2 to achieve the constraint:
// 2 * [q_m * w_1 * w_2 + \sum_{i=1..4} q_i * w_i + q_c + w_4_shift] = 0
const FF mul_scaling = include_next_gate_w_4 ? in.mul_scaling * FF(2) : in.mul_scaling;
blocks.arithmetic.q_m().emplace_back(mul_scaling);
blocks.arithmetic.q_1().emplace_back(in.a_scaling);
blocks.arithmetic.q_2().emplace_back(in.b_scaling);
blocks.arithmetic.q_3().emplace_back(in.c_scaling);
Expand Down Expand Up @@ -1661,13 +1665,16 @@ std::array<uint32_t, 5> UltraCircuitBuilder_<ExecutionTrace>::evaluate_non_nativ
block.populate_wires(x_2, y_2, z_2, z_1);
block.populate_wires(x_3, y_3, z_3, this->zero_idx());

// When q_arith == 3, w_4_shift is scaled by 2 (see ArithmeticRelation for details). Therefore, for consistency we
// also scale each linear term by this factor of 2 so that the constraint is effectively:
// (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c + w_4_shift = 0
const FF linear_term_scale_factor = 2;
block.q_m().emplace_back(addconstp);
block.q_1().emplace_back(0);
block.q_2().emplace_back(-x_mulconst0 *
2); // scale constants by 2. If q_arith = 3 then w_4_omega value (z0) gets scaled by 2x
block.q_3().emplace_back(-y_mulconst0 * 2); // z_0 - (x_0 * -xmulconst0) - (y_0 * ymulconst0) = 0 => z_0 = x_0 + y_0
block.q_2().emplace_back(-x_mulconst0 * linear_term_scale_factor);
block.q_3().emplace_back(-y_mulconst0 * linear_term_scale_factor);
block.q_4().emplace_back(0);
block.q_c().emplace_back(-addconst0 * 2);
block.q_c().emplace_back(-addconst0 * linear_term_scale_factor);
block.set_gate_selector(3);

block.q_m().emplace_back(0);
Expand Down Expand Up @@ -1773,12 +1780,16 @@ std::array<uint32_t, 5> UltraCircuitBuilder_<ExecutionTrace>::evaluate_non_nativ
block.populate_wires(x_2, y_2, z_2, z_1);
block.populate_wires(x_3, y_3, z_3, this->zero_idx());

// When q_arith == 3, w_4_shift is scaled by 2 (see ArithmeticRelation for details). Therefore, for consistency we
// also scale each linear term by this factor of 2 so that the constraint is effectively:
// (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c + w_4_shift = 0
const FF linear_term_scale_factor = 2;
block.q_m().emplace_back(-addconstp);
block.q_1().emplace_back(0);
block.q_2().emplace_back(-x_mulconst0 * 2);
block.q_3().emplace_back(y_mulconst0 * 2); // z_0 + (x_0 * -xmulconst0) + (y_0 * ymulconst0) = 0 => z_0 = x_0 - y_0
block.q_2().emplace_back(-x_mulconst0 * linear_term_scale_factor);
block.q_3().emplace_back(y_mulconst0 * linear_term_scale_factor);
block.q_4().emplace_back(0);
block.q_c().emplace_back(-addconst0 * 2);
block.q_c().emplace_back(-addconst0 * linear_term_scale_factor);
block.set_gate_selector(3);

block.q_m().emplace_back(0);
Expand Down
Loading