barretenberg
Loading...
Searching...
No Matches
array.hpp
1#pragma once
2#include "../bool/bool.hpp"
3#include "../safe_uint/safe_uint.hpp"
4#include "field.hpp"
5
6namespace proof_system::plonk {
7namespace stdlib {
8
14template <typename Builder, size_t SIZE> field_t<Builder> array_length(std::array<field_t<Builder>, SIZE> const& arr)
15{
16 field_t<Builder> length = 0;
17 bool_t<Builder> hit_zero = false;
18 for (const auto& e : arr) {
19 bool_t<Builder> is_zero = e.is_zero();
20 hit_zero.must_imply(is_zero, "Once we've hit the first zero, there must only be zeros thereafter!");
21 hit_zero |= is_zero;
22 const field_t<Builder> increment = !hit_zero;
23 length += increment;
24 }
25 return length;
26};
27
34template <typename Builder, size_t SIZE> field_t<Builder> array_pop(std::array<field_t<Builder>, SIZE> const& arr)
35{
36 field_t<Builder> popped_value = 0;
37 bool_t<Builder> already_popped = false;
38 for (size_t i = arr.size() - 1; i != (size_t)-1; i--) {
39 bool_t<Builder> is_non_zero = arr[i] != 0;
40 popped_value = field_t<Builder>::conditional_assign(!already_popped && is_non_zero, arr[i], popped_value);
41
42 already_popped |= is_non_zero;
43 }
44 already_popped.assert_equal(true, "array_pop cannot pop from an empty array");
45
46 return popped_value;
47};
48
53template <typename Builder, size_t SIZE>
54void array_push(std::array<field_t<Builder>, SIZE>& arr, field_t<Builder> const& value)
55{
56 bool_t<Builder> already_pushed = false;
57 for (size_t i = 0; i < arr.size(); ++i) {
58 bool_t<Builder> is_zero = arr[i] == 0;
59 arr[i] = field_t<Builder>::conditional_assign(!already_pushed && is_zero, value, arr[i]);
60
61 already_pushed |= is_zero;
62 }
63 already_pushed.assert_equal(true, "array_push cannot push to a full array");
64};
65
70template <typename Builder, size_t SIZE>
71inline size_t array_push(std::array<std::optional<field_t<Builder>>, SIZE>& arr, field_t<Builder> const& value)
72{
73 for (size_t i = 0; i < arr.size(); ++i) {
74 if (arr[i] == std::nullopt) {
75 arr[i] = value;
76 return i;
77 }
78 }
79 throw_or_abort("array_push cannot push to a full array");
80};
81
86template <typename T, size_t SIZE>
87inline size_t array_push(std::array<std::shared_ptr<T>, SIZE>& arr, std::shared_ptr<T> const& value)
88{
89 for (size_t i = 0; i < arr.size(); ++i) {
90 if (arr[i] == nullptr) {
91 arr[i] = value;
92 return i;
93 }
94 }
95 throw_or_abort("array_push cannot push to a full array");
96};
97
102template <typename Builder, typename T, size_t SIZE> inline void array_push(std::array<T, SIZE>& arr, T const& value)
103{
104 bool_t<Builder> already_pushed = false;
105 for (size_t i = 0; i < arr.size(); ++i) {
106 bool_t<Builder> is_zero = arr[i].is_empty();
107 arr[i].conditional_select(!already_pushed && is_zero, value);
108
109 already_pushed |= is_zero;
110 }
111 already_pushed.assert_equal(true, "array_push cannot push to a full array");
112};
113
118template <typename Builder, size_t SIZE>
119typename plonk::stdlib::bool_t<Builder> is_array_empty(std::array<field_t<Builder>, SIZE> const& arr)
120{
121 bool_t<Builder> nonzero_found = false;
122 for (size_t i = arr.size() - 1; i != (size_t)-1; i--) {
123 bool_t<Builder> is_non_zero = arr[i] != 0;
124 nonzero_found |= is_non_zero;
125 }
126 return !nonzero_found;
127};
128
133template <typename Builder, size_t size_1, size_t size_2>
134void push_array_to_array(std::array<field_t<Builder>, size_1> const& source,
135 std::array<field_t<Builder>, size_2>& target)
136{
137 field_t<Builder> target_length = array_length<Builder>(target);
138 const field_t<Builder> overflow_capacity = target.max_size() + 1;
139
140 field_t<Builder> j_ct = 0; // circuit-type index for the inner loop
141 // Find the first empty slot in the target:
142 field_t<Builder> next_target_index = target_length;
143
144 bool_t<Builder> hit_s_zero = false;
145 bool_t<Builder> not_hit_s_zero = true;
146
147 for (size_t i = 0; i < source.max_size(); ++i) {
148 // Loop over each source value we want to push:
149 auto& s = source[i];
150 {
151 auto is_s_zero = s.is_zero();
152 hit_s_zero.must_imply(is_s_zero,
153 "Once we've hit the first source zero, there must only be zeros thereafter!");
154 hit_s_zero |= is_s_zero;
155 not_hit_s_zero = !hit_s_zero;
156 }
157
158 // Triangular loop:
159 for (size_t j = i; j < target.max_size(); ++j) {
160 auto& t = target[j];
161
162 // Check whether we've reached the next target index at which we can push `s`:
163 bool_t<Builder> at_next_target_index = j_ct == next_target_index;
164
165 t = field_t<Builder>::conditional_assign(at_next_target_index && not_hit_s_zero, s, t);
166
167 j_ct++;
168 }
169
170 next_target_index += not_hit_s_zero;
171
172 next_target_index.assert_not_equal(overflow_capacity, "push_array_to_array target array capacity exceeded");
173
174 j_ct = i + 1;
175 }
176}
177
178} // namespace stdlib
179} // namespace proof_system::plonk
Definition: field.hpp:10
Definition: widget.bench.cpp:13