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