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