This is related to a question I asked a while back about the semantics of Hashable
. The short version is basically that a type which used the hash(into:)
implementation from IdentifiableHashable
to satisfy its Hashable.hash(into:)
requirement would not validly conform to Hashable
(unless id
is the only "essential" component of that type). Notable snippets linked in the thread:
Beyond simplifying hashing, the intent of SE-0206 is to enable Swift to provide certain guarantees about its quality. In particular: as long as
hash(into:)
feeds enough data the hasher to unambiguously decide equality, Swift attempts to guarantee that collision attacks won't be possible . For this to work, it is critically important forHashable
implementations to include everything thatEquatable.==
looks at; and this is especially the case for the basic boundary types that come built-in with Swift, likeData
.
While this is not a hard requirement for user code, for boundary types provided in the stdlib/SDK, we require that hashing isn't just consistent with equality, but that it's equivalent to it. The Swift test suite has checks to actively enforce this -- this is possible through repeatedly salting the hash function . "Optimizing" hashing by omitting some of the data compared by
==
is generally a mistake in Swift, because it completely breaks all guarantees about the strength of hashing, and opens the door to (accidental or deliberate) collision attacks.It's perfectly acceptable to hash a gigabyte of data if someone inserts some large value (such as a big collection) as a key in a hash table. Multi-megabyte String keys are easy to protect against; hidden hashing weaknesses aren't.