github.com/pidato/unsafe@v0.1.4/memory/hash/wyhashf3.go (about) 1 package hash 2 3 import ( 4 "math" 5 "math/bits" 6 "unsafe" 7 ) 8 9 const ( 10 DefaultSeed uint64 = 0xa0761d6478bd642f // s0 11 s1 uint64 = 0xe7037ed1a0b428db 12 s2 uint64 = 0x8ebc6af09c88c6e3 13 s3 uint64 = 0x589965cc75374cc3 14 s4 uint64 = 0x1d8e4e27c47d124f 15 ) 16 17 var ( 18 r = Rand{} 19 ) 20 21 func SetSeed(s uint64) { 22 r.seed = s 23 } 24 func Next() uint64 { 25 return r.Next() 26 } 27 func NextFloat() float64 { 28 return r.NextFloat() 29 } 30 func NextGaussian() float64 { 31 return r.NextGaussian() 32 } 33 34 type Rand struct { 35 seed uint64 36 } 37 38 func (w *Rand) Next() uint64 { 39 return wyrand(&w.seed) 40 } 41 42 func (w *Rand) NextFloat() float64 { 43 return wy2u01(wyrand(&w.seed)) 44 } 45 46 func (w *Rand) NextGaussian() float64 { 47 return wy2gau(wyrand(&w.seed)) 48 } 49 50 func wyrand(seed *uint64) uint64 { 51 *seed += uint64(0xa0761d6478bd642f) 52 return wymum(*seed, *seed^0xe7037ed1a0b428db) 53 } 54 55 func wy2u01(r uint64) float64 { 56 const norm = float64(1.0) / float64(uint64(1)<<52) 57 return float64(r>>12) * norm 58 } 59 60 func wy2gau(r uint64) float64 { 61 const norm = float64(1.0) / float64(uint64(1)<<20) 62 return float64((r&0x1fffff)+((r>>21)&0x1fffff)+((r>>42)&0x1fffff))*norm - 3.0 63 } 64 65 func wymumSlow(a, b uint64) uint64 { 66 var ( 67 hh = (a >> 32) * (b >> 32) 68 hl = (a >> 32) * (b & 0xFFFF_FFFF) 69 lh = (a & 0xFFFF_FFFF) * (b >> 32) 70 ll = (a & 0xFFFF_FFFF) * (b & 0xFFFF_FFFF) 71 ) 72 //a = wyrotate(hl) ^ hh 73 //b = wyrotate(lh) ^ ll 74 a = ((hl >> 32) | (hl << 32)) ^ hh 75 b = ((lh >> 32) | (lh << 32)) ^ ll 76 return a ^ b 77 } 78 79 func wymum(a, b uint64) uint64 { 80 a, b = bits.Mul64(a, b) 81 return a ^ b 82 } 83 84 func Bytes(b []byte) uint64 { 85 return Hash(*(*unsafe.Pointer)(unsafe.Pointer(&b)), uint64(len(b)), DefaultSeed) 86 } 87 88 func String(s string) uint64 { 89 return Hash(*(*unsafe.Pointer)(unsafe.Pointer(&s)), uint64(len(s)), DefaultSeed) 90 } 91 92 func I8(v int8) uint64 { 93 return U8(*(*uint8)(unsafe.Pointer(&v))) 94 } 95 96 func U8(v uint8) uint64 { 97 value := uint64(v) 98 return wymum(s1^1, wymum(((value<<16)|(value<<8)|value)^s1, 0^DefaultSeed)) 99 } 100 101 func I16(v int16) uint64 { 102 return U16(*(*uint16)(unsafe.Pointer(&v))) 103 } 104 105 func U16(v uint16) uint64 { 106 var ( 107 b2 = uint64(*(*byte)(unsafe.Add(unsafe.Pointer(&v), 1))) 108 a = uint64(*(*byte)(unsafe.Pointer(&v)))<<16 | b2<<8 | b2 109 ) 110 return wymum(s1^2, wymum(a^s1, 0^DefaultSeed)) 111 } 112 113 func I32(v int32) uint64 { 114 value := uint64(*(*uint32)(unsafe.Pointer(&v))) 115 value = (value << 32) | value 116 return wymum(s1^4, wymum(value^s1, value^DefaultSeed)) 117 } 118 119 func U32(v uint32) uint64 { 120 value := uint64(v) 121 value = (value << 32) | value 122 return wymum(s1^4, wymum(value^s1, value^DefaultSeed)) 123 124 //return Hash(unsafe.Pointer(&v), 4, DefaultSeed) 125 } 126 127 func F32(v float32) uint64 { 128 return U32(math.Float32bits(v)) 129 } 130 131 func F64(v float64) uint64 { 132 return U64(math.Float64bits(v)) 133 } 134 135 func I64(v int64) uint64 { 136 return U64(*(*uint64)(unsafe.Pointer(&v))) 137 } 138 139 func U64(v uint64) uint64 { 140 return wymum(s1^8, wymum( 141 (v<<32|(v>>32&0xFFFFFFFF))^s1, 142 (v>>32|(v&0xFFFFFFFF))^DefaultSeed)) 143 } 144 145 func HashBytes(b []byte) uint64 { 146 return Hash(unsafe.Pointer(&b[0]), uint64(len(b)), DefaultSeed) 147 } 148 149 func Hash(bytes unsafe.Pointer, length uint64, seed uint64) uint64 { 150 var ( 151 a uint64 152 b uint64 153 ) 154 if length <= 16 { 155 if length >= 4 { 156 a = read32(bytes)<<32 | read32(unsafe.Add(bytes, (length>>3)<<2)) 157 b = read32(unsafe.Add(bytes, length-4))<<32 | 158 read32(unsafe.Add(bytes, length-4-((length>>3)<<2))) 159 } else if length > 0 { 160 a = uint64(*(*byte)(bytes))<<16 | 161 uint64(*(*byte)(unsafe.Add(bytes, length>>1)))<<8 | 162 uint64(*(*byte)(unsafe.Add(bytes, length-1))) 163 } 164 } else { 165 var ( 166 index = length 167 ) 168 if length > 48 { 169 var ( 170 see1 = seed 171 see2 = seed 172 ) 173 for index > 48 { 174 seed = wymum(read64(bytes)^s1, read64(unsafe.Add(bytes, 8))^seed) 175 see1 = wymum(read64(unsafe.Add(bytes, 16))^s2, read64(unsafe.Add(bytes, 24))^see1) 176 see2 = wymum(read64(unsafe.Add(bytes, 32))^s3, read64(unsafe.Add(bytes, 40))^see2) 177 index -= 48 178 bytes = unsafe.Add(bytes, 48) 179 } 180 seed ^= see1 ^ see2 181 } 182 183 for index > 16 { 184 seed = wymum(read64(bytes)^s1, read64(unsafe.Add(bytes, 8))^seed) 185 index -= 16 186 bytes = unsafe.Add(bytes, 16) 187 } 188 189 a = read64(unsafe.Add(bytes, index-16)) 190 b = read64(unsafe.Add(bytes, index-8)) 191 } 192 193 return wymum(s1^length, wymum(a^s1, b^seed)) 194 } 195 196 func WithSecret(bytes unsafe.Pointer, length uint64, secret *[4]uint64) uint64 { 197 var ( 198 a uint64 199 b uint64 200 seed = secret[0] 201 ) 202 if length <= 16 { 203 if length >= 4 { 204 a = read32(bytes)<<32 | read32(unsafe.Add(bytes, (length>>3)<<2)) 205 b = read32(unsafe.Add(bytes, length-4))<<32 | 206 read32(unsafe.Add(bytes, length-4-((length>>3)<<2))) 207 } else if length > 0 { 208 a = uint64(*(*byte)(bytes))<<16 | 209 uint64(*(*byte)(unsafe.Add(bytes, length>>1)))<<8 | 210 uint64(*(*byte)(unsafe.Add(bytes, length-1))) 211 } 212 } else { 213 var ( 214 index = length 215 ) 216 if length > 48 { 217 var ( 218 see1 = seed 219 see2 = seed 220 ) 221 for index > 48 { 222 seed = wymum(read64(bytes)^secret[1], read64(unsafe.Add(bytes, 8))^seed) 223 see1 = wymum(read64(unsafe.Add(bytes, 16))^secret[2], read64(unsafe.Add(bytes, 24))^see1) 224 see2 = wymum(read64(unsafe.Add(bytes, 32))^secret[3], read64(unsafe.Add(bytes, 40))^see2) 225 index -= 48 226 bytes = unsafe.Add(bytes, 48) 227 } 228 seed ^= see1 ^ see2 229 } 230 231 for index > 16 { 232 seed = wymum(read64(bytes)^secret[1], read64(unsafe.Add(bytes, 8))^seed) 233 index -= 16 234 bytes = unsafe.Add(bytes, 16) 235 } 236 237 a = read64(unsafe.Add(bytes, index-16)) 238 b = read64(unsafe.Add(bytes, index-8)) 239 } 240 241 return wymum(secret[1]^length, wymum(a^secret[1], b^seed)) 242 } 243 244 var wyf3Secret = [...]byte{ 245 15, 23, 27, 29, 30, 39, 43, 45, 46, 51, 53, 54, 57, 58, 60, 71, 75, 77, 78, 83, 85, 246 86, 89, 90, 92, 99, 101, 102, 105, 106, 108, 113, 114, 116, 120, 135, 139, 141, 142, 247 147, 149, 150, 153, 154, 156, 163, 165, 166, 169, 170, 172, 177, 178, 180, 184, 195, 248 197, 198, 201, 202, 204, 209, 210, 212, 216, 225, 226, 228, 232, 240} 249 250 func MakeSecret(seed uint64) [4]uint64 { 251 var secret [4]uint64 252 for i := 0; i < 4; i++ { 253 var ok bool 254 255 for !ok { 256 ok = true 257 secret[i] = 0 258 259 for j := 0; j < 64; j += 8 { 260 secret[i] |= uint64(wyf3Secret[wyrand(&seed)%uint64(len(wyf3Secret))]) << j 261 } 262 if secret[i]%2 == 0 { 263 ok = false 264 continue 265 } 266 for j := 0; j < i; j++ { 267 if popcnt64(secret[j]^secret[i]) != 32 { 268 ok = false 269 break 270 } 271 272 x := secret[j] ^ secret[i] 273 x -= (x >> 1) & 0x5555555555555555 274 x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333) 275 x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f 276 x = (x * 0x0101010101010101) >> 56 277 if x != 32 { 278 ok = false 279 break 280 } 281 } 282 } 283 } 284 return secret 285 } 286 287 func popcnt64(x uint64) uint64 { 288 x = (x & 0x5555555555555555) + ((x & 0xAAAAAAAAAAAAAAAA) >> 1) 289 x = (x & 0x3333333333333333) + ((x & 0xCCCCCCCCCCCCCCCC) >> 2) 290 x = (x & 0x0F0F0F0F0F0F0F0F) + ((x & 0xF0F0F0F0F0F0F0F0) >> 4) 291 x *= 0x0101010101010101 292 return (x >> 56) & 0xFF 293 }