Installations
npm install xxhash-wasm
Developer
jungomi
Developer Guide
Module System
ESM
Min. Node Version
Typescript Support
Yes
Node Version
22.11.0
NPM Version
10.9.0
Statistics
126 Stars
138 Commits
21 Forks
5 Watching
1 Branches
6 Contributors
Updated on 28 Nov 2024
Languages
WebAssembly (63.75%)
JavaScript (35.65%)
Dockerfile (0.6%)
Total Downloads
Cumulative downloads
Total Downloads
87,310,602
Last day
-4.6%
228,325
Compared to previous day
Last week
9.4%
1,356,602
Compared to previous week
Last month
14.8%
5,301,435
Compared to previous month
Last year
49.9%
44,553,104
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
xxhash-wasm
A WebAssembly implementation of xxHash, a fast non-cryptographic hash algorithm. It can be called seamlessly from JavaScript. You can use it like any other JavaScript library but still get the benefits of WebAssembly, no special setup needed.
Table of Contents
Installation
From npm
1npm install --save xxhash-wasm
Or with Yarn:
1yarn add xxhash-wasm
From Unpkg
ES Modules
1<script type="module"> 2 import xxhash from "https://unpkg.com/xxhash-wasm/esm/xxhash-wasm.js"; 3</script>
UMD build
1<script src="https://unpkg.com/xxhash-wasm/umd/xxhash-wasm.js"></script>
The global xxhash
will be available.
Cloudflare Workers
If you are using Cloudflare Workers (workerd) you can use the installed
npm package as is. The xxhash-wasm
package is compatible with Cloudflare Workers.
1import xxhash from "xxhash-wasm";
Importing it will pick the correct file base on the conditional import from the package.json.
Usage
The WebAssembly is contained in the JavaScript bundle, so you don't need to manually fetch it and create a new WebAssembly instance.
1import xxhash from "xxhash-wasm"; 2 3// Creates the WebAssembly instance. 4xxhash().then(hasher => { 5 const input = "The string that is being hashed"; 6 7 // 32-bit version 8 hasher.h32(input); // 3998627172 (decimal representation) 9 // For convenience, get hash as string of its zero-padded hex representation 10 hasher.h32ToString(input); // "ee563564" 11 12 // 64-bit version 13 hasher.h64(input); // 5776724552493396044n (BigInt) 14 // For convenience, get hash as string of its zero-padded hex representation 15 hasher.h64ToString(input); // "502b0c5fc4a5704c" 16});
Or with async
/await
and destructuring:
1// Creates the WebAssembly instance. 2const { h32, h64 } = await xxhash(); 3 4const input = "The string that is being hashed"; 5// 32-bit version 6h32(input); // 3998627172 (decimal representation) 7// 64-bit version 8h64(input); // 5776724552493396044n (BigInt)
Streaming Example
xxhash-wasm
supports a crypto
-like streaming api, useful for avoiding memory
consumption when hashing large amounts of data:
1const { create32, create64 } = await xxhash(); 2 3// 32-bit version 4create32() 5 .update("some data") 6 // update accepts either a string or Uint8Array 7 .update(Uint8Array.from([1, 2, 3])) 8 .digest(); // 955607085 9 10// 64-bit version 11create64() 12 .update("some data") 13 // update accepts either a string or Uint8Array 14 .update(Uint8Array.from([1, 2, 3])) 15 .digest(); // 883044157688673477n
Node
It doesn't matter whether you are using CommonJS or ES Modules in Node
(e.g. with "type": "module"
in package.json
or using the explicit file
extensions .cjs
or .mjs
respectively), importing xxhash-wasm
will always
load the corresponding module, as both bundles are provided and specified in
the exports
field of its package.json
, therefore the appropriate one will
automatically be selected.
Using ES Modules
1import xxhash from "xxhash-wasm";
Using CommonJS
1const xxhash = require("xxhash-wasm");
Performance
For performance sensitive applications, xxhash-wasm
provides the h**
and
h**Raw
APIs, which return raw numeric hash results rather than zero-padded hex
strings. The overhead of the string conversion in the h**ToString
APIs can be
as much as 20% of overall runtime when hashing small byte-size inputs, and the
string result is often inconsequential (for example when simply checking if the
the resulting hashes are the same). When necessary, getting a zero-padded hex
string from the provided number
or BigInt
results is easily
achieved via result.toString(16).padStart(16, "0")
and the h**ToString
APIs
are purely for convenience.
The h**
, h**ToString
, and streaming APIs make use of
TextEncoder.encodeInto
to directly encode
strings as a stream of UTF-8 bytes into the WebAssembly memory buffer, meaning
that for string-hashing purposes, these APIs will be significantly faster than
converting the string to bytes externally and using the Raw
API. That said,
for large strings it may be beneficial to consider the streaming API or another
approach to encoding, as encodeInto
is forced to allocate 3-times the string
length to account for the chance the input string contains high-byte-count
code units.
If possible, defer the encoding of the string to the hashing, unless you need
to use the encoded string (bytes) for other purposes as well, or you are
creating the bytes differently (e.g. different encoding), in which case it's
much more efficient to use the h**Raw
APIs instead of having to unnecessarily
convert them to a string first.
Engine Requirements
In an effort to make this library as performant as possible, it uses several recent additions to browsers, Node and the WebAssembly specification. Notably, these include:
BigInt
support in WebAssembly- Bulk memory operations in WebAssembly
TextEncoder.encodeInto
Taking all of these requirements into account, xxhash-wasm
should be
compatible with:
- Chrome >= 85
- Edge >= 79
- Firefox >= 79
- Safari >= 15.0
- Node >= 15.0
If support for an older engine is required, xxhash-wasm@0.4.2
is available
with much broader engine support, but 3-4x slower hashing performance.
API
1const { 2 h32, 3 h32ToString, 4 h32Raw, 5 create32, 6 h64, 7 h64ToString, 8 h64Raw, 9 create64, 10} = await xxhash();
Create a WebAssembly instance.
h32
1h32(input: string, [seed: u32]): number
Generate a 32-bit hash of the UTF-8 encoded bytes of input
. The optional
seed
is a u32
and any number greater than the maximum (0xffffffff
) is
wrapped, which means that 0xffffffff + 1 = 0
.
Returns a u32
number
containing the hash value.
1h32ToString(input: string, [seed: u32]): string
Same as h32
, but returning a zero-padded hex string.
1h32Raw(input: Uint8Array, [seed: u32]): number
Same as h32
but with a Uint8Array
as input instead of a string
.
h64
1h64(input: string, [seed: bigint]): bigint
Generate a 64-bit hash of the UTF-8 encoded bytes of input
. The optional
seed
is a u64
provided as a BigInt.
Returns a u64
bigint
containing the hash value.
1h64ToString(input: string, [seed: bigint]): string
Same as h64
, but returning a zero-padded hex string.
1h64Raw(input: Uint8Array, [seed: bigint]): bigint
Same as h64
but with a Uint8Array
as input instead of a string
.
Streaming
1type XXHash<T> { 2 update(input: string | Uint8Array): XXHash<T>; 3 digest(): T 4}
The streaming API mirrors Node's built-in crypto.createHash
, providing
update
and digest
methods to add data to the hash and compute the final hash
value, respectively.
1create32([seed: number]): XXHash<number>
Create a 32-bit hash for streaming applications.
1create64([seed: bigint]): XXHash<bigint>
Create a 64-bit hash for streaming applications.
Comparison to xxhashjs
xxhashjs
is implemented in pure JavaScript and because JavaScript
is lacking support for 64-bit integers, it uses a workaround with
cuint
. Not only is that a big performance hit, but it also increases
the bundle size by quite a bit when it's used in the browser.
This library (xxhash-wasm
) has the big advantage that WebAssembly supports
u64
and also some instructions (e.g. rotl
), which would otherwise have
to be emulated. However, The downside is that you have to initialise
a WebAssembly instance, which takes a little over 2ms in Node and about 1ms in
the browser. But once the instance is created, it can be used without any
further overhead. For the benchmarks below, the instantiation is done before the
benchmark and therefore it's excluded from the results, since it wouldn't make
sense to always create a new WebAssembly instance.
Benchmarks
Benchmarks are using Benchmark.js with random strings of different lengths. Higher is better
String length | xxhashjs 32-bit | xxhashjs 64-bit | xxhash-wasm 32-bit | xxhash-wasm 64-bit |
---|---|---|---|---|
1 byte | 513,517 ops/sec | 11,896 ops/sec | 5,752,446 ops/sec | 4,438,501 ops/sec |
10 bytes | 552,133 ops/sec | 12,953 ops/sec | 6,240,640 ops/sec | 4,855,340 ops/sec |
100 bytes | 425,277 ops/sec | 10,838 ops/sec | 5,470,011 ops/sec | 4,314,904 ops/sec |
1,000 bytes | 102,165 ops/sec | 6,697 ops/sec | 3,283,526 ops/sec | 3,332,556 ops/sec |
10,000 bytes | 13,010 ops/sec | 1,452 ops/sec | 589,068 ops/sec | 940,350 ops/sec |
100,000 bytes | 477 ops/sec | 146 ops/sec | 61,824 ops/sec | 98,959 ops/sec |
1,000,000 bytes | 36.40 ops/sec | 12.93 ops/sec | 5,122 ops/sec | 8,632 ops/sec |
10,000,000 bytes | 3.12 ops/sec | 1.19 ops/sec | 326 ops/sec | 444 ops/sec |
100,000,000 bytes | 0.31 ops/sec | 0.13 ops/sec | 27.84 ops/sec | 34.56 ops/sec |
xxhash-wasm
outperforms xxhashjs
significantly, the 32-bit is up to 90 times
faster (generally increases as the size of the input grows), and the 64-bit is
up to 350 times faster (generally increases as the size of the input grows).
The 64-bit version is the faster algorithm but there is a small degree of overhead involved in using BigInts, and so it retains a performance advantage over all lengths over xxhashjs and the 32-bit algorithm above ~1000 bytes.
xxhash-wasm
also significantly outperforms Node's built-in hash algorithms,
making it suitable for use in a wide variety of situations, where
non-cryptographic hashes are acceptable. Benchmarks from an x64 MacBook Pro
running Node 17.3:
String length | Node crypto md5 | Node crypto sha1 | xxhash-wasm 64-bit |
---|---|---|---|
1 byte | 342,924 ops/sec | 352,825 ops/sec | 4,438,501 ops/sec |
10 bytes | 356,596 ops/sec | 352,209 ops/sec | 4,855,340 ops/sec |
100 bytes | 354,898 ops/sec | 355,024 ops/sec | 4,314,904 ops/sec |
1,000 bytes | 249,242 ops/sec | 271,383 ops/sec | 3,332,556 ops/sec |
10,000 bytes | 62,896 ops/sec | 80,986 ops/sec | 940,350 ops/sec |
100,000 bytes | 7,316 ops/sec | 10,198 ops/sec | 98,959 ops/sec |
1,000,000 bytes | 698 ops/sec | 966 ops/sec | 8,632 ops/sec |
10,000,000 bytes | 58.98 ops/sec | 79.78 ops/sec | 444 ops/sec |
100,000,000 bytes | 6.30 ops/sec | 8.20 ops/sec | 34.56 ops/sec |
If suitable for your use case, the Raw
API offers significant throughput
improvements over the string-hashing API, particularly for smaller inputs,
assuming that you have access to the Uint8Array
already (see also the
Performance section):
String length | xxhash-wasm 64-bit Raw | xxhash-wasm 64-bit |
---|---|---|
1 byte | 9,342,811 ops/sec | 4,438,501 ops/sec |
10 bytes | 9,668,989 ops/sec | 4,855,340 ops/sec |
100 bytes | 8,775,845 ops/sec | 4,314,904 ops/sec |
1,000 bytes | 5,541,403 ops/sec | 3,332,556 ops/sec |
10,000 bytes | 1,079,866 ops/sec | 940,350 ops/sec |
100,000 bytes | 113,350 ops/sec | 98,959 ops/sec |
1,000,000 bytes | 9,779 ops/sec | 8,632 ops/sec |
10,000,000 bytes | 563 ops/sec | 444 ops/sec |
100,000,000 bytes | 43.77 ops/sec | 34.56 ops/sec |
Bundle size
Both libraries can be used in the browser and they provide a UMD bundle. The bundles are self-contained, that means they can be included and used without having to add any other dependencies. The table shows the bundle size of the minified versions. Lower is better.
xxhashjs | xxhash-wasm | |
---|---|---|
Bundle size | 41.5kB | 11.4kB |
Gzipped Size | 10.3kB | 2.3kB |
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
license file detected
Details
- Info: project has a license file: LICENSE.md:0
- Info: FSF or OSI recognized license: MIT License: LICENSE.md:0
Reason
packaging workflow detected
Details
- Info: Project packages its releases by way of GitHub Actions.: .github/workflows/publish.yml:8
Reason
binaries present in source code
Details
- Warn: binary detected: src/xxhash.wasm:1
Reason
10 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 8
Reason
3 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-rc47-6667-2j5j
- Warn: Project is vulnerable to: GHSA-78xj-cgh5-2h22
- Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp
Reason
Found 3/27 approved changesets -- score normalized to 1
Reason
detected GitHub workflow tokens with excessive permissions
Details
- Warn: no topLevel permission defined: .github/workflows/nodejs.yml:1
- Warn: no topLevel permission defined: .github/workflows/publish.yml:1
- Info: no jobLevel write permissions found
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/nodejs.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/jungomi/xxhash-wasm/nodejs.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/nodejs.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/jungomi/xxhash-wasm/nodejs.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/jungomi/xxhash-wasm/publish.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/jungomi/xxhash-wasm/publish.yml/main?enable=pin
- Warn: containerImage not pinned by hash: Dockerfile:1: pin your Docker image by updating ubuntu to ubuntu@sha256:278628f08d4979fb9af9ead44277dbc9c92c2465922310916ad0c46ec9999295
- Info: 0 out of 4 GitHub-owned GitHubAction dependencies pinned
- Info: 0 out of 1 containerImage dependencies pinned
Reason
branch protection not enabled on development/release branches
Details
- Warn: branch protection not enabled for branch 'main'
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 8 are checked with a SAST tool
Score
4.3
/10
Last Scanned on 2024-11-25
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More