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

SHA-256算法详解——Github工程结合示例和动画演示

近日笔者在学习区块链的相关知识,接触到SHA-256算法,这里做一个知识梳理和总结。

强烈推荐大家自行去学习下面链接github上的工程,作者的动画演示和解释做的非常出色,逻辑非常清晰,B站搬运的对应的油管的讲解视频也放在下面,本文也是基于此github工程和作者学习过程的思路进行呈现。

github:

https://github.com/in3rsha/sha256-animation

B站讲解视频:

https://www.bilibili.com/video/BV1Jg411G7tc

ruby(windows)安装教程:

https://www.cnblogs.com/minisayo/p/14015747.html

可以先将github工程下载到本地,因为作者是用的ruby进行动画展示,所以需要再windows/Linux系统上安装ruby,之后在工程目录下调用ruby xxx.rb指令即可啦。

下面是整个工程的流程图,也对应着SHA-256算法的设计思路。

一、运算定义

为了后续分析思路与流程的连贯性,在这里先统一声明一下一些运算的定义,后续一些函数会直接对这些运算进行封装使用。

1、右移Right Shift (shr.rb)

这里的右移会产生两种结果,第一种结果是左侧移动完之后位为0,右侧被移走的位丢失,如上图所示SHR 32的操作,原数据为32位,在右移32位之后原数据都被右移丢失,剩下的左侧移动完的位全为0。

2、旋转右移Right Shift (rotr.rb)

这里要尤其注意和SHR右移的区别,观察演示图可以发现对于旋转右移而言数据组成了一个环形,移动位数只是改变位的绝对位置,并不会丢弃数据,所以原数据32位,再进行ROTR 32的操作实际上就是所有数据位旋转了一整圈,又回到了原来的位置。

3、异或XOR (xor.rb)

按位异或,0^0 = 0,1^0 = 1,0^1 = 1,1^1 = 0。

4、加法Addition (add.rb) 

这里和二进制加法一样,但是由于多个32位的数据相加,最终的存在着溢出的风险,因此最终的结果进行取模2*32将其约束在32位输出。

二、函数定义

第一部分的运算被封装组合起来就是这部分的函数,在这里先列出一些后续算法流程分析会用到的函数,读者可以先有个大概印象,后面第三部分算法流程分析的时候再回看也可以。

前四个函数使用希腊符号 Sigma(小写 σ,大写 Σ)命名。这些名称没有特殊含义,只是为了方便给一些组合运算命名。

1、σ0 (sigma0.rb)

σ0(x) = ROTR7(x) ^ ROTR18(x) ^ SHR3(x)

先分别计算ROTR 7位和ROTR18位和SHR 3位,再将三者异或

2、σ1 (sigma1.rb)

σ1(x) = ROTR17(x) ^ ROTR19(x) ^ SHR10(x)

先分别计算ROTR 17位和ROTR 19位和SHR 10位,再将三者异或

3、Σ0 (usigma0.rb)

Σ0(x) = ROTR2(x) ^ ROTR13(x) ^ ROTR22(x)

先分别计算ROTR 2位和ROTR 13位和ROTR 22位,再将三者异或

4、Σ1 (usigma1.rb) 

Σ1(x) = ROTR6(x) ^ ROTR11(x) ^ ROTR25(x)

先分别计算ROTR 6位和ROTR 11位和ROTR 25位,再将三者异或

5、Choice (ch.rb)

这个函数使用x位在y位和z位之间进行选择。如果x=1,则选择y位;如果x=0,则选择z位。

6、Majority (maj.rb)  

这个函数返回三位中的多数位。

7、常量Constants (constants.rb)

SHA-256 使用六十四个常量 Kt 来帮助在主哈希计算过程中混合比特。

首先计算前64个质数的立方根,然后取其小数部分乘2^32,将得到的常量作为Kt使用,其中t表示第t个质数运算后的结果。

这些立方根的小数部分是无理数(它们无限延伸),因此它们是用于常量的良好随机比特选择。这比使用特别选择的常量更好,因为这降低了哈希函数被设计成具有后门的可能。

三、算法流程分析 

在这里message的内容是可以自己指定的,我们以message = dyq 为例(在每个rb文件的开头可以自定义默认输入)

1、message.rb 

输入一个message字符串时,我们将每个字符转换为 ASCII 表中的对应数字。这些数字被转换为二进制,我们使用这些二进制数据作为哈希函数的输入。 

2、padding.rb

SHA-256 哈希函数以 512 位的block数据块为单位进行操作,因此所有消息都需要用零填充至最接近的 512 位的倍数,可以是512、1024等,这里先填充到448位,后64位预留出用来表示message的比特位数。

为了防止相似输入哈希到相同的结果,我们用 1 位将消息与零分隔开,并在填充的最后 64 位中包含消息的大小。 

以上这种用 1 分隔消息并在填充中包含消息大小的方法被称为 Merkle–Damgård 加强(MD 加强)。 

3、blocks.rb

消息经过填充后,我们将其切割成等长的 512 位消息块 Mi 以便哈希函数处理。

每个消息块也可以进一步分成 16 个词Wj ( 512 / 32 = 16 words ),每个词的长度为32bit,这将在后续使用。 

4、schedule.rb

 对于前16个word,每个word有32个bit,相当于是把原本的block0分为了32*16。

从第17个word开始根据下面的公式进行计算

Wt = σ1(Wt-2) + Wt-7 + σ0(Wt-15) + Wt-16

其中σ1和σ0在第二部分可以找到函数的定义。

5、expansion.rb

这一步展示的是上面最后一个word W63生成的运算过程。 

6、initial.rb

初始哈希值使用了前八个质数的平方根的小数部分。我们将这八个字母作为状态寄存器,我们可以将其作为开始哈希计算的起点(初始状态)

7、t1.rb t2.rb

我们需要先使用状态寄存器中的当前值来计算两个新的临时词( T1 和 T2 ),为后续的压缩过程做准备。

T1 = Σ1(e) + Ch(e, f, g) + h + Kt + Wt

其中Σ1和Ch函数在第二部分,h为h状态寄存器存储的值,Kt为第二部分的64个常数值,Wt为schedule.rb求得的word。

T2 = Σ0(a) + Maj(a, b, c)

其中Σ0函数和Maj函数均在第二部分。

8、compression.rb

压缩是整个算法的核心。我们再将其细化进行分析

(1) step1:计算出T1和T2

 (2) step2:所有寄存器下移一个

 (3) step3:更新a和e寄存器的值

以上三步可以概括为计算T1,T2;下移寄存器;更新a和e值,至此我们称为完成一轮压缩。这样的压缩要对一共64个word都进行一遍。

以上就是第二轮的step1开始以此类推。 

压缩完64轮之后,将最终的abcdefgh寄存器的值和initial.rb中的abcdefgh中的值相加得到最后的寄存器值

如果还有进一步要处理的消息块(block1,block2……),按照下图当前的哈希值将作为下一个压缩的初始哈希值。 

9、final.rb

 最终将8个32位的寄存器值转化为8个16进制的哈希值并拼接在一起,最终得到message的哈希值

 

使用哈希计算器验证一下是没问题的

10、sha256.rb 

# 直接进行哈希运算
ruby sha256.rb abc# 也可以输出二进制和十六进制数据
ruby sha256.rb 0b01100001
ruby sha256.rb 0xaabbccdd# 哈希一个文件 (请注意,文件末尾将有一个换行符)
ruby sha256.rb file.txt# 添加不同的命令行参数
ruby sha256.rb abc normal # 默认
ruby sha256.rb abc fast   # 加速演示
ruby sha256.rb abc enter  # 每按一次回车,步进一次动画

sha256.rb是一个集成上述功能的完整代码,除此之外,还可以指定命令行参数实现不同操作。

将sha-256.rd的输出改成可分为多个block的长message,测试多个block条件下hash算法 

观察以上代码运行后的结果发现,进行了多个block的流水线运算,最终的结果正确,真是太吊了。但是这里注意改变输入时不能直接在命令行输入段落,因为作者的代码中不能识别空格,所以只能在rb文件里改变input,但是也无伤大雅,笔者有时间会完善一下这个小bug的。

http://www.dtcms.com/a/270504.html

相关文章:

  • 中望CAD2026亮点速递(5):【相似查找】高效自动化识别定位
  • Python(30)基于itertools生成器的量子计算模拟技术深度解析
  • 【SQL】使用UPDATE修改表字段的时候,遇到1054 或者1064的问题怎么办?
  • (八)PS识别:使用 Python 自动化生成图像PS数据集
  • Linux驱动05 --- TCP 服务器
  • 分库分表之实战-sharding-JDBC绑定表配置实战
  • uniapp+vue3+ts项目:实现小程序文件下载、预览、进度监听(含项目、案例、插件)
  • PostgreSQL如何进行跨服务器迁移数据
  • ARIA UWB安全雷达主要产品型号与核心功能全解析
  • 【数字后端】- Standard Cell Status
  • 亚马逊广告进阶指南:CPC与竞价的底层逻辑
  • 游戏开发学习记录
  • 基于Flask 3.1和Python 3.13的简易CMS
  • LLM中 最后一个词语的表征(隐藏状态)通常会融合前面所有词语的信息吗?
  • Java项目集成Log4j2全攻略
  • 速卖通跨境运营破局:亚矩阵云手机如何用“本地化黑科技”撬动俄罗斯市场25%客单价增长
  • 今日行情明日机会——20250709
  • 伪装计算器软件,隐藏手机隐私文件
  • 3.常⽤控件
  • jmeter做跨线程组
  • 第二章:创建登录页面
  • 函数-3-日期函数
  • Java垃圾收集机制Test1
  • css 设置 input 插入光标样式
  • OpenCV图片操作100例:从入门到精通指南(2)
  • java17 gc笔记
  • 论文阅读|汽车虚拟环绕音响系统设计与实现策略的比较研究
  • 新加坡国立大学基于多维度EHR数据实现细粒度患者队列建模,住院时间预测准确率提升16.3%
  • Android网络层架构:统一错误处理的问题分析到解决方案与设计实现
  • java中list.remove(item); // 直接移除会导致ConcurrentModificationException