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
86TEST(Databus, BadReadFailure)
87{
89 databus_ct databus;
90
91 // Populate return data with a single arbitrary value
92 fr actual_value = 13;
93 databus.return_data.set_values({ witness_ct(&builder, actual_value) });
94
95 // Read the value from the return data
96 size_t raw_idx = 0; // read at 0th index
97 field_ct idx(witness_ct(&builder, raw_idx));
98 field_ct read_result = databus.return_data[idx];
99
100 // The result of the read should be as expected
101 EXPECT_EQ(actual_value, read_result.get_value());
102
103 // Since the read gate implicitly created by using operator[] on return data is valid, the witness is valid
104 EXPECT_TRUE(CircuitChecker::check(builder));
105
106 // Now assert that the read result is equal to some erroneous value. This effectively updates the return data read
107 // gate to attest to the erroneous value being present at index 0 in the return data.
108 field_ct erroneous_value(witness_ct(&builder, actual_value - 1));
109 erroneous_value.assert_equal(read_result);
110
111 // Since the read gate is no longer valid, the circuit checker will fail
112 EXPECT_FALSE(CircuitChecker::check(builder));
113}
114
119TEST(Databus, BadCopyFailure)
120{
122 databus_ct databus;
123
124 // Populate calldata with a single input
125 fr input = 13;
126 databus.calldata.set_values({ witness_ct(&builder, input) });
127
128 // Populate return data with an output different from the input
129 fr output = input - 1;
130 databus.return_data.set_values({ witness_ct(&builder, output) });
131
132 // Attempt to attest that the calldata has been copied into the return data
133 size_t raw_idx = 0; // read at 0th index
134 field_ct idx(witness_ct(&builder, raw_idx));
135 databus.calldata[idx].assert_equal(databus.return_data[idx]);
136
137 // Since the output data is not a copy of the input, the checker should fail
138 EXPECT_FALSE(CircuitChecker::check(builder));
139}
140
145TEST(Databus, DuplicateRead)
146{
148 databus_ct databus;
149
150 // Define some arbitrary bus data
151 std::array<bb::fr, 3> raw_calldata_values = { 5, 1, 2 };
152 std::array<bb::fr, 3> raw_return_data_values = { 25, 6, 3 };
153
154 // Populate the calldata in the databus
155 std::vector<field_ct> calldata_values;
156 for (auto& value : raw_calldata_values) {
157 calldata_values.emplace_back(witness_ct(&builder, value));
158 }
159 databus.calldata.set_values(calldata_values);
160
161 // Populate the return data in the databus
162 std::vector<field_ct> return_data_values;
163 for (auto& value : raw_return_data_values) {
164 return_data_values.emplace_back(witness_ct(&builder, value));
165 }
166 databus.return_data.set_values(return_data_values);
167
168 // Perform some arbitrary reads from both calldata and return data with some repeated indices
169 field_ct idx_1(witness_ct(&builder, 1));
170 field_ct idx_2(witness_ct(&builder, 2));
171
172 databus.calldata[idx_1];
173 databus.calldata[idx_1];
174 databus.calldata[idx_1];
175 databus.calldata[idx_2];
176
177 databus.return_data[idx_2];
178 databus.return_data[idx_2];
179 databus.return_data[idx_1];
180
181 EXPECT_TRUE(CircuitChecker::check(builder));
182}
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:64
bus_vector calldata
Definition databus.hpp:62
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:929
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
Definition field.cpp:827
AluTraceBuilder builder
Definition alu.test.cpp:123
numeric::RNG & engine
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:190
Entry point for Barretenberg command-line interface.
TEST(MegaCircuitBuilder, CopyConstructor)
Inner sum(Cont< Inner, Args... > const &in)
Definition container.hpp:70
MegaCircuitBuilder_< field< Bn254FrParams > > MegaCircuitBuilder
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
stdlib::witness_t< Builder > witness_ct