26#include <gtest/gtest.h>
38 for (
auto&
field : entities.get_all()) {
56 return entities.w_l_shift;
58 return entities.w_r_shift;
60 return entities.w_o_shift;
62 return entities.w_4_shift;
64 __builtin_unreachable();
71 .q_m_nz = !entities.q_m.is_zero(),
72 .q_1_nz = !entities.q_l.is_zero(),
73 .q_2_nz = !entities.q_r.is_zero(),
74 .q_3_nz = !entities.q_o.is_zero(),
75 .q_4_nz = !entities.q_4.is_zero(),
76 .q_c_nz = !entities.q_c.is_zero(),
86 for (
const auto& wire_spec : pattern.
wires) {
87 if (wire_spec.condition(selectors)) {
88 result.insert(wire_spec.wire);
99template <
typename Relation,
typename E>
106 Relation::accumulate(base_result, entities, parameters,
FF(1));
109 for (
Wire wire : { Wire::W_L,
117 E perturbed = entities;
121 Relation::accumulate(perturbed_result, perturbed, parameters,
FF(1));
123 if (base_result != perturbed_result) {
124 constrained.insert(wire);
136template <
typename Relation,
typename E = Entities>
139 E entities = get_random_entities<E>();
140 FF gate_selector = configure_selectors(entities);
141 int64_t gate_selector_value =
static_cast<int64_t
>(uint64_t(gate_selector));
147 auto actually_constrained = get_actually_constrained_wires<Relation, E>(entities, parameters);
149 EXPECT_EQ(actually_constrained, pattern_claims);
158 verify_pattern<ArithmeticRelation<FF>>(
ARITHMETIC, [](
Entities& e) {
return e.q_arith =
FF(1); });
163 verify_pattern<ArithmeticRelation<FF>>(
ARITHMETIC, [](
Entities& e) {
return e.q_arith =
FF(2); });
168 verify_pattern<ArithmeticRelation<FF>>(
ARITHMETIC, [](
Entities& e) {
return e.q_arith =
FF(3); });
171TEST(PatternTest, Arithmetic3WithQmZero)
175 return e.q_arith =
FF(3);
184 return e.q_elliptic =
FF(1);
188TEST(PatternTest, EllipticDouble)
193 return e.q_elliptic =
FF(1);
199 verify_pattern<DeltaRangeConstraintRelation<FF>>(
DELTA_RANGE, [](
Entities& e) {
return e.q_delta_range =
FF(1); });
202TEST(PatternTest, NNFLimbAccum1)
209 return e.q_nnf =
FF(1);
213TEST(PatternTest, NNFLimbAccum2)
220 return e.q_nnf =
FF(1);
231 return e.q_nnf =
FF(1);
242 return e.q_nnf =
FF(1);
253 return e.q_nnf =
FF(1);
257TEST(PatternTest, MemoryRamRomAccess)
262 return e.q_memory =
FF(1);
266TEST(PatternTest, MemoryRamTimestamp)
271 return e.q_memory =
FF(1);
275TEST(PatternTest, MemoryRomConsistency)
280 return e.q_memory =
FF(1);
284TEST(PatternTest, MemoryRamConsistency)
288 return e.q_memory =
FF(1);
292TEST(PatternTest, Poseidon2Internal)
297 verify_pattern<Poseidon2InternalRelation<FF>, UltraEntities>(
301TEST(PatternTest, Poseidon2External)
304 [](
Entities& e) {
return e.q_poseidon2_external =
FF(1); });
307TEST(PatternTest, Poseidon2InitialExternal)
309 verify_pattern<Poseidon2InitialExternalRelation<FF>>(
315 verify_pattern<LogDerivLookupRelation<FF>>(
LOOKUP, [](
Entities& e) {
320 return e.q_lookup =
FF(1);
324TEST(PatternTest, LookupWithShiftedWires)
326 verify_pattern<LogDerivLookupRelation<FF>>(
LOOKUP, [](
Entities& e) {
331 return e.q_lookup =
FF(1);
337 verify_pattern<DatabusLookupRelation<FF>>(
DATABUS, [](
Entities& e) {
return e.q_busread =
FF(1); });
355TEST(PatternTest, DetectOverConstrained)
358 const GatePattern OVERCONSTRAINED_PATTERN = { .
name =
"overconstrained",
361 [](
const Selectors& sel) {
return sel.q_1_nz || sel.q_m_nz; } },
364 return sel.q_2_nz || sel.q_m_nz;
366 { Wire::W_O, [](
const Selectors& sel) {
return sel.q_3_nz; } },
369 return sel.q_4_nz || sel.gate_selector >= 2;
372 [](
const Selectors& sel) {
return sel.gate_selector >= 2; } },
374 [](
const Selectors& sel) {
return sel.gate_selector == 3; } },
378 Entities entities = get_random_entities<Entities>();
379 entities.q_arith =
FF(3);
380 entities.q_m =
FF(1);
381 entities.q_l =
FF(1);
382 entities.q_r =
FF(0);
388 auto actually_constrained = get_actually_constrained_wires<ArithmeticRelation<FF>,
Entities>(entities, parameters);
390 EXPECT_TRUE(pattern_claims.contains(Wire::W_R)) <<
"Over-constrained pattern claims W_R";
391 EXPECT_FALSE(actually_constrained.contains(Wire::W_R)) <<
"Relation does not constrain W_R in this config";
392 EXPECT_NE(pattern_claims, actually_constrained) <<
"Over-constrained pattern should not match relation";
393 EXPECT_EQ(correct_claims, actually_constrained) <<
"Correct ARITHMETIC pattern should match relation";
402TEST(PatternTest, DetectUnderConstrained)
406 UNDERCONSTRAINED_PATTERN = { .
name =
"underconstrained",
408 { Wire::W_O, [](
const Selectors& sel) {
return sel.q_3_nz; } },
409 { Wire::W_4, [](
const Selectors& sel) {
return sel.q_3_nz; } },
410 { Wire::W_L_SHIFT, [](
const Selectors& sel) {
return sel.q_3_nz; } },
411 { Wire::W_R_SHIFT, [](
const Selectors& sel) {
return sel.q_3_nz; } },
412 { Wire::W_O_SHIFT, [](
const Selectors& sel) {
return sel.q_3_nz; } },
413 { Wire::W_4_SHIFT, [](
const Selectors& sel) {
return sel.q_3_nz; } },
417 Entities entities = get_random_entities<Entities>();
418 entities.q_memory =
FF(1);
419 entities.q_o =
FF(1);
425 auto actually_constrained = get_actually_constrained_wires<MemoryRelation<FF>,
Entities>(entities, parameters);
427 EXPECT_FALSE(pattern_claims.contains(Wire::W_L)) <<
"Under-constrained pattern missing W_L";
428 EXPECT_FALSE(pattern_claims.contains(Wire::W_R)) <<
"Under-constrained pattern missing W_R";
429 EXPECT_TRUE(actually_constrained.contains(Wire::W_L)) <<
"Relation constrains W_L";
430 EXPECT_TRUE(actually_constrained.contains(Wire::W_R)) <<
"Relation constrains W_R";
431 EXPECT_NE(pattern_claims, actually_constrained) <<
"Under-constrained pattern should not match relation";
432 EXPECT_EQ(correct_claims, actually_constrained) <<
"Correct MEMORY pattern should match relation";
A base class labelling all entities (for instance, all of the polynomials used by the prover during s...
AllEntities_< FF > AllValues
A field element for each entity of the flavor. These entities represent the prover polynomials evalua...
ArrayOfValues< FF, RelationImpl::SUBRELATION_PARTIAL_LENGTHS > SumcheckArrayOfValuesOverSubrelations
AllValues_< HasZK > AllValues
Selectors make_selectors(const E &entities, int64_t gate_selector_value)
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.
TEST(PatternTest, Arithmetic1)
std::set< Wire > get_actually_constrained_wires(const E &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 POSEIDON2_INITIAL_EXTERNAL
const GatePattern DATABUS
const GatePattern NON_NATIVE_FIELD
const GatePattern ELLIPTIC
const GatePattern DELTA_RANGE
const GatePattern ARITHMETIC
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.