319 lines
5.8 KiB
Go
319 lines
5.8 KiB
Go
// Written in 2012-2014 by Dmitry Chestnykh.
|
|
//
|
|
// To the extent possible under law, the author have dedicated all copyright
|
|
// and related and neighboring rights to this software to the public domain
|
|
// worldwide. This software is distributed without any warranty.
|
|
// http://creativecommons.org/publicdomain/zero/1.0/
|
|
|
|
// Package siphash implements SipHash-2-4, a fast short-input PRF
|
|
// created by Jean-Philippe Aumasson and Daniel J. Bernstein.
|
|
package siphash
|
|
|
|
import "hash"
|
|
|
|
const (
|
|
// BlockSize is the block size of hash algorithm in bytes.
|
|
BlockSize = 8
|
|
|
|
// Size is the size of hash output in bytes.
|
|
Size = 8
|
|
|
|
// Size128 is the size of 128-bit hash output in bytes.
|
|
Size128 = 16
|
|
)
|
|
|
|
type digest struct {
|
|
v0, v1, v2, v3 uint64 // state
|
|
k0, k1 uint64 // two parts of key
|
|
x [8]byte // buffer for unprocessed bytes
|
|
nx int // number of bytes in buffer x
|
|
size int // output size in bytes (8 or 16)
|
|
t uint8 // message bytes counter (mod 256)
|
|
}
|
|
|
|
// newDigest returns a new digest with the given output size in bytes (must be 8 or 16).
|
|
func newDigest(size int, key []byte) *digest {
|
|
if size != Size && size != Size128 {
|
|
panic("size must be 8 or 16")
|
|
}
|
|
d := new(digest)
|
|
d.k0 = uint64(key[0]) | uint64(key[1])<<8 | uint64(key[2])<<16 | uint64(key[3])<<24 |
|
|
uint64(key[4])<<32 | uint64(key[5])<<40 | uint64(key[6])<<48 | uint64(key[7])<<56
|
|
d.k1 = uint64(key[8]) | uint64(key[9])<<8 | uint64(key[10])<<16 | uint64(key[11])<<24 |
|
|
uint64(key[12])<<32 | uint64(key[13])<<40 | uint64(key[14])<<48 | uint64(key[15])<<56
|
|
d.size = size
|
|
d.Reset()
|
|
return d
|
|
}
|
|
|
|
// New returns a new hash.Hash64 computing SipHash-2-4 with 16-byte key and 8-byte output.
|
|
func New(key []byte) hash.Hash64 {
|
|
return newDigest(Size, key)
|
|
}
|
|
|
|
// New128 returns a new hash.Hash computing SipHash-2-4 with 16-byte key and 16-byte output.
|
|
//
|
|
// Note that 16-byte output is considered experimental by SipHash authors at this time.
|
|
func New128(key []byte) hash.Hash {
|
|
return newDigest(Size128, key)
|
|
}
|
|
|
|
func (d *digest) Reset() {
|
|
d.v0 = d.k0 ^ 0x736f6d6570736575
|
|
d.v1 = d.k1 ^ 0x646f72616e646f6d
|
|
d.v2 = d.k0 ^ 0x6c7967656e657261
|
|
d.v3 = d.k1 ^ 0x7465646279746573
|
|
d.t = 0
|
|
d.nx = 0
|
|
if d.size == Size128 {
|
|
d.v1 ^= 0xee
|
|
}
|
|
}
|
|
|
|
func (d *digest) Size() int { return d.size }
|
|
|
|
func (d *digest) BlockSize() int { return BlockSize }
|
|
|
|
func (d *digest) Write(p []byte) (nn int, err error) {
|
|
nn = len(p)
|
|
d.t += uint8(nn)
|
|
if d.nx > 0 {
|
|
n := len(p)
|
|
if n > BlockSize-d.nx {
|
|
n = BlockSize - d.nx
|
|
}
|
|
d.nx += copy(d.x[d.nx:], p)
|
|
if d.nx == BlockSize {
|
|
once(d)
|
|
d.nx = 0
|
|
}
|
|
p = p[n:]
|
|
}
|
|
if len(p) >= BlockSize {
|
|
n := len(p) &^ (BlockSize - 1)
|
|
blocks(d, p[:n])
|
|
p = p[n:]
|
|
}
|
|
if len(p) > 0 {
|
|
d.nx = copy(d.x[:], p)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (d *digest) Sum64() uint64 {
|
|
for i := d.nx; i < BlockSize-1; i++ {
|
|
d.x[i] = 0
|
|
}
|
|
d.x[7] = d.t
|
|
return finalize(d)
|
|
}
|
|
|
|
func (d0 *digest) sum128() (r0, r1 uint64) {
|
|
// Make a copy of d0 so that caller can keep writing and summing.
|
|
d := *d0
|
|
|
|
for i := d.nx; i < BlockSize-1; i++ {
|
|
d.x[i] = 0
|
|
}
|
|
d.x[7] = d.t
|
|
blocks(&d, d.x[:])
|
|
|
|
v0, v1, v2, v3 := d.v0, d.v1, d.v2, d.v3
|
|
v2 ^= 0xee
|
|
|
|
// Round 1.
|
|
v0 += v1
|
|
v1 = v1<<13 | v1>>(64-13)
|
|
v1 ^= v0
|
|
v0 = v0<<32 | v0>>(64-32)
|
|
|
|
v2 += v3
|
|
v3 = v3<<16 | v3>>(64-16)
|
|
v3 ^= v2
|
|
|
|
v0 += v3
|
|
v3 = v3<<21 | v3>>(64-21)
|
|
v3 ^= v0
|
|
|
|
v2 += v1
|
|
v1 = v1<<17 | v1>>(64-17)
|
|
v1 ^= v2
|
|
v2 = v2<<32 | v2>>(64-32)
|
|
|
|
// Round 2.
|
|
v0 += v1
|
|
v1 = v1<<13 | v1>>(64-13)
|
|
v1 ^= v0
|
|
v0 = v0<<32 | v0>>(64-32)
|
|
|
|
v2 += v3
|
|
v3 = v3<<16 | v3>>(64-16)
|
|
v3 ^= v2
|
|
|
|
v0 += v3
|
|
v3 = v3<<21 | v3>>(64-21)
|
|
v3 ^= v0
|
|
|
|
v2 += v1
|
|
v1 = v1<<17 | v1>>(64-17)
|
|
v1 ^= v2
|
|
v2 = v2<<32 | v2>>(64-32)
|
|
|
|
// Round 3.
|
|
v0 += v1
|
|
v1 = v1<<13 | v1>>(64-13)
|
|
v1 ^= v0
|
|
v0 = v0<<32 | v0>>(64-32)
|
|
|
|
v2 += v3
|
|
v3 = v3<<16 | v3>>(64-16)
|
|
v3 ^= v2
|
|
|
|
v0 += v3
|
|
v3 = v3<<21 | v3>>(64-21)
|
|
v3 ^= v0
|
|
|
|
v2 += v1
|
|
v1 = v1<<17 | v1>>(64-17)
|
|
v1 ^= v2
|
|
v2 = v2<<32 | v2>>(64-32)
|
|
|
|
// Round 4.
|
|
v0 += v1
|
|
v1 = v1<<13 | v1>>(64-13)
|
|
v1 ^= v0
|
|
v0 = v0<<32 | v0>>(64-32)
|
|
|
|
v2 += v3
|
|
v3 = v3<<16 | v3>>(64-16)
|
|
v3 ^= v2
|
|
|
|
v0 += v3
|
|
v3 = v3<<21 | v3>>(64-21)
|
|
v3 ^= v0
|
|
|
|
v2 += v1
|
|
v1 = v1<<17 | v1>>(64-17)
|
|
v1 ^= v2
|
|
v2 = v2<<32 | v2>>(64-32)
|
|
|
|
r0 = v0 ^ v1 ^ v2 ^ v3
|
|
|
|
v1 ^= 0xdd
|
|
|
|
// Round 1.
|
|
v0 += v1
|
|
v1 = v1<<13 | v1>>(64-13)
|
|
v1 ^= v0
|
|
v0 = v0<<32 | v0>>(64-32)
|
|
|
|
v2 += v3
|
|
v3 = v3<<16 | v3>>(64-16)
|
|
v3 ^= v2
|
|
|
|
v0 += v3
|
|
v3 = v3<<21 | v3>>(64-21)
|
|
v3 ^= v0
|
|
|
|
v2 += v1
|
|
v1 = v1<<17 | v1>>(64-17)
|
|
v1 ^= v2
|
|
v2 = v2<<32 | v2>>(64-32)
|
|
|
|
// Round 2.
|
|
v0 += v1
|
|
v1 = v1<<13 | v1>>(64-13)
|
|
v1 ^= v0
|
|
v0 = v0<<32 | v0>>(64-32)
|
|
|
|
v2 += v3
|
|
v3 = v3<<16 | v3>>(64-16)
|
|
v3 ^= v2
|
|
|
|
v0 += v3
|
|
v3 = v3<<21 | v3>>(64-21)
|
|
v3 ^= v0
|
|
|
|
v2 += v1
|
|
v1 = v1<<17 | v1>>(64-17)
|
|
v1 ^= v2
|
|
v2 = v2<<32 | v2>>(64-32)
|
|
|
|
// Round 3.
|
|
v0 += v1
|
|
v1 = v1<<13 | v1>>(64-13)
|
|
v1 ^= v0
|
|
v0 = v0<<32 | v0>>(64-32)
|
|
|
|
v2 += v3
|
|
v3 = v3<<16 | v3>>(64-16)
|
|
v3 ^= v2
|
|
|
|
v0 += v3
|
|
v3 = v3<<21 | v3>>(64-21)
|
|
v3 ^= v0
|
|
|
|
v2 += v1
|
|
v1 = v1<<17 | v1>>(64-17)
|
|
v1 ^= v2
|
|
v2 = v2<<32 | v2>>(64-32)
|
|
|
|
// Round 4.
|
|
v0 += v1
|
|
v1 = v1<<13 | v1>>(64-13)
|
|
v1 ^= v0
|
|
v0 = v0<<32 | v0>>(64-32)
|
|
|
|
v2 += v3
|
|
v3 = v3<<16 | v3>>(64-16)
|
|
v3 ^= v2
|
|
|
|
v0 += v3
|
|
v3 = v3<<21 | v3>>(64-21)
|
|
v3 ^= v0
|
|
|
|
v2 += v1
|
|
v1 = v1<<17 | v1>>(64-17)
|
|
v1 ^= v2
|
|
v2 = v2<<32 | v2>>(64-32)
|
|
|
|
r1 = v0 ^ v1 ^ v2 ^ v3
|
|
|
|
return r0, r1
|
|
}
|
|
|
|
func (d *digest) Sum(in []byte) []byte {
|
|
if d.size == Size {
|
|
r := d.Sum64()
|
|
in = append(in,
|
|
byte(r),
|
|
byte(r>>8),
|
|
byte(r>>16),
|
|
byte(r>>24),
|
|
byte(r>>32),
|
|
byte(r>>40),
|
|
byte(r>>48),
|
|
byte(r>>56))
|
|
} else {
|
|
r0, r1 := d.sum128()
|
|
in = append(in,
|
|
byte(r0),
|
|
byte(r0>>8),
|
|
byte(r0>>16),
|
|
byte(r0>>24),
|
|
byte(r0>>32),
|
|
byte(r0>>40),
|
|
byte(r0>>48),
|
|
byte(r0>>56),
|
|
byte(r1),
|
|
byte(r1>>8),
|
|
byte(r1>>16),
|
|
byte(r1>>24),
|
|
byte(r1>>32),
|
|
byte(r1>>40),
|
|
byte(r1>>48),
|
|
byte(r1>>56))
|
|
}
|
|
return in
|
|
}
|