Fast XXH3, XXH64 and rapidhash for Go. Three packages with reference-compatible results, automatic CPU dispatch, and no dependencies outside the standard library. No cgo or assembly toolchain is needed to use them.
The assembly kernels are generated and checked by simulating their instruction streams, including backends the test machine cannot execute. Published XXH3 measurements at 64 KiB reach 97 GB/s on Zen 4 and 28 GB/s on Neoverse N2, against zeebo/xxh3's 83 and 12.5 GB/s; see Speed for the context.
Quick start · Choose a package · API reference · Benchmarks · Contributing · Help
Requires Go 1.21 or newer. In your Go module:
go get github.com/JohanLindvall/haste/xxh3Save this as main.go, then run go run .:
package main
import (
"fmt"
"github.com/JohanLindvall/haste/xxh3"
)
func main() {
data := []byte("haste")
fmt.Printf("%016x\n", xxh3.Sum64(data))
fmt.Printf("%x\n", xxh3.Sum128(data).Bytes())
}Output:
29a60a4033936c78
26b6ef3229e32bf9476854cadb11bc32
These are non-cryptographic hashes for checksums, fingerprints, and fast lookup keys. Seeds and custom secrets do not make them suitable for passwords, authentication, or collision resistance against hostile input.
| Package | Use it when | Output | Streaming |
|---|---|---|---|
xxh3 |
You want a general starting point, or need XXH3 compatibility | 64 or 128 bits | Yes; both widths from one digest |
xxh64 |
You need existing XXH64 checksums, including cespare/xxhash output | 64 bits | Yes |
rapidhash |
You need rapidhash V3, or want to compare a scalar hash on your workload | 64 bits | No |
All three accept byte slices, strings, and seeds. They compute different hashes; choose the algorithm your data format expects. XXH3 and XXH64 match xxHash v0.8.3, and rapidhash matches V3's default, unprotected form. Older rapidhash versions can produce different results.
Install another package with go get github.com/JohanLindvall/haste/xxh64 or
go get github.com/JohanLindvall/haste/rapidhash. Import a subpackage: the module
root exports no hash functions.
With fmt and xxh3 imported, a function body can start with:
data := []byte("haste")
h := xxh3.Sum64(data)
textHash := xxh3.Sum64String("haste") // same result, without copying the string
seeded := xxh3.Sum64Seed(data, 42)
wide := xxh3.Sum128(data) // wide.Hi, wide.Lo; wide.Bytes() for encoding
fmt.Printf("%016x %016x %016x %x\n", h, textHash, seeded, wide.Bytes())Sum64String, Sum64Seed, and Sum64SeedString are available in all three
packages. XXH3 also has 128-bit forms and custom-secret entry points. A custom
secret must contain at least xxh3.MinSecretSize bytes; NewSecret retains it,
so keep it unchanged while the digest is in use.
XXH3 and XXH64 digests implement hash.Hash64 and work with io.Copy:
package main
import (
"fmt"
"io"
"log"
"strings"
"github.com/JohanLindvall/haste/xxh3"
)
func main() {
d := xxh3.New()
if _, err := io.Copy(d, strings.NewReader("haste")); err != nil {
log.Fatal(err)
}
fmt.Printf("%016x\n", d.Sum64())
fmt.Printf("%x\n", d.Sum128().Bytes())
}This prints the same two hashes as the quick start. Replace the reader with a
file or another io.Reader to hash incrementally. Sum64 and Sum128 preserve
the digest state, and Reset lets you reuse it. NewSeed(seed) retains the
seed across resets. Use a separate digest per concurrent stream; a digest is
not safe for concurrent mutation. Construct XXH3 digests with New, NewSeed,
or NewSecret; their zero value is not usable.
All three packages provide Sum64Uint32, Sum64Uint64, and
Sum64Uint128(lo, hi) for integer keys. They hash the same bytes as Sum64
with the integers encoded in little-endian order. XXH3 and XXH64 also have
seeded forms. See the runnable integer-key example.
XXH3's Uint128.Bytes() returns the canonical big-endian 16-byte result,
high half first. Digest.Sum(nil) in XXH3 and XXH64 returns the big-endian
64-bit hash; use Sum128().Bytes() when you need 128 bits.
The common Sum64, Sum64String, New, Digest.Write, and Digest.Sum64
calls match cespare/xxhash's API. To keep existing xxhash call sites for
those operations:
import xxhash "github.com/JohanLindvall/haste/xxh64"The seeded constructor is named NewSeed. With the alias above, replace
xxhash.NewWithSeed(seed) with xxhash.NewSeed(seed). Check the
API reference for the
rest of your call sites; the two packages' exported APIs are not identical.
Use rapidhash.Sum64(data) or rapidhash.Sum64Seed(data, seed) for a whole
input. rapidhash needs the full input and its length, so it has no streaming
API. Compare it with XXH3 on your own workload; the
measurement notes describe its different
use of the CPU and the algorithm versions compared.
A sample from the published 64 KiB XXH3 measurements, using Go 1.26. Throughput in GB/s, higher is better:
| CPU | haste/xxh3 | zeebo/xxh3 |
|---|---|---|
| Ryzen 7 8840HS (Zen 4, AVX-512) | 97 | 83 |
| Azure Cobalt 100 (Neoverse N2) | 28 | 12.5 |
| Core Ultra 9 185H (Redwood Cove, AVX2) | 63 | 59 |
These are measurements on specific hardware, not a promise for every CPU or input length. For short inputs, call overhead and code alignment can dominate. The full tables and analysis retain input sizes, nanoseconds per hash, streaming results, and XXH64 and rapidhash comparisons. Automated runner results cover additional platforms.
To reproduce a comparison, follow the benchmark procedure.
The comparison suite lives in a separate bench/ module, keeping its Go and C
reference dependencies out of the library.
CPU detection happens automatically at package initialization:
| Build | XXH3 | XXH64 and rapidhash |
|---|---|---|
| amd64 | AVX-512, AVX2, or SSE2 | Scalar assembly |
| arm64 | NEON, a core-specific hybrid, or supported SVE2 widths | Scalar assembly |
Other architectures, or -tags purego |
Portable Go | Portable Go |
Each package exposes Backend() to report the active implementation. To select
the portable paths for your application, use go build -tags purego ./....
See backend selection and verification for details.
All three packages are checked against C-derived reference vectors, portable Go implementations, and simulated instruction streams. Streaming tests compare chunked input with one-shot hashing. CI runs native amd64 and arm64 tests, race and purego configurations, fuzz targets, cross-compilation, and generated file checks. The separate comparison module also checks independent Go ports and, when cgo is available, the reference C implementations.
Read how the kernels are verified or run
go test ./... from a checkout. The Go examples run as
part of the test suite and appear in the package documentation.
The module is v0.x while the API evolves; a minor version may break source
compatibility. Pin a tagged version in your application's go.mod and review
changes when upgrading. See available versions
and tags.
A green CI run on main tags the next patch when Go, assembly, or module files
have changed since the last tag. Markdown-only changes do not earn a version.
Earlier versions exposed XXH3 at the module root; update that import to
github.com/JohanLindvall/haste/xxh3 to use the current layout.
Documentation fixes, small reproductions, test cases, and benchmark reports on new CPUs are welcome. You do not need assembly experience to help. CONTRIBUTING.md covers setup, the repository layout, checks, and performance measurements. The issue forms help you report a bug, suggest a feature, or share a performance result.
The generated kernels are checked in. For generator work, edit
internal/asmgen, then run go generate ./... with the target binutils
installed. See the setup and verification steps
and how generation works.
See SUPPORT.md for questions and troubleshooting, and the code of conduct for participation expectations. Johan Lindvall maintains haste, with help from contributors.
If haste is useful to you, a star helps other Go developers discover it. Sharing a reproducible benchmark or a use case helps people judge whether it fits their workload.
Report vulnerabilities through the private reporting form. See SECURITY.md for scope and supported versions.
MIT. Source files carry SPDX license identifiers. The vendored
reference C implementations live only in the separate bench/ module and
are not downloaded with the library. For academic use, see CITATION.cff.