Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
byte_array.test.cpp
Go to the documentation of this file.
1#include <gtest/gtest.h>
2
4#include "byte_array.hpp"
5
6#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
7
8using namespace bb;
9using namespace bb::stdlib;
10namespace {
12}
14
15template <class Builder> class ByteArrayTest : public ::testing::Test {
16 public:
21
22 void check_byte_decomposition(const byte_array_ct& arr, const field_ct& original_val)
23 {
24 size_t num_bytes = arr.size();
25 fr reconstructed = 0;
26
27 for (size_t i = 0; i < num_bytes; ++i) {
28 auto byte = arr[i].get_value();
29 reconstructed += byte * fr(uint256_t(1) << ((num_bytes - 1 - i) * 8));
30 }
31 EXPECT_TRUE(original_val.get_value() == reconstructed);
32 };
33
34 fr slice_to_n_bytes(const fr& value, const uint64_t n)
35 {
36 uint256_t val(value);
37 uint256_t mask = (uint256_t(1) << (8 * n)) - 1; // lower n bytes
38 return fr(val & mask);
39 };
40
42 {
44
45 std::vector<uint8_t> expected = { 0x04, 0x03, 0x02, 0x01 };
46 byte_array_ct arr(&builder, std::vector<uint8_t>{ 0x01, 0x02, 0x03, 0x04 });
47
48 // Unset the free witness tag, so it doesn't interfere
49 for (const auto& byte : arr.bytes()) {
51 }
52
53 // Set tag on the first byte
54 arr.bytes()[0].set_origin_tag(submitted_value_origin_tag);
55
56 auto reversed_arr = arr.reverse();
57
58 EXPECT_EQ(arr.size(), 4UL);
59 EXPECT_EQ(reversed_arr.get_value(), expected);
60 // The tag is preserved in reverse
61 EXPECT_EQ(reversed_arr.bytes()[3].get_origin_tag(), submitted_value_origin_tag);
62 // A general tag contains this tag
63 EXPECT_EQ(reversed_arr.get_origin_tag(), submitted_value_origin_tag);
64 // Other bytes are untouched by the tag
65 EXPECT_EQ(reversed_arr.bytes()[0].get_origin_tag(), clear_tag);
66 EXPECT_EQ(reversed_arr.bytes()[1].get_origin_tag(), clear_tag);
67 EXPECT_EQ(reversed_arr.bytes()[2].get_origin_tag(), clear_tag);
68 }
69
71 {
73
74 std::string a = "ascii";
75 byte_array_ct arr(&builder, a);
76 EXPECT_EQ(arr.get_string(), a);
77 }
78
80 {
81 for (size_t num_bytes = 1; num_bytes < 32; num_bytes++) {
83
85 fr expected_val = slice_to_n_bytes(raw_val, num_bytes);
86
87 field_ct field = witness_ct(&builder, expected_val);
88 field.set_origin_tag(submitted_value_origin_tag);
89
90 byte_array_ct byte_arr(field, num_bytes);
91 EXPECT_EQ(byte_arr.size(), num_bytes);
92
94
95 // Convert back to field
96 field_ct reconstructed_field(byte_arr);
97 EXPECT_EQ(reconstructed_field.get_value(), expected_val);
98 EXPECT_EQ(reconstructed_field.get_origin_tag(), submitted_value_origin_tag);
99
100 EXPECT_TRUE(CircuitChecker::check(builder));
101 }
102 }
103
105 {
106 for (size_t num_bytes = 1; num_bytes < 32; num_bytes++) {
108 size_t num_gates_start = builder.get_estimated_num_finalized_gates();
109
111 fr expected_val = slice_to_n_bytes(raw_val, num_bytes);
112
113 field_ct field(&builder, expected_val);
114 field.set_origin_tag(submitted_value_origin_tag);
115
116 byte_array_ct byte_arr(field, num_bytes);
117 EXPECT_EQ(byte_arr.size(), num_bytes);
118
120
121 // Convert back to field
122 field_ct reconstructed_field(byte_arr);
123 EXPECT_EQ(reconstructed_field.get_value(), expected_val);
124 EXPECT_EQ(reconstructed_field.get_origin_tag(), submitted_value_origin_tag);
125
126 // Make sure no gates are added
127 EXPECT_TRUE(builder.get_estimated_num_finalized_gates() - num_gates_start == 0);
128 }
129 }
130
132 {
133
134 auto builder = Builder();
135
137
138 byte_array_ct arr(test_val, 32);
139
140 check_byte_decomposition(arr, test_val);
141
142 EXPECT_TRUE(CircuitChecker::check(builder));
143
144 {
145 // Produce a 256 bit value `x` such that the high limb of (r-1) - x is overflowing.
146 uint256_t overflowing_value(fr::modulus + 100);
147
148 test_val = witness_ct(&builder, overflowing_value);
149
150 byte_array<Builder> failure_array(test_val, 32, overflowing_value);
151 check_byte_decomposition(failure_array, test_val);
152
153 EXPECT_FALSE(CircuitChecker::check(builder));
154 EXPECT_TRUE(builder.err() == "byte_array: y_hi doesn't fit in 128 bits.");
155 }
156
157 {
158 // Test the case when (r-1).lo - x.lo + 2^128 is not a 129 bit integer, i.e. is negative.
160 uint256_t random_overflowing_value("0xcf9bb18d1ece5fd647afba497e7ea7a3d3bdb158855487614a97cd3d2a1954b2");
161 test_val = witness_ct(&builder, random_overflowing_value);
162
163 byte_array<Builder> failure_array(test_val, 32, random_overflowing_value);
164 check_byte_decomposition(failure_array, test_val);
165
166 EXPECT_FALSE(CircuitChecker::check(builder));
167 EXPECT_TRUE(builder.err() == "byte_array: y_hi doesn't fit in 128 bits.");
168 }
169 }
170
172 {
173
175 size_t gates_start = builder.get_estimated_num_finalized_gates();
176 field_ct test_val(&builder, fr::random_element());
177
178 byte_array_ct arr(test_val, 32);
179
180 check_byte_decomposition(arr, test_val);
181
182 {
183 // Produce a 256 bit value `x` such that the high limb of (r-1) - x is overflowing.
184 uint256_t overflowing_value(fr::modulus + 100);
185
186 test_val = field_ct(&builder, bb::fr(overflowing_value));
187 EXPECT_THROW_OR_ABORT(byte_array<Builder> failure_array(test_val, 32, overflowing_value),
188 "byte_array: y_hi doesn't fit in 128 bits");
189 }
190
191 {
192 // Test the case when (r-1).lo - x.lo + 2^128 is not a 129 bit integer, i.e. is negative.
193 uint256_t random_overflowing_value("0xcf9bb18d1ece5fd647afba497e7ea7a3d3bdb158855487614a97cd3d2a1954b2");
194 test_val = field_ct(&builder, bb::fr(random_overflowing_value));
195 EXPECT_THROW_OR_ABORT(byte_array<Builder> failure_array(test_val, 32, random_overflowing_value),
196 "byte_array: y_hi doesn't fit in 128 bits");
197 }
198 // Make sure no gates are added
199 EXPECT_TRUE(gates_start == builder.get_estimated_num_finalized_gates());
200 }
201
203 {
205
206 uint256_t a_expected = engine.get_random_uint256();
207 uint256_t b_expected = engine.get_random_uint256();
208
209 field_ct a = witness_ct(&builder, slice_to_n_bytes(a_expected, 31));
210 a.set_origin_tag(submitted_value_origin_tag);
211 field_ct b = witness_ct(&builder, slice_to_n_bytes(b_expected, 31));
212 b.set_origin_tag(challenge_origin_tag);
213
215
216 arr.write(byte_array_ct(a, 31));
217 arr.write(byte_array_ct(b, 31));
218
219 EXPECT_EQ(arr.size(), 62UL);
220
221 field_ct a_result(arr.slice(0, 31));
222 field_ct b_result(arr.slice(31));
223
224 EXPECT_EQ(a_result.get_value(), slice_to_n_bytes(a_expected, 31));
225 EXPECT_EQ(b_result.get_value(), slice_to_n_bytes(b_expected, 31));
226 // Tags should be preserved through write and slice
227 EXPECT_EQ(a_result.get_origin_tag(), submitted_value_origin_tag);
228 EXPECT_EQ(b_result.get_origin_tag(), challenge_origin_tag);
229
230 bool verified = CircuitChecker::check(builder);
231 EXPECT_EQ(verified, true);
232 }
233
235 {
236 for (size_t arr_length = 1; arr_length < 32; arr_length++) {
237
239 byte_array_ct test_array(&builder, arr_length);
240
241 std::vector<uint8_t> native_bytes(arr_length);
242 for (size_t idx = 0; idx < arr_length; idx++) {
243 uint8_t byte = engine.get_random_uint8();
244 native_bytes[idx] = byte;
245 test_array[idx] = witness_ct(&builder, byte);
246 }
247
248 // Convert to field_t using the byte_array conversion
249 field_ct represented_field_elt = static_cast<field_ct>(test_array);
250
251 // Compute the expected value manually (big-endian)
252 uint256_t expected_value = 0;
253 for (size_t i = 0; i < arr_length; ++i) {
254 expected_value = (expected_value << 8) + native_bytes[i];
255 }
256
257 // Assert values match
258 EXPECT_EQ(represented_field_elt.get_value(), fr(expected_value));
259
260 // Check that the circuit is valid
261 bool result = CircuitChecker::check(builder);
262 EXPECT_TRUE(result);
263 }
264 }
265
267 {
269
270 std::string a = "\1\2\3a";
271 byte_array_ct arr(&builder, a);
272 std::ostringstream os;
273 os << arr;
274 EXPECT_EQ(os.str(), "[ 01 02 03 61 ]");
275 }
276};
277
278using CircuitTypes = ::testing::Types<bb::UltraCircuitBuilder>;
279
281
283{
284 TestFixture::test_reverse();
285}
286
287TYPED_TEST(ByteArrayTest, ConstructFromString)
288{
289 TestFixture::test_from_string_constructor();
290}
291
292TYPED_TEST(ByteArrayTest, ByteDecompositionUnique)
293{
294 TestFixture::test_into_bytes_decomposition_less_than_32_bytes();
295}
296
297TYPED_TEST(ByteArrayTest, ByteDecompositionUniqueConst)
298{
299 TestFixture::test_into_bytes_decomposition_less_than_32_bytes_const();
300}
301
302TYPED_TEST(ByteArrayTest, ByteDecomposition32Bytes)
303{
304 TestFixture::test_into_bytes_decomposition_32_bytes();
305}
306
307TYPED_TEST(ByteArrayTest, ByteDecomposition32BytesConst)
308{
309 TestFixture::test_into_bytes_decomposition_32_bytes_const();
310}
311
312TYPED_TEST(ByteArrayTest, InputOutputConsistency)
313{
314 TestFixture::test_byte_array_input_output_consistency();
315}
316
317TYPED_TEST(ByteArrayTest, ConvertToField)
318{
319 TestFixture::test_conversion_to_field();
320}
321
322TYPED_TEST(ByteArrayTest, OstreamOperator)
323{
324 TestFixture::test_ostream_operator();
325}
#define EXPECT_THROW_OR_ABORT(statement, matcher)
Definition assert.hpp:150
stdlib::witness_t< Builder > witness_ct
void test_into_bytes_decomposition_32_bytes_const()
stdlib::field_t< Builder > field_ct
void test_into_bytes_decomposition_32_bytes()
fr slice_to_n_bytes(const fr &value, const uint64_t n)
void test_into_bytes_decomposition_less_than_32_bytes_const()
void test_from_string_constructor()
void test_byte_array_input_output_consistency()
stdlib::byte_array< Builder > byte_array_ct
void check_byte_decomposition(const byte_array_ct &arr, const field_ct &original_val)
void test_conversion_to_field()
void test_into_bytes_decomposition_less_than_32_bytes()
size_t get_estimated_num_finalized_gates() const
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
virtual uint8_t get_random_uint8()=0
virtual uint256_t get_random_uint256()=0
Implements boolean logic in-circuit.
Definition bool.hpp:59
Represents a dynamic array of bytes in-circuit.
byte_array slice(size_t offset) const
Slice bytes from the byte array starting at offset. Does not add any constraints.
byte_array & write(byte_array const &other)
Appends the contents of another byte_array (other) to the end of this one.
void unset_free_witness_tag()
Unset the free witness flag for the byte array.
std::vector< uint8_t > get_value() const
A helper converting a byte_array into the vector of its uint8_t values.
size_t size() const
std::string get_string() const
Given a byte_array, compute a vector containing the values of its entries and convert it to a string.
OriginTag get_origin_tag() const
Definition field.hpp:333
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
FF a
FF b
ECCVMCircuitBuilder Builder
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.
TYPED_TEST_SUITE(ShpleminiTest, TestSettings)
field< Bn254FrParams > fr
Definition fr.hpp:174
TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching)
#define STANDARD_TESTING_TAGS
testing::Types< bb::UltraCircuitBuilder > CircuitTypes
static constexpr uint256_t modulus
static field random_element(numeric::RNG *engine=nullptr) noexcept