Fowler–Noll–Vo hash function
{{Short description|Non-cryptographic hash function}}
Fowler–Noll–Vo (or FNV) is a non-cryptographic hash function created by Glenn Fowler, Landon Curt Noll, and Kiem-Phong Vo.
The basis of the FNV hash algorithm was taken from an idea sent as reviewer comments to the IEEE POSIX P1003.2 committee by Glenn Fowler and Phong Vo in 1991. In a subsequent ballot round, Landon Curt Noll improved on their algorithm. In an email message to Noll, they named it the Fowler/Noll/Vo or FNV hash.{{Cite web|url=http://www.isthe.com/chongo/tech/comp/fnv/index.html#history|title=FNV Hash - FNV hash history|website=www.isthe.com}}
Overview
The current versions are FNV-1 and FNV-1a, which supply a means of creating non-zero FNV offset basis. FNV currently{{As of when|date=August 2024}} comes in 32-, 64-, 128-, 256-, 512-, and 1024-bit variants. For pure FNV implementations, this is determined solely by the availability of FNV primes for the desired bit length; however, the FNV webpage discusses methods of adapting one of the above versions to a smaller length that may or may not be a power of two.{{Cite web|url=http://www.isthe.com/chongo/tech/comp/fnv/index.html#xor-fold|title=FNV Hash - Changing the FNV hash size - xor-folding|website=www.isthe.com}}{{Cite web|url=http://www.isthe.com/chongo/tech/comp/fnv/index.html#other-folding|title=FNV Hash - Changing the FNV hash size - non-powers of 2|website=www.isthe.com}}
The FNV hash algorithms and reference FNV source code{{Cite journal|last1=Eastlake|first1=Donald|last2=Hansen|first2=Tony|last3=Fowler|first3=Glenn|last4=Vo|first4=Kiem-Phong|last5=Noll|first5=Landon|date=29 May 2019|title=The FNV Non-Cryptographic Hash Algorithm|url=https://tools.ietf.org/html/draft-eastlake-fnv-17.html|archive-url=|archive-date=|access-date=|website=tools.ietf.org}}{{Cite web|url=http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-source|title=FNV Hash - FNV source|website=www.isthe.com}} have been released into the public domain.[http://www.isthe.com/chongo/tech/comp/fnv/index.html#public_domain FNV put into the public domain] on isthe.com
The Python programming language previously used a modified version of the FNV scheme for its default hash
function. From Python 3.4, FNV has been replaced with SipHash to resist "hash flooding" denial-of-service attacks.{{Cite web|url=https://www.python.org/dev/peps/pep-0456/|title=PEP 456 -- Secure and interchangeable hash algorithm|website=Python.org}}
FNV is not a cryptographic hash.
The hash
One of FNV's key advantages is that it is very simple to implement.
{{cite web
| first = James
| last = Smith
| work = Golang Project Structure
| title = Hash Functions in Go
| url = https://golangprojectstructure.com/hash-functions-go-code/#implementing-the-fowler%e2%80%93noll%e2%80%93vo-fnv-hash-function
| date = 2022-05-29
| access-date = 2024-10-19
}}
Start with an initial hash value of FNV offset basis. For each byte in the input, multiply hash by the FNV prime, then XOR it with the byte from the input. The alternate algorithm, FNV-1a, reverses the multiply and XOR steps.
=FNV-1 hash=
The FNV-1 hash algorithm is as follows:{{Cite journal|last1=Eastlake|first1=Donald|last2=Hansen|first2=Tony|last3=Fowler|first3=Glenn|last4=Vo|first4=Kiem-Phong|last5=
algorithm fnv-1 is
hash := FNV_offset_basis
for each byte_of_data to be hashed do
hash := hash × FNV_prime
hash := hash XOR byte_of_data
return hash
In the above pseudocode, all variables are unsigned integers. All variables, except for byte_of_data, have the same number of bits as the FNV hash. The variable, byte_of_data, is an 8-bit unsigned integer.
As an example, consider the 64-bit FNV-1 hash:
- All variables, except for byte_of_data, are 64-bit unsigned integers.
- The variable, byte_of_data, is an 8-bit unsigned integer.
- The FNV_offset_basis is the 64-bit value: 14695981039346656037 (in hex, 0xcbf29ce484222325).
- The FNV_prime is the 64-bit value 1099511628211 (in hex, 0x100000001b3).
- The multiply returns the lower 64 bits of the product.
- The XOR is an 8-bit operation that modifies only the lower 8-bits of the hash value.
- The hash value returned is a 64-bit unsigned integer.
=FNV-1a hash=
The FNV-1a hash differs from the FNV-1 hash only by the order in which the multiply and XOR is performed:{{Cite web|url=http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-1a|title=FNV Hash - FNV-1a alternate algorithm|website=www.isthe.com}}
algorithm fnv-1a is
hash := FNV_offset_basis
for each byte_of_data to be hashed do
hash := hash XOR byte_of_data
hash := hash × FNV_prime
return hash
The above pseudocode has the same assumptions that were noted for the FNV-1 pseudocode. The change in order leads to slightly better avalanche characteristics.{{Cite web|url=https://sites.google.com/site/murmurhash/avalanche|title=avalanche - murmurhash|website=sites.google.com}}
=FNV-0 hash (deprecated)=
The FNV-0 hash differs from the FNV-1 hash only by the initialisation value of the hash variable:{{Cite web|url=http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-0|title=FNV Hash - FNV-0 Historic not|website=www.isthe.com}}
algorithm fnv-0 is
hash := 0
for each byte_of_data to be hashed do
hash := hash × FNV_prime
hash := hash XOR byte_of_data
return hash
The above pseudocode has the same assumptions that were noted for the FNV-1 pseudocode.
A consequence of the initialisation of the hash to 0 is that empty messages and all messages consisting of only the byte 0, regardless of their length, hash to 0.
Use of the FNV-0 hash is deprecated except for the computing of the FNV offset basis for use as the FNV-1 and FNV-1a hash parameters.
=FNV offset basis=
There are several different FNV offset bases for various bit lengths. These offset bases are computed by computing the FNV-0 from the following 32 octets when expressed in ASCII:
:
chongo/\../\
This is one of Landon Curt Noll's signature lines. This is the only current practical use for the deprecated FNV-0.
=FNV prime=
An FNV prime is a prime number and is determined as follows:{{Cite web|url=http://www.isthe.com/chongo/tech/comp/fnv/index.html#fnv-prime|title=FNV Hash - A few remarks on FNV primes|website=www.isthe.com}}
For a given integer {{Mvar|s}} such that {{Math|4 < s < 11}}, let {{Math|1=n = 2s}} and {{Math|1=t = {{floor|(5 + n) / 12}}}}; then the {{Mvar|n}}-bit FNV prime is the smallest prime number {{Mvar|p}} that is of the form
:
such that:
:* {{Math|0 < b < 28}},
:* the number of one-bits in the binary representation of {{Mvar|b}} is either 4 or 5, and
:* {{Math|p mod (240 − 224 − 1) > 224 + 28 + 27}}.
Experimentally, FNV primes matching the above constraints tend to have better dispersion properties. They improve the polynomial feedback characteristic when an FNV prime multiplies an intermediate hash value. As such, the hash values produced are more scattered throughout the {{Mvar|n}}-bit hash space.
=FNV hash parameters=
The above FNV prime constraints and the definition of the FNV offset basis yield the following table of FNV hash parameters:
border="1" class="wikitable" style="text-align: center;" align="center"
|+ FNV parameters {{Cite web|url=http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param|title=FNV Hash - Parameters of the FNV-1/FNV-1a hash|website=www.isthe.com}} ! Size in bits ! Representation ! FNV prime ! FNV offset basis |
rowspan="3" | 32
! Expression | 224 + 28 + 0x93 | |
---|
Decimal
|16777619 |2166136261 |
Hexadecimal
|0x01000193 |0x811c9dc5 |
rowspan="3" | 64
! Expression |240 + 28 + 0xb3 | |
Decimal
|1099511628211 |14695981039346656037 |
Hexadecimal
|0x00000100000001b3 |0xcbf29ce484222325 |
rowspan="3" | 128
! Representation |288 + 28 + 0x3b | |
Decimal
|309485009821345068724781371 |144066263297769815596495629667062367629 |
Hexadecimal
|0x0000000001000000000000000000013b |0x6c62272e07bb014262b821756295c58d |
rowspan="3" | 256
! Representation |2168 + 28 + 0x63 | |
Decimal
| 374144419156711147060143317 175368453031918731002211 | 100029257958052580907070968620625704837 092796014241193945225284501741471925557 |
Hexadecimal
| 0x00000000000000000000010000000000 00000000000000000000000000000163 | 0xdd268dbcaac550362d98c384c4e576ccc8b153 6847b6bbb31023b4c8caee0535 |
rowspan="3" | 512
! Representation |2344 + 28 + 0x57 | |
Decimal
| 358359158748448673689190764 890951084499463279557543925 583998256154206699388825751 26094039892345713852759 | 965930312949666949800943540071631046609 041874567263789610837432943446265799458 293219771643844981305189220653980578449 5328239340083876191928701583869517785 |
Hexadecimal
| 0x0000000000000000 0000000000000000 0000000001000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000157 | 0xb86db0b1171f4416 dca1e50f309990ac ac87d059c9000000 0000000000000d21 e948f68a34c192f6 2ea79bc942dbe7ce 182036415f56e34b ac982aac4afe9fd9 |
rowspan="3" | 1024
! Representation |2680 + 28 + 0x8d | |
Decimal
| 501645651011311865543459881103 527895503076534540479074430301 752383111205510814745150915769 222029538271616265187852689524 938529229181652437508374669137 180409427187316048473796672026 0389217684476157468082573 | 14197795064947621068722070641403218320 88062279544193396087847491461758272325 22967323037177221508640965212023555493 65628174669108571814760471015076148029 75596980407732015769245856300321530495 71501574036444603635505054127112859663 61610267868082893823963790439336411086 884584107735010676915 |
Hexadecimal
| 0x0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000010000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 000000000000018d | 0x0000000000000000 005f7a76758ecc4d 32e56d5a591028b7 4b29fc4223fdada1 6c3bf34eda3674da 9a21d90000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 000000000004c6d7 eb6e73802734510a 555f256cc005ae55 6bde8cc9c6a93b21 aff4b16c71ee90b3 |
Non-cryptographic hash
The FNV hash was designed for fast hash table and checksum use, not cryptography. The authors have identified the following properties as making the algorithm unsuitable as a cryptographic hash function:{{Cite journal|last1=Eastlake|first1=Donald|last2=Hansen|first2=Tony|last3=Fowler|first3=Glenn|last4=Vo|first4=Kiem-Phong|last5=Noll|first5=Landon|date=29 May 2019|title=The FNV Non-Cryptographic Hash Algorithm|url=https://tools.ietf.org/html/draft-eastlake-fnv-17.html|archive-url=|archive-date=|access-date=2021-01-12|website=tools.ietf.org|language=en}}
- Speed of computation – As a hash designed primarily for hashtable and checksum use, FNV-1 and FNV-1a were designed to be fast to compute. However, this same speed makes finding specific hash values (collisions) by brute force faster.
- Sticky state – Being an iterative hash based primarily on multiplication and XOR, the algorithm is sensitive to the number zero. Specifically, if the hash value were to become zero at any point during calculation, and the next byte hashed were also all zeroes, then the hash would not change. This makes colliding messages trivial to create given a message that results in a hash value of zero at some point in its calculation. Additional operations, such as the addition of a third constant prime on each step, can mitigate this but may have detrimental effects on avalanche effect or random distribution of hash values.
- Diffusion – The ideal secure hash function is one in which each byte of input has an equally-complex effect on every bit of the hash. In the FNV hash, the ones place (the rightmost bit) is always the XOR of the rightmost bit of every input byte. This can be mitigated by XOR-folding (computing a hash twice the desired length, and then XORing the bits in the "upper half" with the bits in the "lower half").
A structural weakness of FNV-1a arises from its use of XOR before multiplication, which can cause predictable relationships between hashes of related inputs. For example, the following identity holds in both the 32-bit and 64-bit variants:
fnv1a("some-string-a") XOR fnv1a("some-id-1231") = fnv1a("some-string-b") XOR fnv1a("some-id-1232")
because the differing characters ('a' vs 'b', and '1' vs '2') differ by the same bit pattern. This illustrates how certain bitwise symmetries in input can lead to unintended hash correlations. XOR-folding does not remove this weakness.
See also
- Bloom filter (application for fast hashes)
- Non-cryptographic hash functions
References
{{reflist|30em}}
External links
- [http://www.isthe.com/chongo/tech/comp/fnv/index.html Landon Curt Noll's webpage on FNV] (with table of base & prime parameters)
- [https://datatracker.ietf.org/doc/html/draft-eastlake-fnv-17 Internet draft by Fowler, Noll, Vo, and Eastlake] (IETF Informational Internet Draft)
{{DEFAULTSORT:Fowler-Noll-Vo hash function}}