github.com/rolandhe/saber@v0.0.4/hash/crc256.go (about)

     1  // Package hash, Golang concurrent tools like java juc.
     2  //
     3  // Copyright 2023 The saber Authors. All rights reserved.
     4  
     5  package hash
     6  
     7  import (
     8  	"errors"
     9  	"github.com/rolandhe/saber/hash/crc"
    10  	"github.com/rolandhe/saber/utils/strutil"
    11  )
    12  
    13  var notSupportError = errors.New("not support sse42")
    14  
    15  type param256 struct {
    16  	a uint64
    17  	b uint64
    18  	c uint64
    19  	d uint64
    20  	e uint64
    21  	f uint64
    22  	g uint64
    23  	h uint64
    24  	x uint64
    25  	y uint64
    26  	z uint64
    27  }
    28  
    29  func cityHashCrc256Long(s []byte, len uint, seed uint32) ([]uint64, error) {
    30  	if !crc.WithSSE42() {
    31  		return nil, notSupportError
    32  	}
    33  	result := make([]uint64, 4)
    34  	var param param256
    35  	param.a = fetch64(s[56:]) + k0
    36  	param.b = fetch64(s[96:]) + k0
    37  	result[0] = hashLen16(param.b, uint64(len))
    38  	param.c = result[0]
    39  	result[1] = fetch64(s[120:])*k0 + uint64(len)
    40  	param.d = result[1]
    41  	param.e = fetch64(s[184:]) + uint64(seed)
    42  	param.f = 0
    43  	param.g = 0
    44  	param.h = param.c + param.d
    45  	param.x = uint64(seed)
    46  	param.y = 0
    47  	param.z = 0
    48  
    49  	iters := len / 240
    50  	len -= iters * 240
    51  
    52  	for {
    53  		chunk(0, &param, s)
    54  		permute3(&param.a, &param.h, &param.c)
    55  		s = s[40:]
    56  
    57  		chunk(33, &param, s)
    58  		permute3(&param.a, &param.h, &param.f)
    59  		s = s[40:]
    60  
    61  		chunk(0, &param, s)
    62  		permute3(&param.b, &param.h, &param.f)
    63  		s = s[40:]
    64  
    65  		chunk(42, &param, s)
    66  		permute3(&param.b, &param.h, &param.d)
    67  		s = s[40:]
    68  
    69  		chunk(0, &param, s)
    70  		permute3(&param.b, &param.h, &param.e)
    71  		s = s[40:]
    72  
    73  		chunk(33, &param, s)
    74  		permute3(&param.a, &param.h, &param.e)
    75  		s = s[40:]
    76  
    77  		iters--
    78  		if iters <= 0 {
    79  			break
    80  		}
    81  	}
    82  
    83  	for len >= 40 {
    84  		chunk(29, &param, s)
    85  		s = s[40:]
    86  
    87  		param.e ^= rotate64(param.a, 20)
    88  		param.h += rotate64(param.b, 30)
    89  		param.g ^= rotate64(param.c, 40)
    90  		param.f += rotate64(param.d, 34)
    91  		permute3(&param.c, &param.h, &param.g)
    92  		len -= 40
    93  	}
    94  	if len > 0 {
    95  		s = s[len-40:]
    96  		chunk(33, &param, s)
    97  		s = s[40:]
    98  		param.e ^= rotate64(param.a, 43)
    99  		param.h += rotate64(param.b, 42)
   100  		param.g ^= rotate64(param.c, 41)
   101  		param.f += rotate64(param.d, 40)
   102  	}
   103  	result[0] ^= param.h
   104  	result[1] ^= param.g
   105  
   106  	param.g += param.h
   107  	param.a = hashLen16(param.a, param.g+param.z)
   108  
   109  	param.x += param.y << 32
   110  	param.b += param.x
   111  	param.c = hashLen16(param.c, param.z) + param.h
   112  	param.d = hashLen16(param.d, param.e+result[0])
   113  	param.g += param.e
   114  	param.h += hashLen16(param.x, param.f)
   115  	param.e = hashLen16(param.a, param.d) + param.g
   116  	param.z = hashLen16(param.b, param.c) + param.a
   117  	param.y = hashLen16(param.g, param.h) + param.c
   118  	result[0] = param.e + param.z + param.y + param.x
   119  	param.a = shiftMix((param.a+param.y)*k0)*k0 + param.b
   120  	result[1] += param.a + result[0]
   121  	param.a = shiftMix(param.a*k0)*k0 + param.c
   122  	result[2] = param.a + result[1]
   123  	param.a = shiftMix((param.a+param.e)*k0) * k0
   124  	result[3] = param.a + result[2]
   125  	return result, nil
   126  }
   127  
   128  // CityHashCrc256String 计算指定字符串的 256 位hash
   129  // 256位hash使用 4个 int64 返回
   130  func CityHashCrc256String(str string) ([]uint64, error) {
   131  	s := strutil.DetachBytesString(str)
   132  	length := uint(len(str))
   133  	return CityHashCrc256(s, length)
   134  }
   135  
   136  // CityHashCrc256 计算指定二进制数组的 256 位hash
   137  // 256位hash使用 4个 int64 返回
   138  func CityHashCrc256(s []byte, len uint) ([]uint64, error) {
   139  	if len >= 240 {
   140  		return cityHashCrc256Long(s, len, 0)
   141  	} else {
   142  		return cityHashCrc256Short(s, len)
   143  	}
   144  }
   145  
   146  func CityHashCrc128WithSeedString(str string, seed *Uint128) (*Uint128, error) {
   147  	s := strutil.DetachBytesString(str)
   148  	length := uint(len(str))
   149  	return CityHashCrc128WithSeed(s, length, seed)
   150  }
   151  
   152  func CityHashCrc128WithSeed(s []byte, length uint, seed *Uint128) (*Uint128, error) {
   153  	if length <= 900 {
   154  		return CityHash128WithSeed(s, length, seed), nil
   155  	} else {
   156  		result, err := CityHashCrc256(s, length)
   157  		if err != nil {
   158  			return nil, err
   159  		}
   160  		u := seed.high + result[0]
   161  		v := seed.low + result[1]
   162  		return MakeUint128(hashLen16(u, v+result[2]), hashLen16(rotate64(v, 32), u*k0+result[3])), nil
   163  	}
   164  }
   165  
   166  func CityHashCrc128String(str string) (*Uint128, error) {
   167  	s := strutil.DetachBytesString(str)
   168  	length := uint(len(str))
   169  	return CityHashCrc128(s, length)
   170  }
   171  
   172  func CityHashCrc128(s []byte, length uint) (*Uint128, error) {
   173  	if length <= 900 {
   174  		return CityHash128(s, length), nil
   175  	} else {
   176  		result, err := CityHashCrc256(s, length)
   177  		if err != nil {
   178  			return nil, err
   179  		}
   180  		return MakeUint128(result[2], result[3]), nil
   181  	}
   182  }
   183  
   184  func chunk(r int, param *param256, s []byte) {
   185  	param.x, param.z, param.y = param.y, param.x, param.z
   186  	param.b += fetch64(s)
   187  	param.c += fetch64(s[8:])
   188  	param.d += fetch64(s[16:])
   189  	param.e += fetch64(s[24:])
   190  	param.f += fetch64(s[32:])
   191  	param.a += param.b
   192  	param.h += param.f
   193  	param.b += param.c
   194  	param.f += param.d
   195  	param.g += param.e
   196  	param.e += param.z
   197  	param.g += param.x
   198  	param.z = crc.Crc32u64(param.z, param.b+param.g)
   199  	param.y = crc.Crc32u64(param.y, param.e+param.h)
   200  	param.x = crc.Crc32u64(param.x, param.f+param.a)
   201  	param.e = rotate64(param.e, r)
   202  	param.c += param.e
   203  }
   204  
   205  func permute3(a *uint64, b *uint64, c *uint64) {
   206  	*a, *b, *c = *c, *a, *b
   207  }
   208  
   209  func cityHashCrc256Short(s []byte, len uint) ([]uint64, error) {
   210  	data := make([]byte, 240)
   211  	copy(data, s)
   212  	return cityHashCrc256Long(data, 240, ^uint32(len))
   213  }