卡掉hash的方法

news/2024/9/29 0:51:14/文章来源:https://www.cnblogs.com/Vanilla-chan/p/18438721

大质数hash

通常,这个质数会选择在 \(10^9\) 附近,如 \(998244353\)\(10^9+7\)

考虑生日碰撞,欲达到 50% 成功率,需要尝试的次数为

\[\begin{align} Q(H)\approx\sqrt{\frac\pi2H}\approx39623 \end{align} \]

可以参考概率表

所以我们可以生成 \(10^5\) 左右个较短的字符串,即可有很大的概率发生hash冲突。

Code

#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<limits.h>
#define LL long long
#define ULL unsigned long long
using namespace std;vector<string> create(unsigned num,unsigned int sze)
{vector<string>ans;while(num--){string str;for(unsigned int i=0;i<sze;i++){str.push_back('a'+rand()%26);}ans.push_back(str);}return ans;
}bool check(vector<string>strs,ULL base,ULL p)
{
//	sort(strs.begin(),strs.end());map<int,string>Map;for(unsigned int i=0;i<strs.size();i++){ULL x=0;for(unsigned int j=0;j<strs[i].size();j++){x=x*base+strs[i][j]-'a';x%=p;}if(Map.find(x)==Map.end()) Map[x]=strs[i];else{if(Map[x]!=strs[i]) return 1;}}return 0;
}int main()
{srand(time(0));int T=100,succ=0;for(int t=0;t<T;t++){vector<string>strs=create(100000,10); // 生成100000个长度为10的随机字符串bool c=check(strs,31,998244853); // base=31,p=998244353,检查是否存在hash冲突cout<<c<<endl;succ+=c;}cout<<succ<<"/"<<T<<endl;return 0;
}

试运行发现,设置字符串数量为\(39623\)时,发生hash冲突的概率近似\(50\%\),符合预期。而当设置字符串数量为\(100000\)时,\(1000\)次测试中只有\(4\)次没有发生hash冲突。所以设置\(10^5\)个字符串就差不多可以卡掉绝大多数单大质数hash了。

64位无符号整数自然溢出

首先需要对base奇偶性分类讨论。

当base是偶数时比较简单:设第 \(i\) 位指的是字符串从右往左数第 \(i\) 个字符,设有相同串 \(C\) ,其长度不小于64.构造字符串 \(A=a+C,B=b+C\),这两个字符串的后64位上均相同,更高位上不相同。

字符串中第 \(i\) 位的权重为 \(base^{i-1}\),则高于64位上的字符的权重一定可以被 \(2^{64}\) 整除。也就是说,高于64位上的字符不会对hash值产生影响。

下面着重说一下base为奇数的情况。

构造方法

考虑使用字符ab构造字符串:

\(\overline A\) 表示字符串 \(A\) 中所有 a 变成 b ,所有 b 变成 a

\(A_1=a\)\(A_i=A_{i-1}+\overline{A_{i-1}}\)

例如 \(A_2=ab,A_3=abba,A_4=abbabaab\)

那么\(len(A_i)=2^{i-1}\)

可以证明,当 \(i\) 大于某个数时,\(hash(A_i)=hash(\overline{A_i})\)

证明

由于我们的hash函数使用的是64位无符号整数自然溢出,所以相当于我们需要证明

\[\begin{align} 2^{64}\mid(hash(A_i)-hash(\overline{A_i})) \end{align} \]

\(f(i)=hash(A_i)-hash(\overline{A_i})\)

根据递推公式可得

\[\begin{align} hash(A_i)&=hash(A_{i-1})\times base^{len(A_{i-1})}+hash(\overline{A_{i-1}})\\ &=hash(A_{i-1})\times base^{2^{i-2}}+hash(\overline{A_{i-1}}) \end{align} \]

则有

\[\begin{align} f(i)&=(hash(A_{i-1})-hash(\overline{A_{i-1}}))\times base^{2^{i-2}}+(hash(\overline{A_{i-1}})-hash(A_{i-1}))\\ &=(hash(A_{i-1})-hash(\overline{A_{i-1}}))\times (base^{2^{i-2}}-1)\\ &=f(i-1)\times (base^{2^{i-2}}-1) \end{align} \]

\(g(i)=base^{2^{i-2}}-1(i\ge2)\)

则有

\[\begin{align} f(i)&=f(i-1)\times g(i)\\ &=f(i-2)\times g(i) \times g(i-1)\\ &=f(1)\times g(i)\times g(i-1)\times g(i-2)\times\dots\times g(2) \end{align} \]

由于 \(base\) 是奇数,所以 \(base^{2^{i-2}}\) 也是奇数,故 \(g(i)\) 是偶数。

故有

\[\begin{align} 2^{i-1}\mid f(i) \end{align} \]

为了达到\(2^{64}\mid f(i)\),需取\(i=65\)即可,但是这样会构造两个长度为\(2^{64}\approx10^{20}\)的字符串,是不可行的。

由于\(g(i)=base^{2^{i-2}}-1=(base^{2^{i-3}}+1)(base^{2^{i-3}}-1)=偶数*g(i-1)\)

所以有

\[\begin{align} 2^{i-1} & \mid g(i)\\ 2^\frac{i(i-1)}{2} & \mid f(i) \end{align} \]

我们需要\(\frac{i(i-1)}{2}\ge64\),则只需取\(i=12\),构造出字符串 \(A_{12}\)\(\overline{A_{12}}\),即可卡掉base为奇数的自然溢出。

最后,在这两字符串后再加上长度大于等于64的相同串,即可同时卡掉base为偶数的自然溢出。

Code

#include<iostream>
#include<string>
#include<cmath>
#include<map>
#include<vector>
#include<limits.h>
#define ULL unsigned long long
using namespace std;string C;string create()
{string str="a";for(int i=2;i<=11;i++) // 会产生长度为2^(i-1)长度的字符串,而我们需要i_max=12{for(int j=0;j<(1<<(i-2));j++) //延拓字符串长度为1<<(i-1){str.push_back(str[j]=='a'?'b':'a');}}return str;
}string Not(string str)
{for(unsigned int i=0;i<str.size();i++){str[i]=(str[i]=='a'?'b':'a');}return str;
}bool check(string a,string b,ULL base)
{ULL aa=0,bb=0;for(unsigned int i=0;i<a.size();i++){aa=aa*base+a[i]-'a';}for(unsigned int i=0;i<b.size();i++){bb=bb*base+b[i]-'a';}return aa==bb;
}int main()
{for(int i=1;i<=65;i++) C.push_back('a');string str=create();string A=str+C,B=Not(str)+C;cout<<"构造的字符串的长度为"<<A.size()<<endl;int T=10000,succ=0;for(int t=0;t<T;t++){bool c=check(A,B,t*2+1);cout<<c<<endl;succ+=c;}cout<<succ<<"/"<<T<<endl;return 0;
}

疑惑:为什么这里取 \(i=11\) 就可以了?

我在研究的过程中,发现取 \(i=11\) 时,对于测试的所有奇数base都成功了。但是明明证明的是 \(i\) 最小取 \(12\)?最后由lzh揭开了谜团。

\(g(3)\) 很特别:\(g(3)=base^{2^{3-2}}-1=base^2-1\)

由于base是奇数,设\(base=2n-1(n\ge1)\),有

\[\begin{align} g(3)=(2n-1)^2-1=4n^2-4n=4n(n+1) \end{align} \]

一定是8的倍数。故 \(2^3 \mid g(3)\)

再结合递推公式,有

\[\begin{align} \begin{cases}2^{i} \mid g(i)\quad i\ge3\\2^1 \mid g(i)\quad i=2\\ \end{cases} \end{align} \]

所以有

\[\begin{align} 2^{\frac{(3+i)(i-2)}{2}+1} \mid f(x) \end{align} \]

\(i=11\)时,刚好是\(2^{64}\)(真巧!)

如何避免被卡

  • 随机base。相当于让不同位置上的权重不一样
  • 双模数hash。
  • 超大质数hash。既能像自然溢出一样有着大值域不易生日攻击,又不会被特殊的构造卡掉。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/805474.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人员摔倒识别预警系统

人员摔倒识别预警系统通过opencv网络模型技术,人员摔倒识别预警系统能够智能检测现场画面中人员有没有摔倒,特别是高危作业范围老弱活动场地,如:工地、工程、社区、养老院等。人员摔倒识别预警系统检测出人员摔倒,无需人为干预系统可以立刻抓拍告警,同步回传后台系统平台…

河道垃圾识别系统

河道垃圾识别系统通过智能视频分析技术,河道垃圾识别系统对河道水面垃圾进行7*24小时自动不间断实时监测,当河道垃圾识别系统监测到河道水面出现垃圾时,立即抓拍告警,通知后台值班人员进行清理。河道垃圾识别系统有利于节省传统河道巡检的人力,提高识别巡检效率。河道垃圾…

全网最适合入门的面向对象编程教程:54 Python字符串与序列化-字符串格式化与format方法

在 Python 中,字符串格式化是将变量插入到字符串中的一种方式,Python 提供了多种字符串格式化的方法,包括旧式的 % 格式化、新式的 str.format 方法以及 f-string(格式化字符串字面量)。全网最适合入门的面向对象编程教程:54 Python 字符串与序列化-字符串格式化与 forma…

智慧工地AI视频分析系统

智慧工地AI视频分析系统通过图像识别技术,智慧工地AI视频分析系统配合现场已有摄像头,不需人为干预自动识别现场作业人员穿戴是否合规如安全帽反光衣有无穿戴、高空作业是否穿戴安全带、抽烟打电话识别、人员打架、危险区域人员闯入识别、工作时间睡岗离岗识别、工地车辆识别…

员工工作服穿戴识别系统

员工工作服穿戴识别系统基于YOLO网络模型图像识别技术,员工工作服穿戴识别系统通过现场已有的监控摄像头,不需新增硬件对现场未按要求穿戴工服的违规行为实时预警,将违规行为信息及时推送给后台管理人员。员工工作服穿戴识别系统通过AI技术手段提高现场对施工作业人员穿戴监…

劳保防护用品穿戴检测系统

劳保防护用品穿戴检测系统通过Opencv深度学习技术,劳保防护用品穿戴检测系统对现场作业人员行为以及安全作业防护穿戴用品进行全天候检测,当劳保防护用品穿戴检测系统检测到现场施工人员未按照要求进行施工穿戴防护用品,劳保防护用品穿戴检测系统立即对现场违规穿戴人员或者…

加油站ai系统视频监测

加油站ai系统视频监测通过深度学习边缘计算技术,加油站ai系统视频监测对现场画面中人员作业行为实时进行检测分析,加油站ai系统视频监测不需人为干预通过AI技术识别异常违规行为信息,加油站ai系统视频监测能将风险及时发现并进行预警,提升加油站作业全流程安全系数。加油站…

办公室人员离岗识别检测系统

办公室人员离岗识别检测系统根据计算机视觉深度学习技术,办公室人员离岗识别检测系统能够7*24小时全天候自动识别工作时间监控画面中人员是否在岗位工作。办公室人员离岗识别检测系统发现监控画面中人员在工作时间没有在岗位时,不需人为干预办公室人员离岗识别检测系统会立刻…

智慧工地安全着装识别系统

智慧工地安全着装识别系统通过AI视频分析技术,智慧工地安全着装识别系统对工地现场物体的不安全状态以及施工人员的不安全行为(不按要求着装)进行自动实时分析,发现异常违规信息立即抓拍预警同步回传工地后台大数据平台提醒后台执勤人员及时处理,避免发生更危险的情况。智…

煤矿风险监测预警系统

煤矿风险监测预警系统基于YOLO网络模型视觉分析,煤矿风险监测预警系统7*24小时不间断自动识别现场人员作业行为、着装合规情况以及传送皮带撕裂跑偏等风险异常情况,煤矿风险监测预警系统检测出人员未按照要求穿安全帽反光衣、抽烟玩手机、皮带跑偏撕裂堆煤异物后,煤矿风险监…

安全帽反光背心穿戴识别系统 反光衣穿戴检测系统

安全帽反光背心穿戴识别系统 反光衣穿戴检测系统利用现场已有摄像头,安全帽反光背心穿戴识别系统 反光衣穿戴检测系统实时分析施工现场人员着装穿戴及作业行为。当安全帽反光背心穿戴识别系统 反光衣穿戴检测系统识别到现场人员未按照要求穿戴安全帽以及反光背心(又称反光衣)…

论信息显示对我生活的影响

论信息显示对我生活的影响 引子 灵感来源是昨天去"桌游社"打万智牌 他们好热情啊,直接就给我开了四包新卡,怪不好意思的 不过我那天手气不错,开出了"兄弟反目"(50元),嘻嘻:happy: 看不到信息的时候 玩《空洞骑士》的时候,像是攻击距离,攻击伤害,闪避…