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