Skip to content

bugc: hash several value-type words with keccak256 - #365

Closed
gnidan wants to merge 2 commits into
mainfrom
bugc-hash-words
Closed

gnidan wants to merge 2 commits into
mainfrom
bugc-hash-words

Conversation

@gnidan

@gnidan gnidan commented Oct 7, 2026

Copy link
Copy Markdown
Member

BUG had no way to hash more than one value: keccak256 took exactly one bytes or string argument, and BUG has no abi.encode or concatenation. A roll like Solidity's keccak256(abi.encode(block.prevrandao, msg.sender)) could not be written.

keccak256 now has two forms, told apart by the argument types:

  • One dynamic bytes or string hashes its data, as before.
  • One or more value types (integers, address, bool, bytesN) hashes their 32-byte words, concatenated in order. For integers, address and bool this is Solidity's keccak256(abi.encode(a, b, ...)), including a negative signed value's sign-extended word.

A bytes or string among several arguments is a type error. A single value-type argument (keccak256(n)) now type-checks too; it hashes its word, which is what a bytesN argument already did.

A bytesN narrower than 32 bytes hashes its full word with its bytes at the right end, as BUG holds it. abi.encode puts them at the left end, so those hashes differ from Solidity's; x as bytes32 moves the bytes to the left end and matches. The examples README documents both forms and this difference.

In the IR, hash now has values: Value[] in place of value (and the unused valueDebug), and each pass that reads operands handles the list. Code generation stores one or two words in the scratch space at 0x00, as before, and more words at the free memory pointer, without allocating them. Constant folding hashes constant words the same way, so a hash of constants folds at levels 1 to 3. @ethdebug/bugc-react's IR and CFG views show every operand.

The behavioral tests compare against keccak256 over the words of abi.encode at levels 0 to 3: constants, locals, storage values, msg.sender, narrow integers, a bool, a negative int8, a bytes32 with three words in all, a bytes4 before and after a cast to bytes32, and a roll. One test checks that the optimizer folds keccak256(7, 9) to the same constant. I also checked one program against solc 0.8.37: its keccak256(abi.encode(...)) results for (int8(-3), a), (uint8(200), true) and (42, msg.sender) equal bugc's at each level.

@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://ethdebug.github.io/format/pr-preview/pr-365/

Built to branch gh-pages at 2026-10-07 02:21 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

gnidan added a commit that referenced this pull request Oct 7, 2026
* bugc: compile `!` as a logical not

* bugc: link the changelog entry to #353

* bugc: end each source range at its last token

* bugc: link the changelog entry to #362

* bugc: add block.prevrandao

* bugc: link the changelog entries to #363

* bugc: hash several value-type words with keccak256

* bugc: link the changelog entries to #365

* bugc: slice a fixed-size bytes value by its bytes

* bugc: link the changelog entry to #357

* bugc: hash the data of dynamic bytes and strings

* bugc: link the changelog entry to #360

* bugc: give a caller's call JUMP the invoke's arguments

* bugc: list variables before a function's first statement

* bugc: store a memory string's bytes when assigning it to storage

A storage write took its value as a word, so a memory string or bytes
reference wrote its memory address into the slot. Code generation now
encodes the referenced bytes as Solidity does: inline with length * 2
up to 31 bytes, else length * 2 + 1 in the slot and the data from
keccak256(slot), with the last word's trailing bytes cleared. A slice
now carries the bytes type, so its value is recognized too.

* bugc: link the changelog entry to #355

* bugc: say why the bytes test slices without naming the copy width

* bugc: copy all of a slice's bytes

irgen built a slice's data as a read and a write, and a read or write
moves at most one word, so only the first 32 bytes were copied. Add a
copy IR instruction (CALLDATACOPY from calldata, MCOPY from memory) and
emit it for the slice's data.

* bugc: link the changelog entries to #359

* bugc: copy a struct read from storage into memory

* bugc: link the changelog entries to #361

* bugc: lay storage arrays out as Solidity does

* bugc: add push to dynamic arrays in storage
@gnidan

gnidan commented Oct 7, 2026

Copy link
Copy Markdown
Member Author

Included in #368.

@gnidan gnidan closed this Oct 7, 2026
@gnidan
gnidan deleted the bugc-hash-words branch October 7, 2026 03:07
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.

1 participant