github.com/fufuok/utils@v1.0.10/xhash/hash.go (about) 1 package xhash 2 3 import ( 4 "bufio" 5 "crypto/hmac" 6 "crypto/md5" 7 "crypto/sha1" 8 "crypto/sha256" 9 "crypto/sha512" 10 "encoding/hex" 11 "hash" 12 "hash/fnv" 13 "hash/maphash" 14 "io" 15 "os" 16 "reflect" 17 "strconv" 18 "unsafe" 19 20 "github.com/fufuok/utils" 21 ) 22 23 const ( 24 bufferSize = 65536 25 26 // FNVa offset basis. See https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function#FNV-1a_hash 27 offset32 = 2166136261 28 offset64 = 14695981039346656037 29 prime32 = 16777619 30 prime64 = 1099511628211 31 ) 32 33 func Sha256Hex(s string) string { 34 return hex.EncodeToString(Sha256(utils.S2B(s))) 35 } 36 37 func Sha256(b []byte) []byte { 38 return Hash(b, sha256.New()) 39 } 40 41 func Sha512Hex(s string) string { 42 return hex.EncodeToString(Sha512(utils.S2B(s))) 43 } 44 45 func Sha512(b []byte) []byte { 46 return Hash(b, sha512.New()) 47 } 48 49 func Sha1Hex(s string) string { 50 return hex.EncodeToString(Sha1(utils.S2B(s))) 51 } 52 53 func Sha1(b []byte) []byte { 54 return Hash(b, sha1.New()) 55 } 56 57 func HmacSHA256Hex(s, key string) string { 58 return hex.EncodeToString(HmacSHA256(utils.S2B(s), utils.S2B(key))) 59 } 60 61 func HmacSHA256(b, key []byte) []byte { 62 return Hmac(b, key, sha256.New) 63 } 64 65 func HmacSHA512Hex(s, key string) string { 66 return hex.EncodeToString(HmacSHA512(utils.S2B(s), utils.S2B(key))) 67 } 68 69 func HmacSHA512(b, key []byte) []byte { 70 return Hmac(b, key, sha512.New) 71 } 72 73 func HmacSHA1Hex(s, key string) string { 74 return hex.EncodeToString(HmacSHA1(utils.S2B(s), utils.S2B(key))) 75 } 76 77 func HmacSHA1(b, key []byte) []byte { 78 return Hmac(b, key, sha1.New) 79 } 80 81 // MD5Hex 字符串 MD5 82 func MD5Hex(s string) string { 83 b := md5.Sum(utils.S2B(s)) 84 return hex.EncodeToString(b[:]) 85 } 86 87 func MD5BytesHex(bs []byte) string { 88 b := md5.Sum(bs) 89 return hex.EncodeToString(b[:]) 90 } 91 92 func MD5(b []byte) []byte { 93 return Hash(b, nil) 94 } 95 96 func Hmac(b []byte, key []byte, h func() hash.Hash) []byte { 97 if h == nil { 98 h = md5.New 99 } 100 mac := hmac.New(h, key) 101 mac.Write(b) 102 103 return mac.Sum(nil) 104 } 105 106 func Hash(b []byte, h hash.Hash) []byte { 107 if h == nil { 108 h = md5.New() 109 } 110 h.Reset() 111 h.Write(b) 112 113 return h.Sum(nil) 114 } 115 116 func MustMD5Sum(filename string) string { 117 s, _ := MD5Sum(filename) 118 return s 119 } 120 121 // MD5Sum 文件 MD5 122 func MD5Sum(filename string) (string, error) { 123 if info, err := os.Stat(filename); err != nil { 124 return "", err 125 } else if info.IsDir() { 126 return "", nil 127 } 128 129 file, err := os.Open(filename) 130 if err != nil { 131 return "", err 132 } 133 134 defer func() { 135 _ = file.Close() 136 }() 137 138 return MD5Reader(file) 139 } 140 141 // MD5Reader 计算 MD5 142 func MD5Reader(r io.Reader) (string, error) { 143 h := md5.New() 144 for buf, reader := make([]byte, bufferSize), bufio.NewReader(r); ; { 145 n, err := reader.Read(buf) 146 if err != nil { 147 if err == io.EOF { 148 break 149 } 150 151 return "", err 152 } 153 154 h.Write(buf[:n]) 155 } 156 157 return hex.EncodeToString(h.Sum(nil)), nil 158 } 159 160 // Sum64 获取字符串的哈希值 161 func Sum64(s string) uint64 { 162 return AddString64(offset64, s) 163 } 164 165 // SumBytes64 获取 bytes 的哈希值 166 func SumBytes64(bs []byte) uint64 { 167 return AddBytes64(offset64, bs) 168 } 169 170 // Sum32 获取字符串的哈希值 171 func Sum32(s string) uint32 { 172 return AddString32(offset32, s) 173 } 174 175 // SumBytes32 获取 bytes 的哈希值 176 func SumBytes32(bs []byte) uint32 { 177 return AddBytes32(offset32, bs) 178 } 179 180 // FnvHash 获取字符串的哈希值 181 func FnvHash(s string) uint64 { 182 h := fnv.New64a() 183 _, _ = h.Write([]byte(s)) 184 return h.Sum64() 185 } 186 187 // FnvHash32 获取字符串的哈希值 188 func FnvHash32(s string) uint32 { 189 h := fnv.New32a() 190 _, _ = h.Write([]byte(s)) 191 return h.Sum32() 192 } 193 194 // MemHashb 使用内置的 memhash 获取哈希值 195 func MemHashb(b []byte) uint64 { 196 h := (*reflect.StringHeader)(unsafe.Pointer(&b)) 197 return uint64(memhash(unsafe.Pointer(h.Data), offset64, uintptr(h.Len))) 198 } 199 200 // MemHash 使用内置的 memhash 获取字符串哈希值 201 func MemHash(s string) uint64 { 202 h := (*reflect.StringHeader)(unsafe.Pointer(&s)) 203 return uint64(memhash(unsafe.Pointer(h.Data), offset64, uintptr(h.Len))) 204 } 205 206 // MemHashb32 使用内置的 memhash 获取哈希值 207 func MemHashb32(b []byte) uint32 { 208 h := (*reflect.StringHeader)(unsafe.Pointer(&b)) 209 return uint32(memhash(unsafe.Pointer(h.Data), offset32, uintptr(h.Len))) 210 } 211 212 // MemHash32 使用内置的 memhash 获取字符串哈希值 213 func MemHash32(s string) uint32 { 214 h := (*reflect.StringHeader)(unsafe.Pointer(&s)) 215 return uint32(memhash(unsafe.Pointer(h.Data), offset32, uintptr(h.Len))) 216 } 217 218 // Djb33 比 FnvHash32 更快的获取字符串哈希值 219 // djb2 with better shuffling. 5x faster than FNV with the hash.Hash overhead. 220 // Ref: patrickmn/go-cache 221 func Djb33(s string) uint32 { 222 var ( 223 l = uint32(len(s)) 224 d = 5381 + utils.Seed + l 225 i = uint32(0) 226 ) 227 // Why is all this 5x faster than a for loop? 228 if l >= 4 { 229 for i < l-4 { 230 d = (d * 33) ^ uint32(s[i]) 231 d = (d * 33) ^ uint32(s[i+1]) 232 d = (d * 33) ^ uint32(s[i+2]) 233 d = (d * 33) ^ uint32(s[i+3]) 234 i += 4 235 } 236 } 237 switch l - i { 238 case 1: 239 case 2: 240 d = (d * 33) ^ uint32(s[i]) 241 case 3: 242 d = (d * 33) ^ uint32(s[i]) 243 d = (d * 33) ^ uint32(s[i+1]) 244 case 4: 245 d = (d * 33) ^ uint32(s[i]) 246 d = (d * 33) ^ uint32(s[i+1]) 247 d = (d * 33) ^ uint32(s[i+2]) 248 } 249 return d ^ (d >> 16) 250 } 251 252 // HashString 合并一串文本, 得到字符串哈希 253 func HashString(s ...string) string { 254 return strconv.FormatUint(HashString64(s...), 10) 255 } 256 257 func HashString64(s ...string) uint64 { 258 return Sum64(utils.JoinString(s...)) 259 } 260 261 func HashString32(s ...string) uint32 { 262 return Sum32(utils.JoinString(s...)) 263 } 264 265 // HashBytes 合并 Bytes, 得到字符串哈希 266 func HashBytes(b ...[]byte) string { 267 return strconv.FormatUint(HashBytes64(b...), 10) 268 } 269 270 func HashBytes64(b ...[]byte) uint64 { 271 return SumBytes64(utils.JoinBytes(b...)) 272 } 273 274 func HashBytes32(b ...[]byte) uint32 { 275 return SumBytes32(utils.JoinBytes(b...)) 276 } 277 278 // HashUint64 returns the hash of u. 279 // Ref: segmentio/fasthash 280 func HashUint64(u uint64) uint64 { 281 return AddUint64(offset64, u) 282 } 283 284 // HashUint32 returns the hash of u. 285 // Ref: segmentio/fasthash 286 func HashUint32(u uint32) uint32 { 287 return AddUint32(offset32, u) 288 } 289 290 // AddString64 adds the hash of s to the precomputed hash value h. 291 // Ref: segmentio/fasthash 292 func AddString64(h uint64, s string) uint64 { 293 /* 294 This is an unrolled version of this algorithm: 295 for _, c := range s { 296 h = (h ^ uint64(c)) * prime64 297 } 298 It seems to be ~1.5x faster than the simple loop in BenchmarkHash64: 299 - BenchmarkHash64/hash_function-4 30000000 56.1 ns/op 642.15 MB/s 0 B/op 0 allocs/op 300 - BenchmarkHash64/hash_function-4 50000000 38.6 ns/op 932.35 MB/s 0 B/op 0 allocs/op 301 */ 302 for len(s) >= 8 { 303 h = (h ^ uint64(s[0])) * prime64 304 h = (h ^ uint64(s[1])) * prime64 305 h = (h ^ uint64(s[2])) * prime64 306 h = (h ^ uint64(s[3])) * prime64 307 h = (h ^ uint64(s[4])) * prime64 308 h = (h ^ uint64(s[5])) * prime64 309 h = (h ^ uint64(s[6])) * prime64 310 h = (h ^ uint64(s[7])) * prime64 311 s = s[8:] 312 } 313 314 if len(s) >= 4 { 315 h = (h ^ uint64(s[0])) * prime64 316 h = (h ^ uint64(s[1])) * prime64 317 h = (h ^ uint64(s[2])) * prime64 318 h = (h ^ uint64(s[3])) * prime64 319 s = s[4:] 320 } 321 322 if len(s) >= 2 { 323 h = (h ^ uint64(s[0])) * prime64 324 h = (h ^ uint64(s[1])) * prime64 325 s = s[2:] 326 } 327 328 if len(s) > 0 { 329 h = (h ^ uint64(s[0])) * prime64 330 } 331 332 return h 333 } 334 335 // AddBytes64 adds the hash of b to the precomputed hash value h. 336 // Ref: segmentio/fasthash 337 func AddBytes64(h uint64, b []byte) uint64 { 338 for len(b) >= 8 { 339 h = (h ^ uint64(b[0])) * prime64 340 h = (h ^ uint64(b[1])) * prime64 341 h = (h ^ uint64(b[2])) * prime64 342 h = (h ^ uint64(b[3])) * prime64 343 h = (h ^ uint64(b[4])) * prime64 344 h = (h ^ uint64(b[5])) * prime64 345 h = (h ^ uint64(b[6])) * prime64 346 h = (h ^ uint64(b[7])) * prime64 347 b = b[8:] 348 } 349 350 if len(b) >= 4 { 351 h = (h ^ uint64(b[0])) * prime64 352 h = (h ^ uint64(b[1])) * prime64 353 h = (h ^ uint64(b[2])) * prime64 354 h = (h ^ uint64(b[3])) * prime64 355 b = b[4:] 356 } 357 358 if len(b) >= 2 { 359 h = (h ^ uint64(b[0])) * prime64 360 h = (h ^ uint64(b[1])) * prime64 361 b = b[2:] 362 } 363 364 if len(b) > 0 { 365 h = (h ^ uint64(b[0])) * prime64 366 } 367 368 return h 369 } 370 371 // AddUint64 adds the hash value of the 8 bytes of u to h. 372 // Ref: segmentio/fasthash 373 func AddUint64(h uint64, u uint64) uint64 { 374 h = (h ^ ((u >> 56) & 0xFF)) * prime64 375 h = (h ^ ((u >> 48) & 0xFF)) * prime64 376 h = (h ^ ((u >> 40) & 0xFF)) * prime64 377 h = (h ^ ((u >> 32) & 0xFF)) * prime64 378 h = (h ^ ((u >> 24) & 0xFF)) * prime64 379 h = (h ^ ((u >> 16) & 0xFF)) * prime64 380 h = (h ^ ((u >> 8) & 0xFF)) * prime64 381 h = (h ^ ((u >> 0) & 0xFF)) * prime64 382 return h 383 } 384 385 // AddString32 adds the hash of s to the precomputed hash value h. 386 // Ref: segmentio/fasthash 387 func AddString32(h uint32, s string) uint32 { 388 for len(s) >= 8 { 389 h = (h ^ uint32(s[0])) * prime32 390 h = (h ^ uint32(s[1])) * prime32 391 h = (h ^ uint32(s[2])) * prime32 392 h = (h ^ uint32(s[3])) * prime32 393 h = (h ^ uint32(s[4])) * prime32 394 h = (h ^ uint32(s[5])) * prime32 395 h = (h ^ uint32(s[6])) * prime32 396 h = (h ^ uint32(s[7])) * prime32 397 s = s[8:] 398 } 399 400 if len(s) >= 4 { 401 h = (h ^ uint32(s[0])) * prime32 402 h = (h ^ uint32(s[1])) * prime32 403 h = (h ^ uint32(s[2])) * prime32 404 h = (h ^ uint32(s[3])) * prime32 405 s = s[4:] 406 } 407 408 if len(s) >= 2 { 409 h = (h ^ uint32(s[0])) * prime32 410 h = (h ^ uint32(s[1])) * prime32 411 s = s[2:] 412 } 413 414 if len(s) > 0 { 415 h = (h ^ uint32(s[0])) * prime32 416 } 417 418 return h 419 } 420 421 // AddBytes32 adds the hash of b to the precomputed hash value h. 422 // Ref: segmentio/fasthash 423 func AddBytes32(h uint32, b []byte) uint32 { 424 for len(b) >= 8 { 425 h = (h ^ uint32(b[0])) * prime32 426 h = (h ^ uint32(b[1])) * prime32 427 h = (h ^ uint32(b[2])) * prime32 428 h = (h ^ uint32(b[3])) * prime32 429 h = (h ^ uint32(b[4])) * prime32 430 h = (h ^ uint32(b[5])) * prime32 431 h = (h ^ uint32(b[6])) * prime32 432 h = (h ^ uint32(b[7])) * prime32 433 b = b[8:] 434 } 435 436 if len(b) >= 4 { 437 h = (h ^ uint32(b[0])) * prime32 438 h = (h ^ uint32(b[1])) * prime32 439 h = (h ^ uint32(b[2])) * prime32 440 h = (h ^ uint32(b[3])) * prime32 441 b = b[4:] 442 } 443 444 if len(b) >= 2 { 445 h = (h ^ uint32(b[0])) * prime32 446 h = (h ^ uint32(b[1])) * prime32 447 b = b[2:] 448 } 449 450 if len(b) > 0 { 451 h = (h ^ uint32(b[0])) * prime32 452 } 453 454 return h 455 } 456 457 // AddUint32 adds the hash value of the 8 bytes of u to h. 458 // Ref: segmentio/fasthash 459 func AddUint32(h, u uint32) uint32 { 460 h = (h ^ ((u >> 24) & 0xFF)) * prime32 461 h = (h ^ ((u >> 16) & 0xFF)) * prime32 462 h = (h ^ ((u >> 8) & 0xFF)) * prime32 463 h = (h ^ ((u >> 0) & 0xFF)) * prime32 464 return h 465 } 466 467 // HashSeedString calculates a hash of s with the given seed. 468 func HashSeedString(seed maphash.Seed, s string) uint64 { 469 return hashString(seed, s) 470 } 471 472 // HashSeedUint64 calculates a hash of n with the given seed. 473 func HashSeedUint64(seed maphash.Seed, n uint64) uint64 { 474 // Java's Long standard hash function. 475 n = n ^ (n >> 32) 476 nseed := *(*uint64)(unsafe.Pointer(&seed)) 477 // 64-bit variation of boost's hash_combine. 478 nseed ^= n + 0x9e3779b97f4a7c15 + (nseed << 12) + (nseed >> 4) 479 return nseed 480 } 481 482 //go:noescape 483 //go:linkname memhash runtime.memhash 484 func memhash(p unsafe.Pointer, h, s uintptr) uintptr