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, ¶m, s) 54 permute3(¶m.a, ¶m.h, ¶m.c) 55 s = s[40:] 56 57 chunk(33, ¶m, s) 58 permute3(¶m.a, ¶m.h, ¶m.f) 59 s = s[40:] 60 61 chunk(0, ¶m, s) 62 permute3(¶m.b, ¶m.h, ¶m.f) 63 s = s[40:] 64 65 chunk(42, ¶m, s) 66 permute3(¶m.b, ¶m.h, ¶m.d) 67 s = s[40:] 68 69 chunk(0, ¶m, s) 70 permute3(¶m.b, ¶m.h, ¶m.e) 71 s = s[40:] 72 73 chunk(33, ¶m, s) 74 permute3(¶m.a, ¶m.h, ¶m.e) 75 s = s[40:] 76 77 iters-- 78 if iters <= 0 { 79 break 80 } 81 } 82 83 for len >= 40 { 84 chunk(29, ¶m, 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(¶m.c, ¶m.h, ¶m.g) 92 len -= 40 93 } 94 if len > 0 { 95 s = s[len-40:] 96 chunk(33, ¶m, 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 }