Go xxHash Code Example (Online Runner)
Go xxHash examples for XXH32, XXH64, XXH3-64, and XXH3-128 with seeds and hex/decimal output.
Online calculator: use the site xxHash text tool.
Note: This snippet requires locally installed dependencies and will not run in the online runner. Run it locally with:
go mod init xxhash-demo && go get github.com/zeebo/xxh3 && go run xxhash_basic.go
Calculation method
XXH32 uses a 32-bit seed, while XXH64/XXH3 use a 64-bit seed built from low/high 32-bit words. Output can be hex or decimal and is formatted to the correct width.
Implementation notes
- Package: pure Go for XXH32/XXH64, plus
github.com/zeebo/xxh3for XXH3. - Implementation: seeds are combined from low/high 32-bit words to match the tool.
- Notes: xxHash is not cryptographic.
Text hashing example
go
package main
import (
"fmt"
"strconv"
"github.com/zeebo/xxh3"
)
func xxh3_64Text(text string) string {
value := xxh3.Hash([]byte(text))
return strconv.FormatUint(value, 10)
}
func main() {
fmt.Println(xxh3_64Text("hello"))
}File hashing example
go
package main
import (
"fmt"
"math/big"
"os"
"github.com/zeebo/xxh3"
)
func xxh3_128File(path string) (string, error) {
data, err := os.ReadFile(path)
if err != nil {
return "", err
}
value := xxh3.Hash128(data)
bigValue := new(big.Int).SetUint64(value.Hi)
bigValue.Lsh(bigValue, 64)
bigValue.Or(bigValue, new(big.Int).SetUint64(value.Lo))
return bigValue.Text(10), nil
}
func main() {
file, err := os.CreateTemp("", "xxhash-example-*.bin")
if err != nil {
panic(err)
}
defer os.Remove(file.Name())
file.WriteString("hello")
file.Close()
value, err := xxh3_128File(file.Name())
if err != nil {
panic(err)
}
fmt.Println(value)
}Complete script (implementation + tests)
go
package main
import (
"encoding/binary"
"fmt"
"math/big"
"math/bits"
"strconv"
"strings"
"github.com/zeebo/xxh3"
)
type Variant string
type OutputFormat string
const (
VarXXH32 Variant = "xxhash32"
VarXXH64 Variant = "xxhash64"
VarXXH3_64 Variant = "xxh3_64"
VarXXH3_128 Variant = "xxh3_128"
)
const (
OutputHex OutputFormat = "hex"
OutputDecimal OutputFormat = "decimal"
)
const (
prime32_1 uint32 = 2654435761
prime32_2 uint32 = 2246822519
prime32_3 uint32 = 3266489917
prime32_4 uint32 = 668265263
prime32_5 uint32 = 374761393
prime64_1 uint64 = 11400714785074694791
prime64_2 uint64 = 14029467366897019727
prime64_3 uint64 = 1609587929392839161
prime64_4 uint64 = 9650029242287828579
prime64_5 uint64 = 2870177450012600261
)
func parseSeed32(value string) uint32 {
trimmed := strings.TrimSpace(value)
if trimmed == "" {
return 0
}
parsed, err := strconv.ParseUint(trimmed, 0, 32)
if err != nil {
return 0
}
return uint32(parsed)
}
func combineSeed(low, high uint32) uint64 {
return (uint64(high) << 32) | uint64(low)
}
func round32(acc, input uint32) uint32 {
acc += input * prime32_2
acc = bits.RotateLeft32(acc, 13)
acc *= prime32_1
return acc
}
func mergeRound32(acc, val uint32) uint32 {
acc ^= round32(0, val)
acc = acc*prime32_1 + prime32_4
return acc
}
func xxh32(data []byte, seed uint32) uint32 {
length := len(data)
var h32 uint32
idx := 0
if length >= 16 {
v1 := seed + prime32_1 + prime32_2
v2 := seed + prime32_2
v3 := seed
v4 := seed - prime32_1
for idx <= length-16 {
v1 = round32(v1, binary.LittleEndian.Uint32(data[idx:]))
v2 = round32(v2, binary.LittleEndian.Uint32(data[idx+4:]))
v3 = round32(v3, binary.LittleEndian.Uint32(data[idx+8:]))
v4 = round32(v4, binary.LittleEndian.Uint32(data[idx+12:]))
idx += 16
}
h32 = bits.RotateLeft32(v1, 1) + bits.RotateLeft32(v2, 7) + bits.RotateLeft32(v3, 12) + bits.RotateLeft32(v4, 18)
h32 = mergeRound32(h32, v1)
h32 = mergeRound32(h32, v2)
h32 = mergeRound32(h32, v3)
h32 = mergeRound32(h32, v4)
} else {
h32 = seed + prime32_5
}
h32 += uint32(length)
for idx <= length-4 {
h32 += binary.LittleEndian.Uint32(data[idx:]) * prime32_3
h32 = bits.RotateLeft32(h32, 17) * prime32_4
idx += 4
}
for idx < length {
h32 += uint32(data[idx]) * prime32_5
h32 = bits.RotateLeft32(h32, 11) * prime32_1
idx++
}
h32 ^= h32 >> 15
h32 *= prime32_2
h32 ^= h32 >> 13
h32 *= prime32_3
h32 ^= h32 >> 16
return h32
}
func round64(acc, input uint64) uint64 {
acc += input * prime64_2
acc = bits.RotateLeft64(acc, 31)
acc *= prime64_1
return acc
}
func mergeRound64(acc, val uint64) uint64 {
acc ^= round64(0, val)
acc = acc*prime64_1 + prime64_4
return acc
}
func xxh64(data []byte, seed uint64) uint64 {
length := len(data)
idx := 0
var h64 uint64
if length >= 32 {
v1 := seed + prime64_1 + prime64_2
v2 := seed + prime64_2
v3 := seed
v4 := seed - prime64_1
for idx <= length-32 {
v1 = round64(v1, binary.LittleEndian.Uint64(data[idx:]))
v2 = round64(v2, binary.LittleEndian.Uint64(data[idx+8:]))
v3 = round64(v3, binary.LittleEndian.Uint64(data[idx+16:]))
v4 = round64(v4, binary.LittleEndian.Uint64(data[idx+24:]))
idx += 32
}
h64 = bits.RotateLeft64(v1, 1) + bits.RotateLeft64(v2, 7) + bits.RotateLeft64(v3, 12) + bits.RotateLeft64(v4, 18)
h64 = mergeRound64(h64, v1)
h64 = mergeRound64(h64, v2)
h64 = mergeRound64(h64, v3)
h64 = mergeRound64(h64, v4)
} else {
h64 = seed + prime64_5
}
h64 += uint64(length)
for idx <= length-8 {
k1 := round64(0, binary.LittleEndian.Uint64(data[idx:]))
h64 ^= k1
h64 = bits.RotateLeft64(h64, 27)*prime64_1 + prime64_4
idx += 8
}
if idx <= length-4 {
h64 ^= uint64(binary.LittleEndian.Uint32(data[idx:])) * prime64_1
h64 = bits.RotateLeft64(h64, 23)*prime64_2 + prime64_3
idx += 4
}
for idx < length {
h64 ^= uint64(data[idx]) * prime64_5
h64 = bits.RotateLeft64(h64, 11) * prime64_1
idx++
}
h64 ^= h64 >> 33
h64 *= prime64_2
h64 ^= h64 >> 29
h64 *= prime64_3
h64 ^= h64 >> 32
return h64
}
func formatOutput(value *big.Int, bits int, output OutputFormat) string {
if output == OutputDecimal {
return value.Text(10)
}
return fmt.Sprintf("%0*x", bits/4, value)
}
func xxhashText(text string, variant Variant, seed32 uint32, seedLow uint32, seedHigh uint32, output OutputFormat) string {
data := []byte(text)
switch variant {
case VarXXH32:
value := xxh32(data, seed32)
return formatOutput(new(big.Int).SetUint64(uint64(value)), 32, output)
case VarXXH64:
value := xxh64(data, combineSeed(seedLow, seedHigh))
return formatOutput(new(big.Int).SetUint64(value), 64, output)
case VarXXH3_64:
value := xxh3.HashSeed(data, combineSeed(seedLow, seedHigh))
return formatOutput(new(big.Int).SetUint64(value), 64, output)
case VarXXH3_128:
value := xxh3.Hash128Seed(data, combineSeed(seedLow, seedHigh))
bigValue := new(big.Int).SetUint64(value.Hi)
bigValue.Lsh(bigValue, 64)
bigValue.Or(bigValue, new(big.Int).SetUint64(value.Lo))
return formatOutput(bigValue, 128, output)
default:
return ""
}
}
func main() {
seed32 := parseSeed32("1234")
seedLow := parseSeed32("0x1234")
seedHigh := parseSeed32("0xabcd")
fmt.Println(xxhashText("hello", VarXXH32, seed32, 0, 0, OutputHex))
fmt.Println(xxhashText("hello", VarXXH3_128, 0, seedLow, seedHigh, OutputDecimal))
}