Fixes rounding loop of MurMur128

This commit is contained in:
Vitor Pamplona
2025-12-12 17:29:49 -05:00
parent 95723479d6
commit 7a61217eb6
@@ -22,7 +22,8 @@ package com.vitorpamplona.quartz.nip01Core.hints.bloom
class MurmurHash3 { class MurmurHash3 {
companion object { companion object {
private const val ROUND_DOWN = 0xFFFFFFFC.toInt() private const val ROUND_DOWN_32 = 0xFFFC
private const val ROUND_DOWN_128 = 0xFFF0
private const val C1_32 = -0x3361d2af // 0xcc9e2d51 private const val C1_32 = -0x3361d2af // 0xcc9e2d51
private const val C2_32 = 0x1b873593 private const val C2_32 = 0x1b873593
private const val N_32: Int = -0x19ab949c // 0xe6546b64 private const val N_32: Int = -0x19ab949c // 0xe6546b64
@@ -46,17 +47,17 @@ class MurmurHash3 {
seed: Int, seed: Int,
): Int { ): Int {
var h1 = seed var h1 = seed
val roundedEnd = data.size and ROUND_DOWN // Round down to 4-byte blocks val roundedEnd = data.size and ROUND_DOWN_32 // Round down to 4-byte blocks
var i = 0 var i = 0
var k1 = 0 var k1 = 0
while (i < roundedEnd) { while (i < roundedEnd) {
k1 = k1 =
( (
data[i++].toInt() and 0xFF or data[i++].int() or
(data[i++].toInt() and 0xFF shl 8) or (data[i++].int() shl 8) or
(data[i++].toInt() and 0xFF shl 16) or (data[i++].int() shl 16) or
(data[i++].toInt() and 0xFF shl 24) (data[i++].int() shl 24)
) * C1_32 ) * C1_32
h1 = h1 xor k1.rotateLeft(15) * C2_32 h1 = h1 xor k1.rotateLeft(15) * C2_32
@@ -67,33 +68,33 @@ class MurmurHash3 {
k1 = 0 k1 = 0
when (data.size and 3) { when (data.size and 3) {
3 -> { 3 -> {
k1 = k1 or ((data[i + 2].toInt() and 0xFF) shl 16) k1 = k1 or ((data[i + 2].int()) shl 16)
k1 = k1 or ((data[i + 1].toInt() and 0xFF) shl 8) k1 = k1 or ((data[i + 1].int()) shl 8)
k1 = k1 or (data[i].toInt() and 0xFF) k1 = k1 or data[i].int()
k1 *= C1_32 k1 *= C1_32
k1 = (k1 shl 15) or (k1 ushr -15) k1 = k1.rotateLeft(15)
k1 *= C2_32 k1 *= C2_32
h1 = h1 xor k1 h1 = h1 xor k1
} }
2 -> { 2 -> {
k1 = k1 or (data[i + 1].toInt() and 0xFF shl 8) k1 = k1 or (data[i + 1].int() shl 8)
k1 = k1 or (data[i].toInt() and 0xFF) k1 = k1 or data[i].int()
k1 *= C1_32 k1 *= C1_32
k1 = (k1 shl 15) or (k1 ushr -15) k1 = k1.rotateLeft(15)
k1 *= C2_32 k1 *= C2_32
h1 = h1 xor k1 h1 = h1 xor k1
} }
1 -> { 1 -> {
k1 = k1 or (data[i].toInt() and 0xFF) k1 = k1 or data[i].int()
k1 *= C1_32 k1 *= C1_32
k1 = (k1 shl 15) or (k1 ushr -15) k1 = k1.rotateLeft(15)
k1 *= C2_32 k1 *= C2_32
h1 = h1 xor k1 h1 = h1 xor k1
@@ -115,11 +116,10 @@ class MurmurHash3 {
): Pair<Long, Long> { ): Pair<Long, Long> {
var h1 = seed var h1 = seed
var h2 = seed var h2 = seed
val len = data.size val roundedEnd = data.size and ROUND_DOWN_128
val nblocks = len / 16
var i = 0 var i = 0
while (i < nblocks) { while (i < roundedEnd) {
val k1 = val k1 =
( (
data[i++].long() or data[i++].long() or
@@ -151,8 +151,8 @@ class MurmurHash3 {
h2 = (h2.rotateLeft(R1_128_X64) + h1) * 5 + 0x38495ab5 h2 = (h2.rotateLeft(R1_128_X64) + h1) * 5 + 0x38495ab5
} }
val index = nblocks * 16 val index = roundedEnd
val rem = len - index val rem = data.size - index
var k1 = 0L var k1 = 0L
var k2 = 0L var k2 = 0L
@@ -204,8 +204,8 @@ class MurmurHash3 {
h1 = h1 xor (k1 * C1_128_X64).rotateLeft(R1_128_X64) * C2_128_X64 h1 = h1 xor (k1 * C1_128_X64).rotateLeft(R1_128_X64) * C2_128_X64
} }
h1 = h1 xor len.toLong() h1 = h1 xor data.size.toLong()
h2 = h2 xor len.toLong() h2 = h2 xor data.size.toLong()
h1 += h2 h1 += h2
h2 += h1 h2 += h1
@@ -221,6 +221,8 @@ class MurmurHash3 {
fun Byte.long() = toLong() and 0xffL fun Byte.long() = toLong() and 0xffL
fun Byte.int() = toInt() and 0xff
private fun Int.fmix(): Int { private fun Int.fmix(): Int {
var h = this var h = this
h = (h xor (h ushr 16)) * -0x7a143595 // 0x85ebca6b h = (h xor (h ushr 16)) * -0x7a143595 // 0x85ebca6b