1package murmur323import (4 "hash"5 "math/bits"6)78const (9 c1 = 0xcc9e2d5110 c2 = 0x1b87359311 r1 = 1512 r2 = 1313 blockSize32 = 414 hashSize32 = 415)1617type digest32 struct {18 seed uint3219 h1 uint3220 tail [4]byte21 tailBytesCount int22 writtenLen int23}2425// New32 returns a new hash.Hash32 computing the MurmurHash3 hash.26// It can generate 2 to the power of 32 unique 32-bit values ranging27// from 0 to 4_294_967_296.28// Hash is not collision safe, so it's recommended to handle potential29// collisions when dealing with more than 65_536 values which is when30// probability raises.31func New32() hash.Hash32 {32 return &digest32{}33}3435// NewWithSeed32 returns a new hash.Hash32 computing the MurmurHash336// hash with the given seed.37// It can generate 2 to the power of 32 unique 32-bit values ranging38// from 0 to 4_294_967_296.39// Hash is not collision safe, so it's recommended to handle potential40// collisions when dealing with more than 65_536 values which is when41// provability raises.42func NewWithSeed32(seed uint32) hash.Hash32 {43 return &digest32{seed: seed, h1: seed}44}4546// Sum32 returns the MurmurHash3 hash of the specified data.47func Sum32(data []byte) uint32 {48 return Sum32WithSeed(data, 0)49}5051// Sum32WithSeed returns the MurmurHash3 hash of the specified data52// using the given seed.53func Sum32WithSeed(data []byte, seed uint32) uint32 {54 h := NewWithSeed32(seed)55 h.Write(data)56 return h.Sum32()57}5859func (digest32) BlockSize() int {60 return blockSize3261}6263func (digest32) Size() int {64 return hashSize3265}6667func (d *digest32) Reset() {68 d.h1 = d.seed69 d.tailBytesCount = 070 d.writtenLen = 071}7273func (d *digest32) Write(bz []byte) (int, error) {74 // Keep track of all written bytes75 total := len(bz)76 d.writtenLen += total7778 // If there are leftover bytes in the tail,79 // try to fill a block with the new data.80 if d.tailBytesCount > 0 {81 need := blockSize32 - d.tailBytesCount82 if len(bz) < need {83 // Append more data to the block84 copy(d.tail[d.tailBytesCount:], bz)85 d.tailBytesCount += len(bz)8687 // Tail block is still not filled88 return total, nil89 }9091 // Append remaining block data and process current block92 copy(d.tail[d.tailBytesCount:], bz[:need])93 d.processBlock(d.tail[:])9495 // Update data to exclude the appended processed data96 bz = bz[need:]97 d.tailBytesCount = 098 }99100 // Process full 4-byte blocks101 for len(bz) >= blockSize32 {102 d.processBlock(bz[:blockSize32])103 bz = bz[blockSize32:]104 }105106 // Save remaining bytes in the tail. Remaining data can be left107 // out of the last block when data size is less than 4 bytes.108 if len(bz) > 0 {109 d.tailBytesCount = copy(d.tail[:], bz)110 }111112 return total, nil113}114115func (d digest32) Sum32() uint32 {116 h1 := d.h1117118 // Process tail bytes when they exist. Blocks have 4 bytes, so depending119 // on the size of the data some bytes might not be processed after the last120 // write if the last block has less than 4 bytes.121 var k1 uint32122 switch d.tailBytesCount {123 case 3:124 k1 ^= uint32(d.tail[2]) << 16125 fallthrough126 case 2:127 k1 ^= uint32(d.tail[1]) << 8128 fallthrough129 case 1:130 k1 ^= uint32(d.tail[0])131 k1 *= c1132 k1 = bits.RotateLeft32(k1, r1)133 k1 *= c2134 h1 ^= k1135 }136137 // Finalization mix138 h1 ^= uint32(d.writtenLen)139140 h1 ^= h1 >> 16141 h1 *= 0x85ebca6b142 h1 ^= h1 >> r2143 h1 *= 0xc2b2ae35144 h1 ^= h1 >> 16145146 return h1147}148149func (d digest32) Sum(bz []byte) []byte {150 // Append hash in little-endian order151 s := d.Sum32()152 return append(bz, byte(s), byte(s>>8), byte(s>>16), byte(s>>24))153}154155// processBlock reads a 4-byte little-endian block156// and mixes it into the hash state.157func (d *digest32) processBlock(bz []byte) {158 k1 := uint32(bz[0]) | uint32(bz[1])<<8 | uint32(bz[2])<<16 | uint32(bz[3])<<24159 k1 *= c1160 k1 = bits.RotateLeft32(k1, r1)161 k1 *= c2162163 d.h1 ^= k1164 d.h1 = bits.RotateLeft32(d.h1, r2)165 d.h1 = d.h1*5 + 0xe6546b64 // MurmurHash3 "m" = 5, "n" = 0xe6546b64166}167Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.