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 {
72 for (size_t num_bytes = 1; num_bytes < 32; num_bytes++) {
74
76 fr expected_val = slice_to_n_bytes(raw_val, num_bytes);
77
78 field_ct field = witness_ct(&builder, expected_val);
79 field.set_origin_tag(submitted_value_origin_tag);
80
81 byte_array_ct byte_arr(field, num_bytes);
82 EXPECT_EQ(byte_arr.size(), num_bytes);
83
85
86 // Convert back to field
87 field_ct reconstructed_field(byte_arr);
88 EXPECT_EQ(reconstructed_field.get_value(), expected_val);
89 EXPECT_EQ(reconstructed_field.get_origin_tag(), submitted_value_origin_tag);
90
91 EXPECT_TRUE(CircuitChecker::check(builder));
92 }
93 }
94
96 {
97 for (size_t num_bytes = 1; num_bytes < 32; num_bytes++) {
99 size_t num_gates_start = builder.get_num_finalized_gates_inefficient();
100
102 fr expected_val = slice_to_n_bytes(raw_val, num_bytes);
103
104 field_ct field(&builder, expected_val);
105 field.set_origin_tag(submitted_value_origin_tag);
106
107 byte_array_ct byte_arr(field, num_bytes);
108 EXPECT_EQ(byte_arr.size(), num_bytes);
109
111
112 // Convert back to field
113 field_ct reconstructed_field(byte_arr);
114 EXPECT_EQ(reconstructed_field.get_value(), expected_val);
115 EXPECT_EQ(reconstructed_field.get_origin_tag(), submitted_value_origin_tag);
116
117 // Make sure no gates are added
118 EXPECT_TRUE(builder.get_num_finalized_gates_inefficient() - num_gates_start == 0);
119 }
120 }
121
123 {
124
125 auto builder = Builder();
126
128
129 byte_array_ct arr(test_val, 32);
130
131 check_byte_decomposition(arr, test_val);
132
133 EXPECT_TRUE(CircuitChecker::check(builder));
134
135 {
136 // Produce a 256 bit value `x` such that the high limb of (r-1) - x is overflowing.
137 uint256_t overflowing_value(fr::modulus + 100);
138
139 test_val = witness_ct(&builder, overflowing_value);
140
141 byte_array<Builder> failure_array(test_val, 32, overflowing_value);
142 check_byte_decomposition(failure_array, test_val);
143
144 EXPECT_FALSE(CircuitChecker::check(builder));
145 EXPECT_TRUE(builder.err() == "byte_array: y_hi doesn't fit in 128 bits.");
146 }
147
148 {
149 // Test the case when (r-1).lo - x.lo + 2^128 is not a 129 bit integer, i.e. is negative.
151 uint256_t random_overflowing_value("0xcf9bb18d1ece5fd647afba497e7ea7a3d3bdb158855487614a97cd3d2a1954b2");
152 test_val = witness_ct(&builder, random_overflowing_value);
153
154 byte_array<Builder> failure_array(test_val, 32, random_overflowing_value);
155 check_byte_decomposition(failure_array, test_val);
156
157 EXPECT_FALSE(CircuitChecker::check(builder));
158 EXPECT_TRUE(builder.err() == "byte_array: y_hi doesn't fit in 128 bits.");
159 }
160 }
161
163 {
164
166 size_t gates_start = builder.get_num_finalized_gates_inefficient();
167 field_ct test_val(&builder, fr::random_element());
168
169 byte_array_ct arr(test_val, 32);
170
171 check_byte_decomposition(arr, test_val);
172
173 {
174 // Produce a 256 bit value `x` such that the high limb of (r-1) - x is overflowing.
175 uint256_t overflowing_value(fr::modulus + 100);
176
177 test_val = field_ct(&builder, bb::fr(overflowing_value));
178 EXPECT_THROW_OR_ABORT(byte_array<Builder> failure_array(test_val, 32, overflowing_value),
179 "byte_array: y_hi doesn't fit in 128 bits");
180 }
181
182 {
183 // Test the case when (r-1).lo - x.lo + 2^128 is not a 129 bit integer, i.e. is negative.
184 uint256_t random_overflowing_value("0xcf9bb18d1ece5fd647afba497e7ea7a3d3bdb158855487614a97cd3d2a1954b2");
185 test_val = field_ct(&builder, bb::fr(random_overflowing_value));
186 EXPECT_THROW_OR_ABORT(byte_array<Builder> failure_array(test_val, 32, random_overflowing_value),
187 "byte_array: y_hi doesn't fit in 128 bits");
188 }
189 // Make sure no gates are added
190 EXPECT_TRUE(gates_start == builder.get_num_finalized_gates_inefficient());
191 }
192
194 {
196
197 uint256_t a_expected = engine.get_random_uint256();
198 uint256_t b_expected = engine.get_random_uint256();
199
200 field_ct a = witness_ct(&builder, slice_to_n_bytes(a_expected, 31));
201 a.set_origin_tag(submitted_value_origin_tag);
202 field_ct b = witness_ct(&builder, slice_to_n_bytes(b_expected, 31));
203 b.set_origin_tag(challenge_origin_tag);
204
205 // byte_array_ct(field, num_bytes) constructor adds range constraints for each byte
206 byte_array_ct a_bytes(a, 31);
207 byte_array_ct b_bytes(b, 31);
208
209 // Build byte_array by writing constrained byte_arrays
210 byte_array_ct arr(&builder, std::vector<uint8_t>());
211 arr.write(a_bytes);
212 arr.write(b_bytes);
213
214 EXPECT_EQ(arr.size(), 62UL);
215
216 field_ct a_result(arr.slice(0, 31));
217 field_ct b_result(arr.slice(31));
218
219 EXPECT_EQ(a_result.get_value(), slice_to_n_bytes(a_expected, 31));
220 EXPECT_EQ(b_result.get_value(), slice_to_n_bytes(b_expected, 31));
221 // Tags should be preserved through write and slice
222 EXPECT_EQ(a_result.get_origin_tag(), submitted_value_origin_tag);
223 EXPECT_EQ(b_result.get_origin_tag(), challenge_origin_tag);
224
225 bool verified = CircuitChecker::check(builder);
226 EXPECT_EQ(verified, true);
227 }
228
230 {
231 for (size_t arr_length = 1; arr_length < 32; arr_length++) {
232
234
235 // Generate random bytes
236 std::vector<uint8_t> native_bytes(arr_length);
237 for (size_t idx = 0; idx < arr_length; idx++) {
238 native_bytes[idx] = engine.get_random_uint8();
239 }
240
241 // Create byte_array from vector (this creates witnesses for each byte)
242 byte_array_ct test_array(&builder, native_bytes);
243
244 // Convert to field_t using the byte_array conversion
245 field_ct represented_field_elt = static_cast<field_ct>(test_array);
246
247 // Compute the expected value manually (big-endian)
248 uint256_t expected_value = 0;
249 for (size_t i = 0; i < arr_length; ++i) {
250 expected_value = (expected_value << 8) + native_bytes[i];
251 }
252
253 // Assert values match
254 EXPECT_EQ(represented_field_elt.get_value(), fr(expected_value));
255
256 // Check that the circuit is valid
257 bool result = CircuitChecker::check(builder);
258 EXPECT_TRUE(result);
259 }
260 }
261
263 {
265
266 std::string a = "\1\2\3a";
267 byte_array_ct arr(&builder, a);
268 std::ostringstream os;
269 os << arr;
270 EXPECT_EQ(os.str(), "[ 01 02 03 61 ]");
271 }
272};
273
274using CircuitTypes = ::testing::Types<bb::UltraCircuitBuilder>;
275
277
279{
280 TestFixture::test_reverse();
281}
282
283TYPED_TEST(ByteArrayTest, ByteDecompositionUnique)
284{
285 TestFixture::test_into_bytes_decomposition_less_than_32_bytes();
286}
287
288TYPED_TEST(ByteArrayTest, ByteDecompositionUniqueConst)
289{
290 TestFixture::test_into_bytes_decomposition_less_than_32_bytes_const();
291}
292
293TYPED_TEST(ByteArrayTest, ByteDecomposition32Bytes)
294{
295 TestFixture::test_into_bytes_decomposition_32_bytes();
296}
297
298TYPED_TEST(ByteArrayTest, ByteDecomposition32BytesConst)
299{
300 TestFixture::test_into_bytes_decomposition_32_bytes_const();
301}
302
303TYPED_TEST(ByteArrayTest, InputOutputConsistency)
304{
305 TestFixture::test_byte_array_input_output_consistency();
306}
307
308TYPED_TEST(ByteArrayTest, ConvertToField)
309{
310 TestFixture::test_conversion_to_field();
311}
312
313TYPED_TEST(ByteArrayTest, OstreamOperator)
314{
315 TestFixture::test_ostream_operator();
316}
#define EXPECT_THROW_OR_ABORT(statement, matcher)
Definition assert.hpp:174
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_byte_array_input_output_consistency()
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()
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
OriginTag get_origin_tag() const
Definition field.hpp:346
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
Definition field.cpp:828
AluTraceBuilder builder
Definition alu.test.cpp:124
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.
Definition api.hpp:5
TYPED_TEST_SUITE(ShpleminiTest, TestSettings)
field< Bn254FrParams > fr
Definition fr.hpp:174
TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching)
#define STANDARD_TESTING_TAGS
testing::Types< bb::MegaCircuitBuilder, bb::UltraCircuitBuilder > CircuitTypes
static constexpr uint256_t modulus
static field random_element(numeric::RNG *engine=nullptr) noexcept