Skip to content

mbo/hash: mumbo/jumbo - in-house MUM hash family takes the defaults; hash_extra_cc split; full same-rig data - #235

Merged
helly25 merged 11 commits into
mainfrom
hash/mh2
Jul 5, 2026
Merged

mbo/hash: mumbo/jumbo - in-house MUM hash family takes the defaults; hash_extra_cc split; full same-rig data#235
helly25 merged 11 commits into
mainfrom
hash/mh2

Conversation

@helly25

@helly25 helly25 commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

The in-house mumbo/jumbo hash family (MUM + mbo; "mumbo jumbo"): built on the widening 64x64->128 multiply, developed in four measured iterations (each: benchmark + full SMHasher3 batteries, documented in mbo/hash/README.md), and now the library default in all forms.

Headlines

  • SMHasher3: PASS 188/188 in BOTH widths (same-rig): mumbo (64) joins rapidhash as the only clean 64-bit passes; jumbo (128) is the only clean 128-bit result we have measured (xxh3-128: 162, murmur3: 123).
  • Performance: trades blows with rapidhash across the 64-bit board (leads bulk at 46.1 GiB/s and ties small-key latency); jumbo is the fastest 128-bit hash from 16 bytes up (1.7-2.4x xxh3-128).
  • Streaming: v4 moved the length from the seed into the finalizer's product operands (equally protective, known only at finalize) - enabling exact chunked==one-shot streaming (eager 128-byte blocks + rolling last-16 window).
  • Defaults: DefaultHashAlgorithm = mumbo::Algorithm, Default128HashAlgorithm = jumbo::Algorithm. Both structs are complete (each delegates the other width), so either plugs in anywhere.
  • //mbo/hash:hash_extra_cc (hash_extra.h): the NOTICE-bearing transcriptions (rapidhash MIT, xxh64/xxh3 BSD-2) now require explicit linkage - the default hash_cc is notice-free. NOTICE/README third-party tables updated accordingly.
  • mh dropped entirely (never released): file deleted, all references scrubbed; the CHANGELOG presents mumbo directly.

Design (hash_mumbo.h)

Unrolled per-length small-key terminal actions with the key in BOTH product operands (quadratic products kill pairwise correlations); 17-127B sequential MUM chain with overlapping end loads (no tail loops anywhere); >= 128B eight chains over a 128-byte fetch window with distinct secrets; finalizer keeps both widening-product halves with the length in the product operands; 128-bit form runs two lanes with distinct secret banks and swapped operand roles over a shared 4-chain bulk tier. Secrets: sqrt fractions of the first 16 primes (= SHA-512/SHA-384 IVs).

The data story (mbo/hash/README.md)

  • New Algorithm overview table: widths, availability (hash.h default vs hash_extra_cc opt-in), NOTICE obligation, seeding, streaming, SMHasher3 verdict.
  • Performance tables extended to ALL algorithms - including fnv1a, the family behind many std::hash implementations (fastest possible 1-byte hash; 10-70x slower than mumbo beyond).
  • Same-rig SMHasher3 for everything: mumbo 188 / jumbo 188 / rapidhash 188 / siphash 186-of-186 clean; xxh64 181, xxh3 166/162, murmur3 123, fnv1a 7 of 186.
  • The measured iteration history (v1 175 -> v2 177 -> v3 188/188 -> v4 re-verified 188/188 with streaming enabled) with root-cause analysis per step.

Also

  • CI: all build/test/benchmark jobs now gate on BOTH trunk and pre-commit.
  • TODO records the resolved hash_extra decision and the one open idea (128-bit streaming needs a HasStreaming concept extension).

CI benchmark results (run 28753339340; informational - shared runners are noisy)

Values are ubuntu-latest (x86_64, gcc, 4 vCPU) / macos-26 (arm64, Apple clang) mean of 3 repetitions, ns/op.

Mixed-length latency (serialized chain):

max len mumbo rapidhash xxh3 xxh64 murmur3 siphash fnv1a simple
16 7.5 / 9.8 8.1 / 10.9 7.7 / 12.0 12.6 / 14.1 12.4 / 16.1 15.4 / 22.2 12.5 / 13.2 20.4 / 9.8
64 9.3 / 11.2 10.1 / 11.4 3.6* / 12.6 25.4 / 21.4 15.7 / 20.1 22.2 / 34.5 0.9* / 38.1 69.9 / 26.7
1024 41.4 / 29.2 18.9 / 27.4 111.5 / 44.2 120.1 / 74.6 105.1 / 78.4 216 / 282 581 / 570 837 / 374

* gcc constant-folding artifacts on the fixed-size lanes; treat with suspicion.

64-bit one-shot:

size mumbo rapidhash xxh3 xxh64
16B 3.1 / 3.0 3.4 / 2.3 1.7 / 2.6 5.4 / 3.5
256B 23.2 / 12.5 13.6 / 9.5 121.8 / 40.4 33.6 / 19.5
4KiB 275 / 103.0 183 / 102.6 749 / 210 445 / 308

128-bit one-shot:

size mumbo (jumbo) xxh3 murmur3
16B 9.3 / 4.4 3.2 / 3.7 9.0 / 8.9
256B 19.6 / 13.3 128.5 / 43.8 47.9 / 53.6
4KiB 184 / 127 683 / 214 721 / 863

Cross-platform reading: the mumbo/rapidhash near-tie holds on both architectures (rapidhash leads x86_64-gcc bulk, they tie on arm64); jumbo is the fastest 128-bit hash from 256 bytes up on BOTH platforms; the xxh3 mid-size dip and the fnv1a/siphash/simple profiles reproduce everywhere.

helly25 added 9 commits July 5, 2026 19:17
…th widths

EXPERIMENTAL successor of mh built on Mul128Fold64 (MUM): unrolled
per-length small-key terminal actions (data in both product operands -
quadratic products kill pairwise correlations), length folded into the
seed, 128-byte 8-chain bulk fetch window with distinct chain secrets,
native dual-lane 128-bit form, two-multiply finalizer keeping both
widening-product halves. Secrets are sqrt fractions of the first 16
primes. Three measured iterations (v1 175 -> v2 177 -> v3 188/188 both
widths, the only clean native 128 measured on our rig); fastest
mixed-length latency <= 16B and fastest bulk throughput in the library.

Also merges SMHASHER3.md into mbo/hash/README.md (Principles ->
Performance -> Quality) with same-run benchmark tables; end-game
decisions (mh retirement, defaults, name, streaming) in TODO.md.
- Rename mh2 -> mumbo (MUM + mbo), drop the EXPERIMENTAL label; v4: the
  length moves from the seed into the finalizer's product operands
  (streaming-enabling; equally protective) and the 128-bit lane seeds
  derive from distinct secret pairs so no lane equals the 64-bit hash.
- Streaming for mumbo: eager 128-byte block consumption + rolling
  last-16 window; chunked == one-shot (typed test).
- mumbo becomes DefaultHashAlgorithm AND Default128HashAlgorithm.
- New //mbo/hash:hash_extra_cc (mbo/hash/hash_extra.h): the
  NOTICE-bearing transcriptions (rapidhash MIT, xxh64/xxh3 BSD-2) now
  require explicit linkage; the default hash_cc is notice-free.
- Drop mh entirely (never released): hash_mh.h deleted, all references
  scrubbed from code, tests, README, and CHANGELOG (which now presents
  mumbo directly).
- README: tables updated (mumbo v4 numbers), mumbo design-iteration
  section replaces the mh failure analysis. v4 SMHasher3 re-verification
  is running; the doc marks it in flight.
…ble break

Every build/test/benchmark job now gates on both lint jobs (benchmark
previously gated on nothing, tests only on pre-commit), so a trunk
failure stops the matrix early. Also fixes the markdownlint MD056 that
trunk caught: the quality table's trailing paragraph had lost its blank
line and was absorbed as a table row.
'mumbo jumbo': jumbo::Algorithm (inherits the complete mumbo surface)
fronts the native 128-bit form and becomes Default128HashAlgorithm;
both structs are complete so either plugs in anywhere. Docs batch:
root README hash section (mumbo/jumbo defaults, extras via
hash_extra.h, hash_extra_cc target bullet), third-party tables point
compliance at hash_extra_cc (hash_cc is notice-free), NOTICE preamble
updated accordingly, TODO records the resolved hash_extra decision and
the remaining jumbo-streaming idea, hash README tables renamed
(jumbo 128 rows) with v4 64-bit re-verification recorded (PASS 188).
… extend perf tables to all algorithms

fnv1a (the std::hash family baseline, e.g. MSVC), murmur3, siphash, and
the legacy simple join the latency/throughput tables; overview table
maps each algorithm to its target (hash.h default vs hash_extra_cc
opt-in), NOTICE obligation, seeding, and streaming. Same-rig SMHasher3
batteries for fnv1a/murmur3/siphash are running; their quality rows
land when complete.
…88), siphash (PASS)

The std::hash baseline quantified: fnv1a passes 7 of 186 tests; murmur3
fails the modern Seed* cluster broadly; siphash is clean as a PRF must
be. Overview cells and quality table complete for all algorithms;
methodology lists the built-in registrations used.
@helly25 helly25 changed the title mbo/hash: mh2 - widening-multiply redesign, SMHasher3 188/188 in both widths mbo/hash: mumbo/jumbo - in-house MUM hash family takes the defaults; hash_extra_cc split; full same-rig data Jul 5, 2026
@helly25
helly25 requested a review from Fab-Cat July 5, 2026 20:25
@helly25
helly25 merged commit 813fbcd into main Jul 5, 2026
8 checks passed
@helly25
helly25 deleted the hash/mh2 branch July 5, 2026 21:00
helly25 added a commit that referenced this pull request Jul 5, 2026
* docs(hash): CI cross-platform performance tables (x86_64 gcc vs arm64 clang)

Latency and throughput from PR #235's CI benchmark artifacts
(ubuntu-latest / macos-26, mean of 3 repetitions), with the noise and
constant-folding caveats stated. The mumbo/rapidhash near-tie and
jumbo's 128-bit lead reproduce on both architectures.

* docs(hash): drop trailing colons from perf headings (markdownlint MD026)
helly25 added a commit that referenced this pull request Jul 6, 2026
- Root README: CombineHashes / Hash64To32 / Streamer and the per-algorithm
  functions were accidentally nested under the hash_mangle_cc heading; they
  are hash.h API and moved back. The mangle flag documentation now uses the
  one-per-bullet 'Custom Bazel flag' convention of the config section.
- CHANGELOG: the mangle bullet presents the released design directly instead
  of describing the replacement of the MBO_HASH_MANGLE define and the
  __DATE__/__TIME__ bucketing - both existed only within the unreleased
  0.13.0 cycle (same treatment as the never-released mh in #235).
- mbo/hash/README: the Offerings pointer distinguishes the mangle section
  (semantics, design) from the Configuration section (flags).
helly25 added a commit that referenced this pull request Jul 7, 2026
…e-version rotation (#238)

* feat(hash): flag-driven build-seed mangle - hash_mangle.h / :hash_mangle_cc split

- GetHash / MangledHasher move out of hash.h into the new public entry
  mbo/hash/hash_mangle.h (//mbo/hash:hash_mangle_cc): hash.h / :hash_cc
  users are never exposed to (or rebuilt for) seed variation.
- The mangle constant is generated into a header by folding the module's
  own version (native.module_version() - every release rotates it by
  construction, for free) with two custom flags: --//mbo/hash:mangle_seed
  (any printable-ASCII string) and --//mbo/hash:mangle_seed_buckets
  (default 8; 0 disables making GetHash == GetHash64, 1 pins one stable
  constant across releases and seeds).
- Neither the version nor raw seed strings reach C++ action keys: both
  fold to a bucket inside the generation rule, so caches see at most
  N + 1 header variants. Replaces the per-TU __DATE__/__TIME__ bucketing
  and the MBO_HASH_MANGLE define (and their ODR risk).
- internal/hash_mangle_seed.h.in is the non-Bazel fallback; a diff_test
  pins it byte-identical to the default-flag generation (regen command in
  its header). CI additionally runs hash_mangle_test with buckets=0.
- hash_mangle_test (replaces hash_no_mangle_test): seed-independent XOR
  properties, exact values via a transparent DummyAlgorithm, constexpr
  static_asserts, enabled<=>differs sweeps, and a typed sweep over
  algo::AllAlgorithms (extras included - tests do not ship, so the
  NOTICE-driven target split does not constrain test deps).
- READMEs: Offerings and Configuration sections, design rationale
  (constexpr rules out ASLR; buckets bound the churn), mumbo lineage
  (simple -> mh -> mh2 -> mumbo).

* style(hash): migrate hash_test.cc to STYLE_CPP.md test conventions

- EXPECT_THAT/ASSERT_THAT with Eq/Ne/Lt/Gt/Le matchers replace all 77
  comparison macros; container size checks use SizeIs.
- All 25 bare TESTs become TEST_F with per-suite empty fixtures.
- NOLINTNEXTLINE(readability-function-cognitive-complexity) lines carry
  reasons; the StreamingMatchesOneShot rng NOLINT now sits on the line
  clang-tidy reports on.
- mbo/types/tstring.h: fix the stale StringHash comment (GetHash64).

* docs(hash): release-consistency pass

- Root README: CombineHashes / Hash64To32 / Streamer and the per-algorithm
  functions were accidentally nested under the hash_mangle_cc heading; they
  are hash.h API and moved back. The mangle flag documentation now uses the
  one-per-bullet 'Custom Bazel flag' convention of the config section.
- CHANGELOG: the mangle bullet presents the released design directly instead
  of describing the replacement of the MBO_HASH_MANGLE define and the
  __DATE__/__TIME__ bucketing - both existed only within the unreleased
  0.13.0 cycle (same treatment as the never-released mh in #235).
- mbo/hash/README: the Offerings pointer distinguishes the mangle section
  (semantics, design) from the Configuration section (flags).

* style(hash): fix NOLINT placement in hash_mumbo.h

- BulkBlock: the *-constant-array-index suppression sat on the for-line;
  as NOLINTNEXTLINE it now covers the chain[i] / kSecret[4 + i] line
  clang-tidy actually reports on.
- StreamUpdate: bracket the pointer/array-walking body with
  NOLINTBEGIN/END(cppcoreguidelines-pro-bounds-constant-array-index).

* docs(hash): Abseil interop section

Compose, do not compete: containers take DefaultHasher outright for byte
keys; structured types inject mbo values (Streamer -> Finalize) into
AbslHashValue combining (Hash128/tstring precedent); absl::HashOf folded
into mbo values imports per-process randomization (in-process only); a
full absl::Hash replacement via a custom combine/combine_contiguous state
is possible by protocol design but a deliberate separate project.
helly25 added a commit that referenced this pull request Jul 7, 2026
…all (#239)

* feat(hash): flag-driven build-seed mangle - hash_mangle.h / :hash_mangle_cc split

- GetHash / MangledHasher move out of hash.h into the new public entry
  mbo/hash/hash_mangle.h (//mbo/hash:hash_mangle_cc): hash.h / :hash_cc
  users are never exposed to (or rebuilt for) seed variation.
- The mangle constant is generated into a header by folding the module's
  own version (native.module_version() - every release rotates it by
  construction, for free) with two custom flags: --//mbo/hash:mangle_seed
  (any printable-ASCII string) and --//mbo/hash:mangle_seed_buckets
  (default 8; 0 disables making GetHash == GetHash64, 1 pins one stable
  constant across releases and seeds).
- Neither the version nor raw seed strings reach C++ action keys: both
  fold to a bucket inside the generation rule, so caches see at most
  N + 1 header variants. Replaces the per-TU __DATE__/__TIME__ bucketing
  and the MBO_HASH_MANGLE define (and their ODR risk).
- internal/hash_mangle_seed.h.in is the non-Bazel fallback; a diff_test
  pins it byte-identical to the default-flag generation (regen command in
  its header). CI additionally runs hash_mangle_test with buckets=0.
- hash_mangle_test (replaces hash_no_mangle_test): seed-independent XOR
  properties, exact values via a transparent DummyAlgorithm, constexpr
  static_asserts, enabled<=>differs sweeps, and a typed sweep over
  algo::AllAlgorithms (extras included - tests do not ship, so the
  NOTICE-driven target split does not constrain test deps).
- READMEs: Offerings and Configuration sections, design rationale
  (constexpr rules out ASLR; buckets bound the churn), mumbo lineage
  (simple -> mh -> mh2 -> mumbo).

* style(hash): migrate hash_test.cc to STYLE_CPP.md test conventions

- EXPECT_THAT/ASSERT_THAT with Eq/Ne/Lt/Gt/Le matchers replace all 77
  comparison macros; container size checks use SizeIs.
- All 25 bare TESTs become TEST_F with per-suite empty fixtures.
- NOLINTNEXTLINE(readability-function-cognitive-complexity) lines carry
  reasons; the StreamingMatchesOneShot rng NOLINT now sits on the line
  clang-tidy reports on.
- mbo/types/tstring.h: fix the stale StringHash comment (GetHash64).

* docs(hash): release-consistency pass

- Root README: CombineHashes / Hash64To32 / Streamer and the per-algorithm
  functions were accidentally nested under the hash_mangle_cc heading; they
  are hash.h API and moved back. The mangle flag documentation now uses the
  one-per-bullet 'Custom Bazel flag' convention of the config section.
- CHANGELOG: the mangle bullet presents the released design directly instead
  of describing the replacement of the MBO_HASH_MANGLE define and the
  __DATE__/__TIME__ bucketing - both existed only within the unreleased
  0.13.0 cycle (same treatment as the never-released mh in #235).
- mbo/hash/README: the Offerings pointer distinguishes the mangle section
  (semantics, design) from the Configuration section (flags).

* style(hash): fix NOLINT placement in hash_mumbo.h

- BulkBlock: the *-constant-array-index suppression sat on the for-line;
  as NOLINTNEXTLINE it now covers the chain[i] / kSecret[4 + i] line
  clang-tidy actually reports on.
- StreamUpdate: bracket the pointer/array-walking body with
  NOLINTBEGIN/END(cppcoreguidelines-pro-bounds-constant-array-index).

* docs(hash): Abseil interop section

Compose, do not compete: containers take DefaultHasher outright for byte
keys; structured types inject mbo values (Streamer -> Finalize) into
AbslHashValue combining (Hash128/tstring precedent); absl::HashOf folded
into mbo values imports per-process randomization (in-process only); a
full absl::Hash replacement via a custom combine/combine_contiguous state
is possible by protocol design but a deliberate separate project.

* bench(hash): boundary-resolved small-key sizes + regenerated throughput tables

The throughput benchmark stepped by x4 (1,4,16,64,...), jumping straight over
the small-string-optimization band. Add tier/SSO boundary lengths - 7/8
(end of the fully-unrolled <=8 path), 15/16 (<=16 path; 15 = libstdc++ SSO
cap), 22 (libc++ SSO cap), 32 (proposed cap), 63/64 (short-chain edge) - so
the small-key cliffs are visible. Regenerate the README 64- and 128-bit
throughput tables and the latency table from one consistent run over all
algorithms at these sizes, and rewrite the reading: the boundary data shows
mumbo trails rapidhash by ~0.3-0.7 ns on inline-string keys (2.45 ns at the
15B cap, 2.49 ns at 22B), the deliberate cost of the clean-both-widths
finalizer; the deficit does not carry into the dependency-bound latency case.

* perf(hash): mumbo small-key LoadSmall - if-ladder instead of jump-table switch

Diagnosis: mumbo's small-key deficit vs rapidhash (~0.3-0.7 ns) is dominated
by load/dispatch, not the finalizer - a one-multiply probe still trailed
rapidhash by 0.34 ns, and the two-multiply finalizer is what earns the clean
188/188 in both widths. The 10-case LoadSmall switch compiled to a jump table
(table load + indirect branch); replacing it with an if-ladder that gates the
common len>=4 range first lets 9..16 (the bulk of hashed keys and the SSO
range) resolve on the first compare.

Values are byte-identical to the switch at every length 0..16 (verified by
construction: each branch reproduces the exact loads/expressions; >16 does not
use LoadSmall), so no re-verification is needed and streaming/one-shot parity
is unchanged. Min-of-30 throughput, rapidhash-normalized: ~0.1-0.25 ns faster
at 1/7/15 B, flat at 8/16, no regression.

* bench(hash): measurement infrastructure - dev module, report tool, fast/full modes

Dev-only measurement tooling for //mbo/hash:hash_benchmark, isolated as its own
Bazel module (mbo/hash/measurements/, listed in .bazelignore) so none of it -
including future plotting deps - enters the helly25_mbo module or any offering.

- hash_benchmark.cc: two size modes. FAST (default, CI, README tables) is a
  dense boundary/SSO-straddling set; FULL (MBO_HASH_BENCHMARK_FULL=1) is a ~3x
  denser slow-exponential sweep for the ns-vs-length curve.
- hash_benchmark_report.py (stdlib only): run / store / tables / plot. Reads
  google/benchmark's native JSON (no transcode). Headline aggregate is the
  MEAN OF THE 3 FASTEST OF 9 reps - the low tail approximates the uncontended
  cost, and averaging the best few rejects the single-sample fluke a pure min
  keeps; best_cv reports the spread of those 3 (not the contention-laden 9).
  Stores full provenance: date, git SHA + dirty + branch (warns when not a
  clean main tree, since a squash-merge discards a dev SHA), host/CPU/OS,
  load, cpu_scaling. Precautions: -c opt, random interleaving, warmup, 9 reps
  (google/benchmark compare.py U-test minimum). Transposed markdown tables
  (length per row) and a dependency-free SVG curve.
- README perf tables regenerated (best-3-of-9, transposed); design doc in
  mbo/hash/measurements/README.md covers methodology, provenance, storage
  (canonical JSON committed as text; raw gzipped, authoritative-only), and the
  measure-after-merge workflow.
- CI benchmark job: main-only, gated on mbo/hash changes (dorny/paths-filter),
  already continue-on-error, now with the same precautions.

Numbers are provisional (dev branch); the authoritative dataset + committed
canonical JSON land post-merge on a clean main checkout.

* bench(hash): timestamped outputs, pre-aligned tables, SMHasher3 mode

- Every written file is prefixed YYYYMMDD_HHMMSS_ (one stamp per invocation),
  so runs never overwrite and the filename records when it was produced.
- The tables command now emits vertically aligned markdown directly (shared
  padding helper; first column right-aligned, rest left) - no reformat needed.
- New 'smhasher' subcommand: runs the SMHasher3 battery over --algos (default
  'all', explicitly including the legacy simple), parses pass/fail + failing
  families, stores JSON with provenance plus each run's full log. It drives a
  built SMHasher3 (--smhasher3); the in-house mumbo/jumbo/simple need a patched
  SMHasher3 that registers them - building that harness is the remaining piece
  (design doc updated).

* bench(hash): smhasher mode parses score + failing families

The stored entry now carries the SMHasher3 score (passed/total, e.g. 181/188)
and the list of failing test/family names (e.g. Avalanche, Sparse [20/3],
SeedBIC [8]), printed per algorithm and stored in the results JSON; the full
per-run log (the complete why) is saved alongside. Tolerant parser: verdict +
optional (X / Y) score, failing lines minus the overall-verdict line.

* refactor(hash)!: rename legacy 'simple' hash to 'dumbo', drop deprecated API

The legacy in-house hash was misnamed 'simple' - it is not simpler than mumbo,
it is the -umbo family's weak member (64-bit, unseeded, does not pass
SMHasher3), kept only for comparison. Rename mbo::hash::simple -> mbo::hash::dumbo
(mumbo/jumbo/dumbo) so the name signals in-house + legacy.

BREAKING (pre-1.0, so no alias kept): the mbo::hash::simple namespace and the
already-deprecated simple::GetHash wrapper are removed; migrate to
mbo::hash::GetHash64 (mumbo) for real hashing, or mbo::hash::dumbo::GetHash64
for the legacy hash.

- hash_simple.h -> hash_dumbo.h (namespace + GetDumboHash), deprecated GetHash
  dropped; added a TODO to actually improve dumbo (it is competitive for tiny
  1-8B keys, where a better finalizer could pay off - SMHasher3-gated).
- Updated hash.h/BUILD, the test descriptor (DumboHash) + tests, the
  measurement tool (dumbo-64), both READMEs, and the CHANGELOG.

Build + all hash tests green; no live mbo::hash::simple references remain.

* bench(hash): reproducible SMHasher3 build harness (build_smhasher3.sh)

Encodes the README 'Methodology (reproduction)' as a script: clone SMHasher3 at
the pinned commit (6ab4343), apply the two documented fixes (missing <cstdlib>
in lib/AEStest.cpp; replace -march=native with a portable arch), and build with
gcc in a container. Third-party algorithms verify immediately via
'report.py smhasher --smhasher3 <path>'; the in-house mumbo/jumbo/dumbo
registration source (SMHasher3 hashes/ plugin) is the remaining piece, to be
run on merged main for an authoritative result. Design doc updated.

* docs(hash): measurements - fix stray 'simple' and 'minimum' aggregate wording

Two leftover references to the pre-rename name / pre-best-k aggregate:
smhasher section said 'legacy simple' (now dumbo), and the script docstring
still described the aggregate as the minimum (now the mean of the k fastest).

* feat(hash): give legacy dumbo (weak) seed support

dumbo ignored its seed, so it failed SMHasher3's seed sanity by construction
and could not be seed-tested. Fold the seed into the initial state (one XOR,
carried through the existing multiply chain) - negligible cost, and it now
reacts to the seed. dumbo::GetHash64 gains an optional seed; the descriptor is
kSeeded. Still a weak legacy hash, not a strong mixer. (First step on the
improve-dumbo TODO; unblocks its SMHasher3 seed tests.)

Verified: //mbo/hash:hash_test + hash_mangle_test green (const==runtime,
seed-avalanche reacts); READMEs + CHANGELOG updated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants