简介
MurmurHash
是一种非加密型哈希函数(Non-cryptographic hash function),适用于一般的哈希检索操作。与其它流行的哈希函数相比,对于规律性较强的 key,MurmurHash 的随机分布特征表现更良好。- 常见的
MD5
、SHA1
是加密型哈希函数(Cryptographic hash function)
Hash 算法评价
杨保华
《区块链·原理、设计与应用》第5章密码学与安全技术
中讲到,一个优秀的 Hash
算法将能实现如下功能:
正向快速
给定明文和 Hash 算法,在有限时间和有限资源内能计算得到 Hash 值
逆向困难
给定(若干) Hash 值,在有限时间内很难(基本不可能)逆推出明文;
输入敏感
原始输入信息发生任何改变,新产生的 Hash 值都应该出现很大不同;
冲突避免
很难找到两段内容不同的明文,使得它们的 Hash 值一致(发生碰撞)。
冲突避免有时候又称为“抗碰撞性”,分为“弱抗碰撞性”和“强抗碰撞性”。如果给定明文前提下,无法找到与之碰撞的其他明文,则算法具有“弱抗碰撞性”;如果无法找到任意两个发生 Hash 碰撞的明文,则称算法具有“强抗碰撞性”。
家族成员
MurmurHash1, MurmurHash2, MurmurHash3
64bit long
Python3(mmh3)
# signed
>>> mmh3.hash64('CN305183362S')
(-1993453447204570204, -4896406162740467071)
# unsigned
>>> mmh3.hash64('CN305183362S', signed=False)
(16453290626504981412, 13550337910969084545)
>>> mmh3.hash('CN305183362S')
2088819274
Java(guava)
import com.google.common.hash.Hashing;
import com.google.common.primitives.UnsignedLong;
import static com.google.common.base.Charsets.UTF_8;
public class Main {
public static void main(String[] args) {
long signed = Hashing.murmur3_128().hashString("CN305183362S", UTF_8).asLong();
UnsignedLong unsigned = UnsignedLong.fromLongBits(signed);
System.out.println(signed); // -1993453447204570204
System.out.println(unsigned); // 16453290626504981412
int hash32 = Hashing.murmur3_32().hashString("CN305183362S", UTF_8).asInt();
System.out.println(hash32); // 2088819274
}
}
计算 mmh3 十六进制字符串
Python3
>>> import binascii
>>> import mmh3
>>> binascii.b2a_hex(mmh3.hash_bytes('CN305183362S')).decode('utf8')
'a4fb17cba6d455e4812ad28989780cbc' # 32个字符,128 bit
>>> hex(mmh3.hash128('CN305183362S'))
'0xbc0c788989d22a81e455d4a6cb17fba4'
Java
借用 BigInteger
import java.math.BigInteger; import org.apache.commons.codec.digest.MurmurHash3; import org.apache.commons.lang.ArrayUtils; public class AppTester { public static void main(String[] args) { final byte[] origin = "CN305183362S".getBytes(); long[] vec = MurmurHash3.hash128(origin, 0, origin.length, 0); // 将 long 转换为 BigInteger BigInteger bigInteger0 = BigInteger.valueOf(vec[0]); BigInteger bigInteger1 = BigInteger.valueOf(vec[1]); // 将 BigInteger 转换为 byte[] byte[] array0 = bigInteger0.toByteArray(); byte[] array1 = bigInteger1.toByteArray(); // 反转 byte[](大小端转换) ArrayUtils.reverse(array0); ArrayUtils.reverse(array1); // 将 byte[] 转换为无符号整数,并转为十六进制字符串 String part0 = (new BigInteger(1, array0)).toString(16); String part1 = (new BigInteger(1, array1)).toString(16); System.out.println(part0 + part1); // a4fb17cba6d455e4812ad28989780cbc } }
借用 ByteBuffer(好文推荐:Java 中 byte、byte 数组和 int、long 之间的转换)
import java.nio.ByteBuffer; import org.apache.commons.codec.digest.MurmurHash3; import org.apache.commons.lang.ArrayUtils; public class AppTester { public static void main(String[] args) { final byte[] origin = "CN305183362S".getBytes(); long[] vec = MurmurHash3.hash128(origin, 0, origin.length, 0); ByteBuffer buf0 = ByteBuffer.allocate(8); ByteBuffer buf1 = ByteBuffer.allocate(8); buf0.putLong(0, vec[0]); buf1.putLong(0, vec[1]); byte[] array0 = buf0.putLong(0, vec[0]).array(); byte[] array1 = buf1.putLong(0, vec[1]).array(); ArrayUtils.reverse(array0); // 反转 byte[](大小端转换) ArrayUtils.reverse(array1); // 反转 byte[](大小端转换) buf0.put(array0, 0, array0.length).flip(); buf1.put(array1, 0, array1.length).flip(); String part0 = String.format("%x", buf0.getLong()); String part1 = String.format("%x", buf1.getLong()); System.out.println(part0 + part1); // a4fb17cba6d455e4812ad28989780cbc } }
浅显易懂版,不用处理字节
import org.apache.commons.codec.digest.MurmurHash3; public class AppTester { public static void main(String[] args) { final byte[] origin = "CN305183362S".getBytes(); long[] vec = MurmurHash3.hash128(origin, 0, origin.length, 0); String part0 = String.format("%x", vec[0]); String part1 = String.format("%x", vec[1]); String line = ""; // 反转前半段(大小端转换) for (int i = 0; i < 8; ++i) { line += part0.substring(14 - 2 * i, 16 - 2 * i); } // 反转后半段(大小端转换) for (int i = 0; i < 8; ++i) { line += part1.substring(14 - 2 * i, 16 - 2 * i); } System.out.println(line); // a4fb17cba6d455e4812ad28989780cbc } }
google guava (推荐)
import com.google.common.hash.Hashing; import static com.google.common.base.Charsets.UTF_8; public class Main { public static void main(String[] args) { String mmh3 = Hashing.murmur3_128().hashString("CN305183362S", UTF_8).toString(); System.out.println(mmh3); // a4fb17cba6d455e4812ad28989780cbc } }
Node.js
- MurmurHash3js
在线测试: http://murmurhash.shorelabs.com/
var murmurHash3 = require("murmurhash3js"); let line = murmurHash3.x64.hash128("CN305183362S"); console.log(line); // e455d4a6cb17fba4bc0c788989d22a81 let newLine = ""; // 反转前半段(大小端转换) for (let i = 0; i < 8; ++i) { newLine += line.slice(14-2*i, 16-2*i); } // 反转后半段(大小端转换) for (let i = 0; i < 8; ++i) { newLine += line.slice(30-2*i, 32-2*i); } console.log(newLine); // a4fb17cba6d455e4812ad28989780cbc
本文出处 qbit snap
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。