Skip to content

Support compile-time evaluation of keccak256 - #16989

Open
matheusaaguiar wants to merge 5 commits into
developfrom
constant-evaluator-keccak-support
Open

matheusaaguiar wants to merge 5 commits into
developfrom
constant-evaluator-keccak-support

Conversation

@matheusaaguiar

@matheusaaguiar matheusaaguiar commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Implements #16421.

Introduces constant evaluation of the keccak256 builtin function.
Support for bytes32 constants is also added since the builtin needs it for argument and return values.
There are no user-visible changes because there is no comp-time context that uses bytes32 currently.

Also note that the commit containing the refactor of TypedValue is here for convenience.
I expected it to be merged already as part of another PR, but now I am tempted to move to its own 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.

Something feels off? Maybe I'm wrong.

Comment on lines +113 to +117
bytes result(_left.size());
unsigned bitWidth = static_cast<unsigned>(_left.size()) * 8;

if (_right.numerator() >= bitWidth)
return result;

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.

Are you sure? On evm.codes we have:

PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
PUSH2 450
SAR

evaluating to 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff

@matheusaaguiar matheusaaguiar Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Shifts are always truncated.
The docs don't say anything for fixed-size byte arrays, but it seems they are following the same rule.

SHL always set the new bits to 0, while SAR set to the value of the previous most significant bit.
Your example shows the described behavior of SAR
However, the codegen apparently always cleanup the value.

contract C {
    function f() public returns (bytes32, bytes32) {
        bytes32 x = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
        bytes32 y;
        assembly {
            y := sar(450, x)
        }
        return (y, x >> 450);
    }
}
// ----
// f() -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0x00

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ah, actually codegen uses SHR for fixed-bytes. So it is not about cleanup.
In both pipelines for unsigned values, it is used SHR.

@msooseth

msooseth commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Maybe we should have a property test for all comptime evaluations? Should not be tooooo hard to write using EVMOne + a generator for these expressions?

@matheusaaguiar

Copy link
Copy Markdown
Contributor Author

Maybe we should have a property test for all comptime evaluations? Should not be tooooo hard to write using EVMOne + a generator for these expressions?

Yeah, I have already started working on a property test for the shift/not PR (16597).
I was thinking about doing the same for this one.

@msooseth

Copy link
Copy Markdown
Contributor

Maybe we should have a property test for all comptime evaluations? Should not be tooooo hard to write using EVMOne + a generator for these expressions?

Yeah, I have already started working on a property test for the shift/not PR (16597). I was thinking about doing the same for this one.

Yay! ❤️

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.

2 participants