Hash function
Introduction
Definition
A hash function $ h $ is a mathematical function that maps data of arbitrary size to values of a fixed size, typically expressed as $ h: D \to R $, where $ D $ represents the domain of possible inputs, such as binary strings of any length $ {0,1}^* $, and $ R $ is a fixed finite set, often the set of $ k $-bit strings $ {0,1}^k $ or integers in the range $ [0, 2^k - 1] $.[6][7] This mapping compresses the input into a shorter output, known as the hash value or digest, whose length is predetermined by the function and independent of the input size.[6] Key characteristics of a hash function include its fixed output size, referred to as the hash length, which ensures consistent digest lengths regardless of input variability. The function is a many-to-one mapping, meaning that the original input cannot be uniquely reconstructed from the hash value alone, as multiple distinct inputs may produce the same output; this distinguishes it from reversible transformations.[7] The digest serves as a compact representation or "fingerprint" of the input data, capturing essential identifying features in a succinct form.[7] A simple illustrative example for integer inputs is the modular hash function $ h(x) = x \mod m $, where $ m $ is a positive integer defining the output range size. This computes the remainder of $ x $ divided by $ m $, yielding a value in $ [0, m-1] $, effectively folding larger integers into a bounded set.[8][9] Unlike encoding, which transforms data into a different format while preserving all information for exact reversal, or compression, which reduces size but often allows recovery of the original (in lossless cases), a hash function does not assume invertibility and prioritizes irreversible summarization over data preservation. Hash functions find brief application in structures like hash tables for efficient key indexing, though detailed uses appear elsewhere.[8]Motivation and Role in Computing
Hash functions serve as a cornerstone in computer science by enabling efficient data management in scenarios involving vast amounts of information. Their primary motivation lies in facilitating rapid data lookup, indexing, and storage efficiency for large datasets, where traditional search methods like linear scanning would be prohibitively slow. By transforming variable-length inputs into compact representations, hash functions allow systems to map complex keys directly to accessible locations, significantly reducing the time required for operations on extensive collections of data.[10] In algorithmic contexts, hash functions play a pivotal role by supporting data structures that achieve average O(1) time complexity for searches, insertions, and deletions through direct mapping of keys to array indices. This efficiency stems from the ability to approximate uniform distribution of outputs, ensuring that most operations avoid exhaustive traversals and instead perform constant-time probes. Early applications highlighted this utility, such as their use in compilers for managing symbol tables to quickly resolve variable names during compilation, a practice dating back to proposals in the 1950s.[11][12] The benefits of hash functions include substantial space efficiency, as they produce fixed-size outputs regardless of input length, allowing for compact indexing without storing full data keys. Additionally, their computational simplicity—often involving basic arithmetic or bitwise operations—ensures high speed even on resource-constrained systems. However, this efficiency introduces trade-offs, such as the potential for collisions where distinct inputs map to the same output, necessitating strategies to resolve conflicts and maintain performance.Fundamental Properties
Determinism and Defined Output Range
A hash function is fundamentally deterministic, meaning that it maps the same input to the identical output every time it is computed, without any influence from randomization or external factors in non-probabilistic settings. This property ensures that the function behaves as a fixed mathematical transformation, allowing consistent results across multiple invocations, which is a core requirement for reliable computational processes.[13] The defined output range of a hash function specifies a fixed size for the result, regardless of the variable length of the input data. Mathematically, this is expressed as $ |h(x)| = k $ for all inputs $ x $, where $ k $ is a constant bit length and $ h $ denotes the hash function.[14] For instance, the SHA-256 algorithm produces outputs of exactly 256 bits. This fixed-length constraint contrasts with the arbitrary input size, compressing or projecting data into a uniform domain, often represented as an integer in the range . These attributes enable key implications for practical use, such as reproducibility in data storage and efficient comparison operations. Determinism guarantees that hash values can be recomputed identically for verification purposes, supporting applications like duplicate detection and integrity checks. The fixed output range facilitates standardized storage allocation and modular arithmetic in implementations, enhancing performance in hash-based structures.[13] In edge cases, hash functions handle empty inputs deterministically; for example, the SHA-256 hash of an empty message (zero-length input) ise3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855. For null or undefined values, practical implementations often treat them equivalently to empty inputs or use predefined representations to maintain the fixed output size, ensuring no exceptions disrupt the defined range.[15]
Collision Resistance and Uniformity
A collision in a hash function occurs when two distinct inputs produce the same output, i.e., .[16] Due to the pigeonhole principle, collisions are inevitable for any hash function mapping an unbounded or large input domain to a finite output range of size , as exceeding inputs guarantees at least one pair sharing an output.[16] While collisions cannot be eliminated, their properties are critical for hash function design, particularly in ensuring that they are computationally difficult to exploit. Collision resistance encompasses several related security notions, each addressing different ways adversaries might find colliding inputs. First-preimage resistance requires that, given an output value , it is computationally infeasible to find any preimage such that .[17] Second-preimage resistance stipulates that, given an input and its hash , finding a distinct with is hard.[17] Collision resistance, the strongest of these, demands that discovering any pair of distinct inputs with is infeasible, and it implies the other two properties under certain conditions.[17] These levels ensure that hash functions behave like random oracles in practice, thwarting attacks that rely on predictable mappings. Beyond resistance to deliberate collision-finding, good hash functions exhibit uniformity, where outputs are distributed as evenly as possible across the output range, approximating a uniform random distribution.[18] This property minimizes clustering in applications like hash tables and enhances unpredictability. Statistical tests, such as the chi-squared test, evaluate uniformity by comparing observed output frequencies against expected uniform probabilities across bins; a low test statistic indicates even distribution.[18] The avalanche effect complements these properties by ensuring sensitivity to input changes: a single-bit alteration in the input should, on average, flip approximately 50% of the output bits, propagating changes rapidly through the function.[19] This diffusion property, observed in well-designed hashes like MD5 and SHA families, makes outputs appear uncorrelated with inputs and resists differential attacks.[19]Efficiency and Performance Metrics
The computational efficiency of hash functions is a critical factor in their practical deployment, as they must process inputs rapidly while maintaining reliability in resource-constrained environments. The time complexity for computing a hash is typically linear in the input size, O(n) where n represents the length of the input in bits or bytes, due to the need to iterate over each element of the input data.[20] This linearity arises from sequential processing steps, such as mixing and compression, but implementations leverage fast bitwise operations—like shifts, XORs, and rotations—to minimize constant factors and achieve high speeds on commodity hardware.[21] Space efficiency is another hallmark of hash functions, requiring only minimal additional working memory during computation—typically O(1) beyond the input buffer and a fixed-size output array for the hash digest.[22] This low overhead stems from the stateless nature of most hash algorithms, which avoid storing intermediate states across multiple invocations unless explicitly designed for streaming inputs, making them suitable for memory-limited applications like embedded systems.[23] Performance is commonly evaluated using metrics such as throughput (e.g., gigabytes processed per second) and latency (time for a single hash computation). For instance, on modern CPUs, non-cryptographic hashes like xxHash can achieve throughputs exceeding 10 GB/s for large inputs, while cryptographic ones like SHA-256 typically range from 0.5 to 2 GB/s depending on input size and hardware. Latency varies with input length but is often sub-microsecond for short messages, influenced by factors like cache efficiency and instruction-level parallelism. Hardware acceleration further boosts these metrics; Intel's SHA Extensions, introduced in 2013, provide dedicated instructions for SHA-1 and SHA-256, yielding significant speedup over software implementations by optimizing round computations.[21] A key trade-off exists between non-cryptographic and cryptographic hash functions: the former emphasize speed for general-purpose tasks like data deduplication, often using simpler mixing to attain 5-10 times higher throughput than cryptographic variants, while the latter incorporate additional operations for security properties, increasing computational cost. This balance ensures non-cryptographic hashes excel in high-volume scenarios without needing provable resistance to attacks, whereas cryptographic ones prioritize integrity at the expense of performance.Types of Hash Functions
Non-Cryptographic Hash Functions
Non-cryptographic hash functions prioritize computational speed and uniform distribution to achieve low collision probabilities for typical inputs, without incorporating mechanisms to withstand adversarial manipulation.[24] These functions are optimized for performance in resource-constrained environments, often producing fixed-size outputs through simple arithmetic operations like multiplication, XOR, and bit shifting, enabling rapid processing of large datasets.[25] Unlike their cryptographic counterparts, they make no guarantees against deliberate collision generation, focusing instead on efficiency for non-security-critical tasks.[26] Prominent examples include the Fowler–Noll–Vo (FNV) hash, MurmurHash, and CityHash. FNV, developed by Glenn Fowler, Landon Curt Noll, and Phong Vo, is a simple iterative algorithm emphasizing good dispersion for nearly identical inputs.[24] The widely used FNV-1a variant initializes the hash to an offset basis and processes each input byte with an XOR followed by multiplication by a prime:uint32_t hash = 2166136261U; // FNV_OFFSET_BASIS_32
uint32_t FNV_PRIME_32 = 16777619U;
for each byte b in input:
hash ^= b;
hash *= FNV_PRIME_32;
[24] MurmurHash, created by Austin Appleby in 2008, employs a mixing function with repeated avalanche steps to ensure high-quality output distribution, making it suitable for general-purpose lookups.[25] CityHash, released by Google in 2011, targets string hashing with variants producing 64- or 128-bit values, optimized for high throughput on modern processors.[27]
These functions find primary use in internal implementations of data structures such as hash tables and in caching mechanisms to enable quick key-value mappings and lookups.[28] However, their lack of resistance to targeted inputs renders them susceptible to hash flooding attacks, where attackers generate collisions to degrade performance, potentially enabling denial-of-service (DoS) scenarios like resource exhaustion in web servers.[26]
Cryptographic Hash Functions
Cryptographic hash functions are specialized hash functions engineered to provide security guarantees essential for protecting data integrity, authenticity, and non-repudiation in cryptographic protocols.[2] Unlike general-purpose hash functions, they are designed under the assumption of computational hardness, making them suitable as building blocks for digital signatures, message authentication, and blockchain technologies.[17] These functions aim to behave as ideal one-way functions, where computing the inverse is infeasible for adversaries with limited resources.[29] The core security properties of cryptographic hash functions are preimage resistance, second-preimage resistance, and collision resistance.[2] Preimage resistance ensures that, given a hash output h, it is computationally infeasible to find any input m such that H(m) = h.[2] Second-preimage resistance requires that, for a given input m, finding a distinct m' with H(m') = H(m) is infeasible.[2] Collision resistance is the strongest property, demanding that discovering any two distinct inputs m and m' where H(m) = H(m') is computationally hard; this implies second-preimage resistance, which in turn implies preimage resistance.[29] These properties collectively prevent attacks like forgery or reversal, with collision resistance typically requiring an output size of at least 256 bits for current security levels.[17] Prominent standards for cryptographic hash functions include the Secure Hash Algorithm (SHA) family, developed and published by the National Institute of Standards and Technology (NIST).[15] SHA-1, producing 160-bit outputs, was deprecated by NIST in 2011 due to collision vulnerabilities and is no longer approved for any security applications, with full phase-out mandated by 2030.[30] SHA-2 variants, such as SHA-256 with 256-bit outputs, remain widely adopted for their proven resistance to known attacks and are recommended for ongoing use in federal systems.[30] SHA-3, standardized in 2015, offers a parallel family with variants like SHA3-256, providing equivalent security to SHA-2 but with a different internal structure to mitigate potential weaknesses in older designs. For high-performance needs, BLAKE3, introduced in 2020, delivers cryptographic security comparable to SHA-2 while achieving significantly higher throughput through parallel processing, making it suitable for resource-constrained environments post-2015.[31] Common construction techniques for cryptographic hash functions include the Merkle–Damgård paradigm and the sponge construction.[32] The Merkle–Damgård construction processes variable-length inputs by iteratively applying a compression function to fixed-size blocks, with a finalization step to produce the output; it underpins MD5 (collision attacks demonstrated in 2004[33]), SHA-1 (practical collisions in 2017), and the secure SHA-2 family. However, its vulnerability to length-extension attacks has led to its deprecation in newer designs. In contrast, the sponge construction, used in SHA-3 (based on the Keccak permutation), alternates between absorbing input into a state (capacity-preserving) and squeezing output bits, enabling flexible output lengths and resistance to length-extension without relying on a dedicated compression function.[32] This approach provides provable security bounds in the random oracle model when based on a secure permutation.[32] As of 2025, developments in post-quantum cryptography emphasize hash functions resilient to quantum attacks, with NIST incorporating SHA-3's extendable-output variants like SHAKE-256 into standards for signature schemes such as SLH-DSA and FN-DSA. These functions maintain collision resistance against Grover's algorithm by requiring doubled output sizes for equivalent security, ensuring their viability in quantum-safe protocols.Applications
Data Structures and Retrieval
Hash tables are fundamental data structures that utilize hash functions to enable efficient storage and retrieval of key-value pairs. In a hash table, an array of fixed size m serves as the underlying storage, where a hash function h maps each key k to an index h(k) in the range [0, m-1], allowing direct access to the corresponding slot. This mapping supports average-case constant-time operations for insertion, deletion, and search, making hash tables ideal for applications requiring fast lookups, such as databases and caches. The efficiency depends on the hash function's ability to distribute keys uniformly across slots, minimizing clustering. The load factor α, defined as the ratio of the number of stored items n to the number of slots m (α = n/m), measures the table's utilization and influences performance. For open addressing schemes, keeping α below 0.7–0.8 typically ensures low collision rates and maintains efficient operation, as higher values can lead to clustering and degraded performance. In contrast, chaining can tolerate higher load factors (e.g., up to 1 or more), with performance degrading more gracefully proportional to α.[34][35][36] Collisions occur when distinct keys hash to the same index, a inevitability addressed through resolution strategies. With simple uniform hashing, the expected number of collisions remains proportional to α, supporting predictable performance. Collision resolution techniques fall into two primary categories: chaining and open addressing. In chaining, each array slot points to a linked list (or other structure) holding all keys that hash to that index; insertions append to the list, and searches traverse it until the key is found or the end is reached. This method tolerates high load factors but incurs overhead from pointer traversals. Open addressing resolves collisions by probing alternative slots within the array for an empty one during insertion, with retrieval following the same probe sequence. Linear probing, a common open addressing variant, uses the sequence h(k, i) = (h(k) + i) mod m for i = 0, 1, 2, ..., where i is the probe number, though it can lead to primary clustering. Variants of hash tables address limitations in static sizing or collision handling. Cuckoo hashing employs two hash functions and two tables (or arrays), relocating conflicting keys via a "cuckoo" eviction process to achieve worst-case O(1) lookups with high probability, at the cost of potential insertion loops resolved by rehashing.[37] Extendible hashing dynamically adjusts the effective table size by using a directory of pointers to buckets, prefixed by a varying number of hash bits, allowing growth without full rehashing and supporting O(1) access in practice for dynamic files.[38] Overall, with a well-designed hash function providing good uniformity, hash tables achieve average O(1) time complexity for core operations, outperforming tree-based structures like balanced binary search trees for unordered access patterns.Security and Integrity Verification
Hash functions are essential in cryptographic protocols for verifying the integrity of data, ensuring that transmitted or stored information has not been altered. In this context, a hash digest serves as a fixed-length fingerprint of the data, allowing efficient comparison to detect tampering. Unlike simple checksums designed primarily for error detection in non-adversarial environments, cryptographic digests must resist intentional modifications by attackers. For instance, the Cyclic Redundancy Check (CRC), introduced as a polynomial-based error-detecting code, excels at identifying accidental bit errors in data transmission over noisy channels, such as in network protocols, but offers no protection against deliberate alterations since its computation is fully deterministic and public.[39] In contrast, mechanisms like the Hash-based Message Authentication Code (HMAC) incorporate a secret key to produce an authenticated digest, providing both integrity and authenticity by preventing an attacker from forging a valid tag without the key. HMAC, defined using iterative hash functions like SHA-256, processes the message and key through nested hashing to mitigate weaknesses in the underlying hash construction.[40] A prominent application of hash functions in security is the digital signature paradigm, where long messages are first hashed to a fixed-size value before signing, known as the hash-then-sign approach. This method reduces the computational load on the signing algorithm while leveraging the collision resistance of the hash to ensure the signature binds to the entire message. For example, in the RSA signature scheme standardized by NIST, the message is hashed using SHA-256 to produce a 256-bit digest, which is then encrypted with the signer's private key to form the signature; verification involves decrypting with the public key and matching the recomputed hash. This combination, specified in the Digital Signature Standard, enables secure authentication in protocols like TLS and email signing, as long as the hash function remains preimage-resistant.[41][42] In blockchain systems, hash functions underpin integrity verification through structures like Merkle trees, which efficiently prove the inclusion and unaltered state of transactions within a block. Each transaction is hashed, and these leaf hashes are pairwise combined up to a root hash, which is included in the block header and linked via a chain of hashes to previous blocks. This allows light clients to verify a transaction's integrity by recomputing the path from the leaf to the root without downloading the full dataset, as demonstrated in the Bitcoin protocol where double-SHA-256 secures the tree against modifications. Any change to a transaction would alter its hash and propagate up the tree, invalidating the root and breaking the chain's cryptographic link.[43] Despite their strengths, certain hash functions are vulnerable to length extension attacks, where an attacker appends data to a message and computes a valid hash without knowing the original secret prefix, exploiting the Merkle-Damgård construction used in MD5 and SHA-1. In this attack, the adversary uses the public hash of a secret-keyed message (e.g., in a naive MAC), appends padding and new data, and derives the extended hash by continuing the internal state compression. MD5 and SHA-1, both based on this iterative padding scheme, allow such extensions because the hash output reveals the internal state after processing the original message plus padding. This vulnerability has led to practical exploits, such as forging API authentication tokens, and contributed to the deprecation of these hashes in security-critical applications.[44]Other Computational Uses
Bloom filters are probabilistic data structures that use multiple independent hash functions to represent a set of elements in a bit array, allowing membership queries with a controlled false positive rate but no false negatives.[45] Introduced by Burton Howard Bloom in 1970, they employ k hash functions to map each element to k positions in an m-bit array, setting those bits to 1 upon insertion; queries check if all corresponding bits are 1.[45] This approach trades space efficiency for potential errors, making it suitable for applications like spell-checkers and network routing caches where exact membership is not critical.[45] The false positive probability p for a Bloom filter is approximated by the formula
where n is the number of elements inserted, m is the bit array size, and k is the number of hash functions, with optimal k around (m/n) ln 2 to minimize p.[45]
Locality-sensitive hashing (LSH) extends hashing to high-dimensional spaces by using families of hash functions that preserve locality, such that similar items are hashed to the same bucket with high probability while dissimilar items are separated. Pioneered by Piotr Indyk and Rajeev Motwani in 1998, LSH enables efficient approximate nearest neighbor search in applications like recommendation systems and image retrieval, avoiding exhaustive comparisons in the curse of dimensionality. For example, random projection-based LSH maps vectors to lower dimensions while approximating distances like Euclidean or cosine similarity.
In storage systems, hash functions facilitate data deduplication by generating fixed-size fingerprints for data chunks, enabling rapid identification and elimination of duplicates to optimize space usage.[46] A 2011 empirical study across diverse datasets showed deduplication ratios exceeding 50% in virtual machine images and backups, using cryptographic hashes such as SHA-256, which provide strong collision resistance to enable reliable duplicate detection for large chunks without practical risk of collisions.[46] This technique underpins systems like ZFS and commercial backup solutions, balancing computational overhead with storage savings.[46]
As of 2025, hash functions play a growing role in artificial intelligence, particularly through feature hashing to manage high-dimensional sparse data in machine learning models.[47] In retrieval-augmented generation (RAG) frameworks, deep hashing integrates with vector databases to accelerate similarity searches for large language models, reducing latency while maintaining semantic accuracy in tasks like question answering.[47] This approach, as demonstrated in Hash-RAG, combines hashing with fine-grained retrieval to handle billion-scale corpora efficiently.[47]
Construction Techniques
Hashing Fixed-Length Data
Hashing fixed-length data, such as integers, forms the basis for many hash table implementations where inputs are of uniform size, typically machine words like 32-bit or 64-bit integers. These methods aim to map the input to a uniform distribution over a range of slots, often using simple arithmetic operations to ensure efficiency on hardware. Common techniques include division, multiplication, mid-square, and specialized variants like Fibonacci and Zobrist hashing, each with trade-offs in uniformity and computational cost.[48] The division method is one of the simplest approaches for integer hashing, defined as $ h(x) = x \mod m $, where $ x $ is the input integer and $ m $ is the number of slots, ideally chosen as a prime not close to a power of 2 to avoid clustering. This operation leverages the modulo arithmetic inherent in integer division, producing values in $ {0, 1, \dots, m-1} $. However, its performance degrades if $ m $ is a power of 2 due to biases in binary representations.[49][50] Multiplicative hashing improves on division by using multiplication with a constant to scramble the bits before reduction, given by $ h(x) = \left\lfloor \frac{(x \cdot A) \mod 2^w}{2^{w-r}} \right\rfloor $, where $ A $ is a multiplier close to the golden ratio (approximately 0.6180339887), $ w $ is the word size (e.g., 32 or 64 bits), and $ r $ is the number of output bits. For 32-bit words, Knuth recommends $ A = 2654435769 $, which is $ \left\lfloor 2^{32} \cdot \frac{\sqrt{5} - 1}{2} \right\rfloor $, ensuring good bit mixing without division. This method is faster than division on most processors, as it replaces modulo with a right shift after multiplication.[48][50] The mid-square method extracts bits from the middle of the squared input to produce the hash, computed as $ h(x) = (x^2 \mod 2^{2w}) \gg w $, where $ \gg $ denotes a right shift by $ w $ bits to isolate the central $ w $ bits of the $ 2w $-bit square. This approach assumes $ x $ fits in $ w $ bits and aims to capture higher-order interactions from the multiplication implicit in squaring. While conceptually simple, it can suffer from short periods and poor distribution for certain inputs, making it less favored in modern use but illustrative of bit-extraction techniques.[51][48] Fibonacci hashing is a refined form of multiplicative hashing that explicitly uses constants derived from the Fibonacci sequence or golden ratio for the multiplier, typically $ A = \frac{2^w}{\phi} $ where $ \phi = \frac{1 + \sqrt{5}}{2} \approx 1.618 $, followed by a shift to extract the high bits. This yields $ h(x) = \left\lfloor \frac{x \cdot A}{2^{w-r}} \right\rfloor \mod 2^r $, promoting optimal spreading due to the irrational properties of $ \phi $, which minimize correlations in the binary expansions. It is particularly effective for power-of-two table sizes, avoiding the division pitfalls.[50] Zobrist hashing, designed for fixed-length representations like game board states, assigns a unique random 64-bit value to each possible feature (e.g., piece position) and computes the hash as the bitwise XOR of the values for active features: $ h(state) = \bigoplus_{i} Z_{feature_i} $, where $ Z $ is a precomputed table of random keys. Updating the hash for a move involves XORing out the old feature and XORing in the new one, enabling incremental computation in $ O(1) $ time. This method excels in applications requiring fast equality checks and transposition detection, with low collision probability under uniform randomness.[52]Hashing Variable-Length Data
Hashing variable-length data, such as strings or sequences, requires techniques that accommodate inputs of arbitrary lengths while producing fixed-size outputs suitable for storage or comparison. These methods transform the entire input into a hash value without padding or truncation, ensuring uniformity across different lengths. Common approaches include polynomial-based hashing, folding techniques, perceptual hashing for multimedia, and radix conversion, each designed to handle variability efficiently while minimizing collisions.[53] One widely used method for string hashing is the polynomial rolling hash, which treats the input string $ s = s[0] s[1] \dots s[n-1] $ as a polynomial evaluated at a base $ p $, typically a large prime number, modulo a prime $ m $ to bound the output size:
Here, each character $ s[i] $ is mapped to an integer (e.g., its ASCII value), and the powers of $ p $ weight positions from left to right, simulating a positional numeral system. This approach, introduced in the Rabin-Karp string matching algorithm, enables efficient computation for substrings via rolling updates, making it ideal for pattern matching in texts of varying lengths. The choice of $ p $ and $ m $ (often $ m $ as a large prime like $ 10^9 + 7 $) reduces collision probability, with expected linear-time performance for most inputs.[54][55]
Folding methods simplify hashing by partitioning the variable-length input into fixed-size segments and combining them, often via summation modulo $ m $. In character folding, the hash is computed as the sum of individual character codes (e.g., ASCII values) modulo $ m $, such as $ h(s) = \left( \sum_{i=0}^{n-1} \text{ASCII}(s[i]) \right) \mod m $, which treats each character equally regardless of position or length. This is straightforward but prone to collisions for similar-length strings with balanced character distributions. Length folding extends this by dividing the string into groups of fixed length (e.g., 2 or 3 characters), converting each group to a number, and summing or XORing them modulo $ m $; for instance, for a string longer than the group size, the last partial group is folded in. These techniques, common in early hash table implementations, prioritize speed over distribution quality for alphanumeric keys.[53][56]
Perceptual or fuzzy hashing adapts to variable-length multimedia data, such as images or audio, by focusing on content similarity rather than exact matches, producing hashes robust to minor alterations like resizing or compression. A representative example is pHash, which processes images by resizing to 32x32 pixels, applying a discrete cosine transform (DCT) to extract low-frequency coefficients, and generating a 64-bit hash from the signs of these coefficients compared to their mean. This method, implemented in open-source libraries, yields Hamming distances under 10 for visually similar images, enabling applications like duplicate detection in large datasets. Unlike exact hashes, perceptual ones tolerate variability in length or format while preserving semantic invariance.[57]
Radix conversion treats the variable-length string as a number in a mixed radix system with base $ b $ (often 256 for byte strings or 128 for printable characters), computing $ h(s) = \left( \sum_{i=0}^{n-1} s[i] \cdot b^{n-1-i} \right) \mod m $, which is mathematically equivalent to the polynomial hash with $ p = b $. This interpretation highlights its roots in numeral systems, allowing direct computation for short strings but requiring modular reduction for long ones to prevent overflow. It is particularly effective for ordered alphabets, providing good distribution when $ b $ and $ m $ are coprime, though it shares collision risks with polynomial methods for adversarial inputs.[55]