13#include <gtest/gtest.h>
16#include <unordered_map>
17#include <unordered_set>
45 .linear_combinations = {},
63 .public_parameters = {},
70 explicit WitnessFactory(uint32_t start = 0)
74 uint32_t next_index() {
return next_++; }
76 Acir::Witness next_witness() {
return make_witness(next_index()); }
80 std::vector<Acir::Witness> next_witnesses(
size_t count)
82 std::vector<Acir::Witness> witnesses;
83 witnesses.reserve(count);
84 for (
size_t i = 0; i < count; ++i) {
85 witnesses.push_back(next_witness());
90 std::vector<Acir::FunctionInput> next_inputs(
size_t count)
92 std::vector<Acir::FunctionInput>
inputs;
94 for (
size_t i = 0; i < count; ++i) {
95 inputs.push_back(next_input());
103 for (
auto& input : *
inputs) {
104 input = next_input();
112 for (
auto& output : *outputs) {
113 output = next_witness();
126 auto builder = create_circuit<AcirComponentsCheckBuilder>(program);
128 return checker.check();
133 if (errors.empty()) {
137 for (
const auto& err : errors) {
147 ASSERT_EQ(errors.size(), 1U);
151size_t count_acir_components_for_witnesses(
const Acir::Circuit& circuit,
const std::vector<uint32_t>& witnesses)
157 std::unordered_set<size_t> components;
158 for (
auto witness : witnesses) {
159 auto it = witness_to_component.find(witness);
160 if (it != witness_to_component.end()) {
161 components.insert(it->second);
164 return components.size();
167size_t count_circuit_components_for_witnesses(
const Acir::Circuit& circuit,
const std::vector<uint32_t>& witnesses)
171 auto builder = create_circuit<AcirComponentsCheckBuilder>(program);
174 auto connected_components = analyzer.find_connected_components();
176 std::unordered_map<uint32_t, size_t> real_variable_to_component;
177 for (
size_t component_id = 0; component_id < connected_components.size(); ++component_id) {
178 for (
auto real_var : connected_components[component_id].vars()) {
179 real_variable_to_component[real_var] = component_id;
183 std::unordered_set<size_t> components;
184 for (
auto witness : witnesses) {
185 if (witness >=
builder.real_variable_index.size()) {
188 auto real_var =
builder.real_variable_index[witness];
189 auto it = real_variable_to_component.find(real_var);
190 if (it != real_variable_to_component.end()) {
191 components.insert(it->second);
194 return components.size();
211 .public_parameters = {},
215 expect_no_component_errors(run_components_check(circuit));
220 WitnessFactory witnesses;
222 auto sha256_inputs = witnesses.next_input_array<16>();
223 auto sha256_hash_values = witnesses.next_input_array<8>();
224 auto sha256_outputs = witnesses.next_witness_array<8>();
226 auto k1_public_key_x = witnesses.next_input_array<32>();
227 auto k1_public_key_y = witnesses.next_input_array<32>();
228 auto k1_signature = witnesses.next_input_array<64>();
229 auto k1_hashed_message = witnesses.next_input_array<32>();
231 auto r1_public_key_x = witnesses.next_input_array<32>();
232 auto r1_public_key_y = witnesses.next_input_array<32>();
233 auto r1_signature = witnesses.next_input_array<64>();
234 auto r1_hashed_message = witnesses.next_input_array<32>();
236 auto msm_outputs = witnesses.next_witness_array<2>();
237 auto ec_add_input1 = witnesses.next_input_array<2>();
238 auto ec_add_input2 = witnesses.next_input_array<2>();
239 auto ec_add_outputs = witnesses.next_witness_array<2>();
240 auto keccak_inputs = witnesses.next_input_array<25>();
241 auto keccak_outputs = witnesses.next_witness_array<25>();
248 .
lhs = witnesses.next_input(),
249 .
rhs = witnesses.next_input(),
251 .output = witnesses.next_witness(),
257 .
lhs = witnesses.next_input(),
258 .
rhs = witnesses.next_input(),
261 witnesses.next_witness(),
268 witnesses.next_input(),
278 witnesses.next_inputs(16),
280 witnesses.next_input_array<16>(),
281 .key = witnesses.next_input_array<16>(),
283 witnesses.next_witnesses(16),
294 .hash_values = sha256_hash_values,
295 .outputs = sha256_outputs,
304 witnesses.next_inputs(64),
306 witnesses.next_witness_array<32>(),
315 witnesses.next_inputs(64),
317 witnesses.next_witness_array<32>(),
326 .public_key_y = k1_public_key_y,
327 .signature = k1_signature,
328 .hashed_message = k1_hashed_message,
330 .output = witnesses.next_witness(),
339 .public_key_y = r1_public_key_y,
340 .signature = r1_signature,
341 .hashed_message = r1_hashed_message,
343 .output = witnesses.next_witness(),
351 .
points = witnesses.next_inputs(2),
352 .scalars = witnesses.next_inputs(2),
354 .outputs = msm_outputs,
363 .input2 = ec_add_input2,
365 .outputs = ec_add_outputs,
371 .outputs = keccak_outputs,
378 .proof = witnesses.next_inputs(8),
379 .public_inputs = witnesses.next_inputs(2),
380 .key_hash = witnesses.next_input(),
388 .
inputs = witnesses.next_inputs(4),
389 .outputs = witnesses.next_witnesses(4),
393 expect_no_component_errors(run_components_check(circuit));
398 WitnessFactory witnesses;
411 .
points = { make_constant_input(generator_x),
412 make_constant_input(generator_y) },
413 .scalars = witnesses.next_inputs(2),
415 .outputs = witnesses.next_witness_array<2>(),
424 .
points = { make_constant_input(generator_x),
425 make_constant_input(generator_y) },
426 .scalars = witnesses.next_inputs(2),
428 .outputs = witnesses.next_witness_array<2>(),
432 const std::vector<uint32_t> relevant_witnesses = { 0, 1, 2, 3, 5, 6, 7, 8 };
434 EXPECT_EQ(count_acir_components_for_witnesses(circuit, relevant_witnesses), 2U);
435 EXPECT_EQ(count_circuit_components_for_witnesses(circuit, relevant_witnesses), 1U);
446 .init = { make_witness(0), make_witness(1) },
455 .index = make_witness(2),
456 .value = make_witness(3),
461 expect_no_component_errors(run_components_check(circuit));
474 .
value = { make_witness_expression(1),
475 make_witness_expression(2) } } },
485 make_witness(5) } } },
487 .predicate = make_constant_expression(
bb::fr::one()),
491 expect_no_component_errors(run_components_check(circuit));
500 .inputs = { make_witness(0), make_witness(1) },
501 .outputs = { make_witness(2) },
502 .predicate = make_constant_expression(
bb::fr::one()),
536 auto builder = create_circuit<AcirComponentsCheckBuilder>(program);
541 auto errors = checker.
check();
561 auto builder = create_circuit<AcirComponentsCheckBuilder>(program);
563 builder.real_variable_index.resize(9);
566 auto errors = checker.
check();
581 .public_parameters = {},
585 expect_no_component_errors(run_components_check(circuit));
601 expect_no_component_errors(run_components_check(circuit));
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
static void SetUpTestSuite()
Undirected graph on ACIR witness indices; connected components = "ACIR components".
std::unordered_map< uint32_t, size_t > get_witness_component_map() const
Map each witness that appears in at least one edge to a component id.
void process_acir_circuit(const Acir::Circuit &circuit)
Walk circuit.opcodes, populate adjacency, then merge per-block memory witnesses.
Structural comparison between ACIR-level and circuit-level connected components.
std::vector< Error > check()
Run the full check. Returns list of errors (empty = pass).
static constexpr affine_element affine_one
TEST_F(AcirComponentsCheckTest, SingleLinearConstraintLinksTwoWitnesses)
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
field< Bn254FrParams > fr
UltraCircuitBuilder_< UltraExecutionTraceBlocks > UltraCircuitBuilder
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
bb::VectorAffineElementPushSpan< BaseParams > rhs
std::vector< Acir::FunctionInput > inputs
std::vector< Acir::FunctionInput > inputs
std::vector< Acir::FunctionInput > inputs
std::shared_ptr< std::array< Acir::FunctionInput, 32 > > public_key_x
std::shared_ptr< std::array< Acir::FunctionInput, 32 > > public_key_x
std::shared_ptr< std::array< Acir::FunctionInput, 2 > > input1
std::shared_ptr< std::array< Acir::FunctionInput, 25 > > inputs
std::vector< Acir::FunctionInput > points
std::vector< Acir::FunctionInput > inputs
Acir::FunctionInput input
std::vector< Acir::FunctionInput > verification_key
std::shared_ptr< std::array< Acir::FunctionInput, 16 > > inputs
std::variant< AES128Encrypt, AND, XOR, RANGE, Blake2s, Blake3, EcdsaSecp256k1, EcdsaSecp256r1, MultiScalarMul, EmbeddedCurveAdd, Keccakf1600, RecursiveAggregation, Poseidon2Permutation, Sha256Compression > value
std::variant< Memory, CallData, ReturnData > value
std::vector< Acir::Witness > value
std::variant< Simple, Array > value
std::vector< Acir::Opcode > opcodes
std::vector< std::tuple< std::vector< uint8_t >, Acir::Witness > > linear_combinations
std::vector< std::tuple< std::vector< uint8_t >, Acir::Witness, Acir::Witness > > mul_terms
Acir::BlackBoxFuncCall value
std::variant< AssertZero, BlackBoxFuncCall, MemoryOp, MemoryInit, BrilligCall, Call > value
static constexpr field one()
BB_INLINE std::vector< uint8_t > to_buffer() const
static constexpr field zero()