Skip to content

Cleanup Verifier.sol and make error handling consistent #96

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Apr 4, 2022

Conversation

recmo
Copy link
Contributor

@recmo recmo commented Mar 23, 2022

Pull request checklist

Please check if your PR fulfills the following requirements:

  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been reviewed and added / updated if needed (for bug fixes / features)
  • Build (yarn compile) was run locally and any changes were pushed
  • Lint (yarn lint) has passed locally and any fixes were made for failures

Pull request type

Please check the type of change your PR introduces:

  • Bugfix
  • Feature
  • Code style update (formatting, renaming)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • Documentation content changes
  • Other (please describe):

What is the current behavior?

Currently when provided with an invalid proof, the verifier will either:

  • return false,
  • execute the invalid() opcode,
  • revert with one of a variety of error messages, like
    • verifier-gte-snark-scalar-field
    • pairing-add-failed,
    • etc..

This makes handling invalid proofs hard. Returning false is especially dangerous because it puts the burden on the caller.

What is the new behavior?

When provided with an invalid proof, the verifier will:

  • revert with InvalidProof()

In the unlikely event that the caller desires different behaviour, the caller can use a Solidity try/catch statement.

Does this introduce a breaking change?

  • Yes
  • No

The revert error message for an invalid proof changes.

Other information

@recmo
Copy link
Contributor Author

recmo commented Mar 24, 2022

My next move would be to remove the return value from _isValidProof, but at that point the name should also change. I want to check in and get maintainers opinion first.

Personally I prefer to revert on invalid proofs. This prevents errors where the result is accidentally ignored. (See for example also safeTransfer and why it exists) I don't think there are cases where callers would want any thing else, but if so they can always intercept the using try/catch.

Copy link
Collaborator

@kobigurk kobigurk left a comment

Choose a reason for hiding this comment

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

Are you sure EIP196 verifies input is in the correct range?

Specifically:

image

@cedoor cedoor self-requested a review March 24, 2022 09:48
Copy link
Member

@cedoor cedoor left a comment

Choose a reason for hiding this comment

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

Hi! After the next Semaphore ceremony we will have more verifiers (> 10). Since this code is regenerated every time from SnarkJS templates I think it is better to create a new verifier_groth16.sol.ejs template with your changes.

@recmo
Copy link
Contributor Author

recmo commented Mar 24, 2022

@kobigurk Looks like you are partially right: field elements are verified, but scalars are not considered field elements.

Screen Shot 2022-03-24 at 09 19 21

@kobigurk
Copy link
Collaborator

@kobigurk Looks like you are partially right: field elements are verified, but scalars are not considered field elements.

Screen Shot 2022-03-24 at 09 19 21

Ah yes, exactly the distinction I was looking for. Super dangerous :)

@recmo
Copy link
Contributor Author

recmo commented Mar 24, 2022

Ok, so let's be conservative here and reject proofs where the input is not reduced. I'll add a commit.

@kobigurk
Copy link
Collaborator

Ok, so let's be conservative here and reject proofs where the input is not reduced. I'll add a commit.

Thanks! Btw, it's not only conservative, it's a direct attack vector - a16z/zkdrops#2

@recmo
Copy link
Contributor Author

recmo commented Mar 24, 2022

I made all the functions in Pairing strict on the input. Note that before Pairing.negate(..) would accept an unreduced Y coordinate, so there was malleability in Proof.A.

I don't know if this removes all proof malleability for people other than the prover. (i.e. given a valid proof but not the private inputs, can I compute a different also valid proof)

@recmo
Copy link
Contributor Author

recmo commented Mar 24, 2022

@cedoor I suspected there was some template involved, despite the usual warning comment missing. Thanks for the link, I will submit a PR there too.

I think we can still merge it here, the only thing that changes with a new ceremony is the contents of the verifyingKey() function, so that should be easy to update. The only other thing that can possibly change (assuming same proof system) is the number of inputs, which is also trivially changed in verifyProof().

@kobigurk
Copy link
Collaborator

I made all the functions in Pairing strict on the input. Note that before Pairing.negate(..) would accept an unreduced Y coordinate, so there was malleability in Proof.A.

I don't know if this removes all proof malleability for people other than the prover. (i.e. given a valid proof but not the private inputs, can I compute a different also valid proof)

It removes "public input" malleability, which is the dangerous part. Proofs can still be modified, because Groth16 is randomizable.

@recmo recmo requested review from cedoor and kobigurk March 31, 2022 19:31
[root, nullifierHash, signalHash, externalNullifier]
);

return true; // TODO: This is redundant
Copy link
Member

Choose a reason for hiding this comment

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

Can't we remove this line? Updating the extension contracts should be sufficient to make this change compatible

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Happy to do so! I left it to limit the scope of changes.

Copy link
Member

@cedoor cedoor Apr 3, 2022

Choose a reason for hiding this comment

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

Seems you need to run yarn prettier:fix to pass tests.

@recmo recmo requested a review from cedoor April 2, 2022 22:05
@cedoor cedoor merged commit d001dd9 into semaphore-protocol:main Apr 4, 2022
@cedoor cedoor added the feature 🚀 This is enhancing something existing or creating something new label Apr 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature 🚀 This is enhancing something existing or creating something new
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants