【密码学】一文读懂MurMurHash3

简介: 本文应该是MurMurHash算法介绍的最后一篇,来一起看一下最新的MurMurHash算法的具体过程,对于最新的算法来说,整个流程和之前的其实也比较相似,这里从维基百科当中找到了伪代码,也就不贴出来Google官方给出的推荐代码了,先来看一下维基百科给出的伪代码,这里只有32位的伪代码。

【密码学】一文读懂MurMurHash3


YXDGY[6I7JLU}U7U~W[L)]A.jpg

本文应该是MurMurHash算法介绍的最后一篇,来一起看一下最新的MurMurHash算法的具体过程,对于最新的算法来说,整个流程和之前的其实也比较相似,这里从维基百科当中找到了伪代码,也就不贴出来Google官方给出的推荐代码了,先来看一下维基百科给出的伪代码,这里只有32位的伪代码。

algorithm Murmur3_32 is
    // Note: In this version, all arithmetic is performed with unsigned 32-bit integers.
    //       In the case of overflow, the result is reduced modulo 232.
    input: key, len, seed
    c1 ← 0xcc9e2d51
    c2 ← 0x1b873593
    r1 ← 15
    r2 ← 13
    m ← 5
    n ← 0xe6546b64
    hash ← seed
    for each fourByteChunk of key do
        k ← fourByteChunk
        k ← k × c1
        k ← k ROL r1
        k ← k × c2
        hash ← hash XOR k
        hash ← hash ROL r2
        hash ← (hash × m) + n
    with any remainingBytesInKey do
        remainingBytes ← SwapToLittleEndian(remainingBytesInKey)
        // Note: Endian swapping is only necessary on big-endian machines.
        //       The purpose is to place the meaningful digits towards the low end of the value,
        //       so that these digits have the greatest potential to affect the low range digits
        //       in the subsequent multiplication.  Consider that locating the meaningful digits
        //       in the high range would produce a greater effect upon the high digits of the
        //       multiplication, and notably, that such high digits are likely to be discarded
        //       by the modulo arithmetic under overflow.  We don't want that.
        remainingBytes ← remainingBytes × c1
        remainingBytes ← remainingBytes ROL r1
        remainingBytes ← remainingBytes × c2
        hash ← hash XOR remainingBytes
    hash ← hash XOR len
    hash ← hash XOR (hash >> 16)
    hash ← hash × 0x85ebca6b
    hash ← hash XOR (hash >> 13)
    hash ← hash × 0xc2b2ae35
    hash ← hash XOR (hash >> 16)

这个入参和之前的两个算法都是一样的,依然可以看做是两个,第一个是需要哈希的值,第二个是seed。对于这个seed的取值,看了一下一些语言的实现,有些是0x0,有些是其他的值,目前也没发现推荐的值,如果有知道这个seed有什么取的方案的话,也欢迎和我交流。


算法过程

image.gifMurMurHash3算法结构

`P6C_TO3L[Z$2OL~4`$}7N9.png

这里依然稍微改了一下之前用到的图,也是一个出现了三次的老演员了,其实除了整个对消息的哈希处理过程当中,对于具体的哈希函数有一些差别,整个算法结构依然一样。好了到这里,有关MurMurHash算法的相关知识就水完了,恭喜我,又填完了一个坑。


代码实现

这里只给出32位的版本了,128位的就不写了,偷一个懒。

Rust

在查找相关代码的时候,这里学了rust的一个新的函数,这些代码主要是借鉴了参考资料里面的代码,他这个seed固定了另外一个值,原因未知,这里我改了一下,seed还是当参数吧。

use std::convert::TryInto;
use std::u32;
const C1: u32 = 0xcc9e_2d51;
const C2: u32 = 0x1b87_3593;
const D: u32 = 0xe654_6b64;
const FMIX1: u32 = 0x85eb_ca6b;
const FMIX2: u32 = 0xc2b2_ae35;
fn fmix32(mut h: u32) -> u32 {
    h ^= h >> 16;
    h = h.wrapping_mul(FMIX1);
    h ^= h >> 13;
    h = h.wrapping_mul(FMIX2);
    h ^= h >> 16;
    h
}
pub fn murmurhash3(key: &[u8], seed: u32) -> u32 {
    let mut h = seed;
    let mut chunks = key.chunks_exact(4);
    while let Some(chunk) = chunks.next() {
        let mut k: u32 = u32::from_le_bytes(chunk.try_into().unwrap());
        k = k.wrapping_mul(C1);
        k = k.rotate_left(15);
        k = k.wrapping_mul(C2);
        h ^= k;
        h = h.rotate_left(13);
        h = (h.wrapping_mul(5)).wrapping_add(D);
    }
    let remainder = chunks.remainder();
    match remainder.len() {
        3 => {
            let mut k = u32::from(remainder[2]) << 16;
            k ^= u32::from(remainder[1]) << 8;
            k ^= u32::from(remainder[0]);
            k = k.wrapping_mul(C1);
            k = k.rotate_left(15);
            k = k.wrapping_mul(C2);
            h ^= k;
        }
        2 => {
            let mut k = u32::from(remainder[1]) << 8;
            k ^= u32::from(remainder[0]);
            k = k.wrapping_mul(C1);
            k = k.rotate_left(15);
            k = k.wrapping_mul(C2);
            h ^= k;
        }
        1 => {
            let mut k = u32::from(remainder[0]);
            k = k.wrapping_mul(C1);
            k = k.rotate_left(15);
            k = k.wrapping_mul(C2);
            h ^= k;
        }
        _ => {}
    }
    fmix32(h ^ key.len() as u32)
}

Go

这里,用Go来在实现一下,就当学习了。

const C1 = 0xcc9e_2d51
const C2 = 0x1b87_3593
const D = 0xe654_6b64
const FMIX1 = 0x85eb_ca6b
const FMIX2 = 0xc2b2_ae35
func fmix32(h uint32) uint32 {
  h ^= h >> 16
  h *= FMIX1
  h ^= h >> 13
  h *= FMIX2
  h ^= h >> 16
  return h
}
func murmurhash3(key []byte, seed uint32) uint32 {
  h := seed
  keyLen := uint32(len(key))
  offset := 0
  e := binary.LittleEndian
  for keyLen >= 4 {
    k := e.Uint32(key[offset : offset+4])
    fmt.Println(k)
    k *= C1
    k = bits.RotateLeft32(k, 15)
    k *= C2
    h ^= k
    h = bits.RotateLeft32(h, 13)
    h *= 5
    h += D
    offset += 4
    keyLen -= 4
  }
  k1 := uint32(0)
  switch keyLen {
  case 3:
    k1 ^= uint32(key[offset+2]) << 16
    fallthrough
  case 2:
    k1 ^= uint32(key[offset+1]) << 8
    fallthrough
  case 1:
    k1 ^= uint32(key[offset])
    k1 *= C1
    k1 = bits.RotateLeft32(k1, 15)
    k1 *= C2
    h ^= k1
  }
  return fmix32(h ^ uint32(len(key)))
}


相关文章
|
Rust 算法 安全
【密码学】一文读懂MurMurHash2
上次我们聊过了一代的MurMurHash算法,是的,我又来水文章了,今天呢,接着来聊一下二代的MurMurHash算法,二代算法的整体结构实际上和一代算法差不太多,只是对于每一轮数据的处理过程当中的运算有一些差异,算法的来源依然是来自于Google官网给提供的源码,对着源码看的结构,对于这个算法呢,有两个版本,一个是32位的,一个是64位的,对于32位的算法和64位的算法,区别在于两个初始的魔数不同,整体运算过程还是十分相似的。
2741 0
【密码学】一文读懂MurMurHash2
|
算法 安全 PHP
密码学系列之二:密码学基本概念
密码学系列之二:密码学基本概念
1203 0
密码学系列之二:密码学基本概念
|
Web App开发 Rust 算法
【密码学】一文读懂ChaCha20
好久没写新的加密算法的原理了, 这次所选取的加密算法结构比较简单, 一起来看一下吧。
9691 1
【密码学】一文读懂ChaCha20
|
存储 Rust 并行计算
【密码学】一文读懂XTS模式
这篇文章的灵感来源于我偶然翻到的一个某U盘有关磁盘加密的一个介绍(这一篇不是广告蛤), 然后发现这个模式我之前还真没遇到过,因此呢,就学习了一下,就出来了这一篇文章。
7753 0
【密码学】一文读懂XTS模式
|
Rust 算法 Go
【密码学】一文读懂FNV Hash
FNV哈希全名为Fowler-Noll-Vo算法,是以三位发明人Glenn Fowler,Landon Curt Noll,Phong Vo的名字来命名的,最早在1991年提出。它可以快速hash大量的数据并保持较小的冲突概率,适合hash一些相近的字符串比如IP地址、URL、文件名等等。目前FNV算法有三个版本,分别是: FNV-0(已废弃)、FNV-1以及FNV-1a。这三个算法的结构非常相似,因此呢,在这里就一块说了。
4073 0
【密码学】一文读懂FNV Hash
|
SQL 存储 Oracle
6 张图带你彻底搞懂分布式事务 XA 模式
XA 协议是由 X/Open 组织提出的分布式事务处理规范,主要定义了事务管理器 TM 和局部资源管理器 RM 之间的接口。目前主流的数据库,比如 oracle、DB2 都是支持 XA 协议的。
14065 1
6 张图带你彻底搞懂分布式事务 XA 模式
|
存储 算法 数据安全/隐私保护
【密码学】一文读懂白盒AES(Chow方案)(一)
本文主要参考了文献^[1], 代码参考了^[2], 这里感谢文献作者和代码作者,如果有能力的大佬,可以自行查看原文献,个人水平有限,有哪里写的不对的地方,也欢迎读者指正。
4764 0
【密码学】一文读懂白盒AES(Chow方案)(一)
|
缓存 Java 索引
Elasticsearch的TermsQuery慢查询分析和优化
前言 本篇文章主要记录业务上的一个TermsQuery优化和分析的过程和一些思考。 在使用ES的时候,经常会遇到慢查询,这时候可以利用profile进行分析,当利用profile也查看不出什么端倪时候,可以尝试通过阅读代码查看查询为什么这么慢。如下是一个我们内部业务的一个慢查询,经常出现4s左右的延时,一模一样的查询,但是延时不一样,且很难复现。 { "from": 0,
3827 0
Elasticsearch的TermsQuery慢查询分析和优化
|
11月前
|
供应链 NoSQL Java
关于Redisson分布式锁的用法
Redisson分布式锁是实现分布式系统中资源同步的有效工具。通过合理配置和使用Redisson的各种锁机制,可以确保系统的高可用性和数据一致性。本文详细介绍了Redisson分布式锁的配置、基本用法和高级用法,并提供了实际应用示例,希望对您在实际项目中使用Redisson分布式锁有所帮助。c
1610 10
|
存储 缓存 负载均衡
图解一致性哈希算法,看这一篇就够了!
近段时间一直在总结分布式系统架构常见的算法。前面我们介绍过布隆过滤器算法。接下来介绍一个非常重要、也非常实用的算法:一致性哈希算法。通过介绍一致性哈希算法的原理并给出了一种实现和实际运用的案例,带大家真正理解一致性哈希算法。
26220 64
图解一致性哈希算法,看这一篇就够了!