xxhashjs
Pure JavaScript implementation of the xxHash algorithm, delivering fast 32-bit and 64-bit non-cryptographic hashing.
Repository Health
Technical Analysis
xxhashjs is a 100% JavaScript port of xxHash, an extremely fast non-cryptographic hash function originally implemented in C. It exposes two hash variants — XXH.h32 for 32-bit hashes and XXH.h64 for 64-bit hashes — through a single unified API that accepts strings, ArrayBuffers, or Node.js Buffers as input, and lets callers seed the hash for use cases like bloom filters, hash tables, and checksum validation.
Because native JavaScript lacks true unsigned 32-bit integer arithmetic, the library builds on the cuint package for UINT32/UINT64 emulation to reproduce xxHash’s bitwise operations faithfully. It supports both one-shot hashing (XXH.h32(data, seed)) and streaming updates (.update().digest()), the latter useful for hashing data incrementally from Node.js streams or large files without loading everything into memory at once.
What You Get
- 32-bit and 64-bit hash functions (
XXH.h32,XXH.h64) under one require - One-shot and streaming APIs — hash in a single call or incrementally via
.update()/.digest() - Seedable hashing so callers can produce distinct hash spaces for the same input
- Works with strings (including UTF-8), Node.js Buffers, and ArrayBuffers as input
- Browser-ready build via the bundled Webpack build in
build/xxhash.js
Common Use Cases
- Generating fast checksums to detect file or data corruption without cryptographic overhead
- Building hash tables and bloom filters that need a quick, well-distributed hash function
- Deduplicating large datasets or cache keys where MD5/SHA are unnecessarily slow
- Hashing streamed file data incrementally in Node.js without buffering the whole file
Under The Hood
Architecture
The library has a minimal, flat module structure — lib/index.js re-exports two independent hash implementations, lib/xxhash.js (32-bit) and lib/xxhash64.js (64-bit), each self-contained with no shared internal abstraction beyond the external cuint UINT32/UINT64 types. The XXH constructor doubles as both a one-shot function (two-argument call: data + seed) and a stateful object constructor via arguments.length/instanceof checks, giving one API surface for both one-shot and streaming (update/digest) usage. State (v1-v4 accumulators, memory buffer, total length) is mutated in place across update() calls and reset at the end of digest() so instances are reusable. There is no dependency injection and no separation of concerns beyond the “core algorithm” vs. “big-integer arithmetic” split delegated to cuint; changing the core rotate/multiply/xor sequence would directly affect hash correctness with no insulating layer.
Tech Stack
Written in plain, pre-ES6 JavaScript (var, function expressions) targeting both Node.js and the browser via a Webpack-based build producing a bundled and minified browser build through an uglifyjs prepublish step. Its only runtime dependency is cuint, a sister project by the same author providing unsigned 32-bit/64-bit integer arithmetic since JavaScript numbers cannot natively perform unsigned bitwise operations at that width. Development dependencies include a benchmarking library and the build toolchain; no transpiler is used beyond the bundler configuration. No CI configuration or lockfile is present in the repository. The test runner is mocha paired with Node’s built-in assert module.
Code Quality A single test file covers the 32-bit hash across several input sizes (small, medium, multiples of four, UTF-8 strings) and both the one-shot and streaming code paths, but no equivalent test coverage exists for the 64-bit hash implementation in that same file. There is no input validation — passing an unsupported type fails with a generic runtime error rather than a descriptive one. The code has no static typing, no linter or formatter configuration, and no CI workflow. Variable naming is terse and mirrors the original C implementation (short accumulator and offset names) rather than idiomatic, verbose JavaScript naming.
API Design
The most distinctive design choice is the dual-mode function that serves as both a one-shot hash call and, when instantiated, a stateful streaming hasher — one function signature covers both idioms without a separate class name to remember. Getting started takes one line with no configuration object or builder pattern required. Digest results are integer-wrapper objects rather than plain numbers, requiring an explicit .toString()/.toNumber() conversion step — a minor ergonomic cost that stems from the era’s lack of native 64-bit integer support in JavaScript, and there are no bundled TypeScript type definitions to guide usage.