Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 17 additions & 16 deletions src/halmos/sevm.py
Original file line number Diff line number Diff line change
Expand Up @@ -1785,6 +1785,18 @@ def assume_sha3_distinct(self, sha3_expr: BitVecRef) -> None:

self.sha3s[sha3_expr] = len(self.sha3s)

def try_preimage_sha3_hash(self, val):
if val.is_concrete:
if (inverse := sha3_inv.get(val.value)) is not None:
# restore precomputed hashes
return BV(self.sha3_data(con(inverse)), size=256)

# TODO: support more commonly used concrete keccak values
elif val.value == EMPTY_KECCAK:
return BV(self.sha3_data(b""), size=256)

return val

def new_gas_id(self) -> int:
self.cnts["gas"] += 1
return self.cnts["gas"]
Expand Down Expand Up @@ -3307,21 +3319,8 @@ def finalize(ex: Exec):
elif opcode == OP_PUSH32:
val = insn.operand
assert val.size == 256

# Special handling for PUSH32 with concrete values
if val.is_concrete:
if (inverse := sha3_inv.get(val.value)) is not None:
# restore precomputed hashes
state.push_any(ex.sha3_data(con(inverse)))

# TODO: support more commonly used concrete keccak values
elif val.value == EMPTY_KECCAK:
state.push_any(ex.sha3_data(b""))
else:
state.push(val)
else:
# Symbolic value
state.push(val)
val = ex.try_preimage_sha3_hash(val)
state.push(val)

elif opcode == OP_POP:
state.pop()
Expand Down Expand Up @@ -3408,7 +3407,9 @@ def finalize(ex: Exec):

elif opcode == OP_MLOAD:
loc: int = ex.mloc(check_size=True)
state.push_any(state.memory.get_word(loc))
val = BV(state.memory.get_word(loc), size=256)
val = ex.try_preimage_sha3_hash(val)
state.push(val)

elif opcode == OP_PUSH0:
state.push(ZERO)
Expand Down
5 changes: 2 additions & 3 deletions tests/regression/test/Sha3.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,8 @@ contract Sha3Test is Test, SymTest {
function check_empty_hash_value() public {
assertEq(keccak256(""), EMPTY_HASH);

// TODO: uncomment when we support empty bytes
// bytes memory data = svm.createBytes(0, "data");
// assertEq(keccak256(data), EMPTY_HASH);
bytes memory data = svm.createBytes(0, "data");
assertEq(keccak256(data), EMPTY_HASH);
}

function check_only_empty_bytes_matches_empty_hash(bytes memory data) public {
Expand Down
Loading