Add msgpack wire protocol with halfsiphash checksums
This commit is contained in:
74
lib/halfsiphash/halfsiphash.go
Normal file
74
lib/halfsiphash/halfsiphash.go
Normal file
@@ -0,0 +1,74 @@
|
||||
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
|
||||
}
|
||||
31
lib/halfsiphash/halfsiphash_test.go
Normal file
31
lib/halfsiphash/halfsiphash_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package halfsiphash
|
||||
|
||||
import "testing"
|
||||
|
||||
// Test vectors from the reference implementation.
|
||||
// Key: 00 01 02 03 04 05 06 07
|
||||
// Input: sequence 00, 00 01, 00 01 02, ...
|
||||
var vectors32 = []uint32{
|
||||
0x5b9f35a9,
|
||||
0xb85a4727,
|
||||
0x03a662fa,
|
||||
0x04e7fe8a,
|
||||
0x89466e2a,
|
||||
0x69b6fac5,
|
||||
0x23fc6358,
|
||||
0xc563cf8b,
|
||||
}
|
||||
|
||||
func TestSum32(t *testing.T) {
|
||||
key := [8]byte{0, 1, 2, 3, 4, 5, 6, 7}
|
||||
for i, want := range vectors32 {
|
||||
data := make([]byte, i)
|
||||
for j := range data {
|
||||
data[j] = byte(j)
|
||||
}
|
||||
got := Sum32(data, key)
|
||||
if got != want {
|
||||
t.Errorf("Sum32(len=%d) = %08x, want %08x", i, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user