Skip to content

chore: makes ec addition opcode unsafe#8814

Closed
guipublic wants to merge 54 commits into
nextfrom
gd/unsafe_ec_add2
Closed

chore: makes ec addition opcode unsafe#8814
guipublic wants to merge 54 commits into
nextfrom
gd/unsafe_ec_add2

Conversation

@guipublic

@guipublic guipublic commented Sep 26, 2024

Copy link
Copy Markdown
Contributor

This PR is the same as #8374, but with some added runtime checks as suggested by @zac-williamson.
#8374 was merged and then rollback because it caused issues with e2e tests.
We should not merge this one until this issue is fixed, but I need the PR as ready for review in order to have the CI to run.

The PR makes the ACIR opcode 'EC ADD' unsafe because the safety checks are now done on the Noir side in the stdlib's embedded curve operations.
It will allow Aztec protocol circuit to use directly the opcode when the 'safety' is already known (and implied by previous operations).

EDIT: this unsafe EC ADD now handles points at infinity.
If they are constant, it works as expected
If not, it simply returns the infinity point.
This ensures that there is no performance impact (the checks are constant-time), but still support in a way the infinite points, i.e it does not crash and returns a valid point, although it is an incorrect result, when the infinite status cannot be resolved at constant time.

@github-actions

github-actions Bot commented Sep 26, 2024

Copy link
Copy Markdown
Contributor

Changes to circuit sizes

Generated at commit: 393fe779227f5114dd6044e3b1c5dda768b6f719, compared to commit: 1801f5b49fb3b153817a1596c6fd568f1c762fe5

🧾 Summary (100% most significant diffs)

Program ACIR opcodes (+/-) % Circuit size (+/-) %
private_kernel_reset_4_4_4_4_4_4_4_4_1 0 ➖ 0.00% -4 ✅ -0.01%
private_kernel_reset 0 ➖ 0.00% -64 ✅ -0.01%

Full diff report 👇
Program ACIR opcodes (+/-) % Circuit size (+/-) %
private_kernel_reset_4_4_4_4_4_4_4_4_1 34,897 (0) 0.00% 74,475 (-4) -0.01%
private_kernel_reset 91,933 (0) 0.00% 467,666 (-64) -0.01%

@guipublic guipublic changed the title chore: makes ec addition opcode unsafe **DO NOT MERGE** chore: makes ec addition opcode unsafe Oct 3, 2024
@guipublic guipublic requested a review from TomAFrench October 4, 2024 16:29

@TomAFrench TomAFrench left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Happy to merge once CI is passing.

Comment thread barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.hpp Outdated
namespace acir_format {

// This functions assumes that:
// 1. the points are on the curve

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What if the points are not on the curve? Where do we check that?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is the responsibility of the user, that's the point of this ec-add-unsafe; to avoid as many check as possible.
The checks done by the function have no cost because they are constant-time.
One use case is when you are adding points coming from a previous addition, so you know that the points are on the curve (if you checked the first ones) and there is no need to check this.

Note that the ec-add in Noir performs most of the checks

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Right, makes sense

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I just noticed that you don't detect the case where x_match by not y_match

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I added a check for this case:

  • if x match and y does not match, at compile time, then return 0
  • else, if x match, then return error
  • else: we assume x-coordinates are distincts and will do the unconditional add

input.input2_y,
input.input2_infinite,
has_valid_witness_assignments,
false,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These two ifs are equivalent, but you create the point with 'use_g1' being set to different values

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Any valid point would do here, it is just for consistency, as I use G1 for point1 and G2=2G1 for point2 elsewhere in the file.
But I don't mind changing it.

input.input1_y,
input.input1_infinite,
has_valid_witness_assignments,
true,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same here. Why is 1 true and 2 false?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Here it matters, because the two points must be distinct (else it would be a doubling).

// Runtime check that the inputs have not the same x coordinate, as assumed by the function.
ASSERT(input1_point.x.get_value() != input2_point.x.get_value());
}
result = input1_point.unconditional_add(input2_point);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why are you using unconditional add? Are you checking that the inputs are different? If the values are the same, this could allow you to create any point as a result

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is the whole point of the PR, the checks have been moved on the Noir side so that we can avoid them in some cases. See this comment in the PR description:
"It will allow Aztec protocol circuit to use directly the opcode when the 'safety' is already known (and implied by previous operations)."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You shouldn't remove the difference!=zero check. It is always necessary. There is no case that it is not necessary, when you are performing non-doubling additions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I disagree, else the function unconditional_add() would not exist. See the comments of the function:

  •    Only use this method if you know the x-coordinates of the operands cannot collide and none of the operands is a point at infinity
    

For instance it is used for batch mul:

  •     If `unconditional_add = true`, we use `::unconditional_add` instead of `::checked_unconditional_add`. Use with caution! Only should be `true` if we're doing an ULTRA fixed-base MSM so we know the points cannot collide with the offset generators.
    

@Rumata888 Rumata888 Jul 4, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The function unconditional add is only used in 2 cases:

  1. We know that the values provided are from a CRS and getting a combination of those that would be equal is tantamount to solving the discrete log
  2. We use it in our own batch mul, when we specifically want to save 1 gate by batching non-zero checks.

However, these are extremely rare situations. It is extremely dangerous to leave the operation like this by default, because then it does not ensure the correctness of additions at all in 99% of cases. If you really want to allow the developer to disable this particular check, then there should be a setting that allows this (with loud disclaimers). It shouldn't be by default

@guipublic guipublic Jul 4, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I will add a setting then.
In fact no, I will add the check because I don't want to have to change ACIR format.
I'll add the setting later, if this PR manage to go through!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

size_t generate_ec_add_constraint(EcAdd& ec_add_constraint, WitnessVector& witness_values)
{
using cycle_group_ct = bb::stdlib::cycle_group<Builder>;
witness_values.push_back(0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could you please add tests for all the edgecases? Right now we are only testing 1 case out of all the possibilities

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I am not sure because the edge cases are not expected to work.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I mean the various combinations of constant and witness elements, cases where it turns into a double, etc.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

@guipublic guipublic requested a review from Rumata888 July 11, 2025 12:49
@guipublic

Copy link
Copy Markdown
Contributor Author

I am closing this because this is now deprecated. Ec-Add is still safe in BB, and the code has been validated and audited, so we cannot change this for now.
This approach is still valid in theory and could be added in the future: having a 'fast' Ec-Add in BB and a validation in Noir, so that one can use the fast version and avoid Noir validation when it is safe to do.

@guipublic guipublic closed this Jun 3, 2026
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.

5 participants