Skip to content

Reject a zero base with a negative exponent in constant evaluation - #17011

Closed
zexoverz wants to merge 1 commit into
argotorg:developfrom
zexoverz:16982-zero-neg-exp
Closed

zexoverz wants to merge 1 commit into
argotorg:developfrom
zexoverz:16982-zero-neg-exp

Conversation

@zexoverz

Copy link
Copy Markdown

The path in non_membership was walked from index, which nothing tied to queried_key, and calculate_root skipped zero siblings, so a sibling's slot was not tied to a level either. The two new pedersen tests are the forgeries from #72 and both passed on main: key 1's siblings moved to slots where key 3's bits give the same left/right order, and key 1's honest path walked with key 3 as the queried key. Each proves key 3 absent from a tree that holds it.

Every level from the deepest sibling up to the root is now hashed, zero siblings included, which is what the zk-kit JS tree does (its add pushes a zero sibling per shared bit and hashes it), so a slot is a level and every path bit above the matching entry is read. That alone rejects the relocation. The index is then bound with T: From<Field>, which Field and the noir-bignum types already implement, so no signatures change and the bignum test still passes. The new poseidon2 fixtures were generated with @zk-kit/smt and a leaf marker of 0, and that setup reproduces the existing roots too. A 254-level Poseidon2 non-membership goes from 4071 to 4372 ACIR opcodes.

Fixes #72

The exponentiation shortcut returned the base unchanged for 0 and 1
without looking at the sign of the exponent, so 0 ** (-1) evaluated to
0 instead of failing as a division by zero. Return nullopt for that
case, the same way the division and modulo cases do for a zero divisor.

Fixes argotorg#16982.
@msooseth

Copy link
Copy Markdown
Contributor

Can you please rebase this on top of develop? The CI has since been fixed :)

@msooseth

Copy link
Copy Markdown
Contributor

The text you put into this description doesn't focus on the change. Please fix it to laser-focus on the changeset in this PR.

@msooseth msooseth left a comment

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.

  1. Fix description.
  2. Explain rationale.
  3. Fix comment

Thanks!


// x ** 0 = 1
// for 0, 1 and -1 the size of the exponent doesn't have to be restricted
// 0 ** -n = 1 / 0 is a division by zero

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.

This goes to the if line below.

@cameel cameel left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It seems that this is a fix for #16982? @msooseth is right - the description is gibberish and must be fixed. It's also ignoring out template and missing the AI disclaimer.

It also looks like the the PR patches only a single symptom instead of addressing the bug thoroughly - the scientific form of literals seems to also be affected (0e-1 evaluates to zero as well, even after this fix).

This is actually a good example of why trying to patch random bugs en masse is often more of a burden than help for us. A critical look at the problem is just as important as the fix itself. We'd rather have one good, complete contribution than multiple PRs that just scratch the surface.

I'm going to close the PR as the issue is not yet ready to be worked on. The example I found indicates that the scope is larger than originally reported and the helpful thing at this stage is to explore that in the issue rather than post code that has to be reviewed. You also have multiple other pending PRs (#17010, #16949) that need to be reviewed first.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

A syntax test does not verify that the result is correct. We should have a semantic test for this.

Comment on lines +2 to +6
uint constant a = 0 ** (-1);
uint constant b = 0 ** (-2);
function f() public pure returns (uint) {
return 0 ** (-1);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

constant is superfluous. The effect would be the same with a normal state variable. If your intention was to guarantee that this is comptime evaluated, you should put it in a layout specifier or array size instead.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The name of this test is misleading and does not really describe what it does. It's not testing only operations with zero base. Seems to be covering negative/positive exponent/base combinations. Though for that it would also cover some values that are not 0 or 1 in each case.

@@ -0,0 +1,11 @@
contract C {
uint constant a = 0 ** (-1);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please check if we have tests for scientific form as well. I.e. 0e-1. If we don't we should add them.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Also constants. But not the way you're using them - constants that are used within the expression, i.e.:

  • uint constant SIZE = ZERO ** MINUS_ONE;
  • uint array[ZERO ** MINUS_ONE];
  • uint array[SIZE];

The first one should compile and revert at runtime. The second and third should fail at compilation time.

Comment on lines +4 to +5
uint constant c = 1 ** (-1);
int constant d = (-1) ** (-1);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No need to parenthesize if it's not a complex expression.

Suggested change
uint constant c = 1 ** (-1);
int constant d = (-1) ** (-1);
uint constant c = 1**-1;
int constant d = (-1)**-1;

Comment thread Changelog.md
Compiler Features:

Bugfixes:
* Type Checker: Reject `0 ** (-1)` and other literal expressions with base `0` and a negative exponent as a division by zero instead of silently evaluating them to `0`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
* Type Checker: Reject `0 ** (-1)` and other literal expressions with base `0` and a negative exponent as a division by zero instead of silently evaluating them to `0`.
* Constant Evaluator: Reject exponentiation with base `0` and a negative exponent in comptime expressions as a division by zero instead of evaluating it to `0`.

@cameel cameel closed this Sep 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

modifier overloading

3 participants