Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
multi_scalar_mul.test.cpp
Go to the documentation of this file.
2#include "acir_format.hpp"
6
7#include <gtest/gtest.h>
8#include <vector>
9
10using namespace ::acir_format;
11
12enum class InputConstancy : uint8_t { None, Points, Scalars, Both };
13
23template <typename Builder_, InputConstancy Constancy> class MultiScalarMulTestingFunctions {
24 public:
25 using Builder = Builder_;
26 using AcirConstraint = MultiScalarMul;
29 using FF = bb::fr;
30
32 public:
33 enum class Target : uint8_t {
34 None,
35 Points, // Invalidate point inputs
36 Scalars, // Invalidate scalar inputs
37 Result // Invalidate result output
38 };
39
44
45 static std::vector<std::string> get_labels() { return { "None", "Points", "Scalars", "Result" }; }
46 };
47
48 static ProgramMetadata generate_metadata() { return ProgramMetadata{}; }
49
50 static void generate_constraints(AcirConstraint& msm_constraint, WitnessVector& witness_values)
51 {
52 // Generate a single point and scalar for simplicity
54 bb::fq scalar_native = bb::fq::random_element();
55 GrumpkinPoint result = point * scalar_native;
56 BB_ASSERT(result != GrumpkinPoint::one()); // Ensure that tampering works correctly
57
58 // Split scalar into low and high limbs (128 bits each) as FF for witness values
59 uint256_t scalar_u256 = uint256_t(scalar_native);
60 FF scalar_lo = scalar_u256.slice(0, 128);
61 FF scalar_hi = scalar_u256.slice(128, 256);
62
63 // Determine which inputs are constants based on the Constancy template parameter
64 constexpr bool points_are_constant = (Constancy == InputConstancy::Points || Constancy == InputConstancy::Both);
65 constexpr bool scalars_are_constant =
66 (Constancy == InputConstancy::Scalars || Constancy == InputConstancy::Both);
67
68 // Helper to add points: either as witnesses or constants based on Constancy
69 auto construct_points = [&]() -> std::vector<WitnessOrConstant<FF>> {
70 if constexpr (points_are_constant) {
71 // Points are constants
72 return { WitnessOrConstant<FF>::from_constant(point.x),
73 WitnessOrConstant<FF>::from_constant(point.y),
74 WitnessOrConstant<FF>::from_constant(point.is_point_at_infinity() ? FF(1) : FF(0)) };
75 }
76 // Points are witnesses
77 std::vector<uint32_t> point_indices = add_to_witness_and_track_indices(witness_values, point);
78 return { WitnessOrConstant<FF>::from_index(point_indices[0]),
79 WitnessOrConstant<FF>::from_index(point_indices[1]),
80 WitnessOrConstant<FF>::from_index(point_indices[2]) };
81 };
82
83 // Helper to add scalars: either as witnesses or constants based on Constancy
84 auto construct_scalars = [&]() -> std::vector<WitnessOrConstant<FF>> {
85 if constexpr (scalars_are_constant) {
86 // Scalars are constants
87 return { WitnessOrConstant<FF>::from_constant(scalar_lo),
88 WitnessOrConstant<FF>::from_constant(scalar_hi) };
89 }
90 // Scalars are witnesses
91 uint32_t scalar_lo_index = static_cast<uint32_t>(witness_values.size());
92 witness_values.emplace_back(scalar_lo);
93 uint32_t scalar_hi_index = static_cast<uint32_t>(witness_values.size());
94 witness_values.emplace_back(scalar_hi);
95 return { WitnessOrConstant<FF>::from_index(scalar_lo_index),
96 WitnessOrConstant<FF>::from_index(scalar_hi_index) };
97 };
98
99 // Add points and scalars according to constancy template parameter
100 auto point_fields = construct_points();
101 auto scalar_fields = construct_scalars();
102
103 // Construct result and predicate as witnesses
104 std::vector<uint32_t> result_indices = add_to_witness_and_track_indices(witness_values, result);
105 uint32_t predicate_index = static_cast<uint32_t>(witness_values.size());
106 witness_values.emplace_back(FF::one()); // predicate
107
108 // Build the constraint
109 msm_constraint = MultiScalarMul{
110 .points = point_fields,
111 .scalars = scalar_fields,
112 .predicate = WitnessOrConstant<FF>::from_index(predicate_index),
113 .out_point_x = result_indices[0],
114 .out_point_y = result_indices[1],
115 .out_point_is_infinite = result_indices[2],
116 };
117 }
118
120 AcirConstraint constraint, WitnessVector witness_values, const InvalidWitness::Target& invalid_witness_target)
121 {
122 switch (invalid_witness_target) {
124 // Invalidate the point by adding 1 to x coordinate
125 if constexpr (Constancy == InputConstancy::None || Constancy == InputConstancy::Scalars) {
126 witness_values[constraint.points[0].index] += bb::fr(1);
127 } else {
128 constraint.points[0] = WitnessOrConstant<FF>::from_constant(constraint.points[0].value + bb::fr(1));
129 }
130 break;
131 }
133 // Invalidate the scalar by adding 1 to the low limb
134 if constexpr (Constancy == InputConstancy::None || Constancy == InputConstancy::Points) {
135 witness_values[constraint.scalars[0].index] += bb::fr(1);
136 } else {
137 constraint.scalars[0] = WitnessOrConstant<FF>::from_constant(constraint.scalars[0].value + bb::fr(1));
138 }
139 break;
140 }
142 // Tamper with the result by setting it to the generator point
143 witness_values[constraint.out_point_x] = GrumpkinPoint::one().x;
144 witness_values[constraint.out_point_y] = GrumpkinPoint::one().y;
145 witness_values[constraint.out_point_is_infinite] = FF::zero();
146 break;
147 }
149 default:
150 break;
151 }
152
153 return { constraint, witness_values };
154 };
155};
156
157template <typename Builder>
159 : public ::testing::Test,
160 public TestClassWithPredicate<MultiScalarMulTestingFunctions<Builder, InputConstancy::None>> {
161 protected:
163};
164
165template <typename Builder>
167 : public ::testing::Test,
168 public TestClassWithPredicate<MultiScalarMulTestingFunctions<Builder, InputConstancy::Points>> {
169 protected:
171};
172
173template <typename Builder>
175 : public ::testing::Test,
176 public TestClassWithPredicate<MultiScalarMulTestingFunctions<Builder, InputConstancy::Scalars>> {
177 protected:
179};
180
181template <typename Builder>
183 : public ::testing::Test,
184 public TestClassWithPredicate<MultiScalarMulTestingFunctions<Builder, InputConstancy::Both>> {
185 protected:
187};
188
189using BuilderTypes = testing::Types<UltraCircuitBuilder, MegaCircuitBuilder>;
190
195
197{
199 TestFixture::template test_vk_independence<Flavor>();
200}
201
203{
205 TestFixture::test_constant_true(TestFixture::InvalidWitnessTarget::Result);
206}
207
209{
211 TestFixture::test_witness_true(TestFixture::InvalidWitnessTarget::Result);
212}
213
215{
217 TestFixture::test_witness_false_slow();
218}
219
221{
223 [[maybe_unused]] std::vector<std::string> _ = TestFixture::test_invalid_witnesses();
224}
225
227{
229 TestFixture::template test_vk_independence<Flavor>();
230}
231
233{
235 TestFixture::test_constant_true(TestFixture::InvalidWitnessTarget::Result);
236}
237
239{
241 TestFixture::test_witness_true(TestFixture::InvalidWitnessTarget::Result);
242}
243
245{
247 TestFixture::test_witness_false_slow();
248}
249
251{
253 [[maybe_unused]] std::vector<std::string> _ = TestFixture::test_invalid_witnesses();
254}
255
257{
259 TestFixture::template test_vk_independence<Flavor>();
260}
261
263{
265 TestFixture::test_constant_true(TestFixture::InvalidWitnessTarget::Result);
266}
267
269{
271 TestFixture::test_witness_true(TestFixture::InvalidWitnessTarget::Result);
272}
273
275{
277 TestFixture::test_witness_false_slow();
278}
279
281{
283 [[maybe_unused]] std::vector<std::string> _ = TestFixture::test_invalid_witnesses();
284}
285
287{
289 TestFixture::template test_vk_independence<Flavor>();
290}
291
293{
295 TestFixture::test_constant_true(TestFixture::InvalidWitnessTarget::Result);
296}
297
299{
301 TestFixture::test_witness_true(TestFixture::InvalidWitnessTarget::Result);
302}
303
305{
307 TestFixture::test_witness_false_slow();
308}
309
311{
313 [[maybe_unused]] std::vector<std::string> _ = TestFixture::test_invalid_witnesses();
314}
#define BB_ASSERT(expression,...)
Definition assert.hpp:80
#define BB_DISABLE_ASSERTS()
Definition assert.hpp:33
Testing functions to generate the MultiScalarMul test suite. Constancy specifies which inputs to the ...
static ProgramMetadata generate_metadata()
static void generate_constraints(AcirConstraint &msm_constraint, WitnessVector &witness_values)
static std::pair< AcirConstraint, WitnessVector > invalidate_witness(AcirConstraint constraint, WitnessVector witness_values, const InvalidWitness::Target &invalid_witness_target)
constexpr bool is_point_at_infinity() const noexcept
static affine_element random_element(numeric::RNG *engine=nullptr) noexcept
Samples a random point on the curve.
static constexpr affine_element one() noexcept
group class. Represents an elliptic curve group element. Group is parametrised by Fq and Fr
Definition group.hpp:36
group_elements::affine_element< Fq, Fr, Params > affine_element
Definition group.hpp:42
constexpr uint256_t slice(uint64_t start, uint64_t end) const
TYPED_TEST(MultiScalarMulTestsNoneConstant, GenerateVKFromConstraints)
TYPED_TEST_SUITE(MultiScalarMulTestsNoneConstant, BuilderTypes)
bb::group< bb::fr, bb::fq, G1Params > g1
Definition grumpkin.hpp:45
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
field< Bn254FrParams > fr
Definition fr.hpp:174
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
::testing::Types< UltraCircuitBuilder, MegaCircuitBuilder > BuilderTypes
static constexpr field one()
static field random_element(numeric::RNG *engine=nullptr) noexcept
static constexpr field zero()