Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ram_table.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Raju], commit: 05a381f8b31ae4648e480f1369e911b148216e8b}
3// external_1: { status: Complete, auditors: [Sherlock], commit: e6694849223 }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#include "ram_table.hpp"
8
9#include "../circuit_builders/circuit_builders.hpp"
13#include <vector>
14
15namespace bb::stdlib {
16
23template <typename Builder>
25 : raw_entries(table_entries)
26 , length(table_entries.size())
28{
29 index_initialized.resize(length, false);
30
31 // For consistency with the other constructor, we delegate the initialization of the table to the first read
32 // operation.
33
34 // Store tags
35 _tags.resize(length);
36 for (size_t i = 0; i < length; i++) {
37 _tags[i] = table_entries[i].get_origin_tag();
38 }
39}
40
48template <typename Builder>
50 : raw_entries(table_entries)
51 , length(raw_entries.size())
52{
53 for (const auto& entry : table_entries) {
54 if (entry.get_context() != nullptr) {
55 context = entry.get_context();
56 break;
57 }
58 }
59
60 index_initialized.resize(length, false);
61
62 // Do not initialize the table yet. The input entries might all be constant,
63 // if this is the case we might not have a valid pointer to a Builder
64 // We get around this, by initializing the table when `read` or `write` operator is called
65 // with a non-const field element.
66
67 // Store tags
68 _tags.resize(length);
69 for (size_t i = 0; i < length; i++) {
70 _tags[i] = table_entries[i].get_origin_tag();
71 }
72}
73
83template <typename Builder> void ram_table<Builder>::initialize_table() const
84{
85 if (ram_table_generated_in_builder) {
86 return;
87 }
88 // only call this when there is a context
89 BB_ASSERT(context != nullptr);
90 ram_id = context->create_RAM_array(length);
91
92 if (raw_entries.size() > 0) {
93 for (size_t i = 0; i < length; ++i) {
94 if (!index_initialized[i]) {
95 field_pt entry;
96 if (raw_entries[i].is_constant()) {
98 context->put_constant_variable(raw_entries[i].get_value()));
99 } else {
100 entry = raw_entries[i];
101 }
102 context->init_RAM_element(ram_id, i, entry.get_witness_index());
103 index_initialized[i] = true;
104 }
105 }
106 }
107
108 // Store the tags of the original entries
109 _tags.resize(length);
110 if (raw_entries.size() > 0) {
111 for (size_t i = 0; i < length; i++) {
112 _tags[i] = raw_entries[i].get_origin_tag();
113 }
114 }
115 ram_table_generated_in_builder = true;
116}
117// constructors and move operators
118template <typename Builder> ram_table<Builder>::ram_table(const ram_table& other) = default;
119
120template <typename Builder>
122 : raw_entries(std::move(other.raw_entries))
123 , _tags(std::move(other._tags))
124 , index_initialized(std::move(other.index_initialized))
125 , length(other.length)
126 , ram_id(other.ram_id)
127 , ram_table_generated_in_builder(other.ram_table_generated_in_builder)
128 , all_entries_written_to_with_constant_index(other.all_entries_written_to_with_constant_index)
129 , context(other.context)
130{
131 other.length = 0;
132 other.ram_id = 0;
133 other.ram_table_generated_in_builder = false;
134 other.all_entries_written_to_with_constant_index = false;
135 other.context = nullptr;
136}
137
138template <typename Builder> ram_table<Builder>& ram_table<Builder>::operator=(const ram_table& other) = default;
139
140template <typename Builder> ram_table<Builder>& ram_table<Builder>::operator=(ram_table&& other) noexcept
141{
142 if (this != &other) {
143 raw_entries = std::move(other.raw_entries);
144 _tags = std::move(other._tags);
145 index_initialized = std::move(other.index_initialized);
146 length = other.length;
147 ram_id = other.ram_id;
148 ram_table_generated_in_builder = other.ram_table_generated_in_builder;
149 all_entries_written_to_with_constant_index = other.all_entries_written_to_with_constant_index;
150 context = other.context;
151
152 other.length = 0;
153 other.ram_id = 0;
154 other.ram_table_generated_in_builder = false;
155 other.all_entries_written_to_with_constant_index = false;
156 other.context = nullptr;
157 }
158 return *this;
159}
160
168template <typename Builder> field_t<Builder> ram_table<Builder>::read(const field_pt& index) const
169{
170 if (context == nullptr) {
173 context,
174 nullptr,
175 "ram_table: Performing a read operation without providing a context. We cannot initialize the table.");
176 }
177
178 // When we perform the first read operation, we initialize the table
179 initialize_table();
180
181 const auto native_index = uint256_t(index.get_value());
182 if (native_index >= length) {
183 // set a failure when the index is out of bounds. another error will be thrown when we try to call
184 // `read_RAM_array`.
185 context->failure("ram_table: RAM array access out of bounds");
186 }
187
188 if (!check_indices_initialized()) {
189 context->failure("ram_table must have initialized every RAM entry before the table can be read");
190 }
191
192 field_pt index_wire = index;
193 if (index.is_constant()) {
194 index_wire = field_pt::from_witness_index(context, context->put_constant_variable(index.get_value()));
195 }
196
197 uint32_t output_idx = context->read_RAM_array(ram_id, index_wire.get_witness_index());
198 auto element = field_pt::from_witness_index(context, output_idx);
199
200 const size_t cast_index = static_cast<size_t>(static_cast<uint64_t>(native_index));
201 // If the index is legitimate, restore the tag
202 if (native_index < length) {
203 element.set_origin_tag(_tags[cast_index]);
204 }
205 return element;
206}
207
217template <typename Builder> void ram_table<Builder>::write(const field_pt& index, const field_pt& value)
218{
219 if (context == nullptr) {
220 context = index.get_context();
222 context,
223 nullptr,
224 "ram_table: Performing a write operation without providing a context. We cannot initialize the table.");
225 }
226
227 // When we perform the first read operation, we initialize the table
228 initialize_table();
229
230 if (uint256_t(index.get_value()) >= length) {
231 // set a failure when the index is out of bounds. an error will be thrown when we try to call either
232 // `init_RAM_element` or `write_RAM_array`.
233 context->failure("ram_table: RAM array access out of bounds");
234 }
235
236 field_pt index_wire = index;
237 const auto native_index = uint256_t(index.get_value());
238 if (index.is_constant()) {
239 // need to write/process every array element at constant indicies before doing reads/writes at prover-defined
240 // indices
242 } else {
243 if (!check_indices_initialized()) {
244 context->failure("ram_table must have initialized every RAM entry before a write can be performed");
245 }
246 }
247
248 field_pt value_wire = value;
249 auto native_value = value.get_value();
250 if (value.is_constant()) {
251 value_wire = field_pt::from_witness_index(context, context->put_constant_variable(native_value));
252 }
253
254 const size_t cast_index = static_cast<size_t>(static_cast<uint64_t>(native_index));
255 if (index.is_constant() && !index_initialized[cast_index]) {
256 context->init_RAM_element(ram_id, cast_index, value_wire.get_witness_index());
257
258 index_initialized[cast_index] = true;
259 } else {
260 context->write_RAM_array(ram_id, index_wire.get_witness_index(), value_wire.get_witness_index());
261 }
262 // Update the value of the stored tag, if index is legitimate
263
264 if (native_index < length) {
265 _tags[cast_index] = value.get_origin_tag();
266 }
267}
268
271} // namespace bb::stdlib
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_ASSERT_NEQ(actual, expected,...)
Definition assert.hpp:98
static field_t from_witness_index(Builder *ctx, uint32_t witness_index)
Definition field.cpp:67
Builder * get_context() const
Definition field.hpp:431
OriginTag get_origin_tag() const
Definition field.hpp:358
void convert_constant_to_fixed_witness(Builder *ctx)
Definition field.hpp:456
uint32_t get_witness_index() const
Get the witness index of the current field element.
Definition field.hpp:518
ram_table & operator=(const ram_table &other)
std::vector< bool > index_initialized
Definition ram_table.hpp:59
field_pt read(const field_pt &index) const
Read a field element from the RAM table at an index value.
std::vector< OriginTag > _tags
Definition ram_table.hpp:58
void write(const field_pt &index, const field_pt &value)
Write a field element from the RAM table at an index value.
void initialize_table() const
internal method, is used to call Builder methods that will generate RAM table.
Definition ram_table.cpp:83
AluTraceBuilder builder
Definition alu.test.cpp:124
StrictMock< MockContext > context
uint8_t const size_t length
Definition data_store.hpp:9
std::conditional_t< IsGoblinBigGroup< C, Fq, Fr, G >, element_goblin::goblin_element< C, goblin_field< C >, Fr, G >, element_default::element< C, Fq, Fr, G > > element
element wraps either element_default::element or element_goblin::goblin_element depending on parametr...
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
This file contains part of the logic for the Origin Tag mechanism that tracks the use of in-circuit p...