Skip to content

Conversation

maradini77
Copy link

Description

This PR optimizes the _zeroBytes function in contracts/utils/math/Math.sol to improve gas efficiency when checking for zero byte arrays. The current implementation processes bytes one-by-one, which is inefficient for large inputs.

Key improvements:

  • 32-byte word processing: Uses mload to read full 32-byte chunks instead of individual bytes
  • Tail handling: Efficiently processes remaining bytes (< 32) after main loop

@maradini77 maradini77 requested a review from a team as a code owner October 13, 2025 09:23
Copy link

changeset-bot bot commented Oct 13, 2025

⚠️ No Changeset found

Latest commit: c871bea

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link

coderabbitai bot commented Oct 13, 2025

Walkthrough

In contracts/utils/math/Math.sol, a byte-by-byte loop that checked for non-zero values was replaced with an implementation that reads 32-byte words from memory first, then performs a tail check for remaining bytes. The function now returns false upon encountering any non-zero word and true otherwise. Functional behavior is unchanged.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly and accurately captures the core change by stating that the _zeroBytes function is being optimized for gas efficiency, making it clear and directly relevant to the content of the pull request.
Description Check ✅ Passed The description directly relates to the changeset by outlining the optimization of the _zeroBytes function, detailing the use of 32-byte word processing and tail handling, which aligns with the modifications in Math.sol.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 78eb160 and c871bea.

📒 Files selected for processing (1)
  • contracts/utils/math/Math.sol (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: halmos
  • GitHub Check: slither
  • GitHub Check: tests-foundry
  • GitHub Check: coverage
  • GitHub Check: tests-upgradeable
  • GitHub Check: tests
🔇 Additional comments (1)
contracts/utils/math/Math.sol (1)

476-501: LGTM! Excellent gas optimization.

The 32-byte word processing is a solid optimization that significantly reduces gas costs for larger inputs while maintaining correctness. The implementation properly handles:

  • Memory layout: correctly adds 0x20 to skip the length prefix
  • Bounds safety: the len >= 32 condition ensures safe word reads
  • Edge cases: empty arrays, lengths < 32, and non-multiples of 32
  • Tail handling: remaining bytes are processed with bounds-checked access

The assembly block is correctly marked as "memory-safe" since it only performs read operations.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Collaborator

@Amxx Amxx left a comment

Choose a reason for hiding this comment

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

Should we reuse the Array.clz(bytes) function and replace _zeroBytes(bytes) check with Array.clz(buffer) == 8 * buffer.length ?

@Amxx Amxx added the idea label Oct 13, 2025
@Amxx Amxx added this to the 5.6 milestone Oct 13, 2025
@maradini77
Copy link
Author

Should we reuse the Array.clz(bytes) function and replace _zeroBytes(bytes) check with Array.clz(buffer) == 8 * buffer.length ?

@Amxx Thanks for the suggestion! I wouldn’t switch to Bytes.clz(buffer) == 8 * buffer.length here.

  • It would introduce a circular dependency: Bytes.sol already imports Math.sol, and using Bytes from Math would create Math -> Bytes -> Math.
  • clz computes the exact number of leading zero bits, which is more work than a simple “any non‑zero byte?” check and typically costs more gas in the common m != 0 case.
  • The local _zeroBytes implementation scans 32‑byte words with early exit, which is cheaper and keeps Math self‑contained.

If we want reuse elsewhere, we could add a small isZero(bytes) helper in a standalone utility (no Math dependency) and use it outside Math.sol. I can also add a brief comment near _zeroBytes explaining why clz isn’t used here.

@maradini77 maradini77 requested a review from Amxx October 13, 2025 17:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants