Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
twin_rom_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 "twin_rom_table.hpp"
8
9#include "../circuit_builders/circuit_builders.hpp"
11
12using namespace bb;
13
14namespace bb::stdlib {
15
16template <typename Builder>
18 : raw_entries(table_entries)
19 , length(raw_entries.size())
20{
21 // get the builder context
22 for (const auto& entry : table_entries) {
23 if (entry[0].get_context() != nullptr) {
24 context = entry[0].get_context();
25 break;
26 }
27 if (entry[1].get_context() != nullptr) {
28 context = entry[1].get_context();
29 break;
30 }
31 }
32
33 // We do not initialize the table yet. The input entries might all be constant,
34 // if this is the case we might not have a valid pointer to a Builder
35 // We get around this, by initializing the table when `operator[]` is called
36 // with a non-const field element.
37
38 // Ensure that the origin tags of all entries are preserved so we can assign them on lookups
39 _tags.resize(length);
40 for (size_t i = 0; i < length; ++i) {
41 _tags[i] = { raw_entries[i][0].get_origin_tag(), raw_entries[i][1].get_origin_tag() };
42 }
43}
44
45// initialize the table once we perform a read. This ensures we always have a valid
46// pointer to a Builder.
47// (if both the table entries and the index are constant, we don't need a builder as we
48// can directly extract the desired value from `raw_entries`)
49template <typename Builder> void twin_rom_table<Builder>::initialize_table() const
50{
51 if (initialized) {
52 return;
53 }
54 BB_ASSERT_EQ(context != nullptr, true, "twin_rom_table: context must be set before initializing the table");
55
56 // populate table. Table entries must be normalized and cannot be constants
57 for (const auto& entry : raw_entries) {
58 field_pt first;
59 field_pt second;
60 if (entry[0].is_constant()) {
61 first = field_pt::from_witness_index(context, context->put_constant_variable(entry[0].get_value()));
62 } else {
63 first = entry[0];
64 }
65 if (entry[1].is_constant()) {
66 second = field_pt::from_witness_index(context, context->put_constant_variable(entry[1].get_value()));
67 } else {
68 second = entry[1];
69 }
70 entries.emplace_back(field_pair_pt{ first, second });
71 }
72
73 // create uninitialized table of size `length`
74 rom_id = context->create_ROM_array(length);
75
76 for (size_t i = 0; i < length; ++i) {
77 context->set_ROM_element_pair(
78 rom_id, i, std::array<uint32_t, 2>{ entries[i][0].get_witness_index(), entries[i][1].get_witness_index() });
79 }
80
81 // Ensure that the origin tags of all entries are preserved so we can assign them on lookups
82 _tags.resize(length);
83 for (size_t i = 0; i < length; ++i) {
84 _tags[i] = { raw_entries[i][0].get_origin_tag(), raw_entries[i][1].get_origin_tag() };
85 }
86 initialized = true;
87}
88
89template <typename Builder> twin_rom_table<Builder>::twin_rom_table(const twin_rom_table& other) = default;
90
91template <typename Builder>
93 : raw_entries(std::move(other.raw_entries))
94 , entries(std::move(other.entries))
95 , _tags(std::move(other._tags))
96 , length(other.length)
97 , rom_id(other.rom_id)
98 , initialized(other.initialized)
99 , context(other.context)
100{
101 other.length = 0;
102 other.rom_id = 0;
103 other.initialized = false;
104 other.context = nullptr;
105}
106
107template <typename Builder>
109
111{
112 if (this != &other) {
113 raw_entries = std::move(other.raw_entries);
114 entries = std::move(other.entries);
115 _tags = std::move(other._tags);
116 length = other.length;
117 rom_id = other.rom_id;
118 initialized = other.initialized;
119 context = other.context;
120
121 other.length = 0;
122 other.rom_id = 0;
123 other.initialized = false;
124 other.context = nullptr;
125 }
126 return *this;
127}
128
129template <typename Builder>
131{
132 if (index >= length) {
133 BB_ASSERT(context != nullptr);
134 context->failure("twin_rom_table: ROM array access out of bounds");
135 }
136
137 return raw_entries[index];
138}
139
140template <typename Builder>
142{
143 if (index.is_constant()) {
144 return operator[](static_cast<size_t>(uint256_t(index.get_value()).data[0]));
145 }
146 if (context == nullptr) {
147 context = index.get_context();
148 }
149
150 initialize_table();
151 if (uint256_t(index.get_value()) >= length) {
152 context->failure("twin_rom_table: ROM array access out of bounds");
153 }
154
155 auto output_indices = context->read_ROM_array_pair(rom_id, index.get_witness_index());
156 auto pair = field_pair_pt{
157 field_pt::from_witness_index(context, output_indices[0]),
158 field_pt::from_witness_index(context, output_indices[1]),
159 };
160
161 const auto native_index = uint256_t(index.get_value());
162 const size_t cast_index = static_cast<size_t>(static_cast<uint64_t>(native_index));
163 // In case of a legitimate lookup, restore the tags of the original entries to the output
164 if (native_index < length) {
165 pair[0].set_origin_tag(_tags[cast_index][0]);
166 pair[1].set_origin_tag(_tags[cast_index][1]);
167 }
168 return pair;
169}
170
173} // namespace bb::stdlib
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
static field_t from_witness_index(Builder *ctx, uint32_t witness_index)
Definition field.cpp:67
OriginTag get_origin_tag() const
Definition field.hpp:358
std::array< field_pt, 2 > field_pair_pt
StrictMock< MockContext > context
uint8_t const size_t length
Definition data_store.hpp:9
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13