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 }