Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ecc_op_queue.test.cpp
Go to the documentation of this file.
2#include <gtest/gtest.h>
3
4using namespace bb;
5
7 public:
12
13 // Perform some basic interactions with the ECC op queue to mock the behavior of a single circuit
14 static void populate_an_arbitrary_subtable_of_ops(const std::shared_ptr<bb::ECCOpQueue>& op_queue)
15 {
16 auto P1 = G1::random_element();
17 auto P2 = G1::random_element();
18 auto z = Fr::random_element();
19
20 op_queue->initialize_new_subtable();
21 op_queue->add_accumulate(P1);
22 op_queue->mul_accumulate(P2, z);
23 op_queue->eq_and_reset();
24 }
25
30 static void check_table_column_polynomials(const std::shared_ptr<bb::ECCOpQueue>& op_queue,
31 MergeSettings settings,
32 std::optional<size_t> ultra_fixed_offset = std::nullopt)
33 {
34 // Construct column polynomials corresponding to the full table (T), the previous table (T_prev), and the
35 // current subtable (t_current)
36 auto table_polynomials = op_queue->construct_ultra_ops_table_columns();
37 auto prev_table_polynomials = op_queue->construct_previous_ultra_ops_table_columns();
38 auto subtable_polynomials = op_queue->construct_current_ultra_ops_subtable_columns();
39
40 // Check T(x) = t_current(x) + x^k * T_prev(x) at a single random challenge point
41 Fr eval_challenge = Fr::random_element();
42 for (auto [table_poly, prev_table_poly, subtable_poly] :
43 zip_view(table_polynomials, prev_table_polynomials, subtable_polynomials)) {
44 const Fr table_eval = table_poly.evaluate(eval_challenge); // T(x)
45 // Check that the previous table polynomial is constructed correctly according to the merge settings by
46 // checking the identity at a single point
47 if (settings == MergeSettings::PREPEND) {
48 // T(x) = t_current(x) + x^k * T_prev(x), where k is the size of the current subtable
49 const size_t current_subtable_size = op_queue->get_current_ultra_ops_subtable_num_rows(); // k
50 const Fr subtable_eval = subtable_poly.evaluate(eval_challenge); // t_current(x)
51 const Fr shifted_previous_table_eval = prev_table_poly.evaluate(eval_challenge) *
52 eval_challenge.pow(current_subtable_size); // x^k * T_prev(x)
53 EXPECT_EQ(table_eval, subtable_eval + shifted_previous_table_eval);
54 } else {
55 // APPEND merge performs concatenation directly to end of previous table or at a specified fixed offset
56 const size_t prev_table_size = op_queue->get_previous_ultra_ops_table_num_rows(); // k
57 const size_t shift_magnitude = ultra_fixed_offset.value_or(prev_table_size);
58 // T(x) = T_prev(x) + x^k * t_current(x), where k is the shift magnitude
59 const Fr prev_table_eval = prev_table_poly.evaluate(eval_challenge); // T_prev(x)
60 const Fr shifted_subtable_eval =
61 subtable_poly.evaluate(eval_challenge) * eval_challenge.pow(shift_magnitude); // x^k * t_current(x)
62 EXPECT_EQ(table_eval, shifted_subtable_eval + prev_table_eval);
63 }
64 }
65 }
66
72 static void check_opcode_consistency_with_eccvm(const std::shared_ptr<bb::ECCOpQueue>& op_queue)
73 {
74 auto ultra_table = op_queue->get_ultra_ops();
75 auto eccvm_table = op_queue->get_eccvm_ops();
76
77 EXPECT_EQ(eccvm_table.size(), ultra_table.size());
78
79 for (auto [ultra_op, eccvm_op] : zip_view(ultra_table, eccvm_table)) {
80 EXPECT_EQ(ultra_op.op_code.value(), eccvm_op.op_code.value());
81 }
82 };
83};
84
86{
87 using G1 = ECCOpQueueTest::G1;
88
89 ECCOpQueue op_queue;
91 op_queue.empty_row_for_testing();
92 op_queue.merge();
93 const auto& eccvm_ops = op_queue.get_eccvm_ops();
94 EXPECT_EQ(eccvm_ops[0].base_point, G1::one());
95 EXPECT_EQ(eccvm_ops[1].op_code.add, false);
96}
97
98TEST(ECCOpQueueTest, InternalAccumulatorCorrectness)
99{
100 using G1 = ECCOpQueueTest::G1;
101 using Fr = ECCOpQueueTest::Fr;
102
103 // Compute a simple point accumulation natively
104 auto P1 = G1::random_element();
105 auto P2 = G1::random_element();
106 auto z = Fr::random_element();
107 auto P_expected = P1 + P2 * z;
108
109 // Add the same operations to the ECC op queue; the native computation is performed under the hood.
110 ECCOpQueue op_queue;
111 op_queue.add_accumulate(P1);
112 op_queue.mul_accumulate(P2, z);
113
114 // The correct result should now be stored in the accumulator within the op queue
115 EXPECT_EQ(op_queue.get_accumulator(), P_expected);
116
117 // Adding an equality op should reset the accumulator to zero (the point at infinity)
118 op_queue.eq_and_reset();
119 EXPECT_TRUE(op_queue.get_accumulator().is_point_at_infinity());
120}
121
122// Check that the ECC op queue correctly constructs the table column polynomials for the full table, the previous table,
123// and the current subtable via successive prepending of subtables
124TEST(ECCOpQueueTest, ColumnPolynomialConstructionPrependOnly)
125{
126
127 // Instantiate an EccOpQueue and populate it with several subtables of ECC ops
128 auto op_queue = std::make_shared<bb::ECCOpQueue>();
129
130 // Check that the table polynomials have the correct form after each subtable concatenation
131 const size_t NUM_SUBTABLES = 5;
132 for (size_t i = 0; i < NUM_SUBTABLES; ++i) {
134 MergeSettings settings = MergeSettings::PREPEND;
135 op_queue->merge(settings);
137 }
138
140}
141
142TEST(ECCOpQueueTest, ColumnPolynomialConstructionPrependThenAppend)
143{
144
145 // Instantiate an EccOpQueue and populate it with several subtables of ECC ops
146 auto op_queue = std::make_shared<bb::ECCOpQueue>();
147
148 // Check that the table polynomials have the correct form after each subtable concatenation
149 const size_t NUM_SUBTABLES = 2;
150 for (size_t i = 0; i < NUM_SUBTABLES; ++i) {
152 MergeSettings settings = MergeSettings::PREPEND;
153 op_queue->merge(settings);
155 }
156
157 // Do a single append operation
159 MergeSettings settings = MergeSettings::APPEND;
160 op_queue->merge(settings);
162
164}
165
166TEST(ECCOpQueueTest, ColumnPolynomialConstructionPrependThenAppendAtFixedOffset)
167{
168
169 // Instantiate an EccOpQueue and populate it with several subtables of ECC ops
170 auto op_queue = std::make_shared<bb::ECCOpQueue>();
171
172 // Check that the table polynomials have the correct form after each subtable concatenation
173 const size_t NUM_SUBTABLES = 2;
174 for (size_t i = 0; i < NUM_SUBTABLES; ++i) {
176 MergeSettings settings = MergeSettings::PREPEND;
177 op_queue->merge(settings);
179 }
180
181 // Do a single append operation at a fixed offset (sufficiently large as to not overlap with the existing table)
182 const size_t ultra_fixed_offset = op_queue->get_ultra_ops_table_num_rows() + 20;
184 MergeSettings settings = MergeSettings::APPEND;
185 op_queue->merge(settings, ultra_fixed_offset);
186 ECCOpQueueTest::check_table_column_polynomials(op_queue, settings, ultra_fixed_offset);
187
189}
static void check_table_column_polynomials(const std::shared_ptr< bb::ECCOpQueue > &op_queue, MergeSettings settings, std::optional< size_t > ultra_fixed_offset=std::nullopt)
Check that the table column polynomials reconstructed by the op queue have the correct relationship.
static void check_opcode_consistency_with_eccvm(const std::shared_ptr< bb::ECCOpQueue > &op_queue)
Check that the opcode values are consistent between the ultra ops table and the eccvm ops table.
Curve::AffineElement G1
Curve::ScalarField Fr
static void populate_an_arbitrary_subtable_of_ops(const std::shared_ptr< bb::ECCOpQueue > &op_queue)
Used to construct execution trace representations of elliptic curve operations.
UltraOp add_accumulate(const Point &to_add)
Write point addition op to queue and natively perform addition.
Point get_accumulator()
void merge(MergeSettings settings=MergeSettings::PREPEND, std::optional< size_t > ultra_fixed_offset=std::nullopt)
std::vector< ECCVMOperation > & get_eccvm_ops()
UltraOp mul_accumulate(const Point &to_mul, const Fr &scalar)
Write multiply and add op to queue and natively perform operation.
UltraOp eq_and_reset()
Write equality op using internal accumulator point.
void empty_row_for_testing()
Write empty row to queue.
Structured polynomial class that represents the coefficients 'a' of a_0 + a_1 x .....
typename Group::affine_element AffineElement
Definition bn254.hpp:22
bb::fr ScalarField
Definition bn254.hpp:18
static constexpr affine_element affine_one
Definition group.hpp:48
Entry point for Barretenberg command-line interface.
TEST(MegaCircuitBuilder, CopyConstructor)
MergeSettings
The MergeSettings define whether an current subtable will be added at the beginning (PREPEND) or at t...
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::AffineElement G1
BB_INLINE constexpr field pow(const uint256_t &exponent) const noexcept
static field random_element(numeric::RNG *engine=nullptr) noexcept