17 for (
size_t i = 0; i < array_size; ++i) {
18 new_transcript.
state.emplace_back(
19 std::array<uint32_t, 2>{ UNINITIALIZED_MEMORY_RECORD, UNINITIALIZED_MEMORY_RECORD });
21 rom_arrays.emplace_back(new_transcript);
22 return rom_arrays.size() - 1;
34template <
typename ExecutionTrace>
37 const size_t index_value,
38 const uint32_t value_witness)
45 "ROM array: single-value op issued on an array already using pair gates");
47 const uint32_t index_witness =
48 (index_value == 0) ?
builder->zero_idx() :
builder->put_constant_variable((uint64_t)index_value);
56 .value_column1_witness = value_witness,
57 .value_column2_witness =
builder->zero_idx(),
58 .index =
static_cast<uint32_t
>(index_value),
63 rom_array.
state[index_value][0] = value_witness;
65 create_ROM_logup_gate(
builder, new_record, rom_id,
false);
66 rom_array.
records.emplace_back(new_record);
71template <
typename ExecutionTrace>
74 const size_t index_value,
75 const std::array<uint32_t, 2>& value_witnesses)
79 BB_ASSERT(!rom_array.
use_logup,
"ROM array: pair op issued on an array already using LogUp single-value gates");
80 const uint32_t index_witness =
builder->put_constant_variable((uint64_t)index_value);
85 .value_column1_witness = value_witnesses[0],
86 .value_column2_witness = value_witnesses[1],
87 .index =
static_cast<uint32_t
>(index_value),
92 rom_array.
state[index_value][0] = value_witnesses[0];
93 rom_array.
state[index_value][1] = value_witnesses[1];
95 create_ROM_gate(
builder, new_record);
96 rom_array.
records.emplace_back(new_record);
99template <
typename ExecutionTrace>
102 const uint32_t index_witness)
107 "ROM array: single-value read issued before any set_ROM_element; or pair-ops already started");
112 const uint32_t value_witness =
builder->add_variable(
value);
115 .value_column1_witness = value_witness,
116 .value_column2_witness =
builder->zero_idx(),
122 create_ROM_logup_gate(
builder, new_record, rom_id,
true);
123 rom_array.
records.emplace_back(new_record);
125 return value_witness;
128template <
typename ExecutionTrace>
131 const uint32_t index_witness)
133 std::array<uint32_t, 2> value_witnesses;
138 BB_ASSERT(!rom_array.
use_logup,
"ROM array: pair read issued on an array already using LogUp single-value gates");
144 value_witnesses[0] =
builder->add_variable(value1);
145 value_witnesses[1] =
builder->add_variable(value2);
148 .value_column1_witness = value_witnesses[0],
149 .value_column2_witness = value_witnesses[1],
155 create_ROM_gate(
builder, new_record);
156 rom_array.
records.emplace_back(new_record);
158 return value_witnesses;
165template <
typename ExecutionTrace>
171 auto row =
builder->memory_selectors_row(CircuitBuilder::MEMORY_SELECTORS::ROM_READ);
175 builder->blocks.memory.append_gate(row);
179 builder->increment_num_gates();
182template <
typename ExecutionTrace>
189 auto row =
builder->memory_selectors_row(CircuitBuilder::MEMORY_SELECTORS::ROM_CONSISTENCY_CHECK);
193 builder->blocks.memory.append_gate(row);
197 builder->increment_num_gates();
211template <
typename ExecutionTrace>
221 auto row =
builder->memory_selectors_row(is_read ? CircuitBuilder::MEMORY_SELECTORS::ROM_LOGUP_READ
222 : CircuitBuilder::MEMORY_SELECTORS::ROM_LOGUP_TABLE);
228 row.q_c =
FF(
static_cast<uint64_t
>(rom_id));
229 builder->blocks.memory.append_gate(row);
233 builder->increment_num_gates();
236template <
typename ExecutionTrace>
239 auto& rom_array = rom_arrays[rom_id];
243 const auto read_tag =
builder->get_new_tag();
244 const auto sorted_list_tag =
builder->get_new_tag();
245 builder->set_tau_transposition(read_tag, sorted_list_tag);
248 for (
size_t i = 0; i < rom_array.state.size(); ++i) {
249 BB_ASSERT_NEQ(rom_array.state[i][0], UNINITIALIZED_MEMORY_RECORD);
250 BB_ASSERT_NEQ(rom_array.state[i][1], UNINITIALIZED_MEMORY_RECORD);
254 std::sort(rom_array.records.begin(), rom_array.records.end());
256 std::sort(std::execution::par_unseq, rom_array.records.begin(), rom_array.records.end());
272 for (
size_t i = 0; i < rom_array.records.size(); ++i) {
273 const RomRecord& record = rom_array.records[i];
277 uint32_t index_witness;
280 index_witness =
builder->zero_idx();
281 }
else if (i == rom_array.records.size() - 1) {
283 index_witness =
builder->put_constant_variable(
static_cast<uint64_t
>(rom_array.state.size()) - 1);
286 builder->update_used_witnesses(index_witness);
288 const auto value1_witness =
builder->add_variable(value1);
289 const auto value2_witness =
builder->add_variable(value2);
294 .value_column1_witness = value1_witness,
295 .value_column2_witness = value2_witness,
302 create_sorted_ROM_gate(
builder, sorted_record);
305 builder->assign_tag(sorted_record.record_witness, sorted_list_tag);
317 builder->memory_read_records.push_back(
static_cast<uint32_t
>(sorted_record.gate_index));
318 builder->memory_read_records.push_back(
static_cast<uint32_t
>(record.
gate_index));
333 FF max_index_value((uint64_t)rom_array.state.size());
334 uint32_t max_index =
builder->add_variable(max_index_value);
336 builder->create_unconstrained_gate(
353template <
typename ExecutionTrace>
356 auto& rom_array = rom_arrays[rom_id];
361 for (
size_t i = 0; i < rom_array.state.size(); ++i) {
362 BB_ASSERT_NEQ(rom_array.state[i][0], UNINITIALIZED_MEMORY_RECORD);
366 std::vector<size_t> table_row_gate_indices(rom_array.state.size(), 0);
367 std::vector<uint64_t> read_counts(rom_array.state.size(), 0);
368 for (
const auto& record : rom_array.records) {
370 table_row_gate_indices[record.index] = record.gate_index;
372 read_counts[record.index]++;
379 for (
size_t i = 0; i < rom_array.state.size(); ++i) {
380 const uint32_t count_witness =
builder->add_variable(
FF(read_counts[i]));
381 builder->update_used_witnesses(count_witness);
382 builder->blocks.memory.w_o()[table_row_gate_indices[i]] = count_witness;
388 for (
size_t i = 0; i < rom_arrays.size(); ++i) {
389 if (rom_arrays[i].use_logup) {
390 process_ROM_logup_array(
builder, i);
400 for (
size_t i = 0; i < array_size; ++i) {
401 new_transcript.
state.emplace_back(UNINITIALIZED_MEMORY_RECORD);
403 ram_arrays.emplace_back(new_transcript);
404 return ram_arrays.size() - 1;
421template <
typename ExecutionTrace>
424 const size_t index_value,
425 const uint32_t value_witness)
429 const uint32_t index_witness =
430 (index_value == 0) ?
builder->zero_idx() :
builder->put_constant_variable((uint64_t)index_value);
435 .value_witness = value_witness,
436 .index =
static_cast<uint32_t
>(index_value),
441 ram_array.
state[index_value] = value_witness;
445 create_RAM_gate(
builder, new_record);
446 ram_array.
records.emplace_back(new_record);
449template <
typename ExecutionTrace>
452 const uint32_t index_witness)
460 const uint32_t value_witness =
builder->add_variable(
value);
464 .value_witness = value_witness,
472 create_RAM_gate(
builder, new_record);
473 ram_array.
records.emplace_back(new_record);
480 return value_witness;
494template <
typename ExecutionTrace>
497 const uint32_t index_witness,
498 const uint32_t value_witness)
508 .value_witness = value_witness,
515 create_RAM_gate(
builder, new_record);
516 ram_array.
records.emplace_back(new_record);
526template <
typename ExecutionTrace>
536 ? CircuitBuilder::MEMORY_SELECTORS::RAM_READ
537 : CircuitBuilder::MEMORY_SELECTORS::RAM_WRITE);
539 builder->blocks.memory.append_gate(row);
544 builder->increment_num_gates();
547template <
typename ExecutionTrace>
552 auto row =
builder->memory_selectors_row(CircuitBuilder::MEMORY_SELECTORS::RAM_CONSISTENCY_CHECK);
554 builder->blocks.memory.append_gate(row);
558 builder->increment_num_gates();
561template <
typename ExecutionTrace>
564 const size_t ram_array_size)
588 -
FF(
static_cast<uint64_t
>(ram_array_size) - 1),
605template <
typename ExecutionTrace>
609 const auto access_tag =
builder->get_new_tag();
610 const auto sorted_list_tag =
builder->get_new_tag();
614 builder->set_tau_transposition(access_tag, sorted_list_tag);
620 for (
size_t i = 0; i < ram_array.
state.size(); ++i) {
638 for (
size_t i = 0; i < ram_array.
records.size(); ++i) {
645 const uint32_t index_witness =
648 const auto value_witness =
builder->add_variable(
value);
653 .timestamp_witness = timestamp_witess,
654 .value_witness = value_witness,
663 sorted_ram_records.emplace_back(sorted_record);
667 if (i < ram_array.
records.size() - 1) {
668 create_sorted_RAM_gate(
builder, sorted_record);
672 create_final_sorted_RAM_gate(
builder, sorted_record, ram_array.
state.size());
677 builder->assign_tag(sorted_record.record_witness, sorted_list_tag);
689 builder->memory_read_records.push_back(
static_cast<uint32_t
>(sorted_record.gate_index));
690 builder->memory_read_records.push_back(
static_cast<uint32_t
>(record.
gate_index));
694 builder->memory_write_records.push_back(
static_cast<uint32_t
>(sorted_record.gate_index));
695 builder->memory_write_records.push_back(
static_cast<uint32_t
>(record.
gate_index));
706 std::vector<uint32_t> timestamp_deltas;
708 if (sorted_ram_records.size() <= 1) {
711 for (
size_t i = 0; i < sorted_ram_records.size() - 1; ++i) {
712 const auto& current = sorted_ram_records[i];
713 const auto& next = sorted_ram_records[i + 1];
715 const bool share_index = current.index == next.index;
717 FF timestamp_delta = 0;
720 timestamp_delta =
FF(next.timestamp - current.timestamp);
723 uint32_t timestamp_delta_witness =
builder->add_variable(timestamp_delta);
728 auto row =
builder->memory_selectors_row(CircuitBuilder::MEMORY_SELECTORS::RAM_TIMESTAMP_CHECK);
730 current.index_witness, current.timestamp_witness, timestamp_delta_witness,
builder->zero_idx()
732 builder->blocks.memory.append_gate(row);
735 builder->increment_num_gates();
739 timestamp_deltas.push_back(timestamp_delta_witness);
744 const auto& last = sorted_ram_records[ram_array.
records.size() - 1];
745 builder->create_unconstrained_gate(
746 builder->blocks.memory, last.index_witness, last.timestamp_witness,
builder->zero_idx(),
builder->zero_idx());
766 const uint32_t max_timestamp = ram_array.
access_count - 1;
767 for (
auto& w : timestamp_deltas) {
768 builder->create_small_range_constraint(w, max_timestamp);
774 for (
size_t i = 0; i < ram_arrays.size(); ++i) {
#define BB_ASSERT(expression,...)
#define BB_ASSERT_GT(left, right,...)
#define BB_ASSERT_NEQ(actual, expected,...)
#define BB_ASSERT_EQ(actual, expected,...)
#define BB_ASSERT_LT(left, right,...)
bb::field< bb::Bn254FrParams > FF
ROM/RAM logic handler for UltraCircuitBuilder.
size_t create_ROM_array(const size_t array_size)
Create a new read-only memory region.
uint32_t read_ROM_array(CircuitBuilder *builder, const size_t rom_id, const uint32_t index_witness)
Read a single element from ROM.
void process_ROM_array(CircuitBuilder *builder, const size_t rom_id)
Compute additional gates required to validate ROM reads. Called when generating the proving key.
void process_ROM_logup_array(CircuitBuilder *builder, const size_t rom_id)
Finalize a LogUp-style ROM array.
void create_sorted_RAM_gate(CircuitBuilder *builder, RamRecord &record)
Gate that performs consistency checks to validate that a claimed RAM read/write value is correct.
void process_ROM_arrays(CircuitBuilder *builder)
Process all of the ROM arrays.
std::array< uint32_t, 2 > read_ROM_array_pair(CircuitBuilder *builder, const size_t rom_id, const uint32_t index_witness)
Read a pair of elements from ROM.
void set_ROM_element(CircuitBuilder *builder, const size_t rom_id, const size_t index_value, const uint32_t value_witness)
Initialize a rom cell to equal value_witness
void create_final_sorted_RAM_gate(CircuitBuilder *builder, RamRecord &record, const size_t ram_array_size)
Performs consistency checks to validate that a claimed RAM read/write value is correct....
void create_ROM_logup_gate(CircuitBuilder *builder, RomRecord &record, const size_t rom_id, const bool is_read)
Emit a ROM-LogUp gate (table entry or read access) at circuit construction time.
void process_RAM_arrays(CircuitBuilder *builder)
void init_RAM_element(CircuitBuilder *builder, const size_t ram_id, const size_t index_value, const uint32_t value_witness)
Initialize a RAM cell to equal value_witness
void create_sorted_ROM_gate(CircuitBuilder *builder, RomRecord &record)
Gate that performs consistency checks to validate that a claimed ROM read value is correct.
void write_RAM_array(CircuitBuilder *builder, const size_t ram_id, const uint32_t index_witness, const uint32_t value_witness)
Write a cell in a RAM array.
void set_ROM_element_pair(CircuitBuilder *builder, const size_t rom_id, const size_t index_value, const std::array< uint32_t, 2 > &value_witnesses)
Initialize a ROM array element with a pair of witness values.
void create_ROM_gate(CircuitBuilder *builder, RomRecord &record)
Gate that'reads' from a ROM table, i.e., the table index is a witness not precomputed.
uint32_t read_RAM_array(CircuitBuilder *builder, const size_t ram_id, const uint32_t index_witness)
typename ExecutionTrace::FF FF
void create_RAM_gate(CircuitBuilder *builder, RamRecord &record)
Gate that performs a read/write operation into a RAM table, i.e. table index is a witness not precomp...
void process_RAM_array(CircuitBuilder *builder, const size_t ram_id)
Compute additional gates required to validate RAM read/writes. Called when generating the proving key...
size_t create_RAM_array(const size_t array_size)
Create a new updatable memory region.
Entry point for Barretenberg command-line interface.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
A RAM memory record that can be ordered, first by index, then by timestamp.
uint32_t timestamp_witness
RamTranscript contains the RamRecords for a particular RAM table (recording READ and WRITE operations...
std::vector< RamRecord > records
std::vector< uint32_t > state
A ROM memory record that can be ordered, where the ordering is given by the index (a....
uint32_t value_column1_witness
uint32_t value_column2_witness
RomTranscript contains the RomRecords for a particular ROM table as well as the vector whose ith entr...
std::vector< std::array< uint32_t, 2 > > state
std::vector< RomRecord > records
void throw_or_abort(std::string const &err)