Go CityHash64 Code Example (Online Runner)

Go CityHash64 examples with decimal output and file hashing to match the CityHash tools.

Online calculator: use the site CityHash text tool.

Calculation method

CityHash64 returns a 64-bit integer. The tool displays the unsigned decimal value.

Implementation notes

  • Package: no external dependencies; this is a pure Go CityHash64 implementation.
  • Implementation: output is formatted as an unsigned base-10 string.
  • Notes: CityHash is not cryptographic; use it for hash tables or checksums only.

Text hashing example

go
package main

import (
	"encoding/binary"
	"fmt"
	"math/bits"
	"strconv"
)

const (
	k0 uint64 = 0xc3a5c85c97cb3127
	k1 uint64 = 0xb492b66fbe98f273
	k2 uint64 = 0x9ae16a3b2f90404f
	k3 uint64 = 0xc949d7c7509e6557
)

type uint128 struct {
	first  uint64
	second uint64
}

func rotate(val uint64, shift uint) uint64 {
	if shift == 0 {
		return val
	}
	return bits.RotateLeft64(val, int(shift))
}

func shiftMix(val uint64) uint64 {
	return val ^ (val >> 47)
}

func fetch64(data []byte, offset int) uint64 {
	return binary.LittleEndian.Uint64(data[offset:])
}

func fetch32(data []byte, offset int) uint64 {
	return uint64(binary.LittleEndian.Uint32(data[offset:]))
}

func hash128to64(x uint128) uint64 {
	const kMul uint64 = 0x9ddfea08eb382d69
	a := (x.first ^ x.second) * kMul
	a ^= a >> 47
	b := (x.second ^ a) * kMul
	b ^= b >> 47
	b *= kMul
	return b
}

func hashLen16(u, v uint64) uint64 {
	return hash128to64(uint128{first: u, second: v})
}

func hashLen0to16(s []byte) uint64 {
	length := len(s)
	if length > 8 {
		a := fetch64(s, 0)
		b := fetch64(s, length-8)
		return hashLen16(a, rotate(b+uint64(length), uint(length))) ^ b
	}
	if length >= 4 {
		a := fetch32(s, 0)
		return hashLen16(uint64(length)+(a<<3), fetch32(s, length-4))
	}
	if length > 0 {
		a := uint64(s[0])
		b := uint64(s[length>>1])
		c := uint64(s[length-1])
		y := a + (b << 8)
		z := uint64(length) + (c << 2)
		return shiftMix(y*k2^z*k3) * k2
	}
	return k2
}

func hashLen17to32(s []byte) uint64 {
	length := len(s)
	a := fetch64(s, 0) * k1
	b := fetch64(s, 8)
	c := fetch64(s, length-8) * k2
	d := fetch64(s, length-16) * k0
	return hashLen16(rotate(a-b, 43)+rotate(c, 30)+d, a+rotate(b^k3, 20)-c+uint64(length))
}

func weakHashLen32WithSeeds(w, x, y, z, a, b uint64) uint128 {
	a += w
	b = rotate(b+a+z, 21)
	c := a
	a += x
	a += y
	b += rotate(a, 44)
	return uint128{first: a + z, second: b + c}
}

func weakHashLen32WithSeedsFromArray(s []byte, offset int, a, b uint64) uint128 {
	return weakHashLen32WithSeeds(
		fetch64(s, offset),
		fetch64(s, offset+8),
		fetch64(s, offset+16),
		fetch64(s, offset+24),
		a,
		b,
	)
}

func hashLen33to64(s []byte) uint64 {
	length := len(s)
	z := fetch64(s, 24)
	a := fetch64(s, 0) + (uint64(length)+fetch64(s, length-16))*k0
	b := rotate(a+z, 52)
	c := rotate(a, 37)
	a += fetch64(s, 8)
	c += rotate(a, 7)
	a += fetch64(s, 16)
	vf := a + z
	vs := b + rotate(a, 31) + c
	a = fetch64(s, 16) + fetch64(s, length-32)
	z2 := fetch64(s, length-8)
	b = rotate(a+z2, 52)
	c = rotate(a, 37)
	a += fetch64(s, length-24)
	c += rotate(a, 7)
	a += fetch64(s, length-16)
	wf := a + z2
	ws := b + rotate(a, 31) + c
	r := shiftMix((vf+ws)*k2 + (wf+vs)*k0)
	return shiftMix(r*k0+vs) * k2
}

func cityHash64(data []byte) uint64 {
	length := len(data)
	if length <= 32 {
		if length <= 16 {
			return hashLen0to16(data)
		}
		return hashLen17to32(data)
	}
	if length <= 64 {
		return hashLen33to64(data)
	}

	x := fetch64(data, 0)
	y := fetch64(data, length-16) ^ k1
	z := fetch64(data, length-56) ^ k0
	v := weakHashLen32WithSeedsFromArray(data, length-64, uint64(length), y)
	w := weakHashLen32WithSeedsFromArray(data, length-32, uint64(length)*k1, k0)
	z += shiftMix(v.second) * k1
	x = rotate(z+x, 39) * k1
	y = rotate(y, 33) * k1

	currentLen := (length - 1) &^ 63
	offset := 0
	for currentLen > 0 {
		x = rotate(x+y+v.first+fetch64(data, offset+16), 37) * k1
		y = rotate(y+v.second+fetch64(data, offset+48), 42) * k1
		x ^= w.second
		y ^= v.first
		z = rotate(z^w.first, 33)
		v = weakHashLen32WithSeedsFromArray(data, offset, v.second*k1, x+w.first)
		w = weakHashLen32WithSeedsFromArray(data, offset+32, z+w.second, y)
		z, x = x, z
		offset += 64
		currentLen -= 64
	}

	return hashLen16(hashLen16(v.first, w.first)+shiftMix(y)*k1+z, hashLen16(v.second, w.second)+x)
}

func cityHash64Text(text string) string {
	value := cityHash64([]byte(text))
	return strconv.FormatUint(value, 10)
}

func main() {
	fmt.Println(cityHash64Text("hello"))
}

File hashing example

go
package main

import (
	"encoding/binary"
	"fmt"
	"math/bits"
	"os"
	"strconv"
)

const (
	k0 uint64 = 0xc3a5c85c97cb3127
	k1 uint64 = 0xb492b66fbe98f273
	k2 uint64 = 0x9ae16a3b2f90404f
	k3 uint64 = 0xc949d7c7509e6557
)

type uint128 struct {
	first  uint64
	second uint64
}

func rotate(val uint64, shift uint) uint64 {
	if shift == 0 {
		return val
	}
	return bits.RotateLeft64(val, int(shift))
}

func shiftMix(val uint64) uint64 {
	return val ^ (val >> 47)
}

func fetch64(data []byte, offset int) uint64 {
	return binary.LittleEndian.Uint64(data[offset:])
}

func fetch32(data []byte, offset int) uint64 {
	return uint64(binary.LittleEndian.Uint32(data[offset:]))
}

func hash128to64(x uint128) uint64 {
	const kMul uint64 = 0x9ddfea08eb382d69
	a := (x.first ^ x.second) * kMul
	a ^= a >> 47
	b := (x.second ^ a) * kMul
	b ^= b >> 47
	b *= kMul
	return b
}

func hashLen16(u, v uint64) uint64 {
	return hash128to64(uint128{first: u, second: v})
}

func hashLen0to16(s []byte) uint64 {
	length := len(s)
	if length > 8 {
		a := fetch64(s, 0)
		b := fetch64(s, length-8)
		return hashLen16(a, rotate(b+uint64(length), uint(length))) ^ b
	}
	if length >= 4 {
		a := fetch32(s, 0)
		return hashLen16(uint64(length)+(a<<3), fetch32(s, length-4))
	}
	if length > 0 {
		a := uint64(s[0])
		b := uint64(s[length>>1])
		c := uint64(s[length-1])
		y := a + (b << 8)
		z := uint64(length) + (c << 2)
		return shiftMix(y*k2^z*k3) * k2
	}
	return k2
}

func hashLen17to32(s []byte) uint64 {
	length := len(s)
	a := fetch64(s, 0) * k1
	b := fetch64(s, 8)
	c := fetch64(s, length-8) * k2
	d := fetch64(s, length-16) * k0
	return hashLen16(rotate(a-b, 43)+rotate(c, 30)+d, a+rotate(b^k3, 20)-c+uint64(length))
}

func weakHashLen32WithSeeds(w, x, y, z, a, b uint64) uint128 {
	a += w
	b = rotate(b+a+z, 21)
	c := a
	a += x
	a += y
	b += rotate(a, 44)
	return uint128{first: a + z, second: b + c}
}

func weakHashLen32WithSeedsFromArray(s []byte, offset int, a, b uint64) uint128 {
	return weakHashLen32WithSeeds(
		fetch64(s, offset),
		fetch64(s, offset+8),
		fetch64(s, offset+16),
		fetch64(s, offset+24),
		a,
		b,
	)
}

func hashLen33to64(s []byte) uint64 {
	length := len(s)
	z := fetch64(s, 24)
	a := fetch64(s, 0) + (uint64(length)+fetch64(s, length-16))*k0
	b := rotate(a+z, 52)
	c := rotate(a, 37)
	a += fetch64(s, 8)
	c += rotate(a, 7)
	a += fetch64(s, 16)
	vf := a + z
	vs := b + rotate(a, 31) + c
	a = fetch64(s, 16) + fetch64(s, length-32)
	z2 := fetch64(s, length-8)
	b = rotate(a+z2, 52)
	c = rotate(a, 37)
	a += fetch64(s, length-24)
	c += rotate(a, 7)
	a += fetch64(s, length-16)
	wf := a + z2
	ws := b + rotate(a, 31) + c
	r := shiftMix((vf+ws)*k2 + (wf+vs)*k0)
	return shiftMix(r*k0+vs) * k2
}

func cityHash64(data []byte) uint64 {
	length := len(data)
	if length <= 32 {
		if length <= 16 {
			return hashLen0to16(data)
		}
		return hashLen17to32(data)
	}
	if length <= 64 {
		return hashLen33to64(data)
	}

	x := fetch64(data, 0)
	y := fetch64(data, length-16) ^ k1
	z := fetch64(data, length-56) ^ k0
	v := weakHashLen32WithSeedsFromArray(data, length-64, uint64(length), y)
	w := weakHashLen32WithSeedsFromArray(data, length-32, uint64(length)*k1, k0)
	z += shiftMix(v.second) * k1
	x = rotate(z+x, 39) * k1
	y = rotate(y, 33) * k1

	currentLen := (length - 1) &^ 63
	offset := 0
	for currentLen > 0 {
		x = rotate(x+y+v.first+fetch64(data, offset+16), 37) * k1
		y = rotate(y+v.second+fetch64(data, offset+48), 42) * k1
		x ^= w.second
		y ^= v.first
		z = rotate(z^w.first, 33)
		v = weakHashLen32WithSeedsFromArray(data, offset, v.second*k1, x+w.first)
		w = weakHashLen32WithSeedsFromArray(data, offset+32, z+w.second, y)
		z, x = x, z
		offset += 64
		currentLen -= 64
	}

	return hashLen16(hashLen16(v.first, w.first)+shiftMix(y)*k1+z, hashLen16(v.second, w.second)+x)
}

func cityHash64File(path string) (string, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return "", err
	}
	value := cityHash64(data)
	return strconv.FormatUint(value, 10), nil
}

func main() {
	file, err := os.CreateTemp("", "cityhash-example-*.bin")
	if err != nil {
		panic(err)
	}
	defer os.Remove(file.Name())
	file.WriteString("hello")
	file.Close()

	value, err := cityHash64File(file.Name())
	if err != nil {
		panic(err)
	}
	fmt.Println(value)
}

Complete script (implementation + tests)

go
package main

import (
	"encoding/binary"
	"fmt"
	"math/bits"
	"os"
	"strconv"
)

const (
	k0 uint64 = 0xc3a5c85c97cb3127
	k1 uint64 = 0xb492b66fbe98f273
	k2 uint64 = 0x9ae16a3b2f90404f
	k3 uint64 = 0xc949d7c7509e6557
)

type uint128 struct {
	first  uint64
	second uint64
}

func rotate(val uint64, shift uint) uint64 {
	if shift == 0 {
		return val
	}
	return bits.RotateLeft64(val, int(shift))
}

func shiftMix(val uint64) uint64 {
	return val ^ (val >> 47)
}

func fetch64(data []byte, offset int) uint64 {
	return binary.LittleEndian.Uint64(data[offset:])
}

func fetch32(data []byte, offset int) uint64 {
	return uint64(binary.LittleEndian.Uint32(data[offset:]))
}

func hash128to64(x uint128) uint64 {
	const kMul uint64 = 0x9ddfea08eb382d69
	a := (x.first ^ x.second) * kMul
	a ^= a >> 47
	b := (x.second ^ a) * kMul
	b ^= b >> 47
	b *= kMul
	return b
}

func hashLen16(u, v uint64) uint64 {
	return hash128to64(uint128{first: u, second: v})
}

func hashLen0to16(s []byte) uint64 {
	length := len(s)
	if length > 8 {
		a := fetch64(s, 0)
		b := fetch64(s, length-8)
		return hashLen16(a, rotate(b+uint64(length), uint(length))) ^ b
	}
	if length >= 4 {
		a := fetch32(s, 0)
		return hashLen16(uint64(length)+(a<<3), fetch32(s, length-4))
	}
	if length > 0 {
		a := uint64(s[0])
		b := uint64(s[length>>1])
		c := uint64(s[length-1])
		y := a + (b << 8)
		z := uint64(length) + (c << 2)
		return shiftMix(y*k2^z*k3) * k2
	}
	return k2
}

func hashLen17to32(s []byte) uint64 {
	length := len(s)
	a := fetch64(s, 0) * k1
	b := fetch64(s, 8)
	c := fetch64(s, length-8) * k2
	d := fetch64(s, length-16) * k0
	return hashLen16(rotate(a-b, 43)+rotate(c, 30)+d, a+rotate(b^k3, 20)-c+uint64(length))
}

func weakHashLen32WithSeeds(w, x, y, z, a, b uint64) uint128 {
	a += w
	b = rotate(b+a+z, 21)
	c := a
	a += x
	a += y
	b += rotate(a, 44)
	return uint128{first: a + z, second: b + c}
}

func weakHashLen32WithSeedsFromArray(s []byte, offset int, a, b uint64) uint128 {
	return weakHashLen32WithSeeds(
		fetch64(s, offset),
		fetch64(s, offset+8),
		fetch64(s, offset+16),
		fetch64(s, offset+24),
		a,
		b,
	)
}

func hashLen33to64(s []byte) uint64 {
	length := len(s)
	z := fetch64(s, 24)
	a := fetch64(s, 0) + (uint64(length)+fetch64(s, length-16))*k0
	b := rotate(a+z, 52)
	c := rotate(a, 37)
	a += fetch64(s, 8)
	c += rotate(a, 7)
	a += fetch64(s, 16)
	vf := a + z
	vs := b + rotate(a, 31) + c
	a = fetch64(s, 16) + fetch64(s, length-32)
	z2 := fetch64(s, length-8)
	b = rotate(a+z2, 52)
	c = rotate(a, 37)
	a += fetch64(s, length-24)
	c += rotate(a, 7)
	a += fetch64(s, length-16)
	wf := a + z2
	ws := b + rotate(a, 31) + c
	r := shiftMix((vf+ws)*k2 + (wf+vs)*k0)
	return shiftMix(r*k0+vs) * k2
}

func cityHash64(data []byte) uint64 {
	length := len(data)
	if length <= 32 {
		if length <= 16 {
			return hashLen0to16(data)
		}
		return hashLen17to32(data)
	}
	if length <= 64 {
		return hashLen33to64(data)
	}

	x := fetch64(data, 0)
	y := fetch64(data, length-16) ^ k1
	z := fetch64(data, length-56) ^ k0
	v := weakHashLen32WithSeedsFromArray(data, length-64, uint64(length), y)
	w := weakHashLen32WithSeedsFromArray(data, length-32, uint64(length)*k1, k0)
	z += shiftMix(v.second) * k1
	x = rotate(z+x, 39) * k1
	y = rotate(y, 33) * k1

	currentLen := (length - 1) &^ 63
	offset := 0
	for currentLen > 0 {
		x = rotate(x+y+v.first+fetch64(data, offset+16), 37) * k1
		y = rotate(y+v.second+fetch64(data, offset+48), 42) * k1
		x ^= w.second
		y ^= v.first
		z = rotate(z^w.first, 33)
		v = weakHashLen32WithSeedsFromArray(data, offset, v.second*k1, x+w.first)
		w = weakHashLen32WithSeedsFromArray(data, offset+32, z+w.second, y)
		z, x = x, z
		offset += 64
		currentLen -= 64
	}

	return hashLen16(hashLen16(v.first, w.first)+shiftMix(y)*k1+z, hashLen16(v.second, w.second)+x)
}

func cityHash64Text(text string) string {
	value := cityHash64([]byte(text))
	return strconv.FormatUint(value, 10)
}

func cityHash64File(path string) (string, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return "", err
	}
	value := cityHash64(data)
	return strconv.FormatUint(value, 10), nil
}

func main() {
	fmt.Println("cityhash64=", cityHash64Text("hello"))

	file, err := os.CreateTemp("", "cityhash-example-*.bin")
	if err != nil {
		panic(err)
	}
	defer os.Remove(file.Name())
	file.WriteString("hello")
	file.Close()

	fileHash, err := cityHash64File(file.Name())
	if err != nil {
		panic(err)
	}
	fmt.Println("cityhash64(file)=", fileHash)
}