// Package xxhash implements the 64-bit variant of xxHash (XXH64) as described // at http://cyan4973.github.io/xxHash/.
package xxhash import ( ) const ( prime1 uint64 = 11400714785074694791 prime2 uint64 = 14029467366897019727 prime3 uint64 = 1609587929392839161 prime4 uint64 = 9650029242287828579 prime5 uint64 = 2870177450012600261 ) // Store the primes in an array as well. // // The consts are used when possible in Go code to avoid MOVs but we need a // contiguous array for the assembly code. var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5} // Digest implements hash.Hash64. // // Note that a zero-valued Digest is not ready to receive writes. // Call Reset or create a Digest using New before calling other methods. type Digest struct { v1 uint64 v2 uint64 v3 uint64 v4 uint64 total uint64 mem [32]byte n int // how much of mem is used } // New creates a new Digest with a zero seed. func () *Digest { return NewWithSeed(0) } // NewWithSeed creates a new Digest with the given seed. func ( uint64) *Digest { var Digest .ResetWithSeed() return & } // Reset clears the Digest's state so that it can be reused. // It uses a seed value of zero. func ( *Digest) () { .ResetWithSeed(0) } // ResetWithSeed clears the Digest's state so that it can be reused. // It uses the given seed to initialize the state. func ( *Digest) ( uint64) { .v1 = + prime1 + prime2 .v2 = + prime2 .v3 = .v4 = - prime1 .total = 0 .n = 0 } // Size always returns 8 bytes. func ( *Digest) () int { return 8 } // BlockSize always returns 32 bytes. func ( *Digest) () int { return 32 } // Write adds more data to d. It always returns len(b), nil. func ( *Digest) ( []byte) ( int, error) { = len() .total += uint64() := .mem[.n&(len(.mem)-1):] if .n+ < 32 { // This new data doesn't even fill the current block. copy(, ) .n += return } if .n > 0 { // Finish off the partial block. := copy(, ) .v1 = round(.v1, u64(.mem[0:8])) .v2 = round(.v2, u64(.mem[8:16])) .v3 = round(.v3, u64(.mem[16:24])) .v4 = round(.v4, u64(.mem[24:32])) = [:] .n = 0 } if len() >= 32 { // One or more full blocks left. := writeBlocks(, ) = [:] } // Store any remaining partial block. copy(.mem[:], ) .n = len() return } // Sum appends the current hash to b and returns the resulting slice. func ( *Digest) ( []byte) []byte { := .Sum64() return append( , byte(>>56), byte(>>48), byte(>>40), byte(>>32), byte(>>24), byte(>>16), byte(>>8), byte(), ) } // Sum64 returns the current hash. func ( *Digest) () uint64 { var uint64 if .total >= 32 { , , , := .v1, .v2, .v3, .v4 = rol1() + rol7() + rol12() + rol18() = mergeRound(, ) = mergeRound(, ) = mergeRound(, ) = mergeRound(, ) } else { = .v3 + prime5 } += .total := .mem[:.n&(len(.mem)-1)] for ; len() >= 8; = [8:] { := round(0, u64([:8])) ^= = rol27()*prime1 + prime4 } if len() >= 4 { ^= uint64(u32([:4])) * prime1 = rol23()*prime2 + prime3 = [4:] } for ; len() > 0; = [1:] { ^= uint64([0]) * prime5 = rol11() * prime1 } ^= >> 33 *= prime2 ^= >> 29 *= prime3 ^= >> 32 return } const ( magic = "xxh\x06" marshaledSize = len(magic) + 8*5 + 32 ) // MarshalBinary implements the encoding.BinaryMarshaler interface. func ( *Digest) () ([]byte, error) { := make([]byte, 0, marshaledSize) = append(, magic...) = appendUint64(, .v1) = appendUint64(, .v2) = appendUint64(, .v3) = appendUint64(, .v4) = appendUint64(, .total) = append(, .mem[:.n]...) = [:len()+len(.mem)-.n] return , nil } // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. func ( *Digest) ( []byte) error { if len() < len(magic) || string([:len(magic)]) != magic { return errors.New("xxhash: invalid hash state identifier") } if len() != marshaledSize { return errors.New("xxhash: invalid hash state size") } = [len(magic):] , .v1 = consumeUint64() , .v2 = consumeUint64() , .v3 = consumeUint64() , .v4 = consumeUint64() , .total = consumeUint64() copy(.mem[:], ) .n = int(.total % uint64(len(.mem))) return nil } func appendUint64( []byte, uint64) []byte { var [8]byte binary.LittleEndian.PutUint64([:], ) return append(, [:]...) } func consumeUint64( []byte) ([]byte, uint64) { := u64() return [8:], } func u64( []byte) uint64 { return binary.LittleEndian.Uint64() } func u32( []byte) uint32 { return binary.LittleEndian.Uint32() } func round(, uint64) uint64 { += * prime2 = rol31() *= prime1 return } func mergeRound(, uint64) uint64 { = round(0, ) ^= = *prime1 + prime4 return } func rol1( uint64) uint64 { return bits.RotateLeft64(, 1) } func rol7( uint64) uint64 { return bits.RotateLeft64(, 7) } func rol11( uint64) uint64 { return bits.RotateLeft64(, 11) } func rol12( uint64) uint64 { return bits.RotateLeft64(, 12) } func rol18( uint64) uint64 { return bits.RotateLeft64(, 18) } func rol23( uint64) uint64 { return bits.RotateLeft64(, 23) } func rol27( uint64) uint64 { return bits.RotateLeft64(, 27) } func rol31( uint64) uint64 { return bits.RotateLeft64(, 31) }