Skip to content

feat(acir static analysis): MSM constraints#20540

Open
defkit wants to merge 19 commits intosn/acir_ec_add_constraints_partial_checkfrom
sn/acir_msm_constraint_validation
Open

feat(acir static analysis): MSM constraints#20540
defkit wants to merge 19 commits intosn/acir_ec_add_constraints_partial_checkfrom
sn/acir_msm_constraint_validation

Conversation

@defkit
Copy link
Contributor

@defkit defkit commented Feb 16, 2026

Checks that

  1. input points' on curve check exist
  2. scalars checks exist
  3. output point is connected with the result of batch_mul

We skip tracing batch_mul, because it is way too complex

@AztecBot
Copy link
Collaborator

AztecBot commented Feb 16, 2026

Flakey Tests

🤖 says: This CI run detected 1 tests that failed, but were tolerated due to a .test_patterns.yml entry.

\033FLAKED\033 (8;;http://ci.aztec-labs.com/a8fb85b08ed5fb8b�a8fb85b08ed5fb8b8;;�): yarn-project/scripts/run_test.sh p2p/src/client/test/p2p_client.integration_message_propagation.test.ts (69s) (code: 1) group:e2e-p2p-epoch-flakes

auto y2 = (*real_input2).y;
auto inf2 = (*real_input2).is_infinite;

// If both points are constant, operator+ is computed natively without gates
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same check twice, we checked is_point_const above

Comment on lines -634 to -639
// Range constraint consists of variable index and num bits to be constrained.
// num bits == 1 => bool gate
// num bits <= 14 => arithmetic gate + create_new_range_constraint <=> arithmetic gate + list[tag]
// num bits > 14 => decompose_into_default_range => decompose chain with additional range constrains for sublimbs
//
const auto& variable_gates = analyzer.get_variable_gates(analyzer.to_real(witness));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DanielKotov FYI, moved to helpers/range_helpers.hpp

@defkit defkit requested a review from Rumata888 February 16, 2026 16:58
* tba = conditional_assign(predicate, input_result, result)
* result.assert_equal(tba)
*
* Tracing batch_mul internals is impractical (complex multi-point multiplication), so the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PLease add a TODO to implement the proper tracing (maybe by using fuzzy hashes) in the future

return std::nullopt;
}

return get_field_from_w_o<FF>(builder, filtered[0]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if several are found?

Copy link
Contributor Author

@defkit defkit Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's actually a bug in all helpers
All helpers assume that the first match is the correct one, which is not true
e.g. in cases when the points shares the same is_infinite witness, to_grumpkin_point will create different variables for conditional_assign result and that will break validation

ii have to refactor all helpers to iterate through all possible gates...

Copy link
Contributor Author

@defkit defkit Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the latest change we assume that the first occurrence of non-consumed normalization gate is the correct one.

It still can be an issue in really strange cases if we encounter the same witness being used in previous constraints, processed by Daniel's functions, but it will be easy to fix in future

* @details mirrors bool_t::assert_bool
*/
template <typename FF, typename CircuitBuilder>
bool is_boolean_gate_exists(StaticAnalyzer_<FF, CircuitBuilder>& analyzer,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does_boolean_gate_exist

bool condition = true;

// 1. Verify on-curve check for all input points
for (size_t i = 0; i < constraint->points.size(); i += 3) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if it's not a multiple of 3?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is asserted by create_multi_scalar_mul_constraint
image

using namespace bb;
using namespace acir_format;
using namespace cdg;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need more extensive tests with longer MSMs and various combinations

uint32_t witness_idx)
{
auto filter_helper = FilterFunctionBuilder<CircuitBuilder, FF>(builder)
.set_w_l(witness_idx)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't check w_r is the same

@defkit
Copy link
Contributor Author

defkit commented Feb 18, 2026

In the latest commit I've refactored filtering logic; introduced "consumed" gates mechanism.

It is needed for special cases, when the same witness is reused in similar ACIR constraints, (e.g #20540 (comment) )

I still think that taking the first non-consumed gate, which matches the condition is good enough, because variable_gates are populated sequentially, keeping the same order as in constraints. I cannot see the case, when the first matching gate is incorrect one

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants