Skip to content

Conversation

@pmikolajczyk41
Copy link
Member

@pmikolajczyk41 pmikolajczyk41 commented Nov 17, 2025

pulled in by OffchainLabs/nitro#4122

upstream PR was rejected as non-essential
closes NIT-4123

Context

Keccak hashing algorithm can be used in two ways: (1) as a one-shot hash function (we are just interested in hash of the data that we already have in full) or (2) as a cryptographic sponge (for cases where we don't know all the data to be hashed yet, we need some intermediate hashes, etc.)

From the caller perspective, (1) is a completely stateless process, but (2) requires keeping some state.

The crypto package exposes Keccak256Hash() and Keccak256() functions realizing (1) and NewKeccakState() for (2).

Problem

There are ~20 places where we use stateful approach (2) for (1). In other words, we:

  • use NewKeccakState() to create the sponge state
  • (optionally) keep it as a field
  • use lower-level methods on this object to compute the hash (Write(), Read(), Sum())
    whereas we could (and should) just use Keccak256() utility.

Proposed changes

  1. Use stateless keccaking wherever possible. It seems that the only place we actually need stateful one is the spongeDb in some testing.
  2. Do some minor refactor to deduplicate logic between Keccak256Hash() and Keccak256()
  3. Make KeccakState interface just extend io.Reader instead of inlining io.Reader's method

Motivation

When running geth within ZK VM (like SP1) it is highly beneficial to outsource heavy computation (like Keccak) to the dedicated VM precompiles. By removing all unnecessarily stateful hashing and reusing the Keccak256Hash() and Keccak256() utilities, it is way easier to replace all keccak invocations than to worry that some of them will persist in this strange form.

@pmikolajczyk41 pmikolajczyk41 marked this pull request as ready for review December 4, 2025 10:19
@pmikolajczyk41 pmikolajczyk41 changed the title arbitrum: Unify keccaking all: Unify keccaking Dec 4, 2025
Copy link
Contributor

@bragaigor bragaigor left a comment

Choose a reason for hiding this comment

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

LGTM, wondering if we should run a complete set of tests on nitro side just to be double sure everything still works?

@pmikolajczyk41
Copy link
Member Author

pmikolajczyk41 commented Dec 4, 2025

LGTM, wondering if we should run a complete set of tests on nitro side just to be double sure everything still works?

@bragaigor good point! I have opened a companion PR in nitro: OffchainLabs/nitro#4108 - CI is green ✅

Copy link
Member

@eljobe eljobe left a comment

Choose a reason for hiding this comment

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

I'm nervous about this change.

I could be completely wrong. But, I seem to remember that the resetting the incremental version of the KeccakState instance is less computationally expensive than allocating and destroying it over and over again (which is what happens inside Keccak256.

Did you run any benchmarks to test for possible regressions?

I could be wrong. But, I don't want to cause a big performance slow-down in our current validators as we get ready for our future ZK-Validators.

@eljobe eljobe assigned pmikolajczyk41 and unassigned eljobe Dec 4, 2025
@pmikolajczyk41
Copy link
Member Author

@eljobe please notice that I'm using Keccak256 and Keccak256Hash functions that do not allocate and destroy any state - they both use a common pool of states and reset a 'borrowed' state.

@eljobe
Copy link
Member

eljobe commented Dec 4, 2025

@eljobe please notice that I'm using Keccak256 and Keccak256Hash functions that do not allocate and destroy any state - they both use a common pool of states and reset a 'borrowed' state.

This does make me more comfortable. In fact, I'm going approve and merge the change. But, I'd still love to have seen the output of a benchmarking run that showed that the replacement doesn't introduce any performance overhead. (For example, I could imagine that a heavily contended for pool of hashers might introduce some locking or something.) But, at least, the code is trying to be as efficient as the previous implementation.

@eljobe eljobe merged commit 9032013 into master Dec 4, 2025
17 checks passed
@eljobe eljobe deleted the pmikolajczyk/nit-4123-keccaking branch December 4, 2025 14:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants