Files
picomap/lib/halfsiphash/halfsiphash.go

75 lines
1.3 KiB
Go
Raw Normal View History

package halfsiphash
import "encoding/binary"
func rotl(x uint32, b uint) uint32 {
return (x << b) | (x >> (32 - b))
}
func sipround(v0, v1, v2, v3 *uint32) {
*v0 += *v1
*v1 = rotl(*v1, 5)
*v1 ^= *v0
*v0 = rotl(*v0, 16)
*v2 += *v3
*v3 = rotl(*v3, 8)
*v3 ^= *v2
*v0 += *v3
*v3 = rotl(*v3, 7)
*v3 ^= *v0
*v2 += *v1
*v1 = rotl(*v1, 13)
*v1 ^= *v2
*v2 = rotl(*v2, 16)
}
// Sum32 computes HalfSipHash-2-4 with an 8-byte key and returns a 4-byte hash.
func Sum32(data []byte, key [8]byte) uint32 {
k0 := binary.LittleEndian.Uint32(key[0:4])
k1 := binary.LittleEndian.Uint32(key[4:8])
v0 := uint32(0) ^ k0
v1 := uint32(0) ^ k1
v2 := uint32(0x6c796765) ^ k0
v3 := uint32(0x74656462) ^ k1
// Process full 4-byte blocks.
nblocks := len(data) / 4
for i := 0; i < nblocks; i++ {
m := binary.LittleEndian.Uint32(data[i*4:])
v3 ^= m
for j := 0; j < 2; j++ {
sipround(&v0, &v1, &v2, &v3)
}
v0 ^= m
}
// Process remaining bytes.
b := uint32(len(data)) << 24
tail := data[nblocks*4:]
switch len(tail) {
case 3:
b |= uint32(tail[2]) << 16
fallthrough
case 2:
b |= uint32(tail[1]) << 8
fallthrough
case 1:
b |= uint32(tail[0])
}
v3 ^= b
for i := 0; i < 2; i++ {
sipround(&v0, &v1, &v2, &v3)
}
v0 ^= b
v2 ^= 0xff
for i := 0; i < 4; i++ {
sipround(&v0, &v1, &v2, &v3)
}
return v1 ^ v3
}