github.com/pidato/unsafe@v0.1.4/memory/hash/wyhashf3.go (about)

     1  package hash
     2  
     3  import (
     4  	"math"
     5  	"math/bits"
     6  	"unsafe"
     7  )
     8  
     9  const (
    10  	DefaultSeed uint64 = 0xa0761d6478bd642f // s0
    11  	s1          uint64 = 0xe7037ed1a0b428db
    12  	s2          uint64 = 0x8ebc6af09c88c6e3
    13  	s3          uint64 = 0x589965cc75374cc3
    14  	s4          uint64 = 0x1d8e4e27c47d124f
    15  )
    16  
    17  var (
    18  	r = Rand{}
    19  )
    20  
    21  func SetSeed(s uint64) {
    22  	r.seed = s
    23  }
    24  func Next() uint64 {
    25  	return r.Next()
    26  }
    27  func NextFloat() float64 {
    28  	return r.NextFloat()
    29  }
    30  func NextGaussian() float64 {
    31  	return r.NextGaussian()
    32  }
    33  
    34  type Rand struct {
    35  	seed uint64
    36  }
    37  
    38  func (w *Rand) Next() uint64 {
    39  	return wyrand(&w.seed)
    40  }
    41  
    42  func (w *Rand) NextFloat() float64 {
    43  	return wy2u01(wyrand(&w.seed))
    44  }
    45  
    46  func (w *Rand) NextGaussian() float64 {
    47  	return wy2gau(wyrand(&w.seed))
    48  }
    49  
    50  func wyrand(seed *uint64) uint64 {
    51  	*seed += uint64(0xa0761d6478bd642f)
    52  	return wymum(*seed, *seed^0xe7037ed1a0b428db)
    53  }
    54  
    55  func wy2u01(r uint64) float64 {
    56  	const norm = float64(1.0) / float64(uint64(1)<<52)
    57  	return float64(r>>12) * norm
    58  }
    59  
    60  func wy2gau(r uint64) float64 {
    61  	const norm = float64(1.0) / float64(uint64(1)<<20)
    62  	return float64((r&0x1fffff)+((r>>21)&0x1fffff)+((r>>42)&0x1fffff))*norm - 3.0
    63  }
    64  
    65  func wymumSlow(a, b uint64) uint64 {
    66  	var (
    67  		hh = (a >> 32) * (b >> 32)
    68  		hl = (a >> 32) * (b & 0xFFFF_FFFF)
    69  		lh = (a & 0xFFFF_FFFF) * (b >> 32)
    70  		ll = (a & 0xFFFF_FFFF) * (b & 0xFFFF_FFFF)
    71  	)
    72  	//a = wyrotate(hl) ^ hh
    73  	//b = wyrotate(lh) ^ ll
    74  	a = ((hl >> 32) | (hl << 32)) ^ hh
    75  	b = ((lh >> 32) | (lh << 32)) ^ ll
    76  	return a ^ b
    77  }
    78  
    79  func wymum(a, b uint64) uint64 {
    80  	a, b = bits.Mul64(a, b)
    81  	return a ^ b
    82  }
    83  
    84  func Bytes(b []byte) uint64 {
    85  	return Hash(*(*unsafe.Pointer)(unsafe.Pointer(&b)), uint64(len(b)), DefaultSeed)
    86  }
    87  
    88  func String(s string) uint64 {
    89  	return Hash(*(*unsafe.Pointer)(unsafe.Pointer(&s)), uint64(len(s)), DefaultSeed)
    90  }
    91  
    92  func I8(v int8) uint64 {
    93  	return U8(*(*uint8)(unsafe.Pointer(&v)))
    94  }
    95  
    96  func U8(v uint8) uint64 {
    97  	value := uint64(v)
    98  	return wymum(s1^1, wymum(((value<<16)|(value<<8)|value)^s1, 0^DefaultSeed))
    99  }
   100  
   101  func I16(v int16) uint64 {
   102  	return U16(*(*uint16)(unsafe.Pointer(&v)))
   103  }
   104  
   105  func U16(v uint16) uint64 {
   106  	var (
   107  		b2 = uint64(*(*byte)(unsafe.Add(unsafe.Pointer(&v), 1)))
   108  		a  = uint64(*(*byte)(unsafe.Pointer(&v)))<<16 | b2<<8 | b2
   109  	)
   110  	return wymum(s1^2, wymum(a^s1, 0^DefaultSeed))
   111  }
   112  
   113  func I32(v int32) uint64 {
   114  	value := uint64(*(*uint32)(unsafe.Pointer(&v)))
   115  	value = (value << 32) | value
   116  	return wymum(s1^4, wymum(value^s1, value^DefaultSeed))
   117  }
   118  
   119  func U32(v uint32) uint64 {
   120  	value := uint64(v)
   121  	value = (value << 32) | value
   122  	return wymum(s1^4, wymum(value^s1, value^DefaultSeed))
   123  
   124  	//return Hash(unsafe.Pointer(&v), 4, DefaultSeed)
   125  }
   126  
   127  func F32(v float32) uint64 {
   128  	return U32(math.Float32bits(v))
   129  }
   130  
   131  func F64(v float64) uint64 {
   132  	return U64(math.Float64bits(v))
   133  }
   134  
   135  func I64(v int64) uint64 {
   136  	return U64(*(*uint64)(unsafe.Pointer(&v)))
   137  }
   138  
   139  func U64(v uint64) uint64 {
   140  	return wymum(s1^8, wymum(
   141  		(v<<32|(v>>32&0xFFFFFFFF))^s1,
   142  		(v>>32|(v&0xFFFFFFFF))^DefaultSeed))
   143  }
   144  
   145  func HashBytes(b []byte) uint64 {
   146  	return Hash(unsafe.Pointer(&b[0]), uint64(len(b)), DefaultSeed)
   147  }
   148  
   149  func Hash(bytes unsafe.Pointer, length uint64, seed uint64) uint64 {
   150  	var (
   151  		a uint64
   152  		b uint64
   153  	)
   154  	if length <= 16 {
   155  		if length >= 4 {
   156  			a = read32(bytes)<<32 | read32(unsafe.Add(bytes, (length>>3)<<2))
   157  			b = read32(unsafe.Add(bytes, length-4))<<32 |
   158  				read32(unsafe.Add(bytes, length-4-((length>>3)<<2)))
   159  		} else if length > 0 {
   160  			a = uint64(*(*byte)(bytes))<<16 |
   161  				uint64(*(*byte)(unsafe.Add(bytes, length>>1)))<<8 |
   162  				uint64(*(*byte)(unsafe.Add(bytes, length-1)))
   163  		}
   164  	} else {
   165  		var (
   166  			index = length
   167  		)
   168  		if length > 48 {
   169  			var (
   170  				see1 = seed
   171  				see2 = seed
   172  			)
   173  			for index > 48 {
   174  				seed = wymum(read64(bytes)^s1, read64(unsafe.Add(bytes, 8))^seed)
   175  				see1 = wymum(read64(unsafe.Add(bytes, 16))^s2, read64(unsafe.Add(bytes, 24))^see1)
   176  				see2 = wymum(read64(unsafe.Add(bytes, 32))^s3, read64(unsafe.Add(bytes, 40))^see2)
   177  				index -= 48
   178  				bytes = unsafe.Add(bytes, 48)
   179  			}
   180  			seed ^= see1 ^ see2
   181  		}
   182  
   183  		for index > 16 {
   184  			seed = wymum(read64(bytes)^s1, read64(unsafe.Add(bytes, 8))^seed)
   185  			index -= 16
   186  			bytes = unsafe.Add(bytes, 16)
   187  		}
   188  
   189  		a = read64(unsafe.Add(bytes, index-16))
   190  		b = read64(unsafe.Add(bytes, index-8))
   191  	}
   192  
   193  	return wymum(s1^length, wymum(a^s1, b^seed))
   194  }
   195  
   196  func WithSecret(bytes unsafe.Pointer, length uint64, secret *[4]uint64) uint64 {
   197  	var (
   198  		a    uint64
   199  		b    uint64
   200  		seed = secret[0]
   201  	)
   202  	if length <= 16 {
   203  		if length >= 4 {
   204  			a = read32(bytes)<<32 | read32(unsafe.Add(bytes, (length>>3)<<2))
   205  			b = read32(unsafe.Add(bytes, length-4))<<32 |
   206  				read32(unsafe.Add(bytes, length-4-((length>>3)<<2)))
   207  		} else if length > 0 {
   208  			a = uint64(*(*byte)(bytes))<<16 |
   209  				uint64(*(*byte)(unsafe.Add(bytes, length>>1)))<<8 |
   210  				uint64(*(*byte)(unsafe.Add(bytes, length-1)))
   211  		}
   212  	} else {
   213  		var (
   214  			index = length
   215  		)
   216  		if length > 48 {
   217  			var (
   218  				see1 = seed
   219  				see2 = seed
   220  			)
   221  			for index > 48 {
   222  				seed = wymum(read64(bytes)^secret[1], read64(unsafe.Add(bytes, 8))^seed)
   223  				see1 = wymum(read64(unsafe.Add(bytes, 16))^secret[2], read64(unsafe.Add(bytes, 24))^see1)
   224  				see2 = wymum(read64(unsafe.Add(bytes, 32))^secret[3], read64(unsafe.Add(bytes, 40))^see2)
   225  				index -= 48
   226  				bytes = unsafe.Add(bytes, 48)
   227  			}
   228  			seed ^= see1 ^ see2
   229  		}
   230  
   231  		for index > 16 {
   232  			seed = wymum(read64(bytes)^secret[1], read64(unsafe.Add(bytes, 8))^seed)
   233  			index -= 16
   234  			bytes = unsafe.Add(bytes, 16)
   235  		}
   236  
   237  		a = read64(unsafe.Add(bytes, index-16))
   238  		b = read64(unsafe.Add(bytes, index-8))
   239  	}
   240  
   241  	return wymum(secret[1]^length, wymum(a^secret[1], b^seed))
   242  }
   243  
   244  var wyf3Secret = [...]byte{
   245  	15, 23, 27, 29, 30, 39, 43, 45, 46, 51, 53, 54, 57, 58, 60, 71, 75, 77, 78, 83, 85,
   246  	86, 89, 90, 92, 99, 101, 102, 105, 106, 108, 113, 114, 116, 120, 135, 139, 141, 142,
   247  	147, 149, 150, 153, 154, 156, 163, 165, 166, 169, 170, 172, 177, 178, 180, 184, 195,
   248  	197, 198, 201, 202, 204, 209, 210, 212, 216, 225, 226, 228, 232, 240}
   249  
   250  func MakeSecret(seed uint64) [4]uint64 {
   251  	var secret [4]uint64
   252  	for i := 0; i < 4; i++ {
   253  		var ok bool
   254  
   255  		for !ok {
   256  			ok = true
   257  			secret[i] = 0
   258  
   259  			for j := 0; j < 64; j += 8 {
   260  				secret[i] |= uint64(wyf3Secret[wyrand(&seed)%uint64(len(wyf3Secret))]) << j
   261  			}
   262  			if secret[i]%2 == 0 {
   263  				ok = false
   264  				continue
   265  			}
   266  			for j := 0; j < i; j++ {
   267  				if popcnt64(secret[j]^secret[i]) != 32 {
   268  					ok = false
   269  					break
   270  				}
   271  
   272  				x := secret[j] ^ secret[i]
   273  				x -= (x >> 1) & 0x5555555555555555
   274  				x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333)
   275  				x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f
   276  				x = (x * 0x0101010101010101) >> 56
   277  				if x != 32 {
   278  					ok = false
   279  					break
   280  				}
   281  			}
   282  		}
   283  	}
   284  	return secret
   285  }
   286  
   287  func popcnt64(x uint64) uint64 {
   288  	x = (x & 0x5555555555555555) + ((x & 0xAAAAAAAAAAAAAAAA) >> 1)
   289  	x = (x & 0x3333333333333333) + ((x & 0xCCCCCCCCCCCCCCCC) >> 2)
   290  	x = (x & 0x0F0F0F0F0F0F0F0F) + ((x & 0xF0F0F0F0F0F0F0F0) >> 4)
   291  	x *= 0x0101010101010101
   292  	return (x >> 56) & 0xFF
   293  }