github.com/spaolacci/murmur3@v1.1.0/murmur128.go (about)

     1  package murmur3
     2  
     3  import (
     4  	//"encoding/binary"
     5  	"hash"
     6  	"unsafe"
     7  )
     8  
     9  const (
    10  	c1_128 = 0x87c37b91114253d5
    11  	c2_128 = 0x4cf5ad432745937f
    12  )
    13  
    14  // Make sure interfaces are correctly implemented.
    15  var (
    16  	_ hash.Hash = new(digest128)
    17  	_ Hash128   = new(digest128)
    18  	_ bmixer    = new(digest128)
    19  )
    20  
    21  // Hash128 represents a 128-bit hasher
    22  // Hack: the standard api doesn't define any Hash128 interface.
    23  type Hash128 interface {
    24  	hash.Hash
    25  	Sum128() (uint64, uint64)
    26  }
    27  
    28  // digest128 represents a partial evaluation of a 128 bites hash.
    29  type digest128 struct {
    30  	digest
    31  	h1 uint64 // Unfinalized running hash part 1.
    32  	h2 uint64 // Unfinalized running hash part 2.
    33  }
    34  
    35  // New128 returns a 128-bit hasher
    36  func New128() Hash128 { return New128WithSeed(0) }
    37  
    38  // New128WithSeed returns a 128-bit hasher set with explicit seed value
    39  func New128WithSeed(seed uint32) Hash128 {
    40  	d := new(digest128)
    41  	d.seed = seed
    42  	d.bmixer = d
    43  	d.Reset()
    44  	return d
    45  }
    46  
    47  func (d *digest128) Size() int { return 16 }
    48  
    49  func (d *digest128) reset() { d.h1, d.h2 = uint64(d.seed), uint64(d.seed) }
    50  
    51  func (d *digest128) Sum(b []byte) []byte {
    52  	h1, h2 := d.Sum128()
    53  	return append(b,
    54  		byte(h1>>56), byte(h1>>48), byte(h1>>40), byte(h1>>32),
    55  		byte(h1>>24), byte(h1>>16), byte(h1>>8), byte(h1),
    56  
    57  		byte(h2>>56), byte(h2>>48), byte(h2>>40), byte(h2>>32),
    58  		byte(h2>>24), byte(h2>>16), byte(h2>>8), byte(h2),
    59  	)
    60  }
    61  
    62  func (d *digest128) bmix(p []byte) (tail []byte) {
    63  	h1, h2 := d.h1, d.h2
    64  
    65  	nblocks := len(p) / 16
    66  	for i := 0; i < nblocks; i++ {
    67  		t := (*[2]uint64)(unsafe.Pointer(&p[i*16]))
    68  		k1, k2 := t[0], t[1]
    69  
    70  		k1 *= c1_128
    71  		k1 = (k1 << 31) | (k1 >> 33) // rotl64(k1, 31)
    72  		k1 *= c2_128
    73  		h1 ^= k1
    74  
    75  		h1 = (h1 << 27) | (h1 >> 37) // rotl64(h1, 27)
    76  		h1 += h2
    77  		h1 = h1*5 + 0x52dce729
    78  
    79  		k2 *= c2_128
    80  		k2 = (k2 << 33) | (k2 >> 31) // rotl64(k2, 33)
    81  		k2 *= c1_128
    82  		h2 ^= k2
    83  
    84  		h2 = (h2 << 31) | (h2 >> 33) // rotl64(h2, 31)
    85  		h2 += h1
    86  		h2 = h2*5 + 0x38495ab5
    87  	}
    88  	d.h1, d.h2 = h1, h2
    89  	return p[nblocks*d.Size():]
    90  }
    91  
    92  func (d *digest128) Sum128() (h1, h2 uint64) {
    93  
    94  	h1, h2 = d.h1, d.h2
    95  
    96  	var k1, k2 uint64
    97  	switch len(d.tail) & 15 {
    98  	case 15:
    99  		k2 ^= uint64(d.tail[14]) << 48
   100  		fallthrough
   101  	case 14:
   102  		k2 ^= uint64(d.tail[13]) << 40
   103  		fallthrough
   104  	case 13:
   105  		k2 ^= uint64(d.tail[12]) << 32
   106  		fallthrough
   107  	case 12:
   108  		k2 ^= uint64(d.tail[11]) << 24
   109  		fallthrough
   110  	case 11:
   111  		k2 ^= uint64(d.tail[10]) << 16
   112  		fallthrough
   113  	case 10:
   114  		k2 ^= uint64(d.tail[9]) << 8
   115  		fallthrough
   116  	case 9:
   117  		k2 ^= uint64(d.tail[8]) << 0
   118  
   119  		k2 *= c2_128
   120  		k2 = (k2 << 33) | (k2 >> 31) // rotl64(k2, 33)
   121  		k2 *= c1_128
   122  		h2 ^= k2
   123  
   124  		fallthrough
   125  
   126  	case 8:
   127  		k1 ^= uint64(d.tail[7]) << 56
   128  		fallthrough
   129  	case 7:
   130  		k1 ^= uint64(d.tail[6]) << 48
   131  		fallthrough
   132  	case 6:
   133  		k1 ^= uint64(d.tail[5]) << 40
   134  		fallthrough
   135  	case 5:
   136  		k1 ^= uint64(d.tail[4]) << 32
   137  		fallthrough
   138  	case 4:
   139  		k1 ^= uint64(d.tail[3]) << 24
   140  		fallthrough
   141  	case 3:
   142  		k1 ^= uint64(d.tail[2]) << 16
   143  		fallthrough
   144  	case 2:
   145  		k1 ^= uint64(d.tail[1]) << 8
   146  		fallthrough
   147  	case 1:
   148  		k1 ^= uint64(d.tail[0]) << 0
   149  		k1 *= c1_128
   150  		k1 = (k1 << 31) | (k1 >> 33) // rotl64(k1, 31)
   151  		k1 *= c2_128
   152  		h1 ^= k1
   153  	}
   154  
   155  	h1 ^= uint64(d.clen)
   156  	h2 ^= uint64(d.clen)
   157  
   158  	h1 += h2
   159  	h2 += h1
   160  
   161  	h1 = fmix64(h1)
   162  	h2 = fmix64(h2)
   163  
   164  	h1 += h2
   165  	h2 += h1
   166  
   167  	return h1, h2
   168  }
   169  
   170  func fmix64(k uint64) uint64 {
   171  	k ^= k >> 33
   172  	k *= 0xff51afd7ed558ccd
   173  	k ^= k >> 33
   174  	k *= 0xc4ceb9fe1a85ec53
   175  	k ^= k >> 33
   176  	return k
   177  }
   178  
   179  /*
   180  func rotl64(x uint64, r byte) uint64 {
   181  	return (x << r) | (x >> (64 - r))
   182  }
   183  */
   184  
   185  // Sum128 returns the MurmurHash3 sum of data. It is equivalent to the
   186  // following sequence (without the extra burden and the extra allocation):
   187  //     hasher := New128()
   188  //     hasher.Write(data)
   189  //     return hasher.Sum128()
   190  func Sum128(data []byte) (h1 uint64, h2 uint64) { return Sum128WithSeed(data, 0) }
   191  
   192  // Sum128WithSeed returns the MurmurHash3 sum of data. It is equivalent to the
   193  // following sequence (without the extra burden and the extra allocation):
   194  //     hasher := New128WithSeed(seed)
   195  //     hasher.Write(data)
   196  //     return hasher.Sum128()
   197  func Sum128WithSeed(data []byte, seed uint32) (h1 uint64, h2 uint64) {
   198  	d := &digest128{h1: uint64(seed), h2: uint64(seed)}
   199  	d.seed = seed
   200  	d.tail = d.bmix(data)
   201  	d.clen = len(data)
   202  	return d.Sum128()
   203  }