github.com/scottcagno/storage@v1.8.0/pkg/hash/murmur3/murmur32.go (about) 1 /* 2 * // Copyright (c) 2021. Scott Cagno. All rights reserved. 3 * // The license can be found in the root of this project; see LICENSE. 4 */ 5 6 package murmur3 7 8 import ( 9 "hash" 10 "unsafe" 11 ) 12 13 // Make sure interfaces are correctly implemented. 14 var ( 15 _ hash.Hash = new(digest32) 16 _ hash.Hash32 = new(digest32) 17 ) 18 19 const ( 20 c1_32 uint32 = 0xcc9e2d51 21 c2_32 uint32 = 0x1b873593 22 ) 23 24 // digest32 represents a partial evaluation of a 32 bites hash. 25 type digest32 struct { 26 digest 27 h1 uint32 // Unfinalized running hash. 28 } 29 30 func New32() hash.Hash32 { 31 d := new(digest32) 32 d.bmixer = d 33 d.Reset() 34 return d 35 } 36 37 func New32Seed(seed uint32) hash.Hash32 { 38 d := new(digest32) 39 d.bmixer = d 40 d.Reset() 41 return d 42 } 43 44 func (d *digest32) Size() int { return 4 } 45 46 func (d *digest32) reset() { d.h1 = 0 } 47 48 func (d *digest32) Sum(b []byte) []byte { 49 h := d.h1 50 return append(b, byte(h>>24), byte(h>>16), byte(h>>8), byte(h)) 51 } 52 53 // Digest as many blocks as possible. 54 func (d *digest32) bmix(p []byte) (tail []byte) { 55 h1 := d.h1 56 57 nblocks := len(p) / 4 58 for i := 0; i < nblocks; i++ { 59 k1 := *(*uint32)(unsafe.Pointer(&p[i*4])) 60 61 k1 *= c1_32 62 k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) 63 k1 *= c2_32 64 65 h1 ^= k1 66 h1 = (h1 << 13) | (h1 >> 19) // rotl32(h1, 13) 67 h1 = h1*5 + 0xe6546b64 68 } 69 d.h1 = h1 70 return p[nblocks*d.Size():] 71 } 72 73 func (d *digest32) Sum32() (h1 uint32) { 74 75 h1 = d.h1 76 77 var k1 uint32 78 switch len(d.tail) & 3 { 79 case 3: 80 k1 ^= uint32(d.tail[2]) << 16 81 fallthrough 82 case 2: 83 k1 ^= uint32(d.tail[1]) << 8 84 fallthrough 85 case 1: 86 k1 ^= uint32(d.tail[0]) 87 k1 *= c1_32 88 k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) 89 k1 *= c2_32 90 h1 ^= k1 91 } 92 93 h1 ^= uint32(d.clen) 94 95 h1 ^= h1 >> 16 96 h1 *= 0x85ebca6b 97 h1 ^= h1 >> 13 98 h1 *= 0xc2b2ae35 99 h1 ^= h1 >> 16 100 101 return h1 102 } 103 104 /* 105 func rotl32(x uint32, r byte) uint32 { 106 return (x << r) | (x >> (32 - r)) 107 } 108 */ 109 110 // Sum32 returns the MurmurHash3 sum of data. It is equivalent to the 111 // following sequence (without the extra burden and the extra allocation): 112 // hasher := New32() 113 // hasher.WriteType(data) 114 // return hasher.Sum32() 115 func Sum32(data []byte) uint32 { 116 117 var h1 uint32 = 0 118 119 nblocks := len(data) / 4 120 var p uintptr 121 if len(data) > 0 { 122 p = uintptr(unsafe.Pointer(&data[0])) 123 } 124 p1 := p + uintptr(4*nblocks) 125 for ; p < p1; p += 4 { 126 k1 := *(*uint32)(unsafe.Pointer(p)) 127 128 k1 *= c1_32 129 k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) 130 k1 *= c2_32 131 132 h1 ^= k1 133 h1 = (h1 << 13) | (h1 >> 19) // rotl32(h1, 13) 134 h1 = h1*5 + 0xe6546b64 135 } 136 137 tail := data[nblocks*4:] 138 139 var k1 uint32 140 switch len(tail) & 3 { 141 case 3: 142 k1 ^= uint32(tail[2]) << 16 143 fallthrough 144 case 2: 145 k1 ^= uint32(tail[1]) << 8 146 fallthrough 147 case 1: 148 k1 ^= uint32(tail[0]) 149 k1 *= c1_32 150 k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) 151 k1 *= c2_32 152 h1 ^= k1 153 } 154 155 h1 ^= uint32(len(data)) 156 157 h1 ^= h1 >> 16 158 h1 *= 0x85ebca6b 159 h1 ^= h1 >> 13 160 h1 *= 0xc2b2ae35 161 h1 ^= h1 >> 16 162 163 return h1 164 }