github.com/bytedance/gopkg@v0.0.0-20240514070511-01b2cbcf35e1/util/xxhash3/hash128.go (about)

     1  // Copyright 2021 ByteDance Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package xxhash3 implements https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h
    16  package xxhash3
    17  
    18  import (
    19  	"math/bits"
    20  	"unsafe"
    21  
    22  	"github.com/bytedance/gopkg/internal/hack"
    23  	"github.com/bytedance/gopkg/internal/runtimex"
    24  )
    25  
    26  // Hash128 returns the hash value of the byte slice in 128bits.
    27  func Hash128(data []byte) [2]uint64 {
    28  	funcPointer := hashSmall
    29  
    30  	if len(data) > 16 {
    31  		funcPointer = hashLarge
    32  	}
    33  	return hashfunc128[funcPointer](*(*unsafe.Pointer)(unsafe.Pointer(&data)), len(data))
    34  
    35  }
    36  
    37  // Hash128String returns the hash value of the string in 128bits.
    38  func Hash128String(s string) [2]uint64 {
    39  	return Hash128(hack.StringToBytes(s))
    40  }
    41  
    42  func xxh3HashSmall128(xinput unsafe.Pointer, l int) [2]uint64 {
    43  	length := uint64(l)
    44  	var h128Low64 uint64
    45  	var h128High64 uint64
    46  
    47  	if length > 8 {
    48  		bitflipl := xsecret_032 ^ xsecret_040
    49  		bitfliph := xsecret_048 ^ xsecret_056
    50  		inputLow := runtimex.ReadUnaligned64(xinput)
    51  		inputHigh := runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput) + uintptr(length) - 8))
    52  		m128High64, m128Low64 := bits.Mul64(inputLow^inputHigh^bitflipl, prime64_1)
    53  
    54  		m128Low64 += uint64(length-1) << 54
    55  		inputHigh ^= bitfliph
    56  
    57  		m128High64 += inputHigh + uint64(uint32(inputHigh))*(prime32_2-1)
    58  		m128Low64 ^= bits.ReverseBytes64(m128High64)
    59  
    60  		h128High64, h128Low64 = bits.Mul64(m128Low64, prime64_2)
    61  		h128High64 += m128High64 * prime64_2
    62  
    63  		h128Low64 = xxh3Avalanche(h128Low64)
    64  		h128High64 = xxh3Avalanche(h128High64)
    65  
    66  		return [2]uint64{h128High64, h128Low64}
    67  	} else if length >= 4 {
    68  		inputLow := runtimex.ReadUnaligned32(xinput)
    69  		inputHigh := runtimex.ReadUnaligned32(unsafe.Pointer(uintptr(xinput) + uintptr(length) - 4))
    70  		input64 := inputLow + (uint64(inputHigh) << 32)
    71  		bitflip := xsecret_016 ^ xsecret_024
    72  		keyed := input64 ^ bitflip
    73  
    74  		h128High64, h128Low64 = bits.Mul64(keyed, prime64_1+(length)<<2)
    75  		h128High64 += h128Low64 << 1
    76  		h128Low64 ^= h128High64 >> 3
    77  
    78  		h128Low64 ^= h128Low64 >> 35
    79  		h128Low64 *= 0x9fb21c651e98df25
    80  		h128Low64 ^= h128Low64 >> 28
    81  
    82  		h128High64 = xxh3Avalanche(h128High64)
    83  		return [2]uint64{h128High64, h128Low64}
    84  	} else if length == 3 {
    85  		c12 := runtimex.ReadUnaligned16(xinput)
    86  		c3 := uint64(*(*uint8)(unsafe.Pointer(uintptr(xinput) + 2)))
    87  		h128Low64 = c12<<16 + c3 + 3<<8
    88  	} else if length == 2 {
    89  		c12 := runtimex.ReadUnaligned16(xinput)
    90  		h128Low64 = c12*(1<<24+1)>>8 + 2<<8
    91  	} else if length == 1 {
    92  		c1 := uint64(*(*uint8)(xinput))
    93  		h128Low64 = c1*(1<<24+1<<16+1) + 1<<8
    94  	} else if length == 0 {
    95  		return [2]uint64{0x99aa06d3014798d8, 0x6001c324468d497f}
    96  	}
    97  	h128High64 = uint64(bits.RotateLeft32(bits.ReverseBytes32(uint32(h128Low64)), 13))
    98  	bitflipl := uint64(xsecret32_000 ^ xsecret32_004)
    99  	bitfliph := uint64(xsecret32_008 ^ xsecret32_012)
   100  
   101  	h128Low64 = h128Low64 ^ bitflipl
   102  	h128High64 = h128High64 ^ bitfliph
   103  
   104  	h128Low64 = xxh64Avalanche(h128Low64)
   105  	h128High64 = xxh64Avalanche(h128High64)
   106  	return [2]uint64{h128High64, h128Low64}
   107  }
   108  
   109  func xxh3HashLarge128(xinput unsafe.Pointer, l int) (acc [2]uint64) {
   110  	length := uintptr(l)
   111  
   112  	if length <= 128 {
   113  
   114  		accHigh := uint64(0)
   115  		accLow := uint64(length * prime64_1)
   116  
   117  		if length > 32 {
   118  			if length > 64 {
   119  				if length > 96 {
   120  					accLow += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+48))^xsecret_096, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+56))^xsecret_104)
   121  					accLow ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-64))) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-56)))
   122  					accHigh += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-64)))^xsecret_112, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-56)))^xsecret_120)
   123  					accHigh ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+48)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+56))
   124  				}
   125  				accLow += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32))^xsecret_064, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+40))^xsecret_072)
   126  				accLow ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-48))) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-40)))
   127  				accHigh += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-48)))^xsecret_080, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-40)))^xsecret_088)
   128  				accHigh ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+40))
   129  			}
   130  			accLow += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16))^xsecret_032, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+3*8))^xsecret_040)
   131  			accLow ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-32))) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-3*8)))
   132  			accHigh += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-32)))^xsecret_048, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-3*8)))^xsecret_056)
   133  			accHigh ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+3*8))
   134  		}
   135  
   136  		accLow += mix(runtimex.ReadUnaligned64(xinput)^xsecret_000, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+8))^xsecret_008)
   137  		accLow ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-16))) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-8)))
   138  		accHigh += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-16)))^xsecret_016, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-8)))^xsecret_024)
   139  		accHigh ^= runtimex.ReadUnaligned64(xinput) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+8))
   140  
   141  		h128Low := accHigh + accLow
   142  		h128High := (accLow * prime64_1) + (accHigh * prime64_4) + uint64(length*prime64_2)
   143  
   144  		h128Low = xxh3Avalanche(h128Low)
   145  		h128High = -xxh3Avalanche(h128High)
   146  
   147  		return [2]uint64{h128High, h128Low}
   148  	} else if length <= 240 {
   149  		accLow64 := uint64(length * prime64_1)
   150  		accHigh64 := uint64(0)
   151  
   152  		accLow64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*0))^xsecret_000, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+8))^xsecret_008)
   153  		accLow64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*0+16)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+24))
   154  		accHigh64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*0+16))^xsecret_016, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+24))^xsecret_024)
   155  		accHigh64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*0)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+8))
   156  
   157  		accLow64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*1))^xsecret_032, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*1+8))^xsecret_040)
   158  		accLow64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*1+16)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*1+24))
   159  		accHigh64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*1+16))^xsecret_048, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*1+24))^xsecret_056)
   160  		accHigh64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*1)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(32*1)+8))
   161  
   162  		accLow64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2))^xsecret_064, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2+8))^xsecret_072)
   163  		accLow64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2+16)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2+24))
   164  		accHigh64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2+16))^xsecret_080, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2+24))^xsecret_088)
   165  		accHigh64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2+8))
   166  
   167  		accLow64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3))^xsecret_096, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3+8))^xsecret_104)
   168  		accLow64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3+16)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3+24))
   169  		accHigh64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3+16))^xsecret_112, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3+24))^xsecret_120)
   170  		accHigh64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3+8))
   171  
   172  		accLow64 = xxh3Avalanche(accLow64)
   173  		accHigh64 = xxh3Avalanche(accHigh64)
   174  
   175  		nbRounds := uintptr(length >> 5 << 5)
   176  		for i := uintptr(4 * 32); i < nbRounds; i += 32 {
   177  			accHigh64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i+16))^runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xsecret)+i-109)), runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i+24))^runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xsecret)+i-101)))
   178  			accHigh64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i+8))
   179  
   180  			accLow64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i))^runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xsecret)+i-125)), runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i+8))^runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xsecret)+i-117)))
   181  			accLow64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i+16)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i+24))
   182  		}
   183  
   184  		// last 32 bytes
   185  		accLow64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-16))^xsecret_103, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-8))^xsecret_111)
   186  		accLow64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-32)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-24))
   187  		accHigh64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-32))^xsecret_119, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-24))^xsecret_127)
   188  		accHigh64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-16)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-8))
   189  
   190  		accHigh64, accLow64 = (accLow64*prime64_1)+(accHigh64*prime64_4)+uint64(length*prime64_2), accHigh64+accLow64
   191  
   192  		accLow64 = xxh3Avalanche(accLow64)
   193  		accHigh64 = -xxh3Avalanche(accHigh64)
   194  
   195  		return [2]uint64{accHigh64, accLow64}
   196  	}
   197  
   198  	var xacc = [8]uint64{
   199  		prime32_3, prime64_1, prime64_2, prime64_3,
   200  		prime64_4, prime32_2, prime64_5, prime32_1}
   201  
   202  	acc[1] = uint64(length * prime64_1)
   203  	acc[0] = uint64(^(length * prime64_2))
   204  
   205  	accum(&xacc, xinput, xsecret, length)
   206  
   207  	// merge xacc
   208  	acc[1] += mix(xacc[0]^xsecret_011, xacc[1]^xsecret_019)
   209  	acc[1] += mix(xacc[2]^xsecret_027, xacc[3]^xsecret_035)
   210  	acc[1] += mix(xacc[4]^xsecret_043, xacc[5]^xsecret_051)
   211  	acc[1] += mix(xacc[6]^xsecret_059, xacc[7]^xsecret_067)
   212  	acc[1] = xxh3Avalanche(acc[1])
   213  
   214  	acc[0] += mix(xacc[0]^xsecret_117, xacc[1]^xsecret_125)
   215  	acc[0] += mix(xacc[2]^xsecret_133, xacc[3]^xsecret_141)
   216  	acc[0] += mix(xacc[4]^xsecret_149, xacc[5]^xsecret_157)
   217  	acc[0] += mix(xacc[6]^xsecret_165, xacc[7]^xsecret_173)
   218  	acc[0] = xxh3Avalanche(acc[0])
   219  
   220  	return acc
   221  }