Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
dynamic_array.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
7#include "dynamic_array.hpp"
8
9#include "../bool/bool.hpp"
10#include "../circuit_builders/circuit_builders.hpp"
12
13namespace bb::stdlib {
14
28template <typename Builder>
30 : _context(builder)
31 , _max_size(maximum_size)
32 , _length(0)
33{
34 static_assert(HasPlookup<Builder>);
35 ASSERT(_context != nullptr);
36 _inner_table = ram_table(_context, maximum_size);
37 // Initialize the ram table with all zeroes
38 for (size_t i = 0; i < maximum_size; ++i) {
39 _inner_table.write(i, 0);
40 }
41}
42
49template <typename Builder>
51 : _context(other._context)
52 , _max_size(other._max_size)
53 , _length(other._length)
54 , _inner_table(other._inner_table)
55{}
56
63template <typename Builder>
65 : _context(other._context)
66 , _max_size(other._max_size)
67 , _length(other._length)
68 , _inner_table(other._inner_table)
69{}
70
79{
80 _context = other._context;
81 _max_size = other._max_size;
82 _length = other._length;
83 _inner_table = other._inner_table;
84 return *this;
85}
86
95{
96 _context = other._context;
97 _max_size = other._max_size;
98 _length = other._length;
99 _inner_table = other._inner_table;
100 return *this;
101}
102
109template <typename Builder> void DynamicArray<Builder>::resize(const field_pt& new_length, const field_pt default_value)
110{
111 // 1: assert new_length < max_size
112 field_pt max_bounds_check = (field_pt(_max_size) - new_length - 1);
113 if (max_bounds_check.is_constant()) {
114 BB_ASSERT_LTE(uint256_t(new_length.get_value()), _max_size);
115 } else {
116 _context->create_new_range_constraint(max_bounds_check.normalize().get_witness_index(), _max_size);
117 }
118
123 for (size_t i = 0; i < _max_size; ++i) {
124 bool_pt index_valid = bool_pt(witness_pt(_context, (uint256_t)(new_length.get_value()) > i));
125 {
126 // index_delta will be between 0 and length - 1 if index valid
127 // i.e. will pass check that index_delta < _max_size
128 field_pt index_delta = (new_length - i - 1);
129
130 // reverse_delta will be between 0 and (_max_size - length) if *invalid*
131 // i.e. will pass check that reverse_delta < _max_size
132 field_pt reverse_delta = (-new_length + i);
133
134 field_pt bounds_check = field_pt::conditional_assign(index_valid, index_delta, reverse_delta);
135
136 // this should do the same for only 2 gates, but hard to read
137 // field_pt t1 = new_length - i;
138 // field_pt t2 = field_pt(index_valid);
139 // field_pt bounds_check = (t2 + t2).madd(t1 - 1, -t1);
140
141 _context->create_new_range_constraint(bounds_check.normalize().get_witness_index(), _max_size);
142 }
143
144 bool_pt index_currently_invalid = bool_pt(witness_pt(_context, i >= native_size()));
145 {
146 // index_delta will be between 0 and length - 1 if index valid
147 // i.e. will pass check that index_delta < _max_size
148 field_pt index_delta = (_length - i - 1);
149
150 // reverse_delta will be between 0 and (_max_size - length) if *invalid*
151 // i.e. will pass check that reverse_delta < _max_size
152 field_pt reverse_delta = (-_length + i);
153
154 field_pt bounds_check = field_pt::conditional_assign(index_currently_invalid, reverse_delta, index_delta);
155
156 _context->create_new_range_constraint(bounds_check.normalize().get_witness_index(), _max_size);
157 }
158
159 field_pt old_value = _inner_table.read(i);
160 field_pt new_value =
161 field_pt::conditional_assign(index_currently_invalid && index_valid, default_value, old_value);
162 _inner_table.write(i, new_value);
163 }
164
165 _length = new_length;
166}
167
175template <typename Builder> field_t<Builder> DynamicArray<Builder>::read(const field_pt& index) const
176{
177 const field_pt index_delta = (_length - index - 1);
178
179 if (index_delta.is_constant()) {
180 bool valid = (uint256_t(index_delta.get_value()) < _max_size);
181 if (!valid) {
182 _context->failure("DynamicArray::read access out of bounds");
183 }
184 } else {
185 _context->create_new_range_constraint(
186 index_delta.normalize().get_witness_index(), _max_size, "DynamicArray::read access out of bounds");
187 }
188
189 return _inner_table.read(index);
190}
191
199template <typename Builder> void DynamicArray<Builder>::write(const field_pt& index, const field_pt& value)
200{
201 const field_pt index_delta = (_length - index - 1);
202
203 if (index_delta.is_constant()) {
204 bool valid = (uint256_t(index_delta.get_value()) < _max_size);
205 if (!valid) {
206 _context->failure("DynamicArray::read access out of bounds");
207 }
208 } else {
209 _context->create_new_range_constraint(
210 index_delta.normalize().get_witness_index(), _max_size, "DynamicArray::read access out of bounds");
211 }
212
213 _inner_table.write(index, value);
214}
215
222template <typename Builder> void DynamicArray<Builder>::push(const field_pt& value)
223{
224 if (native_size() >= _max_size) {
225 _context->failure("DynamicArray::push array is already at its maximum size");
226 }
227
228 _inner_table.write(_length, value);
229 _length += 1;
230}
231
237template <typename Builder> void DynamicArray<Builder>::pop()
238{
239 if (native_size() == 0) {
240 _context->failure("DynamicArray::pop array is already empty");
241 }
242
243 _length.assert_is_not_zero();
244 _length -= 1;
245}
246
254template <typename Builder>
256{
257 if (native_size() >= _max_size) {
258 _context->failure("DynamicArray::push array is already at its maximum size");
259 }
260
261 _inner_table.write(_length, value);
262 _length += predicate;
263}
264
271template <typename Builder> void DynamicArray<Builder>::conditional_pop(const bool_pt& predicate)
272{
273 if (native_size() == 0) {
274 _context->failure("DynamicArray::pop array is already empty");
275 }
276
277 field_pt length_check = field_pt::conditional_assign(predicate, _length, 1);
278 length_check.assert_is_not_zero();
279 _length -= predicate;
280}
281
284} // namespace bb::stdlib
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:129
#define ASSERT(expression,...)
Definition assert.hpp:49
A dynamic array of field elements.
DynamicArray(Builder *builder, const size_t maximum_size)
Construct a new Dynamic Array< Builder>:: Dynamic Array object.
void conditional_pop(const bool_pt &predicate)
Conditionallhy pop a field element off of the dynamic array.
ram_table< Builder > _inner_table
void write(const field_pt &index, const field_pt &value)
Write a field element into the dynamic array at an index value.
void resize(const field_pt &new_length, const field_pt default_value=0)
Resize array. Current method v. inefficient!
void push(const field_pt &index)
Push a field element onto the dynamic array.
field_pt read(const field_pt &index) const
Read a field element from the dynamic array at an index value.
void pop()
Pop a field element off of the dynamic array.
DynamicArray & operator=(const DynamicArray &other)
Assignment Operator.
void conditional_push(const bool_pt &predicate, const field_pt &index)
Conditionally push a field element onto the dynamic array.
Implements boolean logic in-circuit.
Definition bool.hpp:59
static field_t conditional_assign(const bool_t< Builder > &predicate, const field_t &lhs, const field_t &rhs)
If predicate == true then return lhs, else return rhs.
Definition field.cpp:884
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
Definition field.cpp:827
field_t normalize() const
Return a new element, where the in-circuit witness contains the actual represented value (multiplicat...
Definition field.cpp:635
bool is_constant() const
Definition field.hpp:399
void assert_is_not_zero(std::string const &msg="field_t::assert_is_not_zero") const
Constrain *this to be non-zero by establishing that it has an inverse.
Definition field.cpp:707
uint32_t get_witness_index() const
Get the witness index of the current field element.
Definition field.hpp:461
Contains all the headers required to adequately compile the types defined in circuit_builders_fwd....
AluTraceBuilder builder
Definition alu.test.cpp:123
stdlib::witness_t< bb::UltraCircuitBuilder > witness_pt
stdlib::field_t< UltraCircuitBuilder > field_pt