1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
//! Keccak256 hash utilities.
use tiny_keccak::{Hasher, Keccak};
/// Perform a Keccak256 hash of data and return its 32-byte result.
pub fn keccak256<B>(data: B) -> [u8; 32]
where
B: AsRef<[u8]>,
{
let mut output = [0u8; 32];
let mut hasher = Keccak::v256();
hasher.update(data.as_ref());
hasher.finalize(&mut output);
output
}
/// A 32-bit prefix of a standard 256-bit Keccak hash.
///
/// This 32-bit prefix is generally used as the first 4 bytes of transaction
/// data in order to select which Solidity method will be called.
pub type H32 = [u8; 4];
/// Calculates the function selector as per the contract ABI specification. This
/// is definied as the first 4 bytes of the Keccak256 hash of the function
/// signature.
pub fn function_selector<S>(signature: S) -> H32
where
S: AsRef<str>,
{
let hash = keccak256(signature.as_ref());
let mut selector = H32::default();
selector.copy_from_slice(&hash[0..4]);
selector
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn simple_keccak_hash() {
// test vector retrieved from
// https://web3js.readthedocs.io/en/v1.2.4/web3-utils.html#sha3
assert_eq!(
&keccak256([0xea]),
b"\x2f\x20\x67\x74\x59\x12\x06\x77\x48\x4f\x71\x04\xc7\x6d\xeb\x68\
\x46\xa2\xc0\x71\xf9\xb3\x15\x2c\x10\x3b\xb1\x2c\xd5\x4d\x1a\x4a"
);
}
#[test]
fn simple_function_signature() {
// test vector retrieved from
// https://web3js.readthedocs.io/en/v1.2.4/web3-eth-abi.html#encodefunctionsignature
assert_eq!(
function_selector("myMethod(uint256,string)"),
[0x24, 0xee, 0x00, 0x97],
);
}
#[test]
fn revert_function_signature() {
assert_eq!(function_selector("Error(string)"), [0x08, 0xc3, 0x79, 0xa0]);
}
}