// Package xxh32 implements the very fast XXH hashing algorithm (32 bits version). // (ported from the reference implementation https://github.com/Cyan4973/xxHash/)
package xxh32 import ( ) const ( prime1 uint32 = 2654435761 prime2 uint32 = 2246822519 prime3 uint32 = 3266489917 prime4 uint32 = 668265263 prime5 uint32 = 374761393 primeMask = 0xFFFFFFFF prime1plus2 = uint32((uint64(prime1) + uint64(prime2)) & primeMask) // 606290984 prime1minus = uint32((-int64(prime1)) & primeMask) // 1640531535 ) // XXHZero represents an xxhash32 object with seed 0. type XXHZero struct { v [4]uint32 totalLen uint64 buf [16]byte bufused int } // Sum appends the current hash to b and returns the resulting slice. // It does not change the underlying hash state. func ( XXHZero) ( []byte) []byte { := .Sum32() return append(, byte(), byte(>>8), byte(>>16), byte(>>24)) } // Reset resets the Hash to its initial state. func ( *XXHZero) () { .v[0] = prime1plus2 .v[1] = prime2 .v[2] = 0 .v[3] = prime1minus .totalLen = 0 .bufused = 0 } // Size returns the number of bytes returned by Sum(). func ( *XXHZero) () int { return 4 } // BlockSizeIndex gives the minimum number of bytes accepted by Write(). func ( *XXHZero) () int { return 1 } // Write adds input bytes to the Hash. // It never returns an error. func ( *XXHZero) ( []byte) (int, error) { if .totalLen == 0 { .Reset() } := len() := .bufused .totalLen += uint64() := len(.buf) - if < { copy(.buf[:], ) .bufused += len() return , nil } var *[16]byte if != 0 { // some data left from previous update = &.buf := copy([:], ) -= = [:] } update(&.v, , ) .bufused = copy(.buf[:], [-%16:]) return , nil } // Portable version of update. This updates v by processing all of buf // (if not nil) and all full 16-byte blocks of input. func updateGo( *[4]uint32, *[16]byte, []byte) { // Causes compiler to work directly from registers instead of stack: , , , := [0], [1], [2], [3] if != nil { = rol13(+binary.LittleEndian.Uint32([:])*prime2) * prime1 = rol13(+binary.LittleEndian.Uint32([4:])*prime2) * prime1 = rol13(+binary.LittleEndian.Uint32([8:])*prime2) * prime1 = rol13(+binary.LittleEndian.Uint32([12:])*prime2) * prime1 } for ; len() >= 16; = [16:] { := [:16] //BCE hint for compiler = rol13(+binary.LittleEndian.Uint32([:])*prime2) * prime1 = rol13(+binary.LittleEndian.Uint32([4:])*prime2) * prime1 = rol13(+binary.LittleEndian.Uint32([8:])*prime2) * prime1 = rol13(+binary.LittleEndian.Uint32([12:])*prime2) * prime1 } [0], [1], [2], [3] = , , , } // Sum32 returns the 32 bits Hash value. func ( *XXHZero) () uint32 { := uint32(.totalLen) if >= 16 { += rol1(.v[0]) + rol7(.v[1]) + rol12(.v[2]) + rol18(.v[3]) } else { += prime5 } := 0 := .bufused := .buf for := - 4; <= ; += 4 { += binary.LittleEndian.Uint32([:+4]) * prime3 = rol17() * prime4 } for ; < ; ++ { += uint32([]) * prime5 = rol11() * prime1 } ^= >> 15 *= prime2 ^= >> 13 *= prime3 ^= >> 16 return } // Portable version of ChecksumZero. func checksumZeroGo( []byte) uint32 { := len() := uint32() if < 16 { += prime5 } else { := prime1plus2 := prime2 := uint32(0) := prime1minus := 0 for := - 16; <= ; += 16 { := [:][:16] //BCE hint for compiler = rol13(+binary.LittleEndian.Uint32([:])*prime2) * prime1 = rol13(+binary.LittleEndian.Uint32([4:])*prime2) * prime1 = rol13(+binary.LittleEndian.Uint32([8:])*prime2) * prime1 = rol13(+binary.LittleEndian.Uint32([12:])*prime2) * prime1 } = [:] -= += rol1() + rol7() + rol12() + rol18() } := 0 for := - 4; <= ; += 4 { += binary.LittleEndian.Uint32([:+4]) * prime3 = rol17() * prime4 } for < { += uint32([]) * prime5 = rol11() * prime1 ++ } ^= >> 15 *= prime2 ^= >> 13 *= prime3 ^= >> 16 return } func rol1( uint32) uint32 { return <<1 | >>31 } func rol7( uint32) uint32 { return <<7 | >>25 } func rol11( uint32) uint32 { return <<11 | >>21 } func rol12( uint32) uint32 { return <<12 | >>20 } func rol13( uint32) uint32 { return <<13 | >>19 } func rol17( uint32) uint32 { return <<17 | >>15 } func rol18( uint32) uint32 { return <<18 | >>14 }