Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
databus.test.cpp
Go to the documentation of this file.
1
2#include <gtest/gtest.h>
3
7#include "databus.hpp"
8
9using namespace bb;
10
15
16namespace {
18}
19
24TEST(Databus, CallDataAndReturnData)
25{
27 databus_ct databus;
28
29 // The databus is advantageous in situations where we want to pass large amounts of public inputs between circuits
30 // in a chain (like private function execution in Aztec) but where we only need to use a small subset of those
31 // values in any given circuit. As an example of this utility, consider the case where the output (return data) is
32 // defined by simply taking the last two elements of the input (calldata) and summing them together. We can use the
33 // databus mechanism to establish that the return data was indeed formed in this way.
34
35 // Define some bus data that conform to the pattern described above
36 std::array<fr, 4> raw_calldata_values = { 4, 5, 6, 7 };
37 std::array<fr, 3> raw_return_data_values = { 4, 5, 13 }; // 13 = 6 + 7
38
39 // Populate the calldata in the databus
40 std::vector<field_ct> calldata_values;
41 for (auto& value : raw_calldata_values) {
42 calldata_values.emplace_back(witness_ct(&builder, value));
43 }
44 databus.calldata.set_values(calldata_values);
45
46 // Populate the return data in the databus
47 std::vector<field_ct> return_data_values;
48 for (auto& value : raw_return_data_values) {
49 return_data_values.emplace_back(witness_ct(&builder, value));
50 }
51 databus.return_data.set_values(return_data_values);
52
53 // Establish that the first two outputs are simply copied over from the inputs. Each 'copy' requires two read gates.
54 field_ct idx_0(witness_ct(&builder, 0));
55 field_ct idx_1(witness_ct(&builder, 1));
56 databus.calldata[idx_0].assert_equal(databus.return_data[idx_0]);
57 databus.calldata[idx_1].assert_equal(databus.return_data[idx_1]);
58
59 // Get the last two entries in calldata and compute their sum
60 field_ct idx_2(witness_ct(&builder, 2));
61 field_ct idx_3(witness_ct(&builder, 3));
62 // This line creates an arithmetic gate and two calldata read gates (via operator[]).
63 field_ct sum = databus.calldata[idx_2] + databus.calldata[idx_3];
64
65 // Read the last index of the return data. (Creates a return data read gate via operator[]).
66 field_ct idx(witness_ct(&builder, 2));
67 field_ct read_result = databus.return_data[idx];
68
69 // By construction, the last return data value is equal to the sum of the last two calldata values
70 EXPECT_EQ(sum.get_value(), read_result.get_value());
71
72 // Asserting that 'sum' is equal to the read result completes the process of establishing that the corresponding
73 // return data entry was formed correctly; 'sum' is equal to the read result (enforced via copy constraint) and the
74 // read result is connected to the value in the databus return data column via the read gate. 'sum' is connected to
75 // the calldata values via an arithmetic gate and the two calldata read gates.
76 sum.assert_equal(read_result);
77
78 EXPECT_TRUE(CircuitChecker::check(builder));
79}
80
85TEST(Databus, ConstantEntryAccess)
86{
87
89 databus_ct databus;
90 fr value_0 = 13;
91 fr value_1 = 12;
92 auto constant_0 = witness_ct::create_constant_witness(&builder, value_0);
93 auto constant_1 = witness_ct::create_constant_witness(&builder, value_1);
94 databus.return_data.set_values({ constant_0, constant_1 });
95 field_ct idx_0(witness_ct(&builder, 0));
96 field_ct idx_1(witness_ct(&builder, 1));
97
98 field_ct read_result_0 = databus.return_data[idx_0];
99 field_ct read_result_1 = databus.return_data[idx_1];
100
101 EXPECT_EQ(value_0, read_result_0.get_value());
102 EXPECT_EQ(value_1, read_result_1.get_value());
103 EXPECT_TRUE(CircuitChecker::check(builder));
104}
105
110TEST(Databus, UnnormalizedEntryAccess)
111{
112
114 databus_ct databus;
115 std::array<fr, 3> raw_calldata_entries = { 3, 2, 1 };
116 std::array<fr, 3> raw_returndata_entries = { 3, 2, 1 };
117 std::vector<field_ct> calldata_entries;
118 for (fr entry : raw_calldata_entries) {
119 calldata_entries.emplace_back(witness_ct(&builder, entry));
120 }
121 std::vector<field_ct> returndata_entries;
122 for (fr entry : raw_returndata_entries) {
123 field_ct entry_witness = witness_ct(&builder, entry);
124 // add the value to itself to make it unnormalized (the multiplicative constant will be 2)
125 returndata_entries.emplace_back(entry_witness + entry_witness);
126 }
127 databus.calldata.set_values(calldata_entries);
128 databus.return_data.set_values(returndata_entries);
129 field_ct idx_0 = witness_ct(&builder, 0);
130 field_ct idx_1 = witness_ct(&builder, 1);
131 field_ct idx_2 = witness_ct(&builder, 2);
132 databus.return_data[idx_0].assert_equal(databus.calldata[idx_0] + databus.calldata[idx_0]);
133 databus.return_data[idx_1].assert_equal(databus.calldata[idx_1] + databus.calldata[idx_1]);
134 databus.return_data[idx_2].assert_equal(databus.calldata[idx_2] + databus.calldata[idx_2]);
135 EXPECT_TRUE(CircuitChecker::check(builder));
136}
137
142TEST(Databus, ConstantAndUnnormalizedIndices)
143{
145 databus_ct databus;
146 std::array<fr, 3> raw_calldata_values = { 54, 32, 30 };
147 std::array<fr, 3> raw_returndata_values = { 54, 32, 116 };
148 // Populate the calldata in the databus
149 std::vector<field_ct> calldata_values;
150 for (auto& value : raw_calldata_values) {
151 calldata_values.emplace_back(witness_ct(&builder, value));
152 }
153 databus.calldata.set_values(calldata_values);
154
155 // Populate the return data in the databus
156 std::vector<field_ct> returndata_values;
157 for (auto& value : raw_returndata_values) {
158 returndata_values.emplace_back(witness_ct(&builder, value));
159 }
160 databus.return_data.set_values(returndata_values);
161
162 // constant first index
164 field_ct idx_1(witness_ct(&builder, 1));
165 // un-normalized index (with multiplicative constant 2)
166 field_ct idx_2 = idx_1 + idx_1;
167 field_ct sum = databus.calldata[idx_0] + databus.calldata[idx_1] + databus.calldata[idx_2];
168
169 databus.return_data[idx_0].assert_equal(databus.calldata[idx_0]);
170 databus.return_data[idx_1].assert_equal(databus.calldata[idx_1]);
171 databus.return_data[idx_2].assert_equal(sum);
172
173 EXPECT_TRUE(CircuitChecker::check(builder));
174}
175
181TEST(Databus, BadReadFailure)
182{
184 databus_ct databus;
185
186 // Populate return data with a single arbitrary value
187 fr actual_value = 13;
188 databus.return_data.set_values({ witness_ct(&builder, actual_value) });
189
190 // Read the value from the return data
191 size_t raw_idx = 0; // read at 0th index
192 field_ct idx(witness_ct(&builder, raw_idx));
193 field_ct read_result = databus.return_data[idx];
194
195 // The result of the read should be as expected
196 EXPECT_EQ(actual_value, read_result.get_value());
197
198 // Since the read gate implicitly created by using operator[] on return data is valid, the witness is valid
199 EXPECT_TRUE(CircuitChecker::check(builder));
200
201 // Now assert that the read result is equal to some erroneous value. This effectively updates the return data read
202 // gate to attest to the erroneous value being present at index 0 in the return data.
203 field_ct erroneous_value(witness_ct(&builder, actual_value - 1));
204 erroneous_value.assert_equal(read_result);
205
206 // Since the read gate is no longer valid, the circuit checker will fail
207 EXPECT_FALSE(CircuitChecker::check(builder));
208}
209
214TEST(Databus, BadCopyFailure)
215{
217 databus_ct databus;
218
219 // Populate calldata with a single input
220 fr input = 13;
221 databus.calldata.set_values({ witness_ct(&builder, input) });
222
223 // Populate return data with an output different from the input
224 fr output = input - 1;
225 databus.return_data.set_values({ witness_ct(&builder, output) });
226
227 // Attempt to attest that the calldata has been copied into the return data
228 size_t raw_idx = 0; // read at 0th index
229 field_ct idx(witness_ct(&builder, raw_idx));
230 databus.calldata[idx].assert_equal(databus.return_data[idx]);
231
232 // Since the output data is not a copy of the input, the checker should fail
233 EXPECT_FALSE(CircuitChecker::check(builder));
234}
235
240TEST(Databus, DuplicateRead)
241{
243 databus_ct databus;
244
245 // Define some arbitrary bus data
246 std::array<bb::fr, 3> raw_calldata_values = { 5, 1, 2 };
247 std::array<bb::fr, 3> raw_return_data_values = { 25, 6, 3 };
248
249 // Populate the calldata in the databus
250 std::vector<field_ct> calldata_values;
251 for (auto& value : raw_calldata_values) {
252 calldata_values.emplace_back(witness_ct(&builder, value));
253 }
254 databus.calldata.set_values(calldata_values);
255
256 // Populate the return data in the databus
257 std::vector<field_ct> return_data_values;
258 for (auto& value : raw_return_data_values) {
259 return_data_values.emplace_back(witness_ct(&builder, value));
260 }
261 databus.return_data.set_values(return_data_values);
262
263 // Perform some arbitrary reads from both calldata and return data with some repeated indices
264 field_ct idx_1(witness_ct(&builder, 1));
265 field_ct idx_2(witness_ct(&builder, 2));
266
267 databus.calldata[idx_1];
268 databus.calldata[idx_1];
269 databus.calldata[idx_1];
270 databus.calldata[idx_2];
271
272 databus.return_data[idx_2];
273 databus.return_data[idx_2];
274 databus.return_data[idx_1];
275
276 EXPECT_TRUE(CircuitChecker::check(builder));
277}
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
void set_values(const std::vector< field_pt > &entries_in)
Set the entries of the bus vector from possibly unnormalized or constant inputs.
Definition databus.cpp:14
bus_vector return_data
Definition databus.hpp:63
bus_vector calldata
Definition databus.hpp:61
void assert_equal(const field_t &rhs, std::string const &msg="field_t::assert_equal") const
Copy constraint: constrain that *this field is equal to rhs element.
Definition field.cpp:931
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
Definition field.cpp:829
static witness_t create_constant_witness(Builder *parent_context, const bb::fr &in)
Definition witness.hpp:45
AluTraceBuilder builder
Definition alu.test.cpp:123
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:190
Entry point for Barretenberg command-line interface.
Inner sum(Cont< Inner, Args... > const &in)
Definition container.hpp:70
TEST(BoomerangMegaCircuitBuilder, BasicCircuit)
MegaCircuitBuilder_< field< Bn254FrParams > > MegaCircuitBuilder
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
stdlib::witness_t< Builder > witness_ct