26#include <gtest/gtest.h>
39 for (
auto&
field : entities.get_all()) {
49 return entities.w_l();
51 return entities.w_r();
53 return entities.w_o();
55 return entities.w_4();
57 return entities.w_l_shift();
59 return entities.w_r_shift();
61 return entities.w_o_shift();
63 return entities.w_4_shift();
65 __builtin_unreachable();
72 .q_m_nz = !entities.q_m().is_zero(),
73 .q_1_nz = !entities.q_l().is_zero(),
74 .q_2_nz = !entities.q_r().is_zero(),
75 .q_3_nz = !entities.q_o().is_zero(),
76 .q_4_nz = !entities.q_4().is_zero(),
77 .q_c_nz = !entities.q_c().is_zero(),
80 if constexpr (
requires { entities.q_5(); }) {
81 selectors.q_5_nz = !entities.q_5().is_zero();
92 for (
const auto& wire_spec : pattern.
wires) {
93 if (wire_spec.condition(selectors)) {
94 result.insert(wire_spec.wire);
105template <
typename Relation,
typename EntitiesT>
112 Relation::accumulate(base_result, entities, parameters,
FF(1));
115 for (
Wire wire : { Wire::W_L,
123 EntitiesT perturbed = entities;
127 Relation::accumulate(perturbed_result, perturbed, parameters,
FF(1));
129 if (base_result != perturbed_result) {
130 constrained.insert(wire);
142template <
typename Relation,
typename EntitiesT = Entities>
145 EntitiesT entities = get_random_entities<EntitiesT>();
146 FF gate_selector = configure_selectors(entities);
147 int64_t gate_selector_value =
static_cast<int64_t
>(uint64_t(gate_selector));
153 auto actually_constrained = get_actually_constrained_wires<Relation>(entities, parameters);
155 EXPECT_EQ(actually_constrained, pattern_claims);
164 verify_pattern<ArithmeticRelation<FF>>(
ARITHMETIC, [](
Entities& e) {
return e.q_arith() =
FF(1); });
169 verify_pattern<ArithmeticRelation<FF>>(
ARITHMETIC, [](
Entities& e) {
return e.q_arith() =
FF(2); });
174 verify_pattern<ArithmeticRelation<FF>>(
ARITHMETIC, [](
Entities& e) {
return e.q_arith() =
FF(3); });
177TEST(PatternTest, Arithmetic3WithQmZero)
181 return e.q_arith() =
FF(3);
190 return e.q_elliptic() =
FF(1);
194TEST(PatternTest, EllipticDouble)
199 return e.q_elliptic() =
FF(1);
205 verify_pattern<DeltaRangeConstraintRelation<FF>>(
DELTA_RANGE,
206 [](
Entities& e) {
return e.q_delta_range() =
FF(1); });
209TEST(PatternTest, NNFLimbAccum1)
216 return e.q_nnf() =
FF(1);
220TEST(PatternTest, NNFLimbAccum2)
227 return e.q_nnf() =
FF(1);
238 return e.q_nnf() =
FF(1);
249 return e.q_nnf() =
FF(1);
260 return e.q_nnf() =
FF(1);
264TEST(PatternTest, MemoryRamRomAccess)
269 return e.q_memory() =
FF(1);
273TEST(PatternTest, MemoryRamTimestamp)
278 return e.q_memory() =
FF(1);
282TEST(PatternTest, MemoryRomConsistency)
287 return e.q_memory() =
FF(1);
291TEST(PatternTest, MemoryRamConsistency)
295 return e.q_memory() =
FF(1);
299TEST(PatternTest, Poseidon2Internal)
301 verify_pattern<Poseidon2InternalRelation<FF>,
UltraEntities>(
305TEST(PatternTest, Poseidon2External)
308 [](
Entities& e) {
return e.q_poseidon2_external() =
FF(1); });
313 verify_pattern<LogDerivLookupRelation<FF>>(
LOOKUP, [](
Entities& e) {
318 return e.q_lookup() =
FF(1);
322TEST(PatternTest, LookupWithShiftedWires)
324 verify_pattern<LogDerivLookupRelation<FF>>(
LOOKUP, [](
Entities& e) {
329 return e.q_lookup() =
FF(1);
338 MegaFlavor::EntityId::kernel_calldata,
339 MegaFlavor::EntityId::kernel_calldata_read_counts,
340 MegaFlavor::EntityId::kernel_calldata_inverses,
341 MegaFlavor::EntityId::kernel_calldata_indicator,
342 MegaFlavor::EntityId::q_l>;
350 verify_pattern<BilinearOrBatchedEqCheckRelation<FF>>(
BILINEAR,
351 [](
Entities& e) {
return e.q_bilinear_batched_eq() =
FF(1); });
354TEST(PatternTest, BilinearSecondProductAndItsLinearsAbsent)
358 verify_pattern<BilinearOrBatchedEqCheckRelation<FF>>(
BILINEAR, [](
Entities& e) {
362 return e.q_bilinear_batched_eq() =
FF(1);
381 combined.insert(half_2.begin(), half_2.end());
384 auto actually_constrained =
385 get_actually_constrained_wires<BilinearOrBatchedEqCheckRelation<FF>>(entities, parameters);
386 EXPECT_EQ(actually_constrained, combined);
389TEST(PatternTest, BatchedEqSingleHalf)
394 entities.
q_o() =
FF(0);
395 entities.
q_4() =
FF(0);
396 entities.
q_m() =
FF(0);
404 EXPECT_TRUE(half_2.empty());
407 combined.insert(half_2.begin(), half_2.end());
410 auto actually_constrained =
411 get_actually_constrained_wires<BilinearOrBatchedEqCheckRelation<FF>>(entities, parameters);
412 EXPECT_EQ(actually_constrained, combined);
430TEST(PatternTest, DetectOverConstrained)
433 const GatePattern OVERCONSTRAINED_PATTERN = { .
name =
"overconstrained",
436 [](
const Selectors& sel) {
return sel.q_1_nz || sel.q_m_nz; } },
439 return sel.q_2_nz || sel.q_m_nz;
441 { Wire::W_O, [](
const Selectors& sel) {
return sel.q_3_nz; } },
444 return sel.q_4_nz || sel.gate_selector >= 2;
447 [](
const Selectors& sel) {
return sel.gate_selector >= 2; } },
449 [](
const Selectors& sel) {
return sel.gate_selector == 3; } },
455 entities.
q_m() =
FF(1);
456 entities.
q_l() =
FF(1);
457 entities.
q_r() =
FF(0);
463 auto actually_constrained = get_actually_constrained_wires<ArithmeticRelation<FF>>(entities, parameters);
465 EXPECT_TRUE(pattern_claims.contains(Wire::W_R)) <<
"Over-constrained pattern claims W_R";
466 EXPECT_FALSE(actually_constrained.contains(Wire::W_R)) <<
"Relation does not constrain W_R in this config";
467 EXPECT_NE(pattern_claims, actually_constrained) <<
"Over-constrained pattern should not match relation";
468 EXPECT_EQ(correct_claims, actually_constrained) <<
"Correct ARITHMETIC pattern should match relation";
477TEST(PatternTest, DetectUnderConstrained)
481 UNDERCONSTRAINED_PATTERN = { .
name =
"underconstrained",
483 { Wire::W_O, [](
const Selectors& sel) {
return sel.q_3_nz; } },
484 { Wire::W_4, [](
const Selectors& sel) {
return sel.q_3_nz; } },
485 { Wire::W_L_SHIFT, [](
const Selectors& sel) {
return sel.q_3_nz; } },
486 { Wire::W_R_SHIFT, [](
const Selectors& sel) {
return sel.q_3_nz; } },
487 { Wire::W_O_SHIFT, [](
const Selectors& sel) {
return sel.q_3_nz; } },
488 { Wire::W_4_SHIFT, [](
const Selectors& sel) {
return sel.q_3_nz; } },
494 entities.
q_o() =
FF(1);
500 auto actually_constrained = get_actually_constrained_wires<MemoryRelation<FF>>(entities, parameters);
502 EXPECT_FALSE(pattern_claims.contains(Wire::W_L)) <<
"Under-constrained pattern missing W_L";
503 EXPECT_FALSE(pattern_claims.contains(Wire::W_R)) <<
"Under-constrained pattern missing W_R";
504 EXPECT_TRUE(actually_constrained.contains(Wire::W_L)) <<
"Relation constrains W_L";
505 EXPECT_TRUE(actually_constrained.contains(Wire::W_R)) <<
"Relation constrains W_R";
506 EXPECT_NE(pattern_claims, actually_constrained) <<
"Under-constrained pattern should not match relation";
507 EXPECT_EQ(correct_claims, actually_constrained) <<
"Correct MEMORY pattern should match relation";
DataType & q_bilinear_batched_eq()
AllEntities< FF > AllValues
A field element for each entity of the flavor. These entities represent the prover polynomials evalua...
A wrapper for Relations to expose methods used by the Sumcheck prover or verifier to add the contribu...
ArrayOfValues< FF, RelationImpl::SUBRELATION_PARTIAL_LENGTHS > SumcheckArrayOfValuesOverSubrelations
A field element for each entity of the flavor. These entities represent the prover polynomials evalua...
EntitiesT get_random_entities()
UltraFlavor::AllValues UltraEntities
std::set< Wire > get_pattern_wires(const GatePattern &pattern, const Selectors &selectors)
Get the set of wires that a pattern claims are constrained.
void verify_pattern(const GatePattern &pattern, auto configure_selectors)
Generic test: verify a pattern matches what the relation actually constrains.
Selectors make_selectors(const EntitiesT &entities, int64_t gate_selector_value)
TEST(PatternTest, Arithmetic1)
std::set< Wire > get_actually_constrained_wires(const EntitiesT &entities, const auto ¶meters)
Get the set of wires that actually affect a relation's output.
uint32_t get_wire(Block &block, size_t gate_index, Wire wire)
const GatePattern POSEIDON2_EXTERNAL
const GatePattern POSEIDON2_INTERNAL
const GatePattern DATABUS
const GatePattern BATCHED_EQ_HALF_1
const GatePattern NON_NATIVE_FIELD
const GatePattern ELLIPTIC
const GatePattern DELTA_RANGE
const GatePattern ARITHMETIC
const GatePattern BILINEAR
const GatePattern BATCHED_EQ_HALF_2
Entry point for Barretenberg command-line interface.
field< Bn254FrParams > fr
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
static RelationParameters get_random()
static field random_element(numeric::RNG *engine=nullptr) noexcept
Pattern defining which wires are constrained by a gate type.
std::vector< WireSpec > wires
Selector values read from a gate.