Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
NB: To test this, you will need to delete your proving_files volume so that new keys are created.
docker compose down -v
will do this. Also, test without stubs because the circuits are changed, thus a stubbed test is inadequate.The nullifier is truncated to 31 bytes to prevent overflow but this truncation is not checked. This means that new nullifiers can be created by adding high-order bits to the nullifier, even without exceeding the modulus.
This PR fixes that by requiring the higher-order byte of the nullifier is zero. If not, a challenge is raised. This is slightly more efficient than including the check in the circuit, which would make the proof bigger but requires less code.
We also need to produce nullifier hashes with a zero higher order byte so that we don't fail our own check! This is done in the Nullifier class.
While we're at it, we make similar checks of the ERC addresses and commitments in the transaction, and that the root is less than the group order. These checks don't cover an obvious security issue, but we do it anyway, in case there's a less obvious one!
TokenIDs and Token values are not checked because these use u32 variables in the circuit, so cannot be overflowed in a useful way. Other variables have data types that are smaller than the group order and so cannot be attacked in this way.
The
compressedSecrets
were also truncated. This is an issue because an adversary could manipulate the higher bits to create encrypted secrets that the recipient cannot decrypt. This is more of a nuisance than a real attack but it does give the recipient plausible deniability of receipt. It is more complex to fix because it requires circuit witness changes (truncating a hash value just reduces entropy, truncating a compressed secret throws away required information) . The compressed secrets can be bigger than the group order because they contain an extra parity bit. We thus pass them into the circuit as a separate parity bit and an ordinate. This avoids any truncation.