pub trait Hash {
/// Returns `true` if the *in-memory representation* of the type is
/// byte-for-byte identical to the *hash bytes representation* that
/// [Hash::hash] writes into the [Hasher]; otherwise, returns `false`.
///
/// # Additional Information
///
/// When a type is trivially hashable, its hash can be computed by using
/// the raw memory of the value (`__size_of::<Self>()` bytes starting at the
/// value's address), without first building an intermediate byte buffer
/// in a [Hasher]. This is what the [sha256] and [keccak256] functions do
/// for trivially hashable types, which is significantly more gas effective.
///
/// **Returning `true` is a strong guarantee: an incorrect `true` will produce
/// wrong hashes when a value is hashed via [sha256] or [keccak256].** When in
/// doubt, return `false`. Returning `false` is always safe; it only forgoes
/// the optimization.
///
/// # Warning
///
/// Several subtleties make types that might look trivially hashable actually
/// **not** trivially hashable. In particular:
///
/// - `u16` and `u32` are stored in memory in an eight-byte slot (as `u64`),
/// but their hash bytes representation is only two and four bytes,
/// respectively. They are therefore **never** trivially hashable, and
/// neither is any aggregate (struct, tuple, array, ...) containing them.
/// - `bool`, `u8`, `u16`, and `u32` fields inside a struct or tuple are
/// padded to eight bytes in memory. An aggregate containing such a field
/// is therefore **not** trivially hashable, even though the field types
/// themselves might be when hashed on their own.
/// - Enum tags are stored in memory as `u64`, but the `Hash` implementations
/// in this library hash them as `u8`. Enums are therefore **not** trivially
/// hashable.
/// - Collections (`Bytes`, `Vec`, `raw_slice`, `str`, `str[N]`, arrays, and
/// aggregates containing them) can be trivially hashable or not depending
/// on the `new_hashing` experimental feature. When `new_hashing` is
/// enabled, collections prefix their content with their length, which means
/// their hash bytes representation no longer matches their in-memory
/// representation, making them **not** trivially hashable.
/// For more details see: https://github.com/FuelLabs/sway/issues/7256.
// TODO-MEMLAY: In this doc-comment we make an assumption about the memory
// layouts. Those can be changed in the future.
// TODO: (TRIVIALLY-HASHABLE-ENUMS) Once we change enum implementations, adapt
// the doc-comment.
fn is_hash_trivial() -> bool;
/// Writes the hash bytes representation of `self` into the [Hasher] `state`.
fn hash(self, ref mut state: Hasher);
}Expand description
Trait for hashing values into a [Hasher].
Types implementing Hash can be hashed using the [Hasher], or via the
[sha256] and [keccak256] convenience functions, and can be used in places
that require a deterministic hash, e.g., as keys in a StorageMap.
Implementing Hash
A Hash implementation defines how the value is written into the [Hasher]
via the [Hash::hash] method, and declares, via [Hash::is_hash_trivial],
whether the value’s in-memory representation is byte-for-byte identical to
the bytes it writes into the [Hasher].
use std::hash::{Hash, Hasher};
struct MyU64Wrapper {
value: u64,
}
impl Hash for MyU64Wrapper {
fn is_hash_trivial() -> bool {
// A struct with a single `u64` field has the same in-memory
// representation as its hash bytes representation.
true
}
fn hash(self, ref mut state: Hasher) {
self.value.hash(state);
}
}
Required Methods
fn is_hash_trivial() -> bool
fn is_hash_trivial() -> bool
Returns true if the in-memory representation of the type is
byte-for-byte identical to the hash bytes representation that
[Hash::hash] writes into the [Hasher]; otherwise, returns false.
Additional Information
When a type is trivially hashable, its hash can be computed by using
the raw memory of the value (__size_of::<Self>() bytes starting at the
value’s address), without first building an intermediate byte buffer
in a [Hasher]. This is what the [sha256] and [keccak256] functions do
for trivially hashable types, which is significantly more gas effective.
Returning true is a strong guarantee: an incorrect true will produce
wrong hashes when a value is hashed via [sha256] or [keccak256]. When in
doubt, return false. Returning false is always safe; it only forgoes
the optimization.
Warning
Several subtleties make types that might look trivially hashable actually
not trivially hashable. In particular:
u16andu32are stored in memory in an eight-byte slot (asu64),
but their hash bytes representation is only two and four bytes,
respectively. They are therefore never trivially hashable, and
neither is any aggregate (struct, tuple, array, …) containing them.bool,u8,u16, andu32fields inside a struct or tuple are
padded to eight bytes in memory. An aggregate containing such a field
is therefore not trivially hashable, even though the field types
themselves might be when hashed on their own.- Enum tags are stored in memory as
u64, but theHashimplementations
in this library hash them asu8. Enums are therefore not trivially
hashable. - Collections (
Bytes,Vec,raw_slice,str,str[N], arrays, and
aggregates containing them) can be trivially hashable or not depending
on thenew_hashingexperimental feature. Whennew_hashingis
enabled, collections prefix their content with their length, which means
their hash bytes representation no longer matches their in-memory
representation, making them not trivially hashable.
For more details see: https://github.com/FuelLabs/sway/issues/7256.
fn hash(
self,
refmut state: Hasher,
)
fn hash(
self,
refmut state: Hasher,
)
Writes the hash bytes representation of self into the [Hasher] state.