Proposal: non-cryptographic hashing (Hash.*) — map keys, content IDs, deterministic seeds, checksums #17

Closed
opened 2026-08-29 20:21:59 +02:00 by orkun · 1 comment
Owner

Summary

A non-cryptographic hashing library for everyday game needs: hashing keys
for maps, content IDs, checksums, deterministic seeds, and change detection.
(Cryptographic/secure hashing is tracked separately — see the Crypto issue.)

Why it matters for game devs

  • String / content IDs: turn "grass_tile" into a fast integer handle.
  • Deterministic seeds: hash (world_seed, chunk_x, chunk_y) into a per-chunk
    seed for procedural generation (pairs with the Noise proposal #3).
  • Change detection / caching: has this asset or config changed?
  • Save integrity: a quick checksum to catch corruption (not tamper-proofing).

Proposed API (illustrative)

# doc-check: skip — illustrative API sketch
let h  = Hash.of("grass_tile")            # 64-bit, fast, stable
let id = Hash.combine(world_seed, cx, cy) # mix several values -> one seed
let ck = Hash.crc32(bytes)                # checksum for corruption detection
let fnv = Hash.fnv1a("key")               # named algorithms available
  • A fast default (e.g. xxHash/FNV-1a) via Hash.of + Hash.combine.
  • crc32 for checksums; expose a couple of named algorithms explicitly.
  • 32- and 64-bit variants.

Considerations

  • Determinism is the whole point: same input → same hash on every platform
    and run (fixed seed, defined byte order). This is what makes it usable for
    procedural generation and networking. Document it loudly.
  • Native/C-free; no allocations for hashing primitives/short strings.
  • Not for passwords or security — steer users to the Crypto library; say so
    in the docs to prevent misuse.

Scope / acceptance

  • Hash.of, Hash.combine, Hash.crc32, one named fast algo, 32/64-bit.
  • Documented cross-platform determinism guarantees.
  • Docs page with the "don't use this for security" note + a chunk-seed example.
  • Tests (known-answer vectors, determinism across types).

Related: #3 (Noise), Crypto, Filesystem (checksums), networking.

## Summary A **non-cryptographic hashing** library for everyday game needs: hashing keys for maps, content IDs, checksums, deterministic seeds, and change detection. (Cryptographic/secure hashing is tracked separately — see the Crypto issue.) ## Why it matters for game devs - **String / content IDs**: turn `"grass_tile"` into a fast integer handle. - **Deterministic seeds**: hash `(world_seed, chunk_x, chunk_y)` into a per-chunk seed for procedural generation (pairs with the Noise proposal #3). - **Change detection / caching**: has this asset or config changed? - **Save integrity**: a quick checksum to catch corruption (not tamper-proofing). ## Proposed API (illustrative) ```ludic # doc-check: skip — illustrative API sketch let h = Hash.of("grass_tile") # 64-bit, fast, stable let id = Hash.combine(world_seed, cx, cy) # mix several values -> one seed let ck = Hash.crc32(bytes) # checksum for corruption detection let fnv = Hash.fnv1a("key") # named algorithms available ``` - A fast default (e.g. xxHash/FNV-1a) via `Hash.of` + `Hash.combine`. - `crc32` for checksums; expose a couple of named algorithms explicitly. - 32- and 64-bit variants. ## Considerations - **Determinism is the whole point**: same input → same hash on every platform and run (fixed seed, defined byte order). This is what makes it usable for procedural generation and networking. Document it loudly. - Native/C-free; no allocations for hashing primitives/short strings. - **Not for passwords or security** — steer users to the Crypto library; say so in the docs to prevent misuse. ## Scope / acceptance - [ ] `Hash.of`, `Hash.combine`, `Hash.crc32`, one named fast algo, 32/64-bit. - [ ] Documented cross-platform determinism guarantees. - [ ] Docs page with the "don't use this for security" note + a chunk-seed example. - [ ] Tests (known-answer vectors, determinism across types). Related: #3 (Noise), Crypto, Filesystem (checksums), networking.
orkun added the
proposal
priority:medium
area:stdlib
labels 2026-08-29 20:21:59 +02:00
orkun closed this issue 2026-08-30 00:08:26 +02:00
Author
Owner

Done — shipped in 2002e97 (pushed to main).

The Hash.* namespace now provides both 32- and 64-bit algorithms, all deterministic and C-free:

  • 32-bit (return int): Hash.of, Hash.fnv1a, Hash.crc32, Hash.mix, Hash.combine(...)
  • 64-bit (return long): Hash.of64, Hash.fnv1a_64, Hash.mix64

Delivering the 64-bit variants required a real language extension — a new long (64-bit signed integer) primitive type — landed in the same commit (llty -> i64, int/long coercion, i64 arithmetic/comparison, print/str, editor vocab sync).

Acceptance: Hash.of/combine/crc32 + a named fast algo in 32- AND 64-bit; deterministic + documented cross-platform guarantee (fixed constants, defined byte order, pure integer IR -> bit-identical everywhere); docs page with the "don't use this for security" note + a chunk-seed example (docs/language/hash/); known-answer tests (CRC-32 poly 0xEDB88320 and FNV vectors verified against reference impls) + a long language test (selfhost/tests/{hash,long}.ludic).

Note: numeric literals are still parsed as 32-bit, so large long values are built by widening (documented on the type page). Prior namespaced-stdlib groundwork: a381951.

Done — shipped in 2002e97 (pushed to `main`). The `Hash.*` namespace now provides both 32- and 64-bit algorithms, all deterministic and C-free: - 32-bit (return `int`): `Hash.of`, `Hash.fnv1a`, `Hash.crc32`, `Hash.mix`, `Hash.combine(...)` - 64-bit (return `long`): `Hash.of64`, `Hash.fnv1a_64`, `Hash.mix64` Delivering the 64-bit variants required a real language extension — a new `long` (64-bit signed integer) primitive type — landed in the same commit (llty -> i64, int/long coercion, i64 arithmetic/comparison, print/str, editor vocab sync). Acceptance: Hash.of/combine/crc32 + a named fast algo in 32- AND 64-bit; deterministic + documented cross-platform guarantee (fixed constants, defined byte order, pure integer IR -> bit-identical everywhere); docs page with the "don't use this for security" note + a chunk-seed example (docs/language/hash/); known-answer tests (CRC-32 poly 0xEDB88320 and FNV vectors verified against reference impls) + a long language test (selfhost/tests/{hash,long}.ludic). Note: numeric literals are still parsed as 32-bit, so large long values are built by widening (documented on the type page). Prior namespaced-stdlib groundwork: a381951.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: workshopsoft/ludic#17
No description provided.