Go MurmurHash3 Code Example (Online Runner)
Go MurmurHash3 examples with 32-bit/128-bit variants, seeds, and number/hex output to match the tools.
Online calculator: use the site MurmurHash3 text tool.
Calculation method
MurmurHash3 supports 32-bit (x86) and 128-bit (x86/x64) variants. This helper mirrors the tool’s variant and output format options.
Implementation notes
- Package: no external dependencies; this is a pure Go implementation.
- Implementation: outputs are masked to unsigned values and formatted as decimal or hex.
- Notes: MurmurHash3 is non-cryptographic; keep the seed consistent across systems.
Text hashing example
go
package main
import (
"encoding/binary"
"fmt"
"math/bits"
)
func murmur3X86_32(data []byte, seed uint32) uint32 {
const (
c1 uint32 = 0xcc9e2d51
c2 uint32 = 0x1b873593
)
h1 := seed
nblocks := len(data) / 4
for i := 0; i < nblocks; i++ {
k1 := binary.LittleEndian.Uint32(data[i*4:])
k1 *= c1
k1 = bits.RotateLeft32(k1, 15)
k1 *= c2
h1 ^= k1
h1 = bits.RotateLeft32(h1, 13)
h1 = h1*5 + 0xe6546b64
}
var k1 uint32
tail := data[nblocks*4:]
switch len(tail) {
case 3:
k1 ^= uint32(tail[2]) << 16
fallthrough
case 2:
k1 ^= uint32(tail[1]) << 8
fallthrough
case 1:
k1 ^= uint32(tail[0])
k1 *= c1
k1 = bits.RotateLeft32(k1, 15)
k1 *= c2
h1 ^= k1
}
h1 ^= uint32(len(data))
h1 ^= h1 >> 16
h1 *= 0x85ebca6b
h1 ^= h1 >> 13
h1 *= 0xc2b2ae35
h1 ^= h1 >> 16
return h1
}
func main() {
value := murmur3X86_32([]byte("hello"), 0)
fmt.Println(value)
}File hashing example
go
package main
import (
"encoding/binary"
"fmt"
"math/bits"
"os"
)
func murmur3X86_32(data []byte, seed uint32) uint32 {
const (
c1 uint32 = 0xcc9e2d51
c2 uint32 = 0x1b873593
)
h1 := seed
nblocks := len(data) / 4
for i := 0; i < nblocks; i++ {
k1 := binary.LittleEndian.Uint32(data[i*4:])
k1 *= c1
k1 = bits.RotateLeft32(k1, 15)
k1 *= c2
h1 ^= k1
h1 = bits.RotateLeft32(h1, 13)
h1 = h1*5 + 0xe6546b64
}
var k1 uint32
tail := data[nblocks*4:]
switch len(tail) {
case 3:
k1 ^= uint32(tail[2]) << 16
fallthrough
case 2:
k1 ^= uint32(tail[1]) << 8
fallthrough
case 1:
k1 ^= uint32(tail[0])
k1 *= c1
k1 = bits.RotateLeft32(k1, 15)
k1 *= c2
h1 ^= k1
}
h1 ^= uint32(len(data))
h1 ^= h1 >> 16
h1 *= 0x85ebca6b
h1 ^= h1 >> 13
h1 *= 0xc2b2ae35
h1 ^= h1 >> 16
return h1
}
func main() {
file, err := os.CreateTemp("", "murmur3-example-*.bin")
if err != nil {
panic(err)
}
defer os.Remove(file.Name())
file.WriteString("hello")
file.Close()
data, err := os.ReadFile(file.Name())
if err != nil {
panic(err)
}
fmt.Println(murmur3X86_32(data, 0))
}Complete script (implementation + tests)
go
package main
import (
"encoding/binary"
"fmt"
"math/big"
"math/bits"
"strconv"
"strings"
)
type OutputFormat string
const (
OutputNumber OutputFormat = "number"
OutputHex OutputFormat = "hex"
)
func parseSeed(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 fmix32(h uint32) uint32 {
h ^= h >> 16
h *= 0x85ebca6b
h ^= h >> 13
h *= 0xc2b2ae35
h ^= h >> 16
return h
}
func fmix64(k uint64) uint64 {
k ^= k >> 33
k *= 0xff51afd7ed558ccd
k ^= k >> 33
k *= 0xc4ceb9fe1a85ec53
k ^= k >> 33
return k
}
func murmur3X86_32(data []byte, seed uint32) uint32 {
const (
c1 uint32 = 0xcc9e2d51
c2 uint32 = 0x1b873593
)
h1 := seed
nblocks := len(data) / 4
for i := 0; i < nblocks; i++ {
k1 := binary.LittleEndian.Uint32(data[i*4:])
k1 *= c1
k1 = bits.RotateLeft32(k1, 15)
k1 *= c2
h1 ^= k1
h1 = bits.RotateLeft32(h1, 13)
h1 = h1*5 + 0xe6546b64
}
var k1 uint32
tail := data[nblocks*4:]
switch len(tail) {
case 3:
k1 ^= uint32(tail[2]) << 16
fallthrough
case 2:
k1 ^= uint32(tail[1]) << 8
fallthrough
case 1:
k1 ^= uint32(tail[0])
k1 *= c1
k1 = bits.RotateLeft32(k1, 15)
k1 *= c2
h1 ^= k1
}
h1 ^= uint32(len(data))
h1 = fmix32(h1)
return h1
}
func murmur3X86_128(data []byte, seed uint32) (uint32, uint32, uint32, uint32) {
const (
c1 uint32 = 0x239b961b
c2 uint32 = 0xab0e9789
c3 uint32 = 0x38b34ae5
c4 uint32 = 0xa1e38b93
)
var h1, h2, h3, h4 uint32 = seed, seed, seed, seed
nblocks := len(data) / 16
for i := 0; i < nblocks; i++ {
block := data[i*16:]
k1 := binary.LittleEndian.Uint32(block[0:4])
k2 := binary.LittleEndian.Uint32(block[4:8])
k3 := binary.LittleEndian.Uint32(block[8:12])
k4 := binary.LittleEndian.Uint32(block[12:16])
k1 *= c1
k1 = bits.RotateLeft32(k1, 15)
k1 *= c2
h1 ^= k1
h1 = bits.RotateLeft32(h1, 19)
h1 += h2
h1 = h1*5 + 0x561ccd1b
k2 *= c2
k2 = bits.RotateLeft32(k2, 16)
k2 *= c3
h2 ^= k2
h2 = bits.RotateLeft32(h2, 17)
h2 += h3
h2 = h2*5 + 0x0bcaa747
k3 *= c3
k3 = bits.RotateLeft32(k3, 17)
k3 *= c4
h3 ^= k3
h3 = bits.RotateLeft32(h3, 15)
h3 += h4
h3 = h3*5 + 0x96cd1c35
k4 *= c4
k4 = bits.RotateLeft32(k4, 18)
k4 *= c1
h4 ^= k4
h4 = bits.RotateLeft32(h4, 13)
h4 += h1
h4 = h4*5 + 0x32ac3b17
}
tail := data[nblocks*16:]
var k1, k2, k3, k4 uint32
switch len(tail) & 15 {
case 15:
k4 ^= uint32(tail[14]) << 16
fallthrough
case 14:
k4 ^= uint32(tail[13]) << 8
fallthrough
case 13:
k4 ^= uint32(tail[12])
k4 *= c4
k4 = bits.RotateLeft32(k4, 18)
k4 *= c1
h4 ^= k4
fallthrough
case 12:
k3 ^= uint32(tail[11]) << 24
fallthrough
case 11:
k3 ^= uint32(tail[10]) << 16
fallthrough
case 10:
k3 ^= uint32(tail[9]) << 8
fallthrough
case 9:
k3 ^= uint32(tail[8])
k3 *= c3
k3 = bits.RotateLeft32(k3, 17)
k3 *= c4
h3 ^= k3
fallthrough
case 8:
k2 ^= uint32(tail[7]) << 24
fallthrough
case 7:
k2 ^= uint32(tail[6]) << 16
fallthrough
case 6:
k2 ^= uint32(tail[5]) << 8
fallthrough
case 5:
k2 ^= uint32(tail[4])
k2 *= c2
k2 = bits.RotateLeft32(k2, 16)
k2 *= c3
h2 ^= k2
fallthrough
case 4:
k1 ^= uint32(tail[3]) << 24
fallthrough
case 3:
k1 ^= uint32(tail[2]) << 16
fallthrough
case 2:
k1 ^= uint32(tail[1]) << 8
fallthrough
case 1:
k1 ^= uint32(tail[0])
k1 *= c1
k1 = bits.RotateLeft32(k1, 15)
k1 *= c2
h1 ^= k1
}
length := uint32(len(data))
h1 ^= length
h2 ^= length
h3 ^= length
h4 ^= length
h1 += h2 + h3 + h4
h2 += h1
h3 += h1
h4 += h1
h1 = fmix32(h1)
h2 = fmix32(h2)
h3 = fmix32(h3)
h4 = fmix32(h4)
h1 += h2 + h3 + h4
h2 += h1
h3 += h1
h4 += h1
return h1, h2, h3, h4
}
func murmur3X64_128(data []byte, seed uint32) (uint64, uint64) {
const (
c1 uint64 = 0x87c37b91114253d5
c2 uint64 = 0x4cf5ad432745937f
)
var h1, h2 uint64 = uint64(seed), uint64(seed)
nblocks := len(data) / 16
for i := 0; i < nblocks; i++ {
block := data[i*16:]
k1 := binary.LittleEndian.Uint64(block[0:8])
k2 := binary.LittleEndian.Uint64(block[8:16])
k1 *= c1
k1 = bits.RotateLeft64(k1, 31)
k1 *= c2
h1 ^= k1
h1 = bits.RotateLeft64(h1, 27)
h1 += h2
h1 = h1*5 + 0x52dce729
k2 *= c2
k2 = bits.RotateLeft64(k2, 33)
k2 *= c1
h2 ^= k2
h2 = bits.RotateLeft64(h2, 31)
h2 += h1
h2 = h2*5 + 0x38495ab5
}
tail := data[nblocks*16:]
var k1, k2 uint64
switch len(tail) & 15 {
case 15:
k2 ^= uint64(tail[14]) << 48
fallthrough
case 14:
k2 ^= uint64(tail[13]) << 40
fallthrough
case 13:
k2 ^= uint64(tail[12]) << 32
fallthrough
case 12:
k2 ^= uint64(tail[11]) << 24
fallthrough
case 11:
k2 ^= uint64(tail[10]) << 16
fallthrough
case 10:
k2 ^= uint64(tail[9]) << 8
fallthrough
case 9:
k2 ^= uint64(tail[8])
k2 *= c2
k2 = bits.RotateLeft64(k2, 33)
k2 *= c1
h2 ^= k2
fallthrough
case 8:
k1 ^= uint64(tail[7]) << 56
fallthrough
case 7:
k1 ^= uint64(tail[6]) << 48
fallthrough
case 6:
k1 ^= uint64(tail[5]) << 40
fallthrough
case 5:
k1 ^= uint64(tail[4]) << 32
fallthrough
case 4:
k1 ^= uint64(tail[3]) << 24
fallthrough
case 3:
k1 ^= uint64(tail[2]) << 16
fallthrough
case 2:
k1 ^= uint64(tail[1]) << 8
fallthrough
case 1:
k1 ^= uint64(tail[0])
k1 *= c1
k1 = bits.RotateLeft64(k1, 31)
k1 *= c2
h1 ^= k1
}
length := uint64(len(data))
h1 ^= length
h2 ^= length
h1 += h2
h2 += h1
h1 = fmix64(h1)
h2 = fmix64(h2)
h1 += h2
h2 += h1
return h1, h2
}
func pack128Little64(low, high uint64) *big.Int {
result := new(big.Int).SetUint64(high)
result.Lsh(result, 64)
result.Or(result, new(big.Int).SetUint64(low))
return result
}
func pack128Little32(h1, h2, h3, h4 uint32) *big.Int {
low := uint64(h1) | (uint64(h2) << 32)
high := uint64(h3) | (uint64(h4) << 32)
return pack128Little64(low, high)
}
func format128(value *big.Int, output OutputFormat) string {
if output == OutputNumber {
return value.Text(10)
}
return fmt.Sprintf("%032x", value)
}
func murmur3Hash(text string, bitLength int, arch string, seed uint32, output OutputFormat) string {
data := []byte(text)
if bitLength == 32 {
value := murmur3X86_32(data, seed)
if output == OutputNumber {
return strconv.FormatUint(uint64(value), 10)
}
return fmt.Sprintf("%08x", value)
}
if arch == "x64" {
h1, h2 := murmur3X64_128(data, seed)
return format128(pack128Little64(h1, h2), output)
}
h1, h2, h3, h4 := murmur3X86_128(data, seed)
return format128(pack128Little32(h1, h2, h3, h4), output)
}
func main() {
seed := parseSeed("0xdeadbeef")
fmt.Println(murmur3Hash("hello", 32, "x86", seed, OutputNumber))
fmt.Println(murmur3Hash("hello", 128, "x64", seed, OutputHex))
if murmur3Hash("hello", 32, "x86", 0, OutputNumber) != "613153351" {
panic("Murmur3 x86_32 mismatch")
}
if murmur3Hash("hello", 128, "x64", 0, OutputNumber) != "121118445609844952839898260755277781762" {
panic("Murmur3 x64_128 mismatch")
}
fmt.Println("MurmurHash3 tests passed")
}