vyper
vyper copied to clipboard
Keccak256 for bytes types
Version Information
- vyper Version (output of
vyper --version): 0.3.7 - OS: osx
- Python Version (output of
python --version): Python 3.9.4
What's your issue about?
Please include information like:
Intent is to produce an address-based merkle tree for a white list (which can also play nicely with Javascript for frontend devs) -- however Vyper Keccak256 does not work on bytes types
Running the following raises a panic:

Converting to Bytes[20] first also triggers an error

How can it be fixed?
Not a big brain Vyper dev, so not sure offhand
@zcor the keccak256 function only accepts a literal string, Bytes, or bytes32. Just convert it to bytes32 instead:
# @version ^0.3.7
@external
@pure
def hash_addr(addr: address) -> bytes32:
return keccak256(convert(addr, bytes32))
Here an example using Titanoboa:

PS: the pure modifier should be enough for this function.
@pcaversaccio it's not the same due to zero padding.
right but it depends on how you construct the Merkle tree of course.
So let me give another couple of options (since I don't know the exact specs here):
Option 1
Solidity version:
function hashAddr(address addr) public pure returns (bytes32) {
return keccak256(abi.encode(addr));
}
is the same in Vyper
@external
@pure
def hash_addr(addr: address) -> bytes32:
return keccak256(_abi_encode(addr))
Option 2
Solidity version:
function hashAddr(address addr) public pure returns (bytes32) {
return keccak256(abi.encodePacked(addr));
}
is the same in Vyper
@external
@pure
def hash_addr(addr: address) -> bytes32:
return keccak256(slice(convert(addr, bytes32), 12, 20))
It's important to understand how Vyper converts
addrtobytes32. It left-padds the resulting type. E.g.hash_addr("0x388C818CA8B9251b393131C08a736A67ccB19297")would result in0x000000000000000000000000388c818ca8b9251b393131c08a736a67ccb19297forconvert(addr, bytes32).
If you search for Merkle proof verification functions in Vyper @zcor, I have written some code here. Disclaimer: This is however not audited.
ah yes, i forgot about slice -- slice( convert(addr, bytes20), 0, 20) should work.
Brilliant, thank you!
ah yes, i forgot about slice -- slice( convert(addr, bytes20), 0, 20) should work.
You must use bytes32 since slice doesn't accept anything else than Bytes, bytes32, or String. So it's:
@external
@pure
def hash_addr(addr: address) -> bytes32:
return keccak256(slice(convert(addr, bytes32), 12, 20))
@zcor FYI, I have now also implemented Merkle tree multiproofs in 🐍 Vyper: https://github.com/pcaversaccio/snekmate/blob/main/src/utils/MerkleProofVerification.vy
@charles-cooper I assume this issue can be closed.
@external @pure def hash_addr(addr: address) -> bytes32: return keccak256(_abi_encode(addr))Option 2
Solidity version:
function hashAddr(address addr) public pure returns (bytes32) { return keccak256(abi.encodePacked(addr)); }
Hit the same issue, glad I found this thread. The second option mimics abi.encodePacked() of solidity.
#simple.vy
@external
@view
def rough() -> bytes32:
addr: address = 0x1aD91ee08f21bE3dE0BA2ba6918E714dA6B45836
addr32:bytes32 = convert(addr, bytes32)
hash:bytes32 = keccak256(slice(addr32, 12, 20))
return hash
>>> import boa
>>> simple = boa.load("./simple.vy")
>>> a = simple.rough()
>>> hex(int.from_bytes(a, "big"))
'0x38b74bc12b97e00aeca693680c257c2a2a8a3ee73b03e5c72dd1e9fb838007f8'
>>>
@pcaversaccio not closing this as I think it's still a valid feature request -- keccak256 should work for all bytes types without the need for slicing.