Skip to content

Conversation

@IlyasRidhuan
Copy link
Contributor

@IlyasRidhuan IlyasRidhuan commented Dec 27, 2025

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_rounds and at the end (aka last) when we add the outputs of the rounds to the original input. We check that the correctness of the modulo operation by doing c = a + b; c = c_hi * 2**32 + c_lo and we check that c_hi < 2**32 && c_lo < 2**32. c_lo is 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_rounds instead of last.

Soundess

perform_rounds and last are 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_rounds the lookups for the outputs were still active (although they shouldnt have been). The active lookups were operating on default values, basically checking that 0 < 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 of 0 < 2**32 in the GT subtrace from 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 a RANGE_COMP_H_LHS error in check_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

Copy link
Contributor Author

IlyasRidhuan commented Dec 27, 2025

Copy link
Contributor

@sirasistant sirasistant left a comment

Choose a reason for hiding this comment

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

It's pretty wild the fuzzer found this. Nice!

@IlyasRidhuan IlyasRidhuan force-pushed the ir/12-27-fix_avm_sha256_modulo_add_bug branch from 374ec40 to 1245550 Compare January 2, 2026 12:10
@IlyasRidhuan IlyasRidhuan merged commit 3c61b8c into merge-train/avm Jan 2, 2026
9 checks passed
@IlyasRidhuan IlyasRidhuan deleted the ir/12-27-fix_avm_sha256_modulo_add_bug branch January 2, 2026 13:54
@AztecBot AztecBot mentioned this pull request Jan 2, 2026
github-merge-queue bot pushed a commit that referenced this pull request Jan 5, 2026
BEGIN_COMMIT_OVERRIDE
fix(fuzzer): Fixes for backfilling (#19279)
fix(avm): sha256 modulo add bug (#19262)
fix(avm): preserve coordinates in embedded curve point (#19263)
fix(avm): precomp trace for get_p_limbs (#19266)
feat(avm): change to_radix backfill (#19277)
END_COMMIT_OVERRIDE
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.

3 participants