24#include <gtest/gtest.h>
54 return entities.w_l_shift;
56 return entities.w_r_shift;
58 return entities.w_o_shift;
60 return entities.w_4_shift;
62 __builtin_unreachable();
69 .q_m_nz = !entities.q_m.is_zero(),
70 .q_1_nz = !entities.q_l.is_zero(),
71 .q_2_nz = !entities.q_r.is_zero(),
72 .q_3_nz = !entities.q_o.is_zero(),
73 .q_4_nz = !entities.q_4.is_zero(),
74 .q_c_nz = !entities.q_c.is_zero(),
84 for (
const auto& wire_spec : pattern.
wires) {
85 if (wire_spec.condition(selectors)) {
86 result.insert(wire_spec.wire);
97template <
typename Relation>
104 Relation::accumulate(base_result, entities, parameters,
FF(1));
107 for (
Wire wire : { Wire::W_L,
119 Relation::accumulate(perturbed_result, perturbed, parameters,
FF(1));
121 if (base_result != perturbed_result) {
122 constrained.insert(wire);
137 FF gate_selector = configure_selectors(entities);
138 int64_t gate_selector_value =
static_cast<int64_t
>(uint64_t(gate_selector));
144 auto actually_constrained = get_actually_constrained_wires<Relation>(entities, parameters);
146 EXPECT_EQ(actually_constrained, pattern_claims);
155 verify_pattern<ArithmeticRelation<FF>>(
ARITHMETIC, [](
Entities& e) {
return e.q_arith =
FF(1); });
160 verify_pattern<ArithmeticRelation<FF>>(
ARITHMETIC, [](
Entities& e) {
return e.q_arith =
FF(2); });
165 verify_pattern<ArithmeticRelation<FF>>(
ARITHMETIC, [](
Entities& e) {
return e.q_arith =
FF(3); });
168TEST(PatternTest, Arithmetic3WithQmZero)
172 return e.q_arith =
FF(3);
181 return e.q_elliptic =
FF(1);
185TEST(PatternTest, EllipticDouble)
190 return e.q_elliptic =
FF(1);
196 verify_pattern<DeltaRangeConstraintRelation<FF>>(
DELTA_RANGE, [](
Entities& e) {
return e.q_delta_range =
FF(1); });
199TEST(PatternTest, NNFLimbAccum1)
206 return e.q_nnf =
FF(1);
210TEST(PatternTest, NNFLimbAccum2)
217 return e.q_nnf =
FF(1);
228 return e.q_nnf =
FF(1);
239 return e.q_nnf =
FF(1);
250 return e.q_nnf =
FF(1);
254TEST(PatternTest, MemoryRamRomAccess)
259 return e.q_memory =
FF(1);
263TEST(PatternTest, MemoryRamTimestamp)
268 return e.q_memory =
FF(1);
272TEST(PatternTest, MemoryRomConsistency)
277 return e.q_memory =
FF(1);
281TEST(PatternTest, MemoryRamConsistency)
285 return e.q_memory =
FF(1);
289TEST(PatternTest, Poseidon2Internal)
292 [](
Entities& e) {
return e.q_poseidon2_internal =
FF(1); });
295TEST(PatternTest, Poseidon2External)
298 [](
Entities& e) {
return e.q_poseidon2_external =
FF(1); });
303 verify_pattern<LogDerivLookupRelation<FF>>(
LOOKUP, [](
Entities& e) {
308 return e.q_lookup =
FF(1);
312TEST(PatternTest, LookupWithShiftedWires)
314 verify_pattern<LogDerivLookupRelation<FF>>(
LOOKUP, [](
Entities& e) {
319 return e.q_lookup =
FF(1);
325 verify_pattern<DatabusLookupRelation<FF>>(
DATABUS, [](
Entities& e) {
return e.q_busread =
FF(1); });
343TEST(PatternTest, DetectOverConstrained)
346 const GatePattern OVERCONSTRAINED_PATTERN = { .
name =
"overconstrained",
349 [](
const Selectors& sel) {
return sel.q_1_nz || sel.q_m_nz; } },
352 return sel.q_2_nz || sel.q_m_nz;
354 { Wire::W_O, [](
const Selectors& sel) {
return sel.q_3_nz; } },
357 return sel.q_4_nz || sel.gate_selector >= 2;
360 [](
const Selectors& sel) {
return sel.gate_selector >= 2; } },
362 [](
const Selectors& sel) {
return sel.gate_selector == 3; } },
367 entities.q_arith =
FF(3);
368 entities.q_m =
FF(1);
369 entities.q_l =
FF(1);
370 entities.q_r =
FF(0);
376 auto actually_constrained = get_actually_constrained_wires<ArithmeticRelation<FF>>(entities, parameters);
378 EXPECT_TRUE(pattern_claims.contains(Wire::W_R)) <<
"Over-constrained pattern claims W_R";
379 EXPECT_FALSE(actually_constrained.contains(Wire::W_R)) <<
"Relation does not constrain W_R in this config";
380 EXPECT_NE(pattern_claims, actually_constrained) <<
"Over-constrained pattern should not match relation";
381 EXPECT_EQ(correct_claims, actually_constrained) <<
"Correct ARITHMETIC pattern should match relation";
390TEST(PatternTest, DetectUnderConstrained)
394 UNDERCONSTRAINED_PATTERN = { .
name =
"underconstrained",
396 { Wire::W_O, [](
const Selectors& sel) {
return sel.q_3_nz; } },
397 { Wire::W_4, [](
const Selectors& sel) {
return sel.q_3_nz; } },
398 { Wire::W_L_SHIFT, [](
const Selectors& sel) {
return sel.q_3_nz; } },
399 { Wire::W_R_SHIFT, [](
const Selectors& sel) {
return sel.q_3_nz; } },
400 { Wire::W_O_SHIFT, [](
const Selectors& sel) {
return sel.q_3_nz; } },
401 { Wire::W_4_SHIFT, [](
const Selectors& sel) {
return sel.q_3_nz; } },
406 entities.q_memory =
FF(1);
407 entities.q_o =
FF(1);
413 auto actually_constrained = get_actually_constrained_wires<MemoryRelation<FF>>(entities, parameters);
415 EXPECT_FALSE(pattern_claims.contains(Wire::W_L)) <<
"Under-constrained pattern missing W_L";
416 EXPECT_FALSE(pattern_claims.contains(Wire::W_R)) <<
"Under-constrained pattern missing W_R";
417 EXPECT_TRUE(actually_constrained.contains(Wire::W_L)) <<
"Relation constrains W_L";
418 EXPECT_TRUE(actually_constrained.contains(Wire::W_R)) <<
"Relation constrains W_R";
419 EXPECT_NE(pattern_claims, actually_constrained) <<
"Under-constrained pattern should not match relation";
420 EXPECT_EQ(correct_claims, actually_constrained) <<
"Correct MEMORY pattern should match relation";
AllValues_< HasZK > AllValues
ArrayOfValues< FF, RelationImpl::SUBRELATION_PARTIAL_LENGTHS > SumcheckArrayOfValuesOverSubrelations
Selectors make_selectors(const Entities &entities, int64_t gate_selector_value)
std::set< Wire > get_actually_constrained_wires(const Entities &entities, const auto ¶meters)
Get the set of wires that actually affect a relation's output.
Entities get_random_entities()
void verify_pattern(const GatePattern &pattern, auto configure_selectors)
Generic test: verify a pattern matches what the relation actually constrains.
std::set< Wire > get_pattern_wires(const GatePattern &pattern, const Selectors &selectors)
Get the set of wires that a pattern claims are constrained.
TEST(PatternTest, Arithmetic1)
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 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.