当前位置: 首页 > news >正文

RocksDB 解密可逆哈希:BijectiveHash的设计奥秘

BijectiveHash(双射哈希,即可逆哈希)的设计精髓在于它借鉴了现代密码学和高性能哈希函数中的核心思想,但目标并非加密,而是实现一种无冲突、可逆的置换(Permutation)

可逆哈希是什么,用来做什么?

首先要明确,它和我们通常说的用于哈希表或数据校验的哈希函数(如 Hash64)完全不同。

  • 普通哈希:是多对一的,输入空间远大于输出空间,必然存在冲突(多个不同输入产生相同输出),并且是单向的(不可逆)。
  • 可逆哈希:是一对一的,输入和输出空间大小相同,绝无冲突,并且是双向的(可逆的)。

它的主要用途是数据混淆(Obfuscation)ID置换。比如,你有一组从0开始连续的ID(0, 1, 2, ...),但你不想直接暴露它们,希望把它们变成一组看起来毫无规律、随机分布的ID,同时还能在需要时恢复成原始ID。这时可逆哈希就派上用场了。

BijectiveHash2x64 设计精髓分析

这个函数的设计巧妙地改编自 XXH3 哈希算法中处理小数据块的部分。XXH3为了达到雪崩效应,混合极其充分,而BijectiveHash则利用了这种充分混合的特性,并确保每一步操作都是可逆的。

我们来看它的核心代码:

hash.cc

// ... existing code ...
void BijectiveHash2x64(uint64_t in_high64, uint64_t in_low64, uint64_t seed,uint64_t* out_high64, uint64_t* out_low64) {// Adapted from XXH3_len_9to16_128bconst uint64_t bitflipl = /*secret part*/ 0x59973f0033362349U - seed;const uint64_t bitfliph = /*secret part*/ 0xc202797692d63d58U + seed;Unsigned128 tmp128 =Multiply64to128(in_low64 ^ in_high64 ^ bitflipl, 0x9E3779B185EBCA87U);uint64_t lo = Lower64of128(tmp128);uint64_t hi = Upper64of128(tmp128);lo += 0x3c0000000000000U;  // (len - 1) << 54in_high64 ^= bitfliph;hi += in_high64 + (Lower32of64(in_high64) * uint64_t{0x85EBCA76});lo ^= EndianSwapValue(hi);tmp128 = Multiply64to128(lo, 0xC2B2AE3D27D4EB4FU);lo = Lower64of128(tmp128);hi = Upper64of128(tmp128) + (hi * 0xC2B2AE3D27D4EB4FU);*out_low64 = XXH3_avalanche(lo);*out_high64 = XXH3_avalanche(hi);
}
// ... existing code ...
设计精髓 1:保证无信息丢失的操作

要实现可逆,最关键的一点是任何操作都不能丢失信息

  • Multiply64to128:这是整个设计的核心。普通的64位乘法 uint64_t * uint64_t 的结果仍然是 uint64_t,这会丢失高64位的信息,导致不可逆。而 Multiply64to128 将两个64位整数相乘,产生一个完整的128位结果(Unsigned128),完整保留了所有信息。这是可逆性的数学基础。
  • XOR (^) 和加法 (+):这些操作本身就是可逆的。a ^ b 可以通过再异或一次 b 恢复 aa + b 可以通过减去 b 恢复 a
设计精髓 2:借鉴密码学的“混淆”与“扩散”

为了让输出看起来随机,它借鉴了密码学中的两个重要概念:

  • 混淆(Confusion):让输入和输出之间的关系变得尽可能复杂。
    • 通过与seed相关的密钥(bitfliplbitfliph)进行XOR操作。
    • 与大的素数(0x9E3779B185EBCA87U 等)相乘。
  • 扩散(Diffusion):让输入的任何一位微小变化都能影响到输出的多位(雪崩效应)。
    • lo ^= EndianSwapValue(hi):这是一个类似Feistel网络的结构。它用一部分数据(hi)去改变另一部分数据(lo),然后再用改变后的lo去影响hi的计算。这种交叉影响能迅速地将输入的变化扩散到整个128位状态中。
    • XXH3_avalanche:最后调用XXH3的雪崩函数,进行最终的、彻底的混合,确保最终输出的随机性。
设计精髓 3:可逆的雪崩函数

XXH3_avalanche 本身是一个单向函数,但设计者巧妙地为它实现了一个逆函数 XXH3_unavalanche

// ... existing code ...
inline uint64_t XXH3_avalanche(uint64_t h64) {h64 ^= h64 >> 37;h64 *= 0x165667919E3779F9U;h64 ^= h64 >> 32;return h64;
}inline uint64_t XXH3_unavalanche(uint64_t h64) {h64 ^= h64 >> 32;h64 *= 0x8da8ee41d6df849U;  // inverse of 0x165667919E3779F9Uh64 ^= h64 >> 37;return h64;
}
// ... existing code ...

这里的关键是 0x8da8ee41d6df849U,它是 0x165667919E3779F9U 在模 2^64 意义下的乘法逆元。这意味着 (a * b) * b_inverse = a (mod 2^64)。通过找到这个逆元,乘法步骤就变得可逆了。而XOR和移位操作的逆运算也相对直接。

BijectiveUnhash2x64:逆向工程的艺术

逆向函数 BijectiveUnhash2x64 的实现完美展示了如何一步步“撤销”正向函数的操作。

// ... existing code ...
void BijectiveUnhash2x64(uint64_t in_high64, uint64_t in_low64, uint64_t seed,uint64_t* out_high64, uint64_t* out_low64) {// Inverted above (also consulting XXH3_len_9to16_128b)const uint64_t bitflipl = /*secret part*/ 0x59973f0033362349U - seed;const uint64_t bitfliph = /*secret part*/ 0xc202797692d63d58U + seed;uint64_t lo = XXH3_unavalanche(in_low64);uint64_t hi = XXH3_unavalanche(in_high64);// ... a series of inverse multiplications, subtractions, and XORs ...// ... in the exact reverse order of the forward function ...*out_high64 = hi;*out_low64 = lo;
}
// ... existing code ...

它的每一步都精确地对应 BijectiveHash2x64 的逆操作,并严格按照相反的顺序执行:

  1. 先用 XXH3_unavalanche 撤销雪崩混合。
  2. 用乘法逆元撤销乘法。
  3. 用减法撤销加法。
  4. 用XOR撤销XOR。

总结:设计精髓

  1. 以无损操作为基石:使用扩展精度运算(如64->128位乘法)来确保计算过程不丢失任何信息,这是可逆性的前提。
  2. 借鉴密码学思想:采用Feistel网络、密钥(seed)混淆、乘大素数等方式实现充分的混淆和扩散,让输出看起来随机。
  3. 依赖数论工具:可逆性的实现严重依赖于数论,特别是模乘法逆元的计算,这是将单向乘法变为双向的关键。
  4. 结构对称:正向和逆向过程在结构上是完全对称的,逆向过程是正向过程的完美“镜像”。

通过学习这个设计,我们可以看到一个看似简单的“可逆哈希”背后,融合了计算机体系结构(扩展精度乘法)、密码学(混淆扩散)和数论(模逆元)的深刻原理,是高性能计算和算法设计的典范。

http://www.lryc.cn/news/624255.html

相关文章:

  • Vue diff简介
  • Rust学习笔记(六)|Rust 中的常用集合(Vector、String、HashMap)
  • MiniMax Agent 上线 Market Place ,AI一键复制克隆网站
  • 部署 HAProxy 高可用
  • python 数据拟合(线性拟合、多项式回归)
  • Android Coil3视频封面抽取封面帧存Disk缓存,Kotlin(2)
  • 云计算:企业数字化转型的核心引擎
  • Kubernetes(K8s)常用命令全解析:从基础到进阶
  • 【Kubernetes】在 K8s 上部署 Prometheus
  • C语言基础:变量与进制详解
  • K8s的命名空间需要创建吗
  • 工具集成强化学习:AI数学推理能力的新跃迁
  • Java基础(九):Object核心类深度剖析
  • 图神经网络分享系列-node2vec(二)
  • 基于51单片机WIFI心率计脉搏体温测量仪APP设计
  • HTML应用指南:利用POST请求获取全国华为旗舰店门店位置信息
  • 《若依》权限控制
  • 上下文切换及线程操作相关内容
  • 学习雪花算法
  • linux-高级IO(中)
  • 【BFS 动态规划】P12382 [蓝桥杯 2023 省 Python B] 树上选点|普及+
  • Redis面试精讲 Day 25:Redis实现分布式Session与购物车
  • 【前端】使用Vue3过程中遇到加载无效设置点击方法提示不存在的情况,原来是少加了一个属性
  • [激光原理与应用-296]:理论 - 非线性光学 - 线性光学与非线性光学对比
  • (第十九期)用 VS Code 管理项目:目录文件夹与根目录,一次讲清
  • Vulkan笔记(五)-逻辑层与队列
  • halcon基于透视的可变形模型匹配
  • C预备知识01:
  • 数字电视:技术演进与未来展望
  • 用户认证技术