a算法的应用
‘壹’ A*算法用于路径规划,有什么缺点
缺点:A*算法通过比较当前路径栅格的8个邻居的启发式函数值F来逐步确定下一个路径栅格,当存在多个最小值时A*算法不能保证搜索的路径最优。
A*算法;A*(A-Star)算法是一种静态路网中求解最短路径最有效的直接搜索方法。估价值与实际值越接近,估价函数取得就越好。A*[1] (A-Star)算法是一种静态路网中求解最短路最有效的直接搜索方法。注意是最有效的直接搜索算法。之后涌现了很多预处理算法(ALT,CH,HL等等),在线查询效率是A*算法的数千甚至上万倍。公式表示为: f(n)=g(n)+h(n),其中 f(n) 是从初始点经由节点n到目标点的估价函数,g(n) 是在状态空间中从初始节点到n节点的实际代价,h(n) 是从n到目标节点最佳路径的估计代价。保证找到最短路径(最优解的)条件,关键在于估价函数f(n)的选取:估价值h(n)<= n到目标节点的距离实际值,这种情况下,搜索的点数多,搜索范围大,效率低。但能得到最优解。并且如果h(n)=d(n),即距离估计h(n)等于最短距离,那么搜索将严格沿着最短路径进行, 此时的搜索效率是最高的。如果 估价值>实际值,搜索的点数少,搜索范围小,效率高,但不能保证得到最优解。
‘贰’ 谁能介绍一下游戏编程中着名的A算法
全书由三部分组成。其中第一部分主要介绍游戏编程的基本概念;第二部分详细介绍游戏编程中的各种技术和算法;第三部分是附录,介绍游戏编程中相关技术和知识以及其他相关读物。第1章 游戏编程时间表1.1 第一阶段:“星球大战”之前1.2 第二阶段:...
‘叁’ 排列a的算法是什么
计算方法:
(1)排列数公式
排列用符号A(n,m)表示,m≦n。
计算公式是:A(n,m)=n(n-1)(n-2)……(n-m+1)=n!/(n-m)!
此外规定0!=1,n!表示n(n-1)(n-2)…1
例如:6!=6x5x4x3x2x1=720,4!=4x3x2x1=24。
(2)组合数公式
组合用符号C(n,m)表示,m≦n。
公式是:C(n,m)=A(n,m)/m!或C(n,m)=C(n,n-m)。
例如:C(5,2)=A(5,2)/[2!x(5-2)!]=(1x2x3x4x5)/[2x(1x2x3)]=10。
两个常用的排列基本计数原理及应用:
1、加法原理和分类计数法:
每一类中的每一种方法都可以独立地完成此任务。两类不同办法中的具体方法,互不相同(即分类不重)。完成此任务的任何一种方法,都属于某一类(即分类不漏)。
2、乘法原理和分步计数法:
任何一步的一种方法都不能完成此任务,必须且只须连续完成这n步才能完成此任务。各步计数相互独立。只要有一步中所采取的方法不同,则对应的完成此事的方法也不同。
‘肆’ 什么是 a算法a* 算法有什么特点
A*算法:A*(A-Star)算法是一种静态路网中求解最短路径最有效的直接搜索方法。估价值与实际值越接近,估价函数取得就越好
A* (A-Star)算法是一种静态路网中求解最短路最有效的直接搜索方法。
注意是最有效的直接搜索算法。之后涌现了很多预处理算法(ALT,CH,HL等等),在线查询效率是A*算法的数千甚至上万倍。
公式表示为: f(n)=g(n)+h(n),
其中 f(n) 是从初始点经由节点n到目标点的估价函数,
g(n) 是在状态空间中从初始节点到n节点的实际代价,
h(n) 是从n到目标节点最佳路径的估计代价。
保证找到最短路径(最优解的)条件,关键在于估价函数f(n)的选取:
估价值h(n)<= n到目标节点的距离实际值,这种情况下,搜索的点数多,搜索范围大,效率低。但能得到最优解。并且如果h(n)=d(n),即距离估计h(n)等于最短距离,那么搜索将严格沿着最短路径进行, 此时的搜索效率是最高的。
如果 估价值>实际值,搜索的点数少,搜索范围小,效率高,但不能保证得到最优解。
‘伍’ A*算法的实际运用
估价值与实际值越接近,估价函数取得就越好
例如对于几何路网来说,可以取两节点间曼哈顿距离做为估价值,即f=g(n) + (abs(dx - nx) + abs(dy - ny));这样估价函数f在g值一定的情况下,会或多或少的受估价值h的制约,节点距目标点近,h值小,f值相对就小,能保证最短路的搜索向终点的方向进行。明显优于Dijkstra算法的毫无方向的向四周搜索。
conditions of heuristic
Optimistic (must be less than or equal to the real cost)
As close to the real cost as possible
详细内容:
创建两个表,OPEN表保存所有已生成而未考察的节点,CLOSED表中记录已访问过的节点。
算起点的估价值;
将起点放入OPEN表; while(OPEN!=NULL){从OPEN表中取估价值f(n)最小的节点n;if(n节点==目标节点)break;for(当前节点n的每个子节点X){算X的估价值;if(XinOPEN)if(X的估价值小于OPEN表的估价值){把n设置为X的父亲;更新OPEN表中的估价值;//取最小路径的估价值}if(XinCLOSE)continue;if(Xnotinboth){把n设置为X的父亲;求X的估价值;并将X插入OPEN表中;//还没有排序}}//endfor将n节点插入CLOSE表中;按照估价值将OPEN表中的节点排序;//实际上是比较OPEN表内节点f的大小,从最小路径的节点向下进行。}//endwhile(OPEN!=NULL)保存路径,即从终点开始,每个节点沿着父节点移动直至起点,这就是你的路径;
用C语言实现A*最短路径搜索算法 ,作者 Tittup frog(跳跳蛙)。 #include<stdio.h>#include<math.h>#defineMaxLength100//用于优先队列(Open表)的数组#defineHeight15//地图高度#defineWidth20//地图宽度#defineReachable0//可以到达的结点#defineBar1//障碍物#definePass2//需要走的步数#defineSource3//起点#defineDestination4//终点#defineSequential0//顺序遍历#defineNoSolution2//无解决方案#defineInfinity0xfffffff#defineEast(1<<0)#defineSouth_East(1<<1)#defineSouth(1<<2)#defineSouth_West(1<<3)#defineWest(1<<4)#defineNorth_West(1<<5)#defineNorth(1<<6)#defineNorth_East(1<<7)typedefstruct{signedcharx,y;}Point;constPointdir[8]={{0,1},//East{1,1},//South_East{1,0},//South{1,-1},//South_West{0,-1},//West{-1,-1},//North_West{-1,0},//North{-1,1}//North_East};unsignedcharwithin(intx,inty){return(x>=0&&y>=0&&x<Height&&y<Width);}typedefstruct{intx,y;unsignedcharreachable,sur,value;}MapNode;typedefstructClose{MapNode*cur;charvis;structClose*from;floatF,G;intH;}Close;typedefstruct//优先队列(Open表){intlength;//当前队列的长度Close*Array[MaxLength];//评价结点的指针}Open;staticMapNodegraph[Height][Width];staticintsrcX,srcY,dstX,dstY;//起始点、终点staticCloseclose[Height][Width];//优先队列基本操作voidinitOpen(Open*q)//优先队列初始化{q->length=0;//队内元素数初始为0}voidpush(Open*q,Closecls[Height][Width],intx,inty,floatg){//向优先队列(Open表)中添加元素Close*t;inti,mintag;cls[x][y].G=g;//所添加节点的坐标cls[x][y].F=cls[x][y].G+cls[x][y].H;q->Array[q->length++]=&(cls[x][y]);mintag=q->length-1;for(i=0;i<q->length-1;i++){if(q->Array[i]->F<q->Array[mintag]->F){mintag=i;}}t=q->Array[q->length-1];q->Array[q->length-1]=q->Array[mintag];q->Array[mintag]=t;//将评价函数值最小节点置于队头}Close*shift(Open*q){returnq->Array[--q->length];}//地图初始化操作voidinitClose(Closecls[Height][Width],intsx,intsy,intdx,intdy){//地图Close表初始化配置inti,j;for(i=0;i<Height;i++){for(j=0;j<Width;j++){cls[i][j].cur=&graph[i][j];//Close表所指节点cls[i][j].vis=!graph[i][j].reachable;//是否被访问cls[i][j].from=NULL;//所来节点cls[i][j].G=cls[i][j].F=0;cls[i][j].H=abs(dx-i)+abs(dy-j);//评价函数值}}cls[sx][sy].F=cls[sx][sy].H;//起始点评价初始值//cls[sy][sy].G=0;//移步花费代价值cls[dx][dy].G=Infinity;}voidinitGraph(constintmap[Height][Width],intsx,intsy,intdx,intdy){//地图发生变化时重新构造地inti,j;srcX=sx;//起点X坐标srcY=sy;//起点Y坐标dstX=dx;//终点X坐标dstY=dy;//终点Y坐标for(i=0;i<Height;i++){for(j=0;j<Width;j++){graph[i][j].x=i;//地图坐标Xgraph[i][j].y=j;//地图坐标Ygraph[i][j].value=map[i][j];graph[i][j].reachable=(graph[i][j].value==Reachable);//节点可到达性graph[i][j].sur=0;//邻接节点个数if(!graph[i][j].reachable){continue;}if(j>0){if(graph[i][j-1].reachable)//left节点可以到达{graph[i][j].sur|=West;graph[i][j-1].sur|=East;}if(i>0){if(graph[i-1][j-1].reachable&&graph[i-1][j].reachable&&graph[i][j-1].reachable)//up-left节点可以到达{graph[i][j].sur|=North_West;graph[i-1][j-1].sur|=South_East;}}}if(i>0){if(graph[i-1][j].reachable)//up节点可以到达{graph[i][j].sur|=North;graph[i-1][j].sur|=South;}if(j<Width-1){if(graph[i-1][j+1].reachable&&graph[i-1][j].reachable&&map[i][j+1]==Reachable)//up-right节点可以到达{graph[i][j].sur|=North_East;graph[i-1][j+1].sur|=South_West;}}}}}}intbfs(){inttimes=0;inti,curX,curY,surX,surY;unsignedcharf=0,r=1;Close*p;Close*q[MaxLength]={&close[srcX][srcY]};initClose(close,srcX,srcY,dstX,dstY);close[srcX][srcY].vis=1;while(r!=f){p=q[f];f=(f+1)%MaxLength;curX=p->cur->x;curY=p->cur->y;for(i=0;i<8;i++){if(!(p->cur->sur&(1<<i))){continue;}surX=curX+dir[i].x;surY=curY+dir[i].y;if(!close[surX][surY].vis){close[surX][surY].from=p;close[surX][surY].vis=1;close[surX][surY].G=p->G+1;q[r]=&close[surX][surY];r=(r+1)%MaxLength;}}times++;}returntimes;}intastar(){//A*算法遍历//inttimes=0;inti,curX,curY,surX,surY;floatsurG;Openq;//Open表Close*p;initOpen(&q);initClose(close,srcX,srcY,dstX,dstY);close[srcX][srcY].vis=1;push(&q,close,srcX,srcY,0);while(q.length){//times++;p=shift(&q);curX=p->cur->x;curY=p->cur->y;if(!p->H){returnSequential;}for(i=0;i<8;i++){if(!(p->cur->sur&(1<<i))){continue;}surX=curX+dir[i].x;surY=curY+dir[i].y;if(!close[surX][surY].vis){close[surX][surY].vis=1;close[surX][surY].from=p;surG=p->G+sqrt((curX-surX)*(curX-surX)+(curY-surY)*(curY-surY));push(&q,close,surX,surY,surG);}}}//printf(times:%d
,times);returnNoSolution;//无结果}constintmap[Height][Width]={{0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,1},{0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1},{0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,1},{0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1},{0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},{0,0,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0},{0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0},{0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0},{0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,1},{0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0}};constcharSymbol[5][3]={□,▓,▽,☆,◎};voidprintMap(){inti,j;for(i=0;i<Height;i++){for(j=0;j<Width;j++){printf(%s,Symbol[graph[i][j].value]);}puts();}puts();}Close*getShortest(){//获取最短路径intresult=astar();Close*p,*t,*q=NULL;switch(result){caseSequential://顺序最近p=&(close[dstX][dstY]);while(p)//转置路径{t=p->from;p->from=q;q=p;p=t;}close[srcX][srcY].from=q->from;return&(close[srcX][srcY]);caseNoSolution:returnNULL;}returnNULL;}staticClose*start;staticintshortestep;intprintShortest(){Close*p;intstep=0;p=getShortest();start=p;if(!p){return0;}else{while(p->from){graph[p->cur->x][p->cur->y].value=Pass;printf((%d,%d)→
,p->cur->x,p->cur->y);p=p->from;step++;}printf((%d,%d)
,p->cur->x,p->cur->y);graph[srcX][srcY].value=Source;graph[dstX][dstY].value=Destination;returnstep;}}voidclearMap(){//ClearMapMarksofStepsClose*p=start;while(p){graph[p->cur->x][p->cur->y].value=Reachable;p=p->from;}graph[srcX][srcY].value=map[srcX][srcY];graph[dstX][dstY].value=map[dstX][dstY];}voidprintDepth(){inti,j;for(i=0;i<Height;i++){for(j=0;j<Width;j++){if(map[i][j]){printf(%s,Symbol[graph[i][j].value]);}else{printf(%2.0lf,close[i][j].G);}}puts();}puts();}voidprintSur(){inti,j;for(i=0;i<Height;i++){for(j=0;j<Width;j++){printf(%02x,graph[i][j].sur);}puts();}puts();}voidprintH(){inti,j;for(i=0;i<Height;i++){for(j=0;j<Width;j++){printf(%02d,close[i][j].H);}puts();}puts();}intmain(intargc,constchar**argv){initGraph(map,0,0,0,0);printMap();while(scanf(%d%d%d%d,&srcX,&srcY,&dstX,&dstY)!=EOF){if(within(srcX,srcY)&&within(dstX,dstY)){if(shortestep=printShortest()){printf(从(%d,%d)到(%d,%d)的最短步数是:%d
,srcX,srcY,dstX,dstY,shortestep);printMap();clearMap();bfs();//printDepth();puts((shortestep==close[dstX][dstY].G)?正确:错误);clearMap();}else{printf(从(%d,%d)不可到达(%d,%d)
,srcX,srcY,dstX,dstY);}}else{puts(输入错误!);}}return(0);}
‘陆’ A*算法是怎么来的,历史背景是啥,谁提出的A*算法帮帮忙,谢谢!
1968年,的一篇论文,“P. E. Hart, N. J. Nilsson, and B. Raphael. A formal basis for the heuristic determination of minimum cost paths in graphs. IEEE Trans. Syst. Sci. and Cybernetics, SSC-4(2):100-107, 1968”。从此,一种精巧、高效的算法------A*算法横空出世了,并在相关领域得到了广泛的应用。
‘柒’ A*算法的好处
其实A*算法也是一种最好优先的算法
只不过要加上一些约束条件罢了。由于在一些问题求解时,我们希望能够求解出状态空间搜索的最短路径,也就是用最快的方法求解问题,A*就是干这种事情的!
我们先下个定义,如果一个估价函数可以找出最短的路径,我们称之为可采纳性。A*算法是一个可采纳的最好优先算法。A*算法的估价函数可表示为:
f'(n) = g'(n) + h'(n)
这里,f'(n)是估价函数,g'(n)是起点到节点n的最短路径值,h'(n)是n到目标的最短路经的启发值。由于这个f'(n)其实是无法预先知道的,所以我们用前面的估价函数f(n)做近似。g(n)代替g'(n),但 g(n)>=g'(n)才可(大多数情况下都是满足的,可以不用考虑),h(n)代替h'(n),但h(n)<=h'(n)才可(这一点特别的重要)。可以证明应用这样的估价函数是可以找到最短路径的,也就是可采纳的。我们说应用这种估价函数的最好优先算法就是A*算法。
举一个例子,其实广度优先算法就是A*算法的特例。其中g(n)是节点所在的层数,h(n)=0,这种h(n)肯定小于h'(n),所以由前述可知广度优先算法是一种可采纳的。实际也是。当然它是一种最臭的A*算法。
再说一个问题,就是有关h(n)启发函数的信息性。h(n)的信息性通俗点说其实就是在估计一个节点的值时的约束条件,如果信息越多或约束条件越多则排除的节点就越多,估价函数越好或说这个算法越好。这就是为什么广度优先算法的那么臭的原因了,谁叫它的h(n)=0,一点启发信息都没有。但在游戏开发中由于实时性的问题,h(n)的信息越多,它的计算量就越大,耗费的时间就越多。就应该适当的减小h(n)的信息,即减小约束条件。但算法的准确性就差了,这里就有一个平衡的问题。
‘捌’ 搜索算法中,A算法A*算法的区别(急)
A算法一般指某个搜索算法的朴素的思路
A*指使用了启发式搜索之后的算法,也就是运算速度会快很多,但不一定能保证最后得到最优解
‘玖’ Apriori算法是什么适用于什么情境
经典的关联规则挖掘算法包括Apriori算法和FP-growth算法。apriori算法多次扫描交易数据库,每次利用候选频繁集产生频繁集;而FP-growth则利用树形结构,无需产生候选频繁集而是直接得到频繁集,大大减少扫描交易数据库的次数,从而提高了算法的效率。但是apriori的算法扩展性较好,可以用于并行计算等领域。
Apriori algorithm是关联规则里一项基本算法。是由Rakesh Agrawal和Ramakrishnan Srikant两位博士在1994年提出的关联规则挖掘算法。关联规则的目的就是在一个数据集中找出项与项之间的关系,也被称为购物蓝分析 (Market Basket analysis),因为“购物蓝分析”很贴切的表达了适用该算法情景中的一个子集。
‘拾’ A*算法应用,大家给点介绍,做课程设计
维基网络有很多的,大陆访问不了,可以设置个香港代理。
SHA 家族
[编辑首段]维基网络,自由的网络全书
跳转到: 导航, 搜寻
安全散列演算法能计算出一个数位讯息所对应到的,长度固定的字串(又称讯息摘要)。且若输入的讯息不同,它们对应到不同字串的机率很高;而 SHA 是FIPS所认证的五种安全杂凑演算法。这些演算法之所以称作“安全”是基于以下两点(根据官方标准的描述):“1)由讯息摘要反推原输入讯息,从计算理论上来说是很困难的。2)想要找到两组不同的讯息对应到相同的讯息摘要,从计算理论上来说也是很困难的。任何对输入讯息的变动,都有很高的机率导致其产生的讯息摘要迥异。”
SHA 家族的五个演算法,分别是SHA-1, SHA-224, SHA-256, SHA-384, 和 SHA-512,由美国国家安全局 (NSA) 所设计,并由美国国家标准与技术研究院(NIST) 发布;是美国的政府标准。后四者有时并称为SHA-2。SHA-1 在许多安全协定中广为使用,包括 TLS 和 SSL、 PGP、SSH、S/MIME 和 IPsec,曾被视为是 MD5(更早之前被广为使用的杂凑函数)的后继者。但 SHA-1 的安全性如今被密码学家严重质疑;虽然至今尚未出现对 SHA-2 有效的攻击,它的演算法跟 SHA-1 基本上仍然相似;因此有些人开始发展其他替代的杂凑演算法。缘于最近对 SHA-1 的种种攻击发表,“美国国家标准与技术研究院(NIST)开始设法经由公开竞争管道(类似高级加密标准AES的发展经过),发展一个或多个新的杂凑演算法。”
目录 [隐藏]
1 SHA-0 和 SHA-1
1.1 SHA-0 的破解
1.2 SHA-1 的破解
2 SHA-2
3 SHA 所定义的长度
4 SHAd
5 应用
6 SHA-1 演算法
7 SHA-2 演算法
8 参见
9 参考资料
10 外部链结
[编辑] SHA-0 和 SHA-1
SHA-1 压缩演算法中的一个回圈。A, B, C, D 和 E 是这个state中的 32 位元文字;F 是会变化的非线性函数;<<<n 代表bit向左循环移动n个位置。n因操作而异。田代表molo 232之下的加法,Kt 是一个常数。最初载明的演算法于 1993年发布,称做安全杂凑标准 (Secure Hash Standard),FIPS PUB 180。这个版本现在常被称为 SHA-0。它在发布之后很快就被 NSA 撤回,并且由 1995年发布的修订版本 FIPS PUB 180-1 (通常称为 SHA-1) 取代。SHA-1 和 SHA-0 的演算法只在压缩函数的讯息转换部份差了一个位元的循环位移。根据 NSA 的说法,它修正了一个在原始演算法中会降低密码安全性的错误。然而 NSA 并没有提供任何进一步的解释或证明该错误已被修正。而后 SHA-0 和 SHA-1 的弱点相继被攻破,SHA-1 似乎是显得比 SHA-0 有抵抗性,这多少证实了 NSA 当初修正演算法以增进安全性的声明。
SHA-0 和 SHA-1 可将一个最大 264 位元的讯息,转换成一串 160 位元的讯息摘要;其设计原理相似于 MIT 教授 Ronald L. Rivest 所设计的密码学杂凑演算法 MD4 和 MD5。
[编辑] SHA-0 的破解
在 CRYPTO 98 上,两位法国研究者提出一种对 SHA-0 的攻击方式 (Chabaud and Joux, 1998): 在 261的计算复杂度之内,就可以发现一次碰撞(即两个不同的讯息对应到相同的讯息摘要);这个数字小于 280 ,也就是说,其安全性不到一个理想的杂凑函数抵抗攻击所应具备的计算复杂度。
2004年时,Biham 和 Chen 也发现了 SHA-0 的近似碰撞 — 两个讯息可以杂凑出几乎相同的数值;其中 162 位元中有 142 位元相同。他们也发现了 SHA-0 的完整碰撞(相对于近似碰撞),将本来需要 80 次方的复杂度降低到 62 次方。
2004年8月12日,Joux, Carribault, Lemuet 和 Jalby 宣布找到 SHA-0 演算法的完整碰撞的方法,这是归纳 Chabaud 和 Joux 的攻击所完成的结果。发现一个完整碰撞只需要 251的计算复杂度。他们使用的是一台有 256 颗 Itanium2 处理器的超级电脑,约耗 80,000 CPU 工时 [1]。
2004年8月17日,在 CRYPTO 2004 的 Rump 会议上,王小云, 冯登国 (Feng), 来学嘉 (Lai), 和于红波 (Yu) 宣布了攻击 MD5、SHA-0 和其他杂凑函数的初步结果。他们攻击 SHA-0 的计算复杂度是 240,这意谓的他们的攻击成果比 Joux 还有其他人所做的更好。请参见 MD5 安全性。2005 年二月,王小云和殷益群、于红波再度发表了对 SHA-0 破密的演算法,可在 239 的计算复杂度内就找到碰撞。
[编辑] SHA-1 的破解
鉴于 SHA-0 的破密成果,专家们建议那些计画利用 SHA-1 实作密码系统的人们也应重新考虑。2004 年 CRYPTO 会议结果公布之后,NIST 即宣布他们将逐渐减少使用 SHA-1,改以 SHA-2 取而代之。
2005年,Rijmen 和 Oswald 发表了对 SHA-1 较弱版本(53次的加密回圈而非80次)的攻击:在 280 的计算复杂度之内找到碰撞。
2005年二月,王小云、殷益群及于红波发表了对完整版 SHA-1 的攻击,只需少于 269 的计算复杂度,就能找到一组碰撞。(利用暴力搜寻法找到碰撞需要 280 的计算复杂度。)
这篇论文的作者们写道;“我们的破密分析是以对付 SHA-0 的差分攻击、近似碰撞、多区块碰撞技术、以及从 MD5 演算法中寻找碰撞的讯息更改技术为基础。没有这些强力的分析工具,SHA-1 就无法破解。”此外,作者还展示了一次对 58 次加密回圈 SHA-1 的破密,在 233 个单位操作内就找到一组碰撞。完整攻击方法的论文发表在 2005 年八月的 CRYPTO 会议中。
殷益群在一次面谈中如此陈述:“大致上来说,我们找到了两个弱点:其一是前置处理不够复杂;其二是前 20 个回圈中的某些数学运算会造成不可预期的安全性问题。”
2005 年八月 17 的 CRYPTO 会议尾声中王小云、姚期智、姚储枫再度发表更有效率的 SHA-1 攻击法,能在 263 个计算复杂度内找到碰撞。
在密码学的学术理论中,任何攻击方式,其计算复杂度若少于暴力搜寻法所需要的计算复杂度,就能被视为针对该密码系统的一种破密法;这并不表示该破密法已经可以进入实际应用的阶段。
就应用层面的考量而言,一种新的破密法出现,暗示着将来可能会出现更有效率、足以实用的改良版本。虽然这些实用的破密法版本根本还没诞生,但确有必要发展更强的杂凑演算法来取代旧的演算法。在“碰撞”攻击法之外,另有一种反译攻击法,就是由杂凑出的字串反推原本的讯息;反译攻击的严重性更在碰撞攻击之上。 在许多会应用到密码杂凑的情境(如用户密码的存放、文件的数位签章等)中,碰撞攻击的影响并不是很大。举例来说,一个攻击者可能不会只想要伪造一份一模一样的文件,而会想改造原来的文件,再附上合法的签章,来愚弄持有私密金钥的验证者。另一方面,如果可以从密文中反推未加密前的使用者密码,攻击者就能利用得到的密码登入其他使用者的帐户,而这种事在密码系统中是不能被允许的。但若存在反译攻击,只要能得到指定使用者密码杂凑过后的字串(通常存在影档中,而且可能不会透露原密码资讯),就有可能得到该使用者的密码。
2006 年的 CRYPTO 会议上,Christian Rechberger 和 Christophe De Cannière 宣布他们能在容许攻击者决定部分原讯息的条件之下,找到 SHA-1 的一个碰撞。
[编辑] SHA-2
SHA-2 的第t个加密回圈。图中的深蓝色方块是事先定义好的非线性函数。ABCDEFGH一开始分别是八个初始值,Kt是第t个金钥,Wt是本区块产生第t个word。原讯息被切成固定长度的区块,对每一个区块,产生n个word(n视演算法而定),透过重复运作回圈n次对ABCDEFGH这八个工作区段循环加密。最后一次回圈所产生的八段字串合起来即是此区块对应到的杂凑字串。若原讯息包含数个区块,则最后还要将这些区块产生的杂凑字串加以混合才能产生最后的杂凑字串。NIST 发布了三个额外的 SHA 变体,这三个函数都将讯息对应到更长的讯息摘要。以它们的摘要长度 (以位元计算) 加在原名后面来命名:SHA-256,SHA-384 和 SHA-512。它们发布于 2001年的 FIPS PUB 180-2 草稿中,随即通过审查和评论。包含 SHA-1 的 FIPS PUB 180-2,于 2002年以官方标准发布。2004年2月,发布了一次 FIPS PUB 180-2 的变更通知,加入了一个额外的变种 "SHA-224",这是为了符合双金钥 3DES 所需的金钥长度而定义。
SHA-256 和 SHA-512 是很新的杂凑函数,前者以定义一个word为32位元,后者则定义一个word为64位元。它们分别使用了不同的偏移量,或用不同的常数,然而,实际上二者结构是相同的,只在回圈执行的次数上有所差异。 SHA-224 以及 SHA-384 则是前述二种杂凑函数的截短版,利用不同的初始值做计算。
这些新的杂凑函数并没有接受像 SHA-1 一样的公众密码社群做详细的检验,所以它们的密码安全性还不被大家广泛的信任。Gilbert 和 Handschuh (2003) 曾对这些新变种作过一些研究,声称他们没有弱点。
[编辑] SHA 所定义的长度
下表中的中继杂凑值(internal state)表示对每个资料区块压缩杂凑过后的中继值(internal hash sum)。详情请参见Merkle-Damgård construction。
演算法 输出杂凑值长度 (bits) 中继杂凑值长度 (bits) 资料区块长度 (bits) 最大输入讯息长度 (bits) 一个Word长度 (bits) 回圈次数 使用到的运运算元 碰撞攻击
SHA-0 160 160 512 264 − 1 32 80 +,and,or,xor,rotl 是
SHA-1 160 160 512 264 − 1 32 80 +,and,or,xor,rotl 存在263 的攻击
SHA-256/224 256/224 256 512 264 − 1 32 64 +,and,or,xor,shr,rotr 尚未出现
SHA-512/384 512/384 512 1024 2128 − 1 64 80 +,and,or,xor,shr,rotr 尚未出现
[编辑] SHAd
SHAd 函数是一个简单的相同 SHA 函数的重述:
SHAd-256(m)=SHA-256(SHA-256(m))。它会克服有关延伸长度攻击的问题。
[编辑] 应用
SHA-1, SHA-224, SHA-256, SHA-384 和 SHA-512 都被需要安全杂凑演算法的美国联邦政府所应用,他们也使用其他的密码演算法和协定来保护敏感的未保密资料。FIPS PUB 180-1 也鼓励私人或商业组织使用 SHA-1 加密。Fritz-chip 将很可能使用 SHA-1 杂凑函数来实现个人电脑上的数位版权管理。
首先推动安全杂凑演算法出版的是已合并的数位签章标准。
SHA 杂凑函数已被做为 SHACAL 分组密码演算法的基础。
[编辑] SHA-1 演算法
以下是 SHA-1 演算法的虚拟码:
Note: All variables are unsigned 32 bits and wrap molo 232 when calculating
Initialize variables:
h0 := 0x67452301
h1 := 0xEFCDAB89
h2 := 0x98BADCFE
h3 := 0x10325476
h4 := 0xC3D2E1F0
Pre-processing:
append the bit '1' to the message
append k bits '0', where k is the minimum number >= 0 such that the resulting message
length (in bits) is congruent to 448 (mod 512)
append length of message (before pre-processing), in bits, as 64-bit big-endian integer
Process the message in successive 512-bit chunks:
break message into 512-bit chunks
for each chunk
break chunk into sixteen 32-bit big-endian words w[i], 0 ≤ i ≤ 15
Extend the sixteen 32-bit words into eighty 32-bit words:
for i from 16 to 79
w[i] := (w[i-3] xor w[i-8] xor w[i-14] xor w[i-16]) leftrotate 1
Initialize hash value for this chunk:
a := h0
b := h1
c := h2
d := h3
e := h4
Main loop:
for i from 0 to 79
if 0 ≤ i ≤ 19 then
f := (b and c) or ((not b) and d)
k := 0x5A827999
else if 20 ≤ i ≤ 39
f := b xor c xor d
k := 0x6ED9EBA1
else if 40 ≤ i ≤ 59
f := (b and c) or (b and d) or (c and d)
k := 0x8F1BBCDC
else if 60 ≤ i ≤ 79
f := b xor c xor d
k := 0xCA62C1D6
temp := (a leftrotate 5) + f + e + k + w[i]
e := d
d := c
c := b leftrotate 30
b := a
a := temp
Add this chunk's hash to result so far:
h0 := h0 + a
h1 := h1 + b
h2 := h2 + c
h3 := h3 + d
h4 := h4 + e
Proce the final hash value (big-endian):
digest = hash = h0 append h1 append h2 append h3 append h4
上述关于 f 运算式列于 FIPS PUB 180-1 中 , 以下替代运算式也许也能在主要回圈里计算 f :
(0 ≤ i ≤ 19): f := d xor (b and (c xor d)) (alternative)
(40 ≤ i ≤ 59): f := (b and c) or (d and (b or c)) (alternative 1)
(40 ≤ i ≤ 59): f := (b and c) or (d and (b xor c)) (alternative 2)
(40 ≤ i ≤ 59): f := (b and c) + (d and (b xor c)) (alternative 3)
[编辑] SHA-2 演算法
以下是SHA-256 演算法的虚拟码。注意,64个word w[16..63]中的位元比起 SHA-1 演算法,混合的程度大幅提升。
Note: All variables are unsigned 32 bits and wrap molo 232 when calculating
Initialize variables
(first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19
Initialize table of round constants
(first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311):
k[0..63] :=
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
Pre-processing:
append the bit '1' to the message
append k bits '0', where k is the minimum number >= 0 such that the resulting message
length (in bits) is congruent to 448 (mod 512)
append length of message (before pre-processing), in bits, as 64-bit big-endian integer
Process the message in successive 512-bit chunks:
break message into 512-bit chunks
for each chunk
break chunk into sixteen 32-bit big-endian words w[0..15]
Extend the sixteen 32-bit words into sixty-four 32-bit words:
for i from 16 to 63
s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)
s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10)
w[i] := w[i-16] + s0 + w[i-7] + s1
Initialize hash value for this chunk:
a := h0
b := h1
c := h2
d := h3
e := h4
f := h5
g := h6
h := h7
Main loop:
for i from 0 to 63
s0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
maj := (a and b) xor (a and c) xor (b and c)
t2 := s0 + maj
s1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
ch := (e and f) xor ((not e) and g)
t1 := h + s1 + ch + k[i] + w[i]
h := g
g := f
f := e
e := d + t1
d := c
c := b
b := a
a := t1 + t2
Add this chunk's hash to result so far:
h0 := h0 + a
h1 := h1 + b
h2 := h2 + c
h3 := h3 + d
h4 := h4 + e
h5 := h5 + f
h6 := h6 + g
h7 := h7 + h
Proce the final hash value (big-endian):
digest = hash = h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7
其中 ch 函数及 maj 函数可利用前述 SHA-1 的优化方式改写。
SHA-224 和 SHA-256 基本上是相同的, 除了:
h0 到 h7 的初始值不同,以及
SHA-224 输出时截掉 h7 的函数值。
SHA-512 和 SHA-256 的结构相同,但:
SHA-512 所有的数字都是64位元,
SHA-512 执行80次加密回圈而非64次,
SHA-512 初始值和常数拉长成64位元,以及
二者位元的偏移量和循环位移量不同。
SHA-384 和 SHA-512 基本上是相同的,除了:
h0 到 h7 的初始值不同,以及
SHA-384 输出时截掉 h6 和 h7 的函数值。