5#include <unordered_set>
9template <>
auto UltraCircuitChecker::init_empty_values<UltraCircuitBuilder_<UltraExecutionTraceBlocks>>()
14template <>
auto UltraCircuitChecker::init_empty_values<MegaCircuitBuilder_<bb::fr>>()
25 if (!
builder.circuit_finalized) {
33MegaCircuitBuilder_<bb::fr> UltraCircuitChecker::prepare_circuit<MegaCircuitBuilder_<bb::fr>>(
34 const MegaCircuitBuilder_<bb::fr>& builder_in)
37 MegaCircuitBuilder_<bb::fr>
builder{ builder_in };
42 if (!
builder.circuit_finalized) {
51 if (builder_in.failed()) {
52 info(
"CircuitChecker: circuit contains invalid witnesses: ", builder_in.err());
59 for (
const auto& table :
builder.get_lookup_tables()) {
60 const FF table_index(table.table_index);
61 for (
size_t i = 0; i < table.size(); ++i) {
62 lookup_hash_table.insert({ table.column_1[i], table.column_2[i], table.column_3[i], table_index });
72 for (
auto& block :
builder.blocks.get()) {
73 result = result &&
check_block(
builder, block, tag_data, memory_data, lookup_hash_table);
75#ifndef FUZZING_DISABLE_WARNINGS
76 info(
"Failed at block idx = ", block_idx);
86 result = result & relaxed_check_delta_range_relation(
builder);
90 result = result & relaxed_check_memory_relation(
builder);
99 info(
"Failed tag check.");
107template <
typename Builder>
115 auto values = init_empty_values<Builder>();
117 params.
eta = memory_data.
eta;
121 auto report_fail = [&](
const char* message,
size_t row_idx) {
122#ifndef FUZZING_DISABLE_WARNINGS
123 info(message, row_idx);
128#ifdef CHECK_CIRCUIT_STACKTRACES
129 block.stack_traces.print(row_idx);
136 for (
size_t idx = 0; idx < block.size(); ++idx) {
140 result = result && check_relation<Arithmetic>(values, params);
142 return report_fail(
"Failed Arithmetic relation at row idx = ", idx);
144 result = result && check_relation<Elliptic>(values, params);
146 return report_fail(
"Failed Elliptic relation at row idx = ", idx);
149 result = result && check_relation<Memory>(values, params);
151 return report_fail(
"Failed Memory relation at row idx = ", idx);
153 result = result && check_relation<NonNativeField>(values, params);
155 return report_fail(
"Failed NonNativeField relation at row idx = ", idx);
157 result = result && check_relation<DeltaRangeConstraint>(values, params);
159 return report_fail(
"Failed DeltaRangeConstraint relation at row idx = ", idx);
163 if (values.q_nnf == 1) {
164 bool f0 = values.q_o == 1 && (values.q_4 == 1 || values.q_m == 1);
165 bool f1 = values.q_r == 1 && (values.q_o == 1 || values.q_4 == 1 || values.q_m == 1);
167 result = result && check_relation<NonNativeField>(values, params);
169 return report_fail(
"Failed NonNativeField relation at row idx = ", idx);
174 result = result &&
check_lookup(values, lookup_hash_table);
176 return report_fail(
"Failed Lookup check relation at row idx = ", idx);
181 result = result && check_relation<PoseidonInternal>(values, params);
183 return report_fail(
"Failed PoseidonInternal relation at row idx = ", idx);
186 result = result && check_relation<PoseidonExternal>(values, params);
188 return report_fail(
"Failed PoseidonExternal relation at row idx = ", idx);
192 result = result && check_relation<PoseidonInitialExternal>(values, params);
194 return report_fail(
"Failed PoseidonInitialExternal relation at row idx = ", idx);
196 result = result && check_relation<PoseidonQuadInternal>(values, params);
198 return report_fail(
"Failed PoseidonQuadInternal relation at row idx = ", idx);
200 result = result && check_relation<PoseidonQuadInternalTerminal>(values, params);
202 return report_fail(
"Failed PoseidonQuadInternalTerminal relation at row idx = ", idx);
204 result = result && check_relation<PoseidonTransitionEntry>(values, params);
206 return report_fail(
"Failed PoseidonTransitionEntry relation at row idx = ", idx);
210 return report_fail(
"Failed databus read at row idx = ", idx);
217 return report_fail(
"Failed at row idx = ", idx);
228 SubrelationEvaluations subrelation_evaluations;
229 for (
auto& eval : subrelation_evaluations) {
234 Relation::accumulate(subrelation_evaluations, values, params, 1);
237 for (
auto& eval : subrelation_evaluations) {
248 if (!values.q_lookup.is_zero()) {
249 return lookup_hash_table.contains({ values.w_l + values.q_r * values.w_l_shift,
250 values.w_r + values.q_m * values.w_r_shift,
251 values.w_o + values.q_c * values.w_o_shift,
259 if (!values.q_busread.is_zero()) {
261 auto raw_read_idx =
static_cast<size_t>(
uint256_t(values.w_r));
262 auto value = values.w_l;
266 &values.q_l, &values.q_r, &values.q_o, &values.q_4, &values.q_m
272 bool read_matched =
false;
274 if (*bus_selectors[bus_idx] == 1) {
275 const auto& bus_vec =
builder.get_bus_vector(bus_idx);
276 bus_value =
builder.get_variable(bus_vec[raw_read_idx]);
281 return (
value == bus_value);
291template <
typename Builder>
296 auto update_tag_check_data = [&](
const size_t variable_index,
const FF&
value) {
297 size_t real_index =
builder.real_variable_index[variable_index];
302 uint32_t tag_in =
builder.real_variable_tags[real_index];
303 if (tag_in != DEFAULT_TAG) {
304 uint32_t tag_out =
builder.tau().at(tag_in);
312 auto compute_memory_record_term =
313 [](
const FF& w_1,
const FF& w_2,
const FF& w_3,
const FF& eta,
const FF& eta_two,
FF& eta_three) {
314 return (w_3 * eta_three + w_2 * eta_two + w_1 * eta);
318 values.w_l =
builder.get_variable(block.w_l()[idx]);
319 values.w_r =
builder.get_variable(block.w_r()[idx]);
320 values.w_o =
builder.get_variable(block.w_o()[idx]);
323 const bool is_ram_rom_block = (&block == &
builder.blocks.memory);
325 values.w_4 = compute_memory_record_term(
326 values.w_l, values.w_r, values.w_o, memory_data.
eta, memory_data.
eta_two, memory_data.
eta_three);
329 compute_memory_record_term(
330 values.w_l, values.w_r, values.w_o, memory_data.
eta, memory_data.
eta_two, memory_data.
eta_three) +
333 values.w_4 =
builder.get_variable(block.w_4()[idx]);
337 if (idx < block.size() - 1) {
338 values.w_l_shift =
builder.get_variable(block.w_l()[idx + 1]);
339 values.w_r_shift =
builder.get_variable(block.w_r()[idx + 1]);
340 values.w_o_shift =
builder.get_variable(block.w_o()[idx + 1]);
342 values.w_4_shift = compute_memory_record_term(values.w_l_shift,
349 values.w_4_shift = compute_memory_record_term(values.w_l_shift,
357 values.w_4_shift =
builder.get_variable(block.w_4()[idx + 1]);
360 values.w_l_shift = 0;
361 values.w_r_shift = 0;
362 values.w_o_shift = 0;
363 values.w_4_shift = 0;
367 update_tag_check_data(block.w_l()[idx], values.w_l);
368 update_tag_check_data(block.w_r()[idx], values.w_r);
369 update_tag_check_data(block.w_o()[idx], values.w_o);
370 update_tag_check_data(block.w_4()[idx], values.w_4);
373 values.q_m = block.q_m()[idx];
374 values.q_c = block.q_c()[idx];
375 values.q_l = block.q_1()[idx];
376 values.q_r = block.q_2()[idx];
377 values.q_o = block.q_3()[idx];
378 values.q_4 = block.q_4()[idx];
387 values.q_5 = block.q_5()[idx];
411template <
typename Builder>
bool UltraCircuitChecker::relaxed_check_delta_range_relation(
Builder&
builder)
413 std::unordered_map<uint32_t, uint64_t> range_tags;
414 for (
const auto& list :
builder.range_lists) {
415 range_tags[list.second.range_tag] = list.first;
419 for (uint32_t i = 0; i <
builder.real_variable_tags.size(); i++) {
421 if (
tag != 0 && range_tags.contains(
tag)) {
425#ifndef FUZZING_DISABLE_WARNINGS
426 info(
"Failed range constraint on variable with index = ", i,
": ",
value,
" > ", range);
434 auto block =
builder.blocks.delta_range;
435 for (
size_t idx = 0; idx < block.size(); idx++) {
443 bb::fr w5 = idx == block.size() - 1 ?
builder.get_variable(0) :
builder.get_variable(block.w_l()[idx + 1]);
447#ifndef FUZZING_DISABLE_WARNINGS
448 info(
"Failed sort constraint relation at row idx = ", idx,
" with delta1 = ", delta);
455#ifndef FUZZING_DISABLE_WARNINGS
456 info(
"Failed sort constraint relation at row idx = ", idx,
" with delta2 = ", delta);
462#ifndef FUZZING_DISABLE_WARNINGS
463 info(
"Failed sort constraint at row idx = ", idx,
" with delta3 = ", delta);
469#ifndef FUZZING_DISABLE_WARNINGS
470 info(
"Failed sort constraint at row idx = ", idx,
" with delta4 = ", delta);
491template <
typename Builder>
bool UltraCircuitChecker::relaxed_check_memory_relation(
Builder&
builder)
493 for (
size_t i = 0; i <
builder.rom_ram_logic.rom_arrays.size(); i++) {
494 auto rom_array =
builder.rom_ram_logic.rom_arrays[i];
497 for (
auto& rr : rom_array.records) {
498 uint32_t value_witness_1 = rr.value_column1_witness;
499 uint32_t value_witness_2 = rr.value_column2_witness;
500 uint32_t
index =
static_cast<uint32_t
>(
builder.get_variable(rr.index_witness));
502 uint32_t table_witness_1 = rom_array.state[
index][0];
503 uint32_t table_witness_2 = rom_array.state[
index][1];
505 if (
builder.get_variable(value_witness_1) !=
builder.get_variable(table_witness_1)) {
506#ifndef FUZZING_DISABLE_WARNINGS
507 info(
"Failed SET/Read ROM[0] in table = ", i,
" at idx = ",
index);
511 if (
builder.get_variable(value_witness_2) !=
builder.get_variable(table_witness_2)) {
512#ifndef FUZZING_DISABLE_WARNINGS
513 info(
"Failed SET/Read ROM[1] in table = ", i,
" at idx = ",
index);
520 for (
size_t i = 0; i <
builder.rom_ram_logic.ram_arrays.size(); i++) {
521 auto ram_array =
builder.rom_ram_logic.ram_arrays[i];
523 std::vector<uint32_t> tmp_state(ram_array.state.size());
526 for (
auto& rr : ram_array.records) {
527 uint32_t
index =
static_cast<uint32_t
>(
builder.get_variable(rr.index_witness));
528 uint32_t value_witness = rr.value_witness;
529 auto access_type = rr.access_type;
531 uint32_t table_witness = tmp_state[
index];
533 switch (access_type) {
535 if (
builder.get_variable(value_witness) !=
builder.get_variable(table_witness)) {
536#ifndef FUZZING_DISABLE_WARNINGS
537 info(
"Failed RAM read in table = ", i,
" at idx = ",
index);
543 tmp_state[
index] = value_witness;
550 if (tmp_state != ram_array.state) {
551#ifndef FUZZING_DISABLE_WARNINGS
552 info(
"Failed RAM final state check at table = ", i);
562template bool UltraCircuitChecker::check<UltraCircuitBuilder_<UltraExecutionTraceBlocks>>(
563 const UltraCircuitBuilder_<UltraExecutionTraceBlocks>& builder_in);
#define BB_ASSERT(expression,...)
A base class labelling all entities (for instance, all of the polynomials used by the prover during s...
ArrayOfValues< FF, RelationImpl::SUBRELATION_PARTIAL_LENGTHS > SumcheckArrayOfValuesOverSubrelations
std::unordered_set< Key, HashFunction > LookupHashTable
static bool check_databus_read(auto &values, Builder &builder)
Check that the {index, value} pair contained in a databus read gate reflects the actual value present...
static bool check_relation(auto &values, auto ¶ms)
Check that a given relation is satisfied for the provided inputs corresponding to a single row.
static bool check_tag_data(const TagCheckData &tag_data)
Check whether the left and right running tag products are equal.
static bool check_lookup(auto &values, auto &lookup_hash_table)
Check whether the values in a lookup gate are contained within a corresponding hash table.
static void populate_values(Builder &builder, auto &block, auto &values, TagCheckData &tag_data, MemoryCheckData &memory_data, size_t idx)
Populate the values required to check the correctness of a single "row" of the circuit.
static bool check(const Builder &builder_in)
Check the correctness of a circuit witness.
static Builder prepare_circuit(const Builder &builder_in)
Copy the builder and finalize it before checking its validity.
static bool check_block(Builder &builder, auto &block, TagCheckData &tag_data, MemoryCheckData &memory_data, LookupHashTable &lookup_hash_table)
Checks that the provided witness satisfies all gates contained in a single execution trace block.
A field element for each entity of the flavor. These entities represent the prover polynomials evalua...
Entry point for Barretenberg command-line interface.
constexpr size_t NUM_BUS_COLUMNS
The DataBus; facilitates storage of public circuit input/output.
FF read_gate_selector(const ExecutionTraceBlock< FF, NUM_WIRES > &block, GateKind kind, size_t idx)
Gate-selector value at (block, idx) for kind, returning zero if block does not own this kind....
@ Poseidon2QuadIntTerminal
@ Poseidon2TransitionEntry
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Struct for managing memory record data for ensuring RAM/ROM correctness.
std::unordered_set< size_t > read_record_gates
std::unordered_set< size_t > write_record_gates
Struct for managing the running tag product data for ensuring tag correctness.
std::unordered_set< size_t > encountered_variables
static constexpr field one()