7#include <gtest/gtest.h>
45 static std::vector<std::string>
get_labels() {
return {
"None",
"Points",
"Scalars",
"Result" }; }
60 FF scalar_lo = scalar_u256.
slice(0, 128);
61 FF scalar_hi = scalar_u256.
slice(128, 256);
65 constexpr bool scalars_are_constant =
69 auto construct_points = [&]() -> std::vector<WitnessOrConstant<FF>> {
70 if constexpr (points_are_constant) {
72 return { WitnessOrConstant<FF>::from_constant(point.
x),
73 WitnessOrConstant<FF>::from_constant(point.
y),
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]) };
84 auto construct_scalars = [&]() -> std::vector<WitnessOrConstant<FF>> {
85 if constexpr (scalars_are_constant) {
87 return { WitnessOrConstant<FF>::from_constant(scalar_lo),
88 WitnessOrConstant<FF>::from_constant(scalar_hi) };
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) };
100 auto point_fields = construct_points();
101 auto scalar_fields = construct_scalars();
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());
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],
122 switch (invalid_witness_target) {
126 witness_values[constraint.points[0].index] +=
bb::fr(1);
128 constraint.points[0] = WitnessOrConstant<FF>::from_constant(constraint.points[0].value +
bb::fr(1));
135 witness_values[constraint.scalars[0].index] +=
bb::fr(1);
137 constraint.scalars[0] = WitnessOrConstant<FF>::from_constant(constraint.scalars[0].value +
bb::fr(1));
145 witness_values[constraint.out_point_is_infinite] =
FF::zero();
153 return { constraint, witness_values };
157template <
typename Builder>
159 :
public ::testing::Test,
160 public TestClassWithPredicate<MultiScalarMulTestingFunctions<Builder, InputConstancy::None>> {
165template <
typename Builder>
167 :
public ::testing::Test,
168 public TestClassWithPredicate<MultiScalarMulTestingFunctions<Builder, InputConstancy::Points>> {
173template <
typename Builder>
175 :
public ::testing::Test,
176 public TestClassWithPredicate<MultiScalarMulTestingFunctions<Builder, InputConstancy::Scalars>> {
181template <
typename Builder>
183 :
public ::testing::Test,
184 public TestClassWithPredicate<MultiScalarMulTestingFunctions<Builder, InputConstancy::Both>> {
189using BuilderTypes = testing::Types<UltraCircuitBuilder, MegaCircuitBuilder>;
199 TestFixture::template test_vk_independence<Flavor>();
205 TestFixture::test_constant_true(TestFixture::InvalidWitnessTarget::Result);
211 TestFixture::test_witness_true(TestFixture::InvalidWitnessTarget::Result);
217 TestFixture::test_witness_false_slow();
223 [[maybe_unused]] std::vector<std::string> _ = TestFixture::test_invalid_witnesses();
229 TestFixture::template test_vk_independence<Flavor>();
235 TestFixture::test_constant_true(TestFixture::InvalidWitnessTarget::Result);
241 TestFixture::test_witness_true(TestFixture::InvalidWitnessTarget::Result);
247 TestFixture::test_witness_false_slow();
253 [[maybe_unused]] std::vector<std::string> _ = TestFixture::test_invalid_witnesses();
259 TestFixture::template test_vk_independence<Flavor>();
265 TestFixture::test_constant_true(TestFixture::InvalidWitnessTarget::Result);
271 TestFixture::test_witness_true(TestFixture::InvalidWitnessTarget::Result);
277 TestFixture::test_witness_false_slow();
283 [[maybe_unused]] std::vector<std::string> _ = TestFixture::test_invalid_witnesses();
289 TestFixture::template test_vk_independence<Flavor>();
295 TestFixture::test_constant_true(TestFixture::InvalidWitnessTarget::Result);
301 TestFixture::test_witness_true(TestFixture::InvalidWitnessTarget::Result);
307 TestFixture::test_witness_false_slow();
313 [[maybe_unused]] std::vector<std::string> _ = TestFixture::test_invalid_witnesses();
340 return { u.
slice(0, 128), u.
slice(128, 256) };
353 uint32_t xi =
static_cast<uint32_t
>(witness.size());
354 witness.emplace_back(pt.
x);
355 uint32_t yi =
static_cast<uint32_t
>(witness.size());
356 witness.emplace_back(pt.
y);
357 uint32_t ii =
static_cast<uint32_t
>(witness.size());
358 witness.emplace_back(pt.
inf);
359 return { xi, yi, ii };
365 uint32_t lo_idx =
static_cast<uint32_t
>(witness.size());
366 witness.emplace_back(s.
lo);
367 uint32_t hi_idx =
static_cast<uint32_t
>(witness.size());
368 witness.emplace_back(s.
hi);
369 return { lo_idx, hi_idx };
376 WitnessVector witness;
380 uint32_t pred_idx =
static_cast<uint32_t
>(witness.size());
381 witness.emplace_back(
MsmFF(1));
384 .points = { WitnessOrConstant<MsmFF>::from_index(p[0]),
385 WitnessOrConstant<MsmFF>::from_index(p[1]),
386 WitnessOrConstant<MsmFF>::from_index(p[2]) },
387 .scalars = { WitnessOrConstant<MsmFF>::from_index(s[0]), WitnessOrConstant<MsmFF>::from_index(s[1]) },
388 .predicate = WitnessOrConstant<MsmFF>::from_index(pred_idx),
391 .out_point_is_infinite = r[2],
393 return { c, witness };
399 AcirFormat cs = constraint_to_acir_format(constraint);
400 AcirProgram program{ cs, witness };
401 auto builder = create_circuit<Builder>(program, ProgramMetadata{});
416 auto [constraint, witness] =
419 auto [ok, err] = TestFixture::run_circuit(constraint, witness);
420 EXPECT_TRUE(ok) <<
"0 * P = infinity should produce a valid circuit";
429 while (scalar_native.
is_zero()) {
434 auto [constraint, witness] = TestFixture::make_msm(
436 witness[constraint.out_point_is_infinite] =
MsmFF(1);
438 auto [ok, err] = TestFixture::run_circuit(constraint, witness);
439 EXPECT_TRUE(!ok || err.find(
"assert_eq") != std::string::npos)
440 <<
"Forged infinity flag on finite result should fail";
449 auto [constraint, witness] = TestFixture::make_msm(
452 auto [ok, err] = TestFixture::run_circuit(constraint, witness);
453 EXPECT_TRUE(!ok || err.find(
"assert_eq") != std::string::npos)
454 <<
"Forged finite flag on infinity result should fail";
492 auto [constraint, witness] = TestFixture::make_msm(
495 auto [ok, err] = TestFixture::run_circuit(constraint, witness);
496 EXPECT_FALSE(ok) <<
"scalar == Grumpkin scalar modulus must not produce a satisfiable circuit";
506 msm_scalar_from_u256(grumpkin_scalar_modulus +
uint256_t(1)),
509 auto [ok, err] = TestFixture::run_circuit(constraint, witness);
510 EXPECT_FALSE(ok) <<
"scalar == Grumpkin scalar modulus + 1 must not produce a satisfiable circuit";
522 msm_scalar_from_u256(grumpkin_scalar_modulus -
uint256_t(1)),
525 auto [ok, err] = TestFixture::run_circuit(constraint, witness);
526 EXPECT_TRUE(ok) <<
"scalar == Grumpkin scalar modulus - 1 (largest in-field scalar) should prove. err: " << err;
538 auto [constraint, witness] = TestFixture::make_msm(
541 auto [ok, err] = TestFixture::run_circuit(constraint, witness);
542 EXPECT_FALSE(ok) <<
"scalar == 2^254 - 1 (> Grumpkin modulus) must not produce a satisfiable circuit";
554 auto [constraint, witness] =
557 auto [ok, err] = TestFixture::run_circuit(constraint, witness);
558 EXPECT_FALSE(ok) <<
"scalar hi limb of 127 bits (value 2^254) must not produce a satisfiable circuit";
573 auto [constraint, witness] = TestFixture::make_msm(
575 auto [ok, err] = TestFixture::run_circuit(constraint, witness);
576 EXPECT_TRUE(ok) <<
"canonical scalar should prove the MSM result. err: " << err;
582 msm_scalar_from_u256(
uint256_t(5) + grumpkin_scalar_modulus),
584 auto [ok, err] = TestFixture::run_circuit(constraint, witness);
585 EXPECT_FALSE(ok) <<
"scalar s + r must not reprove the output of scalar s";
#define BB_ASSERT(expression,...)
#define BB_DISABLE_ASSERTS()
static std::pair< bool, std::string > run_circuit(MultiScalarMul constraint, WitnessVector witness)
static void SetUpTestSuite()
static std::array< uint32_t, 3 > push_point(WitnessVector &witness, const MsmAcirPoint &pt)
static std::array< uint32_t, 2 > push_scalar(WitnessVector &witness, const MsmScalar &s)
static std::pair< MultiScalarMul, WitnessVector > make_msm(MsmAcirPoint point, MsmScalar scalar, MsmAcirPoint result)
static std::vector< Target > get_all()
static std::vector< std::string > get_labels()
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)
MultiScalarMul AcirConstraint
static std::pair< AcirConstraint, WitnessVector > invalidate_witness(AcirConstraint constraint, WitnessVector witness_values, const InvalidWitness::Target &invalid_witness_target)
static void SetUpTestSuite()
static void SetUpTestSuite()
static void SetUpTestSuite()
static void SetUpTestSuite()
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
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
group_elements::affine_element< Fq, Fr, Params > affine_element
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
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
field< Bn254FqParams > fq
field< Bn254FrParams > fr
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
::testing::Types< UltraCircuitBuilder, MegaCircuitBuilder > BuilderTypes
static MsmAcirPoint infinity()
static MsmAcirPoint from_native(const MsmGrumpkinPoint &p)
static MsmScalar from_native(const bb::fq &s)
static constexpr field one()
static constexpr uint256_t modulus
static field random_element(numeric::RNG *engine=nullptr) noexcept
BB_INLINE constexpr bool is_zero() const noexcept
static constexpr field zero()