Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
array.hpp
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#pragma once
8#include "../bool/bool.hpp"
9#include "../safe_uint/safe_uint.hpp"
10#include "field.hpp"
11
12namespace bb::stdlib {
13
19template <typename Builder, size_t SIZE> field_t<Builder> array_length(std::array<field_t<Builder>, SIZE> const& arr)
20{
22 bool_t<Builder> hit_zero = false;
23 for (const auto& e : arr) {
24 bool_t<Builder> is_zero = e.is_zero();
25 hit_zero.must_imply(is_zero, "Once we've hit the first zero, there must only be zeros thereafter!");
26 hit_zero |= is_zero;
27 const field_t<Builder> increment = !hit_zero;
28 length += increment;
29 }
30 return length;
31};
32
39template <typename Builder, size_t SIZE> field_t<Builder> array_pop(std::array<field_t<Builder>, SIZE> const& arr)
40{
41 field_t<Builder> popped_value = 0;
42 bool_t<Builder> already_popped = { arr[0].context, false };
43
44 for (size_t i = arr.size() - 1; i != (size_t)-1; i--) {
45 bool_t<Builder> is_non_zero = arr[i] != 0;
46 popped_value = field_t<Builder>::conditional_assign(!already_popped && is_non_zero, arr[i], popped_value);
47
48 already_popped |= is_non_zero;
49 }
50 already_popped.assert_equal(true, "array_pop cannot pop from an empty array");
51
52 return popped_value;
53};
54
59template <typename Builder, size_t SIZE>
60void array_push(std::array<field_t<Builder>, SIZE>& arr, field_t<Builder> const& value)
61{
62 bool_t<Builder> already_pushed = false;
63 for (size_t i = 0; i < arr.size(); ++i) {
64 bool_t<Builder> is_zero = arr[i] == 0;
65 arr[i] = field_t<Builder>::conditional_assign(!already_pushed && is_zero, value, arr[i]);
66
67 already_pushed |= is_zero;
68 }
69 already_pushed.assert_equal(true, "array_push cannot push to a full array");
70};
71
76template <typename Builder, size_t SIZE>
77inline size_t array_push(std::array<std::optional<field_t<Builder>>, SIZE>& arr, field_t<Builder> const& value)
78{
79 for (size_t i = 0; i < arr.size(); ++i) {
80 if (arr[i] == std::nullopt) {
81 arr[i] = value;
82 return i;
83 }
84 }
85 throw_or_abort("array_push cannot push to a full array");
86};
87
92template <typename T, size_t SIZE>
93inline size_t array_push(std::array<std::shared_ptr<T>, SIZE>& arr, std::shared_ptr<T> const& value)
94{
95 for (size_t i = 0; i < arr.size(); ++i) {
96 if (arr[i] == nullptr) {
97 arr[i] = value;
98 return i;
99 }
100 }
101 throw_or_abort("array_push cannot push to a full array");
102};
103
108template <typename Builder, typename T, size_t SIZE> inline void array_push(std::array<T, SIZE>& arr, T const& value)
109{
110 bool_t<Builder> already_pushed = false;
111 for (size_t i = 0; i < arr.size(); ++i) {
112 bool_t<Builder> is_zero = arr[i].is_empty();
113 arr[i].conditional_select(!already_pushed && is_zero, value);
114
115 already_pushed |= is_zero;
116 }
117 already_pushed.assert_equal(true, "array_push cannot push to a full array");
118};
119
124template <typename Builder, size_t SIZE>
125typename stdlib::bool_t<Builder> is_array_empty(std::array<field_t<Builder>, SIZE> const& arr)
126{
127 bool_t<Builder> nonzero_found = false;
128 for (size_t i = arr.size() - 1; i != (size_t)-1; i--) {
129 bool_t<Builder> is_non_zero = arr[i] != 0;
130 nonzero_found |= is_non_zero;
131 }
132 return !nonzero_found;
133};
134
139template <typename Builder, size_t size_1, size_t size_2>
140void push_array_to_array(std::array<field_t<Builder>, size_1> const& source,
141 std::array<field_t<Builder>, size_2>& target)
142{
143 field_t<Builder> target_length = array_length<Builder>(target);
144 const field_t<Builder> overflow_capacity = target.max_size() + 1;
145
146 field_t<Builder> j_ct = 0; // circuit-type index for the inner loop
147 // Find the first empty slot in the target:
148 field_t<Builder> next_target_index = target_length;
149
150 bool_t<Builder> hit_s_zero = false;
151 bool_t<Builder> not_hit_s_zero = true;
152
153 for (size_t i = 0; i < source.max_size(); ++i) {
154 // Loop over each source value we want to push:
155 auto& s = source[i];
156 {
157 auto is_s_zero = s.is_zero();
158 hit_s_zero.must_imply(is_s_zero,
159 "Once we've hit the first source zero, there must only be zeros thereafter!");
160 hit_s_zero |= is_s_zero;
161 not_hit_s_zero = !hit_s_zero;
162 }
163
164 // Triangular loop:
165 for (size_t j = i; j < target.max_size(); ++j) {
166 auto& t = target[j];
167
168 // Check whether we've reached the next target index at which we can push `s`:
169 bool_t<Builder> at_next_target_index = j_ct == next_target_index;
170
171 t = field_t<Builder>::conditional_assign(at_next_target_index && not_hit_s_zero, s, t);
172
173 j_ct++;
174 }
175
176 next_target_index += not_hit_s_zero;
177
178 next_target_index.assert_not_equal(overflow_capacity, "push_array_to_array target array capacity exceeded");
179
180 j_ct = i + 1;
181 }
182}
183
184} // namespace bb::stdlib
Implements boolean logic in-circuit.
Definition bool.hpp:59
Builder * context
Definition bool.hpp:130
void must_imply(const bool_t &other, std::string const &msg="bool_t::must_imply") const
Constrains the (a => b) == true.
Definition bool.cpp:460
void assert_equal(const bool_t &rhs, std::string const &msg="bool_t::assert_equal") const
Implements copy constraint for bool_t elements.
Definition bool.cpp:396
void assert_not_equal(const field_t &rhs, std::string const &msg="field_t::assert_not_equal") const
Constrain *this to be not equal to rhs.
Definition field.cpp:964
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
uint8_t const size_t length
Definition data_store.hpp:9
void array_push(std::array< field_t< Builder >, SIZE > &arr, field_t< Builder > const &value)
Definition array.hpp:60
stdlib::bool_t< Builder > is_array_empty(std::array< field_t< Builder >, SIZE > const &arr)
Definition array.hpp:125
field_t< Builder > array_length(std::array< field_t< Builder >, SIZE > const &arr)
Definition array.hpp:19
field_t< Builder > array_pop(std::array< field_t< Builder >, SIZE > const &arr)
Definition array.hpp:39
void push_array_to_array(std::array< field_t< Builder >, size_1 > const &source, std::array< field_t< Builder >, size_2 > &target)
Definition array.hpp:140
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
void throw_or_abort(std::string const &err)