fix(avm): sha256 modulo add bug #19262
Merged
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.

This is a really good one! The bug is both a soundness and completeness one.
Preamble
We perform addition (mod 32-bits) in Sha256Compression in two key places: during
perform_roundsand at the end (akalast) when we add the outputs of the rounds to the original input. We check that the correctness of the modulo operation by doingc = a + b; c = c_hi * 2**32 + c_loand we check thatc_hi < 2**32 && c_lo < 2**32.c_lois then the result of our addition.The bug
Turns out the selectors that turn on the range check for the modulo addition of the outputs with the inputs was wrong; it was using
perform_roundsinstead oflast.Soundess
perform_roundsandlastare mutually exclusive so actually we were not checking that the modulo addition of the outputs with the inputs were correct!Completeness
This is how the fuzzer found it. During
perform_roundsthe lookups for the outputs were still active (although they shouldnt have been). The active lookups were operating on default values, basically checking that0 < 2**32.Now in most cases if you perform "small" modulo addition (i.e 1 + 2 = 3), then
c_hi = 0(i.e. the upper bits are empty). Because of the nature of lookups (i.e. many-to-1 relationships) the buggy lookup was "passing" as they would be an entry of0 < 2**32in theGT subtracefrom some other modulo add.This means that the fuzzer found this bug because it found an input such that ALL modulo addition operations performed during the 64 rounds of XOR, ROTs, etc resulted in an overflow into the upper bits! This meant that the buggy lookup would fail (since there was no free
0 < 2**32). This manifests as aRANGE_COMP_H_LHSerror incheck_circuit. Additionally the fuzzer needed to generate a bytecode that had no OTHER operation that would have placed a trivial 0 < 2**32 entry in the GT trace