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
9 changes: 9 additions & 0 deletions eth_utils/crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,13 @@ def keccak(
hexstr: str | None = None,
text: str | None = None,
) -> bytes:
if isinstance(primitive, bytes) and hexstr is None and text is None:
return bytes(keccak_256(primitive))
elif (
isinstance(primitive, (bytearray, memoryview))
and hexstr is None
and text is None
):
return bytes(keccak_256(bytes(primitive)))

return bytes(keccak_256(to_bytes(primitive, hexstr, text)))
3 changes: 3 additions & 0 deletions newsfragments/95.performance.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Reduced ``keccak()`` overhead for raw ``bytes``-like inputs by bypassing
the generic conversion path when no ``hexstr`` or ``text`` argument is
provided.
38 changes: 38 additions & 0 deletions tests/core/crypto-utils/test_crypto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import pytest

from eth_hash.auto import (
keccak as raw_keccak,
)

import eth_utils.crypto as crypto_utils


@pytest.mark.parametrize(
"kwargs,expected_payload",
(
({"primitive": b"\x12\x34"}, b"\x12\x34"),
({"primitive": bytearray(b"\x12\x34")}, b"\x12\x34"),
({"primitive": memoryview(b"\x12\x34")}, b"\x12\x34"),
({"hexstr": "0x1234"}, b"\x12\x34"),
({"text": "ethereum"}, b"ethereum"),
),
)
def test_keccak_matches_backend_for_supported_inputs(kwargs, expected_payload):
assert crypto_utils.keccak(**kwargs) == bytes(raw_keccak(expected_payload))


def test_keccak_bytes_input_skips_to_bytes_conversion(monkeypatch):
def fail_if_called(*args, **kwargs):
raise AssertionError("to_bytes should not be called for raw bytes input")

monkeypatch.setattr(crypto_utils, "to_bytes", fail_if_called)

payload = b"\xde\xad\xbe\xef"
assert crypto_utils.keccak(payload) == bytes(raw_keccak(payload))


def test_keccak_still_validates_multiple_input_sources():
with pytest.raises(
TypeError, match="Exactly one of the passed values can be specified"
):
crypto_utils.keccak(b"\x12\x34", hexstr="0x1234")