{
  "checked": "2026-09-19",
  "profiles": [
    {
      "ids": [
        "city"
      ],
      "authors": "Geoff Pike and Jyrki Alakuijala · Google",
      "background": "CityHash is a family of fast string hashes developed at Google. It is designed for uses such as hash tables, where a string needs to be turned into a small integer quickly. This entry studies the 64-bit function that accepts a seed.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/google/cityhash"
        },
        {
          "label": "Verifier package",
          "url": "verify/cityhash-64/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "city": "Two different eight-byte messages already have the same intermediate result before the seed is mixed in. From that point onward, the computation is identical. The pair therefore collides for every seed, so keeping the seed secret or replacing it does not help."
      },
      "sources": [
        "https://github.com/google/cityhash",
        "verify/cityhash-64/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "city": {
          "evidence": "The algebra shows that this pair collides for every seed. Trying a new seed cannot separate these two messages.",
          "key": "The experiment chooses a 64-bit seed at random, with every possible value equally likely. The two messages are chosen first and do not depend on that seed.",
          "scope": "The result covers the studied CityHash64 seeded functions, including the version that accepts two seeds. It extends earlier published attacks; the appendix credits that work and gives the exact inputs."
        }
      },
      "smhasher": {
        "city": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/CityHash-64.txt#L3172",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "farm"
      ],
      "authors": "Geoff Pike · Google",
      "background": "FarmHash is Google’s successor to CityHash. It offers several implementations tuned for different processors. The chart uses the 64-bit NA implementation, so this entry should not be read as a result about every FarmHash variant.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/google/farmhash"
        },
        {
          "label": "Verifier package",
          "url": "verify/farmhash-64/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "farm": "The two eight-byte messages become indistinguishable before the seed is used. Adding a secret after that step cannot recover the lost distinction: both messages get the same final hash for every seed."
      },
      "sources": [
        "https://github.com/google/farmhash",
        "verify/farmhash-64/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "farm": {
          "evidence": "The algebra shows that this pair collides for every seed. Trying a new seed cannot separate these two messages.",
          "key": "The experiment chooses a 64-bit seed at random, with every possible value equally likely. The two messages are chosen first and do not depend on that seed.",
          "scope": "The pair applies to FarmHash64 NA with either one or two seeds. Direct upstream checks also reproduce it through the UO, XO and TE entry points, which use the NA path for these short inputs."
        }
      },
      "smhasher": {
        "farm": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/FarmHash-64.NA.txt#L3172",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "murmur"
      ],
      "authors": "Austin Appleby",
      "background": "MurmurHash3 is Austin Appleby’s widely used non-cryptographic hash family. Appleby also created SMHasher, the testing tool discussed in this post. The x64_128 variant is built for 64-bit processors and returns a 128-bit result.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/aappleby/smhasher"
        },
        {
          "label": "Verifier package",
          "url": "verify/murmurhash3-128/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "murmur": "A carefully chosen change in one part of the message can be cancelled by a later change. Both halves of the 128-bit result then agree for every seed. The wider output does not protect against two messages that reach the same internal state."
      },
      "sources": [
        "https://github.com/aappleby/smhasher",
        "verify/murmurhash3-128/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "murmur": {
          "evidence": "The argument is algebraic, and the supplied verification also checks every possible 32-bit seed.",
          "key": "The public function accepts a 32-bit seed. Each of its roughly 4.3 billion possible values is equally likely in the stated experiment.",
          "scope": "The result concerns MurmurHash3 x64_128. It builds on a previously published method; the appendix explains the extension and credits the original work."
        }
      },
      "smhasher": {
        "murmur": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/MurmurHash3-128.txt#L3815",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "mx3"
      ],
      "authors": "Jon Maiga",
      "background": "mx3 combines a small integer mixer, a random-number generator and a string hash. Its hash uses ordinary multiplication and bit operations, making the implementation compact. The version studied here is v3.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/jonmaiga/mx3"
        },
        {
          "label": "Verifier package",
          "url": "verify/mx3/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "mx3": "One one-byte message and one eight-byte message are chosen so that their contents cancel the difference in their lengths. They reach the same state before the final mixing step and collide for every seed."
      },
      "sources": [
        "https://github.com/jonmaiga/mx3",
        "verify/mx3/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "mx3": {
          "evidence": "The algebra shows that this pair collides for every seed. Trying a new seed cannot separate these two messages.",
          "key": "The experiment chooses a 64-bit seed at random, with every possible value equally likely. The two messages are chosen first and do not depend on that seed.",
          "scope": "This is an unequal-length collision in mx3 v3’s string-hashing function. It is not a finding about the project’s random-number generator."
        }
      },
      "smhasher": {
        "mx3": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/mx3.v3.txt#L3168",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "fasthash-64",
        "fasthash-32"
      ],
      "authors": "Zilong Tan",
      "background": "Fasthash is a compact C hash by Zilong Tan. It processes eight bytes at a time with multiplication and bit mixing. The 32-bit function is derived from the same computation as the 64-bit function.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/ztanml/fast-hash"
        },
        {
          "label": "Verifier package",
          "url": "verify/fasthash/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "fasthash-64": "A seven-byte message and an eight-byte message cancel the hash’s attempt to encode their different lengths. They then follow the same computation for every seed. Reducing the output to 32 bits preserves the collision.",
        "fasthash-32": "A seven-byte message and an eight-byte message cancel the hash’s attempt to encode their different lengths. They then follow the same computation for every seed. Reducing the output to 32 bits preserves the collision."
      },
      "sources": [
        "https://github.com/ztanml/fast-hash",
        "verify/fasthash/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "fasthash-64": {
          "evidence": "The algebra shows that this pair collides for every seed. Trying a new seed cannot separate these two messages.",
          "key": "The experiment chooses a 64-bit seed at random, with every possible value equally likely. The two messages are chosen first and do not depend on that seed.",
          "scope": "Both fasthash32 and fasthash64 are affected by this pair. The appendix gives the bytes and shows how the length difference is cancelled."
        },
        "fasthash-32": {
          "evidence": "The algebra shows that this pair collides for every seed. Trying a new seed cannot separate these two messages.",
          "key": "The native 32-bit function takes a 32-bit seed. The benchmark passes a wider seed, but the pair collides under either convention.",
          "scope": "Both fasthash32 and fasthash64 are affected by this pair. The appendix gives the bytes and shows how the length difference is cancelled."
        }
      },
      "smhasher": {
        "fasthash-64": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/fasthash-64.txt#L3177",
          "scope": "full"
        },
        "fasthash-32": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/fasthash-32.txt#L2003",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "muse"
      ],
      "authors": "K--Aethiax",
      "background": "MuseAir is a portable hash built around multiplication of large integers. This entry concerns the historical v0.3 implementation retained in SMHasher3. Later releases are different algorithms and need separate analysis.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/eternal-io/museair"
        },
        {
          "label": "Verifier package",
          "url": "verify/museair/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "muse": "The v0.3 implementation loses the distinction between two messages before secret mixing. They therefore collide for every seed, giving a 1.59-bit cap. Algorithm v2 has a separate 32-byte witness and a sampled cap of 19.45 bits."
      },
      "sources": [
        "https://github.com/eternal-io/museair",
        "verify/museair/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "muse": {
          "evidence": "The every-seed algebraic witness applies to v0.3 and v0.4. It does not transfer to v1 or v2; the separate v2 row uses a different, sampled witness.",
          "key": "The experiment chooses a 64-bit seed at random, with every possible value equally likely. The two messages are chosen first and do not depend on that seed.",
          "scope": "This 1.59-bit result is version-bound to v0.3 and v0.4. Current algorithm v2 (crate 0.6.0) has its own 19.45-bit sampled result."
        }
      },
      "smhasher": {
        "muse": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/MuseAir.txt#L3166",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "komi"
      ],
      "authors": "Aleksey Vaneev",
      "background": "Komihash is a fast 64-bit hash supplied as a C/C++ header. It splits work among several parallel calculations to improve speed. This result concerns versions 5.27 and 5.34 and messages of 64–127 bytes.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/avaneev/komihash"
        },
        {
          "label": "Verifier package",
          "url": "verify/komihash/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "komi": "Two fixed messages that differ in just two bits collide for about 91% of sampled seeds. The parallel calculations are related in a way that lets carefully chosen message changes cancel. A fresh random seed will therefore usually leave this particular pair colliding."
      },
      "sources": [
        "https://github.com/avaneev/komihash",
        "verify/komihash/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "komi": {
          "evidence": "The sample contains 3,910,946,997 collisions in 2³² seeds: about 91.06%. This is a measured rate, not an exact formula for every possible seed.",
          "key": "The experiment chooses a 64-bit seed at random, with every possible value equally likely. The two messages are chosen first and do not depend on that seed.",
          "scope": "The construction works at lengths from 64 through 127 bytes. The analysis does not extend this rate to longer inputs that go through another processing round."
        }
      },
      "smhasher": {
        "komi": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/komihash.txt#L3166",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "t1ha"
      ],
      "authors": "Leonid Yuriev · Positive Technologies",
      "background": "t1ha, short for Fast Positive Hash, is a family designed for fast hashing on ordinary processors. This entry studies t1ha2’s one-shot 64-bit function, which hashes a complete message in a single call.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/erthink/t1ha"
        },
        {
          "label": "Verifier package",
          "url": "verify/t1ha2-64/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "t1ha": "A 13-byte input and a 16-byte input can reach the same internal state when multiplication carries cancel. An exactly counted seed class and a measured success rate within it give a sampled cap of 29.19 bits. The result permits different message lengths."
      },
      "sources": [
        "https://github.com/erthink/t1ha",
        "verify/t1ha2-64/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "t1ha": {
          "evidence": "The seed class fixes 24 bits. The upstream verifier found 58,715,203 collisions in 2^30 class samples, giving a class-weighted rate of about 2^-28.19. Fresh uniform-seed runs support the result.",
          "key": "The experiment chooses a 64-bit seed at random, with every possible value equally likely. The two messages are chosen first and do not depend on that seed.",
          "scope": "This result concerns the t1ha2_atonce 64-bit function. Other t1ha versions and the streaming interface are separate cases."
        }
      },
      "smhasher": {
        "t1ha": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/t1ha2-64.txt#L3167",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "a5",
        "a5wide"
      ],
      "authors": "Aleksey Vaneev",
      "background": "a5hash is a C/C++ hash-table hash from the author of komihash. Version 5.21 offers both 64-bit and 128-bit outputs. The two output sizes have different collision results here.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/avaneev/a5hash"
        },
        {
          "label": "Verifier package",
          "url": "verify/a5hash/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "a5": "For a particular set of seeds, one multiplication has a zero operand. Multiplying by zero erases a change in the other operand, so two distinct messages collide. Counting those seeds gives an exact upper limit on the collision score; other collisions could make that limit lower.",
        "a5wide": "The messages force a multiplication by zero regardless of the seed. A message difference is erased, and both halves of the 128-bit output agree for every seed. This variant passes all 250 published SMHasher3 tests, showing why passing a finite test suite cannot guarantee safety for every pair."
      },
      "sources": [
        "https://github.com/avaneev/a5hash",
        "verify/a5hash/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "a5": {
          "evidence": "At least 118 out of every 2⁴⁵ seeds produce this collision. The count is exact for the identified class, which need not include every colliding seed.",
          "key": "The experiment chooses a 64-bit seed at random, with every possible value equally likely. The two messages are chosen first and do not depend on that seed.",
          "scope": "The results apply to the respective 64-bit and 128-bit functions in the studied a5hash version. The appendix gives separate witnesses and derivations."
        },
        "a5wide": {
          "evidence": "The algebra shows that this pair collides for every seed. Trying a new seed cannot separate these two messages.",
          "key": "The experiment chooses a 64-bit seed at random, with every possible value equally likely. The two messages are chosen first and do not depend on that seed.",
          "scope": "The results apply to the respective 64-bit and 128-bit functions in the studied a5hash version. The appendix gives separate witnesses and derivations."
        }
      },
      "smhasher": {
        "a5": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/a5hash.txt#L3166",
          "scope": "full"
        },
        "a5wide": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/a5hash-128.txt#L3810",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "rapid3"
      ],
      "authors": "Nicolas De Carli · based on wyhash by Wang Yi",
      "background": "Rapidhash develops ideas from Wang Yi’s wyhash, using multiplication to mix message data quickly. Version 3 offers standard, Micro and Nano variants with different speed and code-size tradeoffs. The chart studies the standard variant.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/Nicoshev/rapidhash"
        },
        {
          "label": "Verifier package",
          "url": "verify/rapidhash-v3/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "rapid3": "Flipping every bit in two chosen message words can leave a multiplication’s mixed result unchanged. That produces a fixed pair with more collisions than its output width might suggest, and the rate is the same whether the secret words are the shipped constants or eight freshly random words, because the cancellation never uses their values. The score is taken under the random-secret model; the shipped constants additionally admit an every-seed pair, noted in the appendix. The rate is estimated from samples; the chart is not a ranking of hashes, because search effort was unequal."
      },
      "sources": [
        "https://github.com/Nicoshev/rapidhash",
        "verify/rapidhash-v3/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "rapid3": {
          "evidence": "Pooled samples found 2,386 collisions in about 2^37.8 keys (a search harness and an independent verifier with different random-number generators). The 95% interval on the cap is 28.5–28.7 bits.",
          "key": "Each trial chooses a 64-bit seed and all eight 64-bit secret words at random, every value equally likely (576 hidden bits), and passes them to rapidhash_internal. The two messages are chosen first and do not depend on the key. With the shipped secret words the same pair collides at the same rate, but the shipped words also allow a pair that collides for every seed; that weakness is excluded by this score and noted separately.",
          "scope": "The experiment uses rapidhash v3’s standard function; the same 32-byte path is shared by Micro and Nano. Callers of the public rapidhash() and rapidhash_withSeed() wrappers use the shipped constants and are covered by the appendix’s default-secret note."
        }
      },
      "smhasher": {
        "rapid3": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/5035a923/results/raw/rapidhash.txt#L3166",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "mum"
      ],
      "authors": "Vladimir Makarov",
      "background": "MUM stands for “multiply and mix”: it combines the two halves of a large integer product. This entry studies v3 with its public constants. The eight-byte collision also survives the November 2025 changes to the default implementation, which protect a different, longer-input path.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/vnmakarov/mum-hash"
        },
        {
          "label": "Verifier package",
          "url": "verify/mum/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "mum": "Two different eight-byte messages give the same product-mixing result before it is combined with the seeded state. Since the seed receives the same value in both cases, the final outputs agree for every seed."
      },
      "sources": [
        "https://github.com/vnmakarov/mum-hash",
        "verify/mum/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "mum": {
          "evidence": "The algebra shows that this pair collides for every seed. Trying a new seed cannot separate these two messages.",
          "key": "The experiment chooses a 64-bit seed at random, with every possible value equally likely. The two messages are chosen first and do not depend on that seed.",
          "scope": "The eight-byte pair still collides in the current default build at commit 595c091. The November 2025 fix protects a longer-input loop that this pair never enters. The optional MUM_QUALITY build needs a different pair, documented in the appendix."
        }
      },
      "smhasher": {
        "mum": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/5035a923/results/raw/mum3.exact.unroll3.txt#L3170",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "mir"
      ],
      "authors": "Vladimir Makarov",
      "background": "This hash comes from Vladimir Makarov’s MIR compiler project. It mixes data by adding the two halves of a large product. The “exact” and “inexact” implementations use different ways to compute that product; the chart times the exact one.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/vnmakarov/mir/blob/master/mir-hash.h"
        },
        {
          "label": "Verifier package",
          "url": "verify/mir/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "mir": "The selected eight-byte messages both produce a zero contribution in the part of the computation that is independent of the seed. They therefore collide for every seed. The same pair works in both implementations."
      },
      "sources": [
        "https://github.com/vnmakarov/mir/blob/master/mir-hash.h",
        "verify/mir/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "mir": {
          "evidence": "The algebra shows that this pair collides for every seed. Trying a new seed cannot separate these two messages.",
          "key": "The experiment chooses a 64-bit seed at random, with every possible value equally likely. The two messages are chosen first and do not depend on that seed.",
          "scope": "The plotted speed is for mir.exact. The collision claim covers both mir.exact and mir.inexact in the studied code."
        }
      },
      "smhasher": {
        "mir": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/mir.exact.txt#L3169",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "xxh3-64",
        "xxh3-128"
      ],
      "authors": "Yann Collet and the xxHash contributors",
      "background": "XXH3 is part of Yann Collet’s xxHash family. It uses different routines for different input lengths and processors to achieve high throughput. These entries study version 0.8.3 keyed with a caller-supplied 192-byte secret (withSecret), the strongest key model the API offers; the seeded functions with the standard public constants are discussed as a separate caveat.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/Cyan4973/xxHash"
        },
        {
          "label": "Algorithm specification",
          "url": "https://github.com/Cyan4973/xxHash/blob/v0.8.3/doc/xxhash_spec.md"
        },
        {
          "label": "Verifier package",
          "url": "verify/xxh3-64/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "xxh3-64": "Complementing one keyed word of a 16-byte block leaves the folded product unchanged for about one key in 2^27, whatever the secret bytes are. Measured through XXH3_64bits_withSecret with a fresh random 192-byte secret per trial, a 24-byte pair gives a sampled cap of 28.5 bits. Callers of the seeded functions (withSeed, and withSecretandSeed or streaming at up to 240 bytes, which use the default secret) face a much weaker case: a 32-byte pair built from the default-secret words collides for one seed in about 1,423, a 12.47-bit cap. That default-secret figure is a caveat, not the score. It does not assert a flooding attack.",
        "xxh3-128": "The pair preserves both a multiplication result and a sum used by the hash, causing both output halves to collide for some keys. With a fresh random 192-byte secret per trial, 479 full 128-bit collisions in about 2^35.5 keys give a measured score cap of 28.6 bits, with a 95% interval of 28.4–28.7 bits; the default-secret seeded function gives the same rate."
      },
      "sources": [
        "https://github.com/Cyan4973/xxHash",
        "https://github.com/Cyan4973/xxHash/blob/v0.8.3/doc/xxhash_spec.md",
        "verify/xxh3-64/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "xxh3-64": {
          "evidence": "An independent verifier against the upstream 0.8.3 source counted 527 collisions in 2^36 keys for the 24-byte pair (260 through withSecret, 267 with seed and secret both random; the two models give the same rate). The score interval is 28.4–28.7 bits. The default-secret 32-byte pair was measured at 2,264,081 collisions in 3 × 2^30 seeds (12.47 bits).",
          "key": "Each trial draws 192 secret bytes at random, every value equally likely (1,536 hidden bits), and calls XXH3_64bits_withSecret. The two messages are chosen first and do not depend on the key. With withSeed, and with withSecretandSeed or the streaming interface for inputs of at most 240 bytes, the library uses its built-in secret and only the 64-bit seed is hidden; the default-secret pair applies there.",
          "scope": "The scored pair is the paper’s fold differential under a uniform secret; the default-secret pair is a bounded-search result for the seeded 0.8.3 functions. The earlier base-1143 pair and historical pair A remain documented as controls."
        },
        "xxh3-128": {
          "evidence": "An independent verifier counted 156 collisions in 2^34 keys through withSecret, 84 in 2^33 with seed and secret both random and 60 in a second 2^32 stream; the search harness counted 179 in 2^34. The default-secret control (165 in 2^34 plus 44 in 2^32) gives the same rate.",
          "key": "Each trial draws 192 secret bytes at random, every value equally likely (1,536 hidden bits), and calls XXH3_128bits_withSecret; the seed adds nothing at these lengths. The two messages are chosen first and do not depend on the key.",
          "scope": "The experiment covers XXH3-128 version 0.8.3 at 32 bytes with full 128-bit equality. withSecretandSeed ignores the custom secret for inputs of at most 240 bytes, so callers of that function with short inputs are in the seeded model, where the same pair collides at the same rate."
        }
      },
      "smhasher": {
        "xxh3-64": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/5035a923/results/raw/XXH3-64.txt#L3176",
          "scope": "full"
        },
        "xxh3-128": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/7ad8939d/results/raw/XXH3-128.txt#L3819",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "highway"
      ],
      "authors": "Jyrki Alakuijala, Bill Cox, and Jan Wassenberg · Google",
      "background": "HighwayHash was designed at Google as a fast keyed hash. It uses processor instructions that work on several values at once and offers 64-, 128- and 256-bit outputs. Its key contains four 64-bit words.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/google/highwayhash"
        },
        {
          "label": "Original paper",
          "url": "https://arxiv.org/abs/1612.06257"
        },
        {
          "label": "Verifier package",
          "url": "verify/highwayhash/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "highway": "A carefully chosen pair of 96-byte messages can reach the same internal state for a rare but exactly counted set of keys. Every output size then inherits the collision. The resulting score cap is about 59.81 bits. Lean, a proof-checking program, has verified the mathematical count; that does not verify the compiled implementation."
      },
      "sources": [
        "https://github.com/google/highwayhash",
        "https://arxiv.org/abs/1612.06257",
        "verify/highwayhash/README.html",
        "records/speeds.json"
      ],
      "lean": {
        "highway": {
          "label": "✓ checked",
          "source": "records/machine-checked.html",
          "scope": "M1–M4 complete: exact full-key trail count 56165·2^184, unconditional state and all three output collision bounds, and score enclosure 59.807–59.808; C/Lean vectors are execution evidence, not compiler correctness."
        }
      },
      "reader_notes": {
        "highway": {
          "evidence": "The identified class contributes at least 56,165 collisions per 2⁷² keys. This is an exact count of one sufficient event, not the total probability of every way the pair could collide.",
          "key": "All four 64-bit key words are chosen independently and uniformly. This is a full 256-bit random key, rather than a small seed expanded into a key.",
          "scope": "The proof checks the mathematical collision path and its key count. Comparisons against implementation outputs support the connection, but no proof of the C code or compiler is claimed."
        }
      },
      "smhasher": {
        "highway": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/HighwayHash-64.txt#L3100",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "spooky"
      ],
      "authors": "Bob Jenkins",
      "background": "SpookyHash is Bob Jenkins’s non-cryptographic hash for 64-bit machines. It computes a 128-bit result and also offers a 64-bit interface. The chart studies that 64-bit interface in version 2.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://burtleburtle.net/bob/hash/spooky.html"
        },
        {
          "label": "Verifier package",
          "url": "verify/spookyhash2-64/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "spooky": "A change near the end of the message can cancel an earlier change before final mixing. The selected pair collides for about half of sampled seeds. The evidence supports that approximate rate; it does not prove that exactly half of all seeds collide."
      },
      "sources": [
        "https://burtleburtle.net/bob/hash/spooky.html",
        "verify/spookyhash2-64/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "spooky": {
          "evidence": "The reported sample found 536,875,475 collisions among 1,073,741,823 seeds, very close to one half.",
          "key": "The 64-bit interface copies one random 64-bit seed into both internal seed words. A similar rate was also measured when those two words were chosen independently.",
          "scope": "The plotted measurement is for SpookyHash V2’s 64-bit interface. An exact one-half probability is not certified by the sampling."
        }
      },
      "smhasher": {
        "spooky": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/SpookyHash2-64.txt#L3168",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "pengyhash"
      ],
      "authors": "Alberto Fajardo",
      "background": "Pengyhash is a compact hash built from additions, rotations and bit operations. Version 0.3 returns 64 bits and accepts a 64-bit seed. Earlier versions used a smaller seed.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/tinypeng/pengyhash"
        },
        {
          "label": "Verifier package",
          "url": "verify/pengyhash/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "pengyhash": "Its main loop processes full message blocks without using the seed. Two chosen messages finish that loop in the same state, so the later seeded steps cannot tell them apart. The collision survives every choice of seed."
      },
      "sources": [
        "https://github.com/tinypeng/pengyhash",
        "verify/pengyhash/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "pengyhash": {
          "evidence": "The algebra shows that this pair collides for every seed. Trying a new seed cannot separate these two messages.",
          "key": "The experiment chooses a 64-bit seed at random, with every possible value equally likely. The two messages are chosen first and do not depend on that seed.",
          "scope": "The result concerns pengyhash v0.3 as retained in SMHasher3. It relies on the seed being introduced only after the colliding full-block calculation."
        }
      },
      "smhasher": {
        "pengyhash": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/pengyhash.txt#L3167",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "nmhash32",
        "nmhash32x"
      ],
      "authors": "James Z. M. Gao",
      "background": "NMHASH32 and NMHASH32X are two distinct 32-bit hashes by James Z. M. Gao. Both accept a 32-bit seed, but use different mixing routines. Each therefore needs its own collision analysis.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/gzm55/hash-garage"
        },
        {
          "label": "Verifier package",
          "url": "verify/nmhash32/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "nmhash32": "A carefully chosen message difference cancels for a large set of seeds. Here every possible seed was checked, so the reported rate is an exact count rather than a sample estimate. Roughly one in four seeds makes the pair collide.",
        "nmhash32x": "The pair introduces a difference and cancels it later in the calculation, regardless of the seed. Both messages therefore get the same hash for every possible seed. Choosing a different seed cannot repair this pair."
      },
      "sources": [
        "https://github.com/gzm55/hash-garage",
        "verify/nmhash32/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "nmhash32": {
          "evidence": "Exhaustive enumeration found 1,078,944,392 colliding seeds out of 2³².",
          "key": "The public function accepts a 32-bit seed. Each of its roughly 4.3 billion possible values is equally likely in the stated experiment.",
          "scope": "The entries concern the respective v2 functions. A result for NMHASH32 should not be transferred to NMHASH32X, or vice versa, without its separate argument."
        },
        "nmhash32x": {
          "evidence": "The algebra shows that this pair collides for every seed. Trying a new seed cannot separate these two messages.",
          "key": "The public function accepts a 32-bit seed. Each of its roughly 4.3 billion possible values is equally likely in the stated experiment.",
          "scope": "The entries concern the respective v2 functions. A result for NMHASH32 should not be transferred to NMHASH32X, or vice versa, without its separate argument."
        }
      },
      "smhasher": {
        "nmhash32": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/NMHASH.txt#L2023",
          "scope": "full"
        },
        "nmhash32x": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/NMHASHX.txt#L2025",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "gx"
      ],
      "authors": "Olivier Giniaux",
      "background": "GxHash is a fast hash implemented in Rust that uses the processor’s AES instructions to mix data. This entry studies version 3.5.0. Using AES instructions inside a hash does not, by itself, establish a collision guarantee.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/ogxd/gxhash"
        },
        {
          "label": "Verifier package",
          "url": "verify/gxhash-64/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "gx": "A 15-byte message and a 16-byte message become identical during the initial padding and length calculation, before the seed is involved. The remaining computation sees the same input. The pair collides for every seed, even when the full 128-bit result is retained."
      },
      "sources": [
        "https://github.com/ogxd/gxhash",
        "verify/gxhash-64/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "gx": {
          "evidence": "The algebra shows that this pair collides for every seed. Trying a new seed cannot separate these two messages.",
          "key": "The experiment chooses a 64-bit seed at random, with every possible value equally likely. The two messages are chosen first and do not depend on that seed.",
          "scope": "This is a short-message encoding collision in the studied version. The appendix credits the earlier report and shows the exact bytes."
        }
      },
      "smhasher": {
        "gx": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/gxhash-64.txt#L3171",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "ahash"
      ],
      "authors": "Tom Kaitchuck",
      "background": "aHash is a Rust hash designed for hash tables. It uses AES hardware instructions when they are available and a different fallback otherwise. This entry concerns the AES implementation in version 0.8.12.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/tkaitchuck/aHash"
        },
        {
          "label": "Design & FAQ",
          "url": "https://github.com/tkaitchuck/aHash/blob/master/FAQ.md"
        },
        {
          "label": "Verifier package",
          "url": "verify/rust-ahash/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "ahash": "The selected 424-byte pair E is a two-S-box 'lane echo' on the long-input path: one AES lane cancels a byte difference twice, six blocks apart, and the shuffled-addition lane cancels the residue. Native crate checks give a sampled cap of 17.84 bits under four independent random key words. The earlier 56-byte three-S-box pair A_2 (22.18 bits) is kept as historical; the new pair needs the key words to be independent and does not fire under SMHasher3's correlated seed convention."
      },
      "sources": [
        "https://github.com/tkaitchuck/aHash",
        "https://github.com/tkaitchuck/aHash/blob/master/FAQ.md",
        "verify/rust-ahash/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "ahash": {
          "evidence": "The upstream 0.8.12 crate counted 967,503 collisions in 2^32 keys, about 2^-12.116. The score's 95% interval is 17.84–17.85 bits. The C reproduction (3783 in 2^24) agrees.",
          "key": "Four RandomState arguments are chosen independently and uniformly. Their fixed XOR with the public constants maps them bijectively to four independent internal key words.",
          "scope": "This covers the AES path and hashing byte slices through the stated constructor. Another key distribution, data type or sequence of write calls needs a separate check."
        }
      },
      "smhasher": {
        "ahash": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/rust-ahash.txt#L3168",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "polymur"
      ],
      "authors": "Orson Peters",
      "background": "PolymurHash is Orson Peters’s fast hash with a mathematical collision guarantee. It treats a message as a polynomial—a sum of powers with the message pieces as coefficients—and evaluates it using a secret key. It uses ordinary integer multiplication, so it does not require specialized carry-less multiplication instructions.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/orlp/polymur-hash"
        },
        {
          "label": "Author’s universality proof",
          "url": "https://github.com/orlp/polymur-hash/blob/master/extras/universality-proof.md"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "polymur": "The audit establishes at least 54.22 bits on this post’s collision score for the full 64-bit output. That guarantee requires choosing the key uniformly from the specified allowed set. It does not automatically cover the library’s seed-based key generator or a hash table that keeps only some output bits."
      },
      "sources": [
        "https://github.com/orlp/polymur-hash",
        "https://github.com/orlp/polymur-hash/blob/master/extras/universality-proof.md",
        "records/speeds.json"
      ],
      "lean": {
        "polymur": {
          "label": "✓ checked",
          "source": "records/machine-checked.html",
          "scope": "The exact restricted-key cardinality lower bound and numerical idealHash collision/score theorems are unconditional; the shipped seed distribution and C arithmetic refinement remain outside scope."
        }
      },
      "reader_notes": {
        "polymur": {
          "evidence": "The key-counting argument and numerical guarantee have been checked in Lean, a program that verifies each step of a mathematical proof.",
          "key": "Choose the polynomial key uniformly from the allowed set and keep the additional tweak fixed. Expanding a small seed into a key gives a different distribution and needs a separate argument.",
          "scope": "The proved result concerns equality of the full 64-bit outputs. The audit does not certify stronger claims about output differences, arbitrary truncation, or correctness of the compiled C implementation."
        }
      },
      "smhasher": {
        "polymur": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/polymurhash.txt#L3166",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "halftimehash-64",
        "halftimehash-128",
        "halftimehash-256",
        "halftimehash-512"
      ],
      "authors": "Jim Apple",
      "background": "HalftimeHash, introduced by Jim Apple in 2021, was designed to hash long strings quickly without relying on wide integer multiplication. Its 64, 128, 256 and 512 style names describe implementation choices: every style here returns a 64-bit hash.",
      "links": [
        {
          "label": "Original project and code",
          "url": "https://github.com/jbapple/HalftimeHash"
        },
        {
          "label": "Corrected bounds and repair (PDF)",
          "url": "records/papers/halftime_repair.pdf"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        },
        {
          "label": "Verifier package",
          "url": "verify/halftime/README.html"
        }
      ],
      "results": {
        "halftimehash-64": "The corrected analysis gives all four styles at least 63 bits on this post’s collision score, within their supported message lengths and with independently random key material. This repairs a gap in the published wrapper argument. The separate advanced function that returns 24 bytes has a different result; it is not one of these four styles.",
        "halftimehash-128": "The corrected analysis gives all four styles at least 63 bits on this post’s collision score, within their supported message lengths and with independently random key material. This repairs a gap in the published wrapper argument. The separate advanced function that returns 24 bytes has a different result; it is not one of these four styles.",
        "halftimehash-256": "The corrected analysis gives all four styles at least 63 bits on this post’s collision score, within their supported message lengths and with independently random key material. This repairs a gap in the published wrapper argument. The separate advanced function that returns 24 bytes has a different result; it is not one of these four styles.",
        "halftimehash-512": "The corrected analysis gives all four styles at least 63 bits on this post’s collision score, within their supported message lengths and with independently random key material. This repairs a gap in the published wrapper argument. The separate advanced function that returns 24 bytes has a different result; it is not one of these four styles."
      },
      "sources": [
        "https://github.com/jbapple/HalftimeHash",
        "records/papers/halftime_repair.pdf",
        "records/speeds.json",
        "verify/halftime/README.html"
      ],
      "lean": {
        "halftimehash-64": {
          "label": "partial: executable refinement remains unproved",
          "source": "records/machine-checked.html",
          "scope": "The abstract Style construction is checked; the implementation correspondence remains partial because the universal executable/Style connection and fixed-header premises are not discharged in Lean."
        },
        "halftimehash-128": {
          "label": "partial: executable refinement remains unproved",
          "source": "records/machine-checked.html",
          "scope": "The abstract Style construction is checked; the implementation correspondence remains partial because the universal executable/Style connection and fixed-header premises are not discharged in Lean."
        },
        "halftimehash-256": {
          "label": "partial: executable refinement remains unproved",
          "source": "records/machine-checked.html",
          "scope": "The abstract Style construction is checked; the implementation correspondence remains partial because the universal executable/Style connection and fixed-header premises are not discharged in Lean."
        },
        "halftimehash-512": {
          "label": "partial: executable refinement remains unproved",
          "source": "records/machine-checked.html",
          "scope": "The abstract Style construction is checked; the implementation correspondence remains partial because the universal executable/Style connection and fixed-header premises are not discharged in Lean."
        }
      },
      "reader_notes": {
        "halftimehash-64": {
          "evidence": "The corrected mathematical argument supplies the plotted guarantee. Parts have been checked in Lean, but the complete connection from the executable wrapper to that argument is still unfinished.",
          "key": "The required key words must be independent and uniformly random. Generating them from the benchmark’s smaller seed is not covered by this theorem.",
          "scope": "This style’s bound applies below 2,761,050,384 bytes. It assumes the stated memory layout and unsigned arithmetic behavior; it is not a proof of arbitrary C++ execution or of the benchmark’s seed generator."
        },
        "halftimehash-128": {
          "evidence": "The corrected mathematical argument supplies the plotted guarantee. Parts have been checked in Lean, but the complete connection from the executable wrapper to that argument is still unfinished.",
          "key": "The required key words must be independent and uniformly random. Generating them from the benchmark’s smaller seed is not covered by this theorem.",
          "scope": "This style’s bound applies below 5,522,100,768 bytes. It assumes the stated memory layout and unsigned arithmetic behavior; it is not a proof of arbitrary C++ execution or of the benchmark’s seed generator."
        },
        "halftimehash-256": {
          "evidence": "The corrected mathematical argument supplies the plotted guarantee. Parts have been checked in Lean, but the complete connection from the executable wrapper to that argument is still unfinished.",
          "key": "The required key words must be independent and uniformly random. Generating them from the benchmark’s smaller seed is not covered by this theorem.",
          "scope": "This style’s bound applies below 11,044,201,536 bytes. It assumes the stated memory layout and unsigned arithmetic behavior; it is not a proof of arbitrary C++ execution or of the benchmark’s seed generator."
        },
        "halftimehash-512": {
          "evidence": "The corrected mathematical argument supplies the plotted guarantee. Parts have been checked in Lean, but the complete connection from the executable wrapper to that argument is still unfinished.",
          "key": "The required key words must be independent and uniformly random. Generating them from the benchmark’s smaller seed is not covered by this theorem.",
          "scope": "This style’s bound applies below 22,088,403,072 bytes. It assumes the stated memory layout and unsigned arithmetic behavior; it is not a proof of arbitrary C++ execution or of the benchmark’s seed generator."
        }
      },
      "smhasher": {
        "halftimehash-64": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/5035a923/results/raw/HalftimeHash-64.txt#L3171",
          "scope": "full"
        },
        "halftimehash-128": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/5035a923/results/raw/HalftimeHash-128.txt#L3172",
          "scope": "full"
        },
        "halftimehash-256": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/5035a923/results/raw/HalftimeHash-256.txt#L3171",
          "scope": "full"
        },
        "halftimehash-512": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/5035a923/results/raw/HalftimeHash-512.txt#L3172",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "umash",
        "umash128"
      ],
      "authors": "Paul Khuong · Backtrace",
      "background": "UMASH was developed at Backtrace to give fast string fingerprints with a mathematical bound on accidental matches. It combines several hashing steps. The 128-bit fingerprint adds a second result to the 64-bit hash.",
      "links": [
        {
          "label": "Original project and code",
          "url": "https://github.com/backtrace-labs/umash"
        },
        {
          "label": "Collision bounds (PDF)",
          "url": "records/papers/umash_bounds.pdf"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "umash": "The published 64-bit guarantee now has a complete proof, with a stronger 56.18-bit score. The proof uses three extra accumulator bits that the implementation keeps beyond its prime-field calculation. With ideal random keys and a fixed seed, the bound at 1 GB is 38.000 bits.",
        "umash128": "The C fingerprint’s published guarantee is also proved, using two independently random polynomial multipliers. The finer bound scores 83.99 bits (about 84) through 2^46 eight-byte words, 88.63 through 64 MiB and about 69 over the full byte-length domain. At 1 GB the bound is 75.98 bits. The single-multiplier Python fingerprint is refuted."
      },
      "sources": [
        "https://github.com/backtrace-labs/umash",
        "records/papers/umash_bounds.pdf",
        "records/speeds.json"
      ],
      "lean": {
        "umash": {
          "label": "partial: 46.52-bit envelope + ENH-only closure machine-checked; 56.18 / 84 are verified paper proofs, not yet machine-checked",
          "source": "records/machine-checked.html",
          "scope": "The earlier 46.52-bit envelope and ENH-only closure are machine-checked. The 53.38-bit refinement, 56.18-bit bound, joint PH+ENH closure and fingerprint headline are verified paper proofs; not yet machine-checked."
        },
        "umash128": {
          "label": "partial: 46.52-bit envelope + ENH-only closure machine-checked; 56.18 / 84 are verified paper proofs, not yet machine-checked",
          "source": "records/machine-checked.html",
          "scope": "The earlier 46.52-bit envelope and ENH-only closure are machine-checked. The 53.38-bit refinement, 56.18-bit bound, joint PH+ENH closure and fingerprint headline are verified paper proofs; not yet machine-checked."
        }
      },
      "reader_notes": {
        "umash": {
          "evidence": "The compiled paper establishes the bound using exact certificates. The original paper’s intermediate projection step remains unvalidated. Lean has checked the earlier 46.52-bit envelope and ENH-only closure; the stronger headlines and PH+ENH closure are verified paper proofs, and are not yet machine-checked.",
          "key": "The seed is fixed. All 34 compression-key words are uniformly random without replacement; independent sampling is also covered. One polynomial multiplier is independently uniform. Both reference and C multiplier ranges are covered.",
          "scope": "The 56.18-bit score holds under both fixed-length and at-most-length conventions. The implemented accumulator was checked in the Python reference and C. These are full-output theorems for ideal keys, not Salsa20 key derivation / umash_params_derive or its OH-repair sampler. Per-call seeds and masked outputs are outside the theorems."
        },
        "umash128": {
          "evidence": "The compiled paper establishes the bound using exact certificates. The original paper’s intermediate projection step remains unvalidated. Lean has checked the earlier 46.52-bit envelope and ENH-only closure; the stronger headlines and PH+ENH closure are verified paper proofs, and are not yet machine-checked.",
          "key": "The seed is fixed. All 34 compression-key words are uniformly random without replacement; independent sampling is also covered. The two polynomial multipliers are independent of each other and of the shared compression key. Both reference and C multiplier ranges are covered.",
          "scope": "The 84-bit display is rounded and applies only through 2^46 words. The C architecture uses two multipliers; the Python reference reuses one and has a block-swap collision for every compression key at special multiplier values. These are full-output theorems for ideal keys, not Salsa20 key derivation / umash_params_derive or its OH-repair sampler. Per-call seeds and masked outputs are outside the theorems."
        }
      },
      "smhasher": {
        "umash": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/UMASH-64.txt#L3180",
          "scope": "full"
        },
        "umash128": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/UMASH-128.txt#L3825",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "clhash"
      ],
      "authors": "Daniel Lemire and Owen Kaser",
      "background": "CLHASH is a fast universal hash designed by Daniel Lemire and Owen Kaser. It uses specialized processor instructions for a form of binary multiplication. The design aims to combine a collision guarantee with high throughput on long messages.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/lemire/clhash"
        },
        {
          "label": "Original paper",
          "url": "https://arxiv.org/abs/1503.03465"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "clhash": "The audited mathematical construction gives at least 64 bits on this post’s score when supplied with the required independent random key. Lean has checked that ideal construction. The benchmark starts from a smaller seed, so its timing does not establish the same guarantee for the benchmark’s key generator."
      },
      "sources": [
        "https://github.com/lemire/clhash",
        "https://arxiv.org/abs/1503.03465",
        "records/speeds.json"
      ],
      "lean": {
        "clhash": {
          "label": "✓ checked",
          "source": "records/machine-checked.html",
          "scope": "Ideal Algorithm-4 bound for distinct byte strings shorter than 2^64 bytes, including empty, partial and unequal-length inputs; no implementation or seed-expander theorem."
        }
      },
      "reader_notes": {
        "clhash": {
          "evidence": "The checked proof covers the paper’s Algorithm 4 and byte strings shorter than 2⁶⁴ bytes. The original paper specifies the length-dependent collision bound.",
          "key": "The theorem requires the independent random key material specified by Algorithm 4. The benchmark’s seed-to-key conversion is a separate construction.",
          "scope": "The proof covers the mathematical algorithm, not the C implementation or compiler. The paper’s separately bit-mixed variant and its claims about output differences must also be distinguished."
        }
      },
      "smhasher": {
        "clhash": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/CLhash.txt#L3181",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "poly1305"
      ],
      "authors": "Daniel J. Bernstein",
      "background": "Poly1305 is the polynomial-hashing component of Daniel J. Bernstein’s message-authentication design. It helps detect whether a message has been altered. The chart compares that mathematical component and an OpenSSL implementation; using it as a complete authenticator requires the surrounding protocol.",
      "results": {
        "poly1305": "The audited polynomial construction gives at least 103 bits on this post’s score with the specified random key. Lean has checked that mathematical result. The timed wrapper generates its key from a 64-bit seed, however, so the theorem does not automatically apply to that wrapper’s key choices."
      },
      "links": [
        {
          "label": "Original paper",
          "url": "https://cr.yp.to/mac/poly1305-20050329.pdf"
        },
        {
          "label": "OpenSSL implementation",
          "url": "https://github.com/openssl/openssl/tree/master/crypto/poly1305"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "sources": [
        "https://cr.yp.to/mac/poly1305-20050329.pdf",
        "https://github.com/openssl/openssl/tree/master/crypto/poly1305",
        "records/speeds.json"
      ],
      "lean": {
        "poly1305": {
          "label": "✓ checked (ideal key)",
          "source": "records/machine-checked.html",
          "scope": "Ideal byte-string families: explicit clamped Poly1305 keys and single-stream GHASH with uniform field key; excludes seeded samplers, AES and OpenSSL C/assembly."
        }
      },
      "reader_notes": {
        "poly1305": {
          "evidence": "The checked bound covers the polynomial calculation with a uniformly selected allowed key. “Clamping” refers to fixing certain key bits as required by Poly1305’s design.",
          "key": "Choose the polynomial key uniformly from the allowed clamped keys. A deterministic expansion of a 64-bit seed does not sample that whole set uniformly.",
          "scope": "The timing includes OpenSSL setup and seed expansion. The proof does not verify OpenSSL’s C or assembly code, and the chart does not evaluate the security of a complete authentication protocol."
        }
      },
      "smhasher": {
        "poly1305": {
          "url": "https://github.com/thomasahle/hash-benchmark-reproduction/blob/038373d7f7a683436ef6dc662814aa0aef7e9e4b/verification/out/Xeon8375C/poly1305-hash.sanity.txt",
          "label": "SMHasher3 basic checks",
          "scope": "sanity"
        }
      }
    },
    {
      "ids": [
        "ghash"
      ],
      "authors": "David A. McGrew and John Viega · GCM construction",
      "background": "GHASH is the polynomial hash inside GCM, an authenticated-encryption design by David McGrew and John Viega. In systems such as AES-GCM it helps detect changes to data. Here it provides a useful comparison with the faster general-purpose hashes.",
      "results": {
        "ghash": "The audited single-message construction gives at least 127 bits on this post’s collision score with a uniformly random 128-bit key. Lean has checked the mathematical bound. The timed code includes additional GMAC setup and uses a smaller seed; its key generator does not inherit that ideal-key guarantee."
      },
      "links": [
        {
          "label": "Original paper",
          "url": "https://eprint.iacr.org/2004/193"
        },
        {
          "label": "OpenSSL implementation",
          "url": "https://github.com/openssl/openssl/blob/master/crypto/modes/gcm128.c"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "sources": [
        "https://eprint.iacr.org/2004/193",
        "https://github.com/openssl/openssl/blob/master/crypto/modes/gcm128.c",
        "records/speeds.json"
      ],
      "lean": {
        "ghash": {
          "label": "✓ checked (ideal key)",
          "source": "records/machine-checked.html",
          "scope": "Ideal byte-string families: explicit clamped Poly1305 keys and single-stream GHASH with uniform field key; excludes seeded samplers, AES and OpenSSL C/assembly."
        }
      },
      "reader_notes": {
        "ghash": {
          "evidence": "The proof covers one message encoded as authenticated data, with no ciphertext stream. Messages must be shorter than 2⁶¹ bytes. The more general two-stream construction has a different bound.",
          "key": "The hash key must be uniformly random over all 128-bit values. The benchmark instead expands a 64-bit seed, which selects a smaller family; that family needs its own analysis.",
          "scope": "Speed is measured through OpenSSL’s GMAC interface, including AES and setup costs. It is not a timing of bare GHASH, nor a proof of OpenSSL, AES or a complete GCM protocol."
        }
      },
      "smhasher": {
        "ghash": {
          "url": "https://github.com/thomasahle/hash-benchmark-reproduction/blob/038373d7f7a683436ef6dc662814aa0aef7e9e4b/verification/out/Xeon8375C/ghash.sanity.txt",
          "label": "SMHasher3 basic checks",
          "scope": "sanity"
        }
      }
    },
    {
      "ids": [
        "foldhash-fast",
        "foldhash-quality"
      ],
      "authors": "Orson Peters",
      "background": "Foldhash is Orson Peters’s Rust hash for hash tables. It mixes data using large integer products. Version 0.2.0 has a fast variant and a quality variant that adds another mixing step.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/orlp/foldhash/tree/v0.2.0"
        },
        {
          "label": "Verifier package",
          "url": "verify/foldhash-fast/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "foldhash-fast": "For an eight-byte input, the same message word is used on both sides of a multiplication. Flipping all its bits can preserve the mixed product and produce a collision. The measured rate limits the score to about 26.57 bits under the experiment’s independent-key setup.",
        "foldhash-quality": "The quality variant adds a final mixing step, but that step receives identical values whenever the fast variant has already collided. It therefore preserves those collisions. The independent-key experiment gives a measured cap of about 26.56 bits."
      },
      "sources": [
        "https://github.com/orlp/foldhash/tree/v0.2.0",
        "verify/foldhash-fast/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "foldhash-fast": {
          "evidence": "The recorded sample contains 2,757 collisions in 2³⁸ random keys.",
          "key": "The experiment chooses the per-hasher seed and six shared 64-bit words independently. The default Rust RandomState and the benchmark wrapper generate related values differently, so these rates should not be transferred to them.",
          "scope": "This is a result about the same input type in version 0.2.0. Separate examples involving different Rust input types are documented in the appendix and should not be confused with this scored pair."
        },
        "foldhash-quality": {
          "evidence": "The recorded sample contains 696 collisions in 2³⁶ random keys.",
          "key": "The experiment chooses the per-hasher seed and six shared 64-bit words independently. The default Rust RandomState and the benchmark wrapper generate related values differently, so these rates should not be transferred to them.",
          "scope": "This is a result about the same input type in version 0.2.0. Separate examples involving different Rust input types are documented in the appendix and should not be confused with this scored pair."
        }
      },
      "smhasher": {
        "foldhash-fast": {
          "url": "https://github.com/thomasahle/hash-benchmark-reproduction/blob/038373d7f7a683436ef6dc662814aa0aef7e9e4b/verification/out/Xeon8375C/foldhash-fast.sanity.txt",
          "label": "SMHasher3 basic checks",
          "scope": "sanity"
        },
        "foldhash-quality": {
          "url": "https://github.com/thomasahle/hash-benchmark-reproduction/blob/038373d7f7a683436ef6dc662814aa0aef7e9e4b/verification/out/Xeon8375C/foldhash-quality.sanity.txt",
          "label": "SMHasher3 basic checks",
          "scope": "sanity"
        }
      }
    },
    {
      "ids": [
        "siphash-1-3",
        "siphash-2-4"
      ],
      "authors": "Jean-Philippe Aumasson and Daniel J. Bernstein",
      "background": "SipHash was designed by Jean-Philippe Aumasson and Daniel J. Bernstein for keyed hashing, including protection against hash-table flooding. The 1-3 and 2-4 variants use different numbers of mixing rounds, trading speed for a larger security margin. Both variants are plotted here as claims at the 64-bit output width.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/veorq/SipHash"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "siphash-1-3": "Plotted as an unresolved claim at 64 bits: a PRF design with no proof of the fixed-pair collision bound and no known attack, so the honest statement is the output width with a hollow marker, not a proved lower bound or a witnessed cap. SipHash-1-3 is the default hasher in Rust's standard HashMap. This audit supplies neither a proof nor a counterexample for these SipHash bounds. The cited 2014 analysis reports collision characteristics of 2^-167 for SipHash-1-x and 2^-236.3 for full SipHash-2-4 (Dobraunig, Mendel and Schläffer, SAC 2014), and our own search over 10,517 XOR differences and fixed pairs at up to 2^28 keys per pair saw nothing above the 2^-26.4 resolution floor (records/README.html). Note that SipHash-1-3, the Rust default, is outside the designers' stated claim (c ≥ 2, d ≥ 4); its basis is Aumasson's 2015 remark on the Rust issue. Its bulk speed, about 1 B/cycle for 1-3 and 0.5 for 2-4, is the price of the cryptographic option; the SMHasher3 wrapper expands a 64-bit seed into the 128-bit key.",
        "siphash-2-4": "Plotted as an unresolved claim at 64 bits: a PRF design with no proof of the fixed-pair collision bound and no known attack, so the honest statement is the output width with a hollow marker, not a proved lower bound or a witnessed cap. SipHash-2-4 is the designers' conservative reference parameter set. This audit supplies neither a proof nor a counterexample for these SipHash bounds. The cited 2014 analysis reports collision characteristics of 2^-167 for SipHash-1-x and 2^-236.3 for full SipHash-2-4 (Dobraunig, Mendel and Schläffer, SAC 2014), and our own search over 10,517 XOR differences and fixed pairs at up to 2^28 keys per pair saw nothing above the 2^-26.4 resolution floor (records/README.html). Its bulk speed, about 1 B/cycle for 1-3 and 0.5 for 2-4, is the price of the cryptographic option; the SMHasher3 wrapper expands a 64-bit seed into the 128-bit key."
      },
      "sources": [
        "https://github.com/veorq/SipHash",
        "records/speeds.json"
      ],
      "reader_notes": {
        "siphash-1-3": {
          "evidence": "No collision witness or proved universal-hashing bound is supplied for this variant. Its hollow marker sits at the 64-bit output width to display an unresolved claim; that height is not a measured or proved score.",
          "key": "SipHash takes a 128-bit secret key. The timing harness uses its registered seed expansion; that setup should be distinguished from choosing the full key uniformly.",
          "scope": "The round counts distinguish the two variants. Their cryptographic security arguments and existing cryptanalysis are outside the chart’s fixed-pair comparison."
        },
        "siphash-2-4": {
          "evidence": "No collision witness or proved universal-hashing bound is supplied for this variant. Its hollow marker sits at the 64-bit output width to display an unresolved claim; that height is not a measured or proved score.",
          "key": "SipHash takes a 128-bit secret key. The timing harness uses its registered seed expansion; that setup should be distinguished from choosing the full key uniformly.",
          "scope": "The round counts distinguish the two variants. Their cryptographic security arguments and existing cryptanalysis are outside the chart’s fixed-pair comparison."
        }
      },
      "smhasher": {
        "siphash-1-3": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/SipHash-1-3.txt#L3100",
          "scope": "full"
        },
        "siphash-2-4": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/3b619371/results/raw/SipHash-2-4.txt#L3069",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "halftime24"
      ],
      "authors": "Jim Apple",
      "background": "HalftimeHash’s advanced interface can return 24 bytes, or 192 bits, rather than the 64 bits returned by its public wrappers. This entry studies that original internal function. It was intended for fixed-length inputs.",
      "links": [
        {
          "label": "Original project and code",
          "url": "https://github.com/jbapple/HalftimeHash"
        },
        {
          "label": "Corrected bounds and repair (PDF)",
          "url": "records/papers/halftime_repair.pdf"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        },
        {
          "label": "Verifier package",
          "url": "verify/halftime/README.html"
        }
      ],
      "results": {
        "halftime24": "An equal-length pair collides for at least one key in 2³², contradicting the claimed bound for this advanced function. Separately, an empty input and one zero byte collide for every key because the raw function does not encode length. That second example matters only if the fixed-length function is used across different lengths. Plotted as shipped until upstream fixes the encoder: Xeon 12.81 B/cycle (AVX-512), M2 Pro 1.37 B/cycle on the scalar fallback because the shipped NEON dispatch does not compile on arm64 (issue #1, PR #2; about 5.6 with the fix). Score at most 36.4 bits for the full 24-byte value; the unequal-length identity is a note, since the core is fixed-length by design."
      },
      "sources": [
        "https://github.com/jbapple/HalftimeHash",
        "records/papers/halftime_repair.pdf",
        "records/speeds.json",
        "verify/halftime/README.html"
      ],
      "reader_notes": {
        "halftime24": {
          "evidence": "The equal-length counterexample has a counted sufficient key class and sampled confirmation. The unequal-length collision is an exact identity.",
          "key": "The experiment uses the independent random key words assumed by the advanced function’s claim.",
          "scope": "These results do not refute the corrected bounds for the public 64-bit wrappers. The original advanced function is plotted using its own timings and equal-length counterexample. The repaired 24-byte construction has a separate entry."
        }
      },
      "smhasher": {
        "halftime24": {
          "url": "https://github.com/thomasahle/hash-benchmark-reproduction/blob/038373d7f7a683436ef6dc662814aa0aef7e9e4b/verification/out/Xeon8375C/HalftimeHash24-shipped.sanity.txt",
          "label": "SMHasher3 basic checks",
          "scope": "sanity"
        }
      }
    },
    {
      "ids": [
        "halftime24-fixed"
      ],
      "authors": "Jim Apple; repairs by Thomas Dybdahl Ahle",
      "background": "This is a repaired version of HalftimeHash’s advanced 24-byte function. It changes how message blocks are encoded and records the input length explicitly. The chart includes its own proof and measurements. This experimental repair is available in the linked branch, not in an upstream HalftimeHash release.",
      "links": [
        {
          "label": "Original project and code",
          "url": "https://github.com/jbapple/HalftimeHash"
        },
        {
          "label": "Corrected bounds and repair (PDF)",
          "url": "records/papers/halftime_repair.pdf"
        },
        {
          "label": "Measurements",
          "url": "records/halftime/speeds_halftime_fixed.json"
        },
        {
          "label": "Verifier package",
          "url": "verify/halftime/README.html"
        }
      ],
      "results": {
        "halftime24-fixed": "The repair addresses the two problems in the original advanced function: an equal-length counterexample and ambiguity between different lengths. The corrected mathematical construction has a proved collision bound, shown at about 83.27 bits here. Lean has checked the construction; a complete proof that the C++ implementation matches it is still missing."
      },
      "sources": [
        "https://github.com/jbapple/HalftimeHash",
        "records/papers/halftime_repair.pdf",
        "records/halftime/speeds_halftime_fixed.json",
        "verify/halftime/README.html"
      ],
      "lean": {
        "halftime24-fixed": {
          "label": "✓ construction (M1–M4)",
          "source": "records/machine-checked.html",
          "scope": "Independent uniform entropy words; supported V4 byte lengths <168·8·(19173960+1). Distance-3 encoder and scalar byte length as last tail word. 83.27 is the requested conservative collision-bound label (exactly 83.2678325743); the source theorem gives stronger bounds on the retained stack-safe domain. Construction M1–M4 checked in Lean; complete C++ refinement is not claimed. Concrete fixed-header encoder/layout refinement remains partial; see records/machine-checked.html."
        }
      },
      "reader_notes": {
        "halftime24-fixed": {
          "evidence": "The displayed bound follows from the corrected construction’s proof. Tests also checked the old counterexample, but a clean test run alone would not establish the guarantee.",
          "key": "The theorem requires independent, uniformly random key words. It does not cover replacing those words with the output of an arbitrary seed expander.",
          "scope": "The supported V4 implementation has a finite message-length limit stated in its theorem. The Lean result checks the construction, rather than all details of the C++ code or compiler. This repaired function is separate from the four 64-bit styles."
        }
      },
      "smhasher": {
        "halftime24-fixed": {
          "url": "https://github.com/thomasahle/hash-benchmark-reproduction/blob/038373d7f7a683436ef6dc662814aa0aef7e9e4b/verification/out/Xeon8375C/HalftimeHash24-fixed.sanity.txt",
          "label": "SMHasher3 basic checks",
          "scope": "sanity"
        }
      }
    },
    {
      "ids": [
        "chainhash128"
      ],
      "authors": "Thomas Dybdahl Ahle · author of this post",
      "background": "ChainHash-128 is the 128-bit member of my ChainHash construction: the same three levels with 128-bit words over the GCM field, 512-byte logical blocks and a secret-key polynomial, ending in an integer twist and quintic finalizer.",
      "links": [
        {
          "label": "Project and code",
          "url": "https://github.com/thomasahle/chainhash"
        },
        {
          "label": "Specification",
          "url": "https://github.com/thomasahle/chainhash/blob/main/docs/SPEC-128.md"
        },
        {
          "label": "Theorem and proof",
          "url": "https://github.com/thomasahle/chainhash/blob/main/docs/THEOREM-128.md"
        },
        {
          "label": "Measurements",
          "url": "records/chainhash/speeds_chainhash128.json"
        }
      ],
      "sources": [
        "https://github.com/thomasahle/chainhash",
        "https://github.com/thomasahle/chainhash/blob/main/docs/SPEC-128.md",
        "https://github.com/thomasahle/chainhash/blob/main/docs/THEOREM-128.md",
        "records/chainhash/speeds_chainhash128.json"
      ],
      "results": {
        "chainhash128": "One function reaches 14.43 B/cycle on Xeon and 10.26 on M2 Pro, with a 127-bit guarantee from 128 independently random key bytes. In the same binaries XXH3-128 runs at 19.82 and 12.53. Short inputs cost about 176 cycles/hash on Xeon and 168 on M2. The bound, the equality of every evaluation strategy and the exact 127-bit minimum are machine-checked in Lean (116 theorems, standard axioms; 625 C/Lean vectors)."
      },
      "lean": {
        "chainhash128": {
          "label": "✓ checked",
          "source": "https://github.com/thomasahle/chainhash/tree/main/lean",
          "scope": "Machine-checked (116 theorems, standard axioms): the collision bound for 128 uniformly random key bytes, evaluation independence for every stride and the exact score minimum 127; 625 C/Lean vectors."
        }
      },
      "reader_notes": {
        "chainhash128": {
          "evidence": "With p the larger number of 512-byte blocks in two fixed messages, a collision has probability at most (p+d)/2^128, where d is at most 32 and equals 1 for messages up to 128 bytes. The theorem is checked by Lean for exactly the stated key distribution; the compiled code is checked by 625 test vectors, not by the proof.",
          "key": "Draw 128 independently random bytes. They are read as eight 128-bit field words: one expands into the block keys as its powers, one keys the combining polynomial, and six supply the finalizer and integer twist. The 64-bit seed used for benchmarking does not meet this assumption.",
          "scope": "The guarantee covers fixed-length and at-most-length messages, including empty, partial-word and unequal-length inputs, for any two messages fixed before the key. Horner stride, SIMD width, schoolbook or Karatsuba products, lazy or eager reduction, streaming chunks and region-aligned thread splits leave the digest unchanged. Bulk timings use 256 KiB messages: Xeon is the higher of two passes, M2 the median of three with no run more than 15% from its median. It passes the full SMHasher3 suite on Xeon: 188 of 188 tests. That statistical result is separate from the collision theorem."
        }
      },
      "smhasher": {
        "chainhash128": {
          "url": "https://github.com/thomasahle/chainhash/blob/541526a3525b07d8e0c273a29bff7395c0965ad8/results/128/suite/smh-xeon-chainhash-128-all.log",
          "label": "SMHasher3 results",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "go-maphash"
      ],
      "authors": "Go team / Google",
      "background": "Go uses its runtime hash for string map keys and exposes the byte-sequence hash through hash/maphash. The implementation selects a processor-specific path; this entry studies go1.27.1 on amd64 with AES instructions.",
      "links": [
        {
          "label": "Documentation and claim",
          "url": "https://pkg.go.dev/hash/maphash"
        },
        {
          "label": "Implementation studied",
          "url": "https://github.com/golang/go/blob/go1.27.1/src/internal/runtime/maps/memhash_amd64.s"
        },
        {
          "label": "Verifier package",
          "url": "verify/go-maphash/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "go-maphash": "A fixed 15-byte string and a fixed 16-byte string collide for about one process key in 16.8 million. In those processes, changing the map seed does not separate them. The resulting 25-bit cap directly contradicts the documented intent to resist adversarial byte sequences, although Go gives no numerical bound and disclaims cryptographic security."
      },
      "sources": [
        "https://pkg.go.dev/hash/maphash",
        "https://github.com/golang/go/blob/go1.27.1/src/internal/runtime/maps/memhash_amd64.s",
        "verify/go-maphash/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "go-maphash": {
          "evidence": "Four AES substitution events give an exact sufficient trail probability of 2^-24. The independent implementation found 66 collisions in 2^30 trials; the real runtime found 20 in 2^28.",
          "key": "The experiment redraws the random process AES key and the 64-bit map seed. The trail depends on four bytes of the process key and is independent of the map seed.",
          "scope": "String map keys and maphash byte sequences on amd64 AES only. Integer keys, ARM64 and the non-AES fallback are different paths; the ARM64 observation is qemu-only and is not scored here."
        }
      },
      "smhasher": {
        "go-maphash": {
          "url": "https://github.com/thomasahle/hash-benchmark-reproduction/blob/038373d7f7a683436ef6dc662814aa0aef7e9e4b/verification/out/Xeon8375C/GoMapHash.sanity.txt",
          "label": "SMHasher3 basic checks",
          "scope": "sanity"
        }
      }
    },
    {
      "ids": [
        "abseil-hash"
      ],
      "authors": "Abseil team / Google",
      "background": "Abseil supplies C++ hash functions and SwissTable containers such as flat_hash_map. absl::Hash aims to mix ordinary inputs well and vary results between processes. Its source explicitly says the process seed is not a security feature.",
      "links": [
        {
          "label": "Documentation and claim",
          "url": "https://github.com/abseil/abseil-cpp/blob/master/absl/hash/hash.h"
        },
        {
          "label": "Implementation studied",
          "url": "https://github.com/abseil/abseil-cpp/blob/73d2688300440c8af028eec865ee0dcd85e93025/absl/hash/internal/hash.h"
        },
        {
          "label": "Verifier package",
          "url": "verify/abseil-hash/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "abseil-hash": "The empty string and one fixed eight-byte string collide for every seed, giving a zero-bit cap. A pair of 16-byte strings also collides for every seed, giving a one-bit cap after length adjustment. These findings contradict no security promise from Abseil."
      },
      "sources": [
        "https://github.com/abseil/abseil-cpp/blob/master/absl/hash/hash.h",
        "https://github.com/abseil/abseil-cpp/blob/73d2688300440c8af028eec865ee0dcd85e93025/absl/hash/internal/hash.h",
        "verify/abseil-hash/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "abseil-hash": {
          "evidence": "The short-input formula gives identical inputs to the final multiplication for the headline pair. Real-library checks cover all 32 table seeds and 2^28 additional seeds.",
          "key": "The headline identity holds for every process and table seed, so neither the ASLR-based process seed nor the five-bit table seed can separate this pair.",
          "scope": "The short-input result covers the 64-bit scalar, x86 AES and ARM-crypto default paths in 20260817.0. ARM coverage follows the shared source path; the independent verifier did not rerun it on ARM hardware."
        }
      },
      "smhasher": {
        "abseil-hash": {
          "url": "https://github.com/thomasahle/hash-benchmark-reproduction/blob/038373d7f7a683436ef6dc662814aa0aef7e9e4b/verification/out/Xeon8375C/AbseilHash-default.sanity.txt",
          "label": "SMHasher3 basic checks",
          "scope": "sanity"
        }
      }
    },
    {
      "ids": [
        "dotnet-marvin"
      ],
      "authors": "Microsoft (Ferguson et al.)",
      "background": "Marvin is the small add–rotate–xor hash used by .NET for string hash codes. It starts from a random 64-bit seed and returns 32 bits. This entry studies the .NET 10 string path, which hashes UTF-16 bytes.",
      "links": [
        {
          "label": "Documentation and claim",
          "url": "https://github.com/dotnet/runtime/blob/main/docs/design/security/System.HashCode.md"
        },
        {
          "label": "Implementation studied",
          "url": "https://github.com/dotnet/runtime/blob/v10.0.12/src/libraries/System.Private.CoreLib/src/System/Marvin.cs"
        },
        {
          "label": "Verifier package",
          "url": "verify/dotnet-marvin/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "dotnet-marvin": "Two fixed six-character strings collide for about one seed in 480, giving a sampled cap of 9.91 bits. Microsoft documents randomized seeds and disclaims cryptographic strength; it does not promise a numerical collision bound. Randomized dictionaries use independent seeds and each has the same odds."
      },
      "sources": [
        "https://github.com/dotnet/runtime/blob/main/docs/design/security/System.HashCode.md",
        "https://github.com/dotnet/runtime/blob/v10.0.12/src/libraries/System.Private.CoreLib/src/System/Marvin.cs",
        "verify/dotnet-marvin/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "dotnet-marvin": {
          "evidence": "The independent implementation found 8,945,794 collisions in 2^32 seeds. A real-runtime check found 34,855 in 2^24, consistent with the same rate.",
          "key": "A uniform 64-bit seed is chosen once for the process string hash. A dictionary that switches to the randomized string comparer draws its own seed; these are separate experiments.",
          "scope": "The pair uses valid UTF-16 code units and applies to ordinal string hashing and randomized string comparers. OrdinalIgnoreCase, the initial nonrandomized comparer and System.HashCode are outside this result."
        }
      },
      "smhasher": {
        "dotnet-marvin": {
          "url": "https://github.com/thomasahle/hash-benchmark-reproduction/blob/038373d7f7a683436ef6dc662814aa0aef7e9e4b/verification/out/Xeon8375C/Marvin32.sanity.txt",
          "label": "SMHasher3 basic checks",
          "scope": "sanity"
        }
      }
    },
    {
      "ids": [
        "chainhash"
      ],
      "authors": "Thomas Dybdahl Ahle · author of this post",
      "background": "ChainHash is my construction for hashing long messages with a collision guarantee. It combines 256-byte logical blocks with a secret-key polynomial over GF(2^64) and a quintic finalizer. Its flat product loop follows Orson Peters’s PolymurHash design lineage.",
      "links": [
        {
          "label": "Project and code",
          "url": "https://github.com/thomasahle/chainhash"
        },
        {
          "label": "Specification",
          "url": "https://github.com/thomasahle/chainhash/blob/main/docs/SPEC.md"
        },
        {
          "label": "Theorem and proof",
          "url": "https://github.com/thomasahle/chainhash/blob/main/docs/THEOREM.md"
        },
        {
          "label": "Measurements",
          "url": "records/chainhash/speeds_chainhash.json"
        }
      ],
      "sources": [
        "https://github.com/thomasahle/chainhash",
        "https://github.com/thomasahle/chainhash/blob/main/docs/SPEC.md",
        "https://github.com/thomasahle/chainhash/blob/main/docs/THEOREM.md",
        "records/chainhash/speeds_chainhash.json"
      ],
      "results": {
        "chainhash": "One function reaches 28.31 B/cycle on Xeon and 26.26 on M2 Pro, with a 63.0-bit guarantee from 64 independently random key bytes. Short inputs cost more: about 155 cycles/hash on Xeon and 87 on M2, against about 29 and 25 for XXH3-64 in the same binaries. The bound, the equality of every evaluation strategy and the exact 63.0-bit minimum are machine-checked in Lean (89 theorems, standard axioms; 464 C/Lean vectors). It passes the complete SMHasher3 suite (200/200, x86 and arm64) and the complete rurban SMHasher suite (All+BIC) with no failures; the untwisted degree-5 finalizer fails 22 of the same 200 tests."
      },
      "lean": {
        "chainhash": {
          "label": "✓ checked",
          "source": "https://github.com/thomasahle/chainhash/tree/main/lean",
          "scope": "Machine-checked (89 theorems, standard axioms): the collision bound for 64 uniformly random key bytes, evaluation independence for every stride and the exact score minimum 63.0; 464 C/Lean vectors."
        }
      },
      "reader_notes": {
        "chainhash": {
          "evidence": "The collision bound is a theorem checked by Lean, a proof-checking program, for exactly the stated key distribution. Squaring is a bijection of the field, so a changed block has fewer keys that cancel it than its formal degree suggests; that is where the 63.0 bits come from. Compiled code is checked only by test vectors, not by the proof.",
          "key": "Draw 64 independently random bytes. They are read as eight field words: one expands into the block keys as its powers, one keys the polynomial that combines the blocks, and six supply the finalizer and integer twist. The small seed used for benchmarking does not meet this assumption.",
          "scope": "The guarantee covers fixed-length and at-most-length messages, including empty, partial-word and unequal-length inputs, for any two messages fixed before the key. Horner stride, SIMD width, lazy or eager reduction, streaming chunks and valid thread splits leave the digest unchanged. Bulk timings use 256 KiB messages; M2 is the median of three."
        }
      },
      "smhasher": {
        "chainhash": {
          "url": "https://github.com/thomasahle/chainhash/blob/541526a3525b07d8e0c273a29bff7395c0965ad8/results/64/suite/REPORT.md",
          "label": "SMHasher3 results",
          "scope": "full"
        }
      }
    },
    {
      "ids": [
        "muse-v2"
      ],
      "authors": "K--Aethiax",
      "background": "MuseAir is a multiply-based non-cryptographic hash. Algorithm v2, released as crate 0.6.0, mixes the seed into tail products and supersedes the deprecated earlier algorithms. Its README warns against direct server use with its single-seed interface.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/eternal-io/museair"
        },
        {
          "label": "Verifier package",
          "url": "verify/museair-v2/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "muse-v2": "A fixed 32-byte change in the tail product can be cancelled by changes in the head when the multiplication carries agree. Upstream crate checks give a sampled cap of 19.45 bits. The v0.3 every-seed witness is a separate result."
      },
      "sources": [
        "https://github.com/eternal-io/museair",
        "verify/museair-v2/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "muse-v2": {
          "evidence": "Two fresh upstream-crate runs found 36,060 collisions in 1.5 × 2^32 seeds, about 2^-17.447. The 95% score interval is 19.43–19.46 bits.",
          "key": "The scored function draws one uniform 64-bit seed. Both messages are fixed independently of that seed.",
          "scope": "This is algorithm v2, crate 0.6.0, timed through a separately validated MuseAir-v2 registration with direct seed mapping. The 64-bit bfast function collides on the same seeds; the 128-bit functions use a separate two-seed model."
        }
      },
      "smhasher": {
        "muse-v2": {
          "url": "https://github.com/thomasahle/hash-benchmark-reproduction/blob/038373d7f7a683436ef6dc662814aa0aef7e9e4b/verification/out/Xeon8375C/MuseAir-v2.sanity.txt",
          "label": "SMHasher3 basic checks",
          "scope": "sanity"
        }
      }
    },
    {
      "ids": [
        "wyhash"
      ],
      "authors": "Wang Yi",
      "background": "Wyhash is a compact, portable 64-bit hash by Wang Yi, designed for fast hashing rather than cryptographic security. It mixes message words by multiplying them and combining the two halves of each product. Its design also influenced rapidhash.",
      "links": [
        {
          "label": "Original project & code",
          "url": "https://github.com/wangyi-fudan/wyhash"
        },
        {
          "label": "Verifier package",
          "url": "verify/wyhash/README.html"
        },
        {
          "label": "Measurements",
          "url": "records/speeds.json"
        }
      ],
      "results": {
        "wyhash": "Flipping every bit in two chosen message words can leave a mixed product unchanged, making the two messages collide. This happens even when the secret words are chosen at random: the attacker does not need their values. The experiment limits the collision score to about 28.5 bits. That is an upper limit exposed by one pair, not a guarantee that no worse pair exists."
      },
      "sources": [
        "https://github.com/wangyi-fudan/wyhash",
        "https://github.com/wangyi-fudan/wyhash/commit/2ac9a50",
        "verify/wyhash/README.html",
        "records/speeds.json"
      ],
      "reader_notes": {
        "wyhash": {
          "evidence": "A search harness and an independent verifier found 1,088 collisions in about 103 billion random keys for the same two 32-byte messages. The 95% sampling interval on this pair’s score cap is 28.4–28.6 bits.",
          "key": "Each trial chooses the 64-bit seed and all four 64-bit secret words independently at random. The two messages are fixed before that choice. Using the public default secret gives a similar rate for this pair, but also allows other pairs that collide for every seed; those are discussed separately in the appendix.",
          "scope": "The collision experiment uses final v4.3 with ordinary 64-bit multiplication. SMHasher3 calls the same hash function non-strict v4.2: the version change renamed the header guard, and the implementations pass the same reference check. The plotted timings use the benchmark’s fixed secret and do not include generating a new key."
        }
      },
      "smhasher": {
        "wyhash": {
          "label": "SMHasher3 results",
          "url": "https://github.com/fwojcik/smhasher3/blob/5035a923/results/raw/wyhash.txt#L3169",
          "scope": "full"
        }
      }
    }
  ]
}
