深入浅出 区块链密码学(学习笔记1.0)——哈希函数

一.引言

        理解区块链密码学是理解区块链技术的关键部分之一。以下是本人总结的一些区块链密码学的知识点以及可能遇到的问题和解决方法,希望对各位有帮助,之后还会对该内容继续补充说明,大家也可以在评论区给予补充:

二.哈希函数(Hash Functions)

2.1什么是哈希函数

        哈希函数是一种将任意长度的数据(输入)映射为固定长度的数据(输出)的函数。这个输出通常被称为哈希值或散列值。哈希函数的特点是:

  1. 固定长度输出:无论输入数据的大小如何,哈希函数都会生成固定长度的输出。
  2. 单向性:哈希函数是单向的,即从哈希值不能反推出原始数据。也就是说,通过哈希值无法得到原始数据的内容。
  3. 唯一性:对于不同的输入,哈希函数应该生成不同的输出。理想情况下,不同的输入应该生成不同的哈希值,但实际上可能会出现哈希碰撞,即不同的输入可能会产生相同的哈希值,但发生的概率应该非常小。
  4. 快速计算:哈希函数应该在合理的时间内能够计算出哈希值。
  5. 抗碰撞性:对于任意一个固定的哈希值,要找到与之对应的原始数据应该是困难的,这种属性称为抗碰撞性。

        哈希函数在密码学、数据结构、安全性等领域有着广泛的应用,比如在密码学中,常用于存储密码的哈希值而不是明文密码,以增加安全性;在数据结构中,常用于快速查找、数据校验等;在区块链中,哈希函数常用于产生区块的唯一标识、验证数据的完整性等。常见的哈希函数包括MD5、SHA-1、SHA-256等。

下图就是Hash函数的一个简单说明,任意长度的数据通过HashFunc映射到一个较短的数据集中

2.2哈希函数的设计

        哈希函数的设计是一个复杂而重要的过程,好的设计能够满足哈希函数的各种要求,并且在实际应用中表现良好。下面是设计哈希函数时需要考虑的一些因素:

  1. 均匀性(Uniformity):哈希函数应该尽可能均匀地将不同的输入映射到不同的输出空间中,以减少哈希碰撞的可能性。
  2. 混淆性(Diffusion):对输入的微小变化应该引起输出的显著变化,这种特性称为扩散性或混淆性。
  3. 不可逆性(Irreversibility):从哈希值不能反推出原始数据,确保哈希函数的单向性。
  4. 抗碰撞性(Collision Resistance):哈希函数应该具有高度的抗碰撞性,即在实践中很难找到两个不同的输入对应相同的哈希值。
  5. 计算效率(Computational Efficiency):哈希函数的计算速度应该尽可能快,以便在实际应用中能够快速处理大量数据。
  6. 安全性(Security):哈希函数应该抵抗各种攻击,如碰撞性攻击、预图攻击、反向工程攻击等。

设计哈希函数时通常会采用一些经典的技术和方法,例如:

  • 迭代加密哈希函数(Iterative Cryptographic Hash Functions):这类哈希函数通常采用迭代结构和复杂的加密算法来增强安全性和抗碰撞性,例如SHA-256就是一种迭代加密哈希函数。
  • 混合哈希函数(Merkle-Damgård Construction):这种构造方法将输入数据分成固定大小的块,然后对每个块进行处理并与前一个块的哈希值混合,最终生成最终的哈希值。
  • 椭圆曲线哈希函数(Elliptic Curve Hash Functions):这种哈希函数利用椭圆曲线加密算法来生成哈希值,具有较高的安全性和效率。

在设计哈希函数时,通常需要进行严格的分析和测试,确保其满足所需的安全性、效率和功能要求。此外,设计哈希函数时还需要考虑未来的发展和演变,以应对不断变化的安全需求。

2.3举个例子

例题:

设计一个哈希函数,输入为字符串,输出为固定长度的哈希值。哈希函数需要满足以下要求:

  1. 输出长度为 32 位。
  2. 均匀性:不同的输入应该生成不同的哈希值。
  3. 不可逆性:不能从哈希值反推出原始字符串。
  4. 计算效率:哈希函数应该在合理的时间内能够计算出哈希值。

请设计一个符合上述要求的哈希函数,并且给出一个示例输入及其对应的哈希值。

解答:

下面是一个简单的哈希函数的设计,该哈希函数基于 SHA-256 算法:

import hashlib

def custom_hash(input_str):
    # 使用 SHA-256 哈希函数
    hashed = hashlib.sha256(input_str.encode()).hexdigest()
    # 截取前 32 位作为哈希值
    return hashed[:32]

# 示例输入
input_data = "Hello, World!"
# 计算哈希值
hashed_value = custom_hash(input_data)
print("Input:", input_data)
print("Hashed Value:", hashed_value)

运行以上代码,将会输出:

Input: Hello, World!
Hashed Value: 46e2e25bfc1523fca08e87f914f2a4b857814d5f52fa94668094e0027f6eefc5

这个哈希函数满足了所提出的要求:输出长度为 32 位,不同的输入会产生不同的哈希值,哈希值是不可逆的,而且计算速度较快。

三.哈希操作

3.1什么是哈希操作

        哈希操作是指通过哈希函数将输入数据转换为固定长度的输出数据的过程。这个输出通常被称为哈希值或散列值。哈希操作的过程通常可以分为以下几个步骤:

  1.  输入数据:哈希操作的输入是任意长度的数据,可以是文本、文件、数字、对象等。
  2.  哈希函数:选择合适的哈希函数对输入数据进行处理。哈希函数是一个确定性的算法,将输入数据映射为固定长度的输出数据。
  3.  处理输入:将输入数据提供给哈希函数进行处理。哈希函数通常会对输入数据进行一系列的计算和转换,以生成哈希值。
  4.  生成哈希值:经过哈希函数处理后,将会生成固定长度的哈希值作为输出。这个哈希值具有唯一性和固定长度的特性。
  5.  输出结果:最终的输出是生成的哈希值,它是一个字符串或二进制数据,通常以十六进制或Base64等格式表示。

        哈希操作在计算机科学和密码学中有着广泛的应用,用于数据完整性校验、密码存储、数据结构、区块链等方面。通过哈希操作,可以实现数据的唯一标识、快速查找、安全存储等功能。

3.2哈希操作的运用领域

        哈希操作在许多领域都有着广泛的应用,下面列举了一些常见的应用场景:

  1. 密码学:在密码学中,哈希操作常用于存储密码的安全性。通常,网站和应用程序不会直接存储用户的明文密码,而是存储其哈希值。当用户登录时,系统会将用户输入的密码进行哈希操作,然后与存储的哈希值进行比较来验证密码的正确性。
  2. 数据完整性验证:哈希操作用于验证数据的完整性,特别是在数据传输和存储过程中。发送方可以计算数据的哈希值,并将其随数据一起发送。接收方收到数据后,可以再次计算哈希值并与发送方提供的哈希值进行比较,以确保数据在传输过程中未被篡改。
  3. 数据结构:哈希表是一种常见的数据结构,用于快速查找和插入数据。在哈希表中,键经过哈希操作得到哈希值,然后映射到哈希表中的索引位置。这样可以实现高效的查找和插入操作。
  4. 文件校验:在下载文件或软件时,通常会提供文件的哈希值,用户可以通过计算文件的哈希值并与提供的哈希值进行比较来验证文件的完整性和真实性,以确保文件未被篡改或感染恶意软件。
  5. 数字签名:数字签名使用哈希操作来确保数据的完整性和身份验证。发送方将数据的哈希值与其私钥进行加密,生成数字签名。接收方使用发送方的公钥来解密签名并验证哈希值,以确保数据的完整性和真实性。
  6. 区块链:在区块链中,哈希操作用于生成区块的唯一标识,并确保区块链的不可篡改性。每个区块都包含前一个区块的哈希值,这样就形成了一个链式结构,任何对区块链的篡改都会导致哈希值的变化,从而被检测到。

        这些是哈希操作常见的应用场景,它们在保障数据安全性、完整性和可靠性方面发挥着重要作用。

3.3举个例子

        当在密码学中运用哈希函数时,常见的应用是存储用户密码的安全性。下面是一个例题:

例题:

        假设你是一个网站的开发者,你需要设计一个安全的用户密码存储系统。你决定使用哈希函数来存储密码的哈希值而不是明文密码。请设计一个方案来实现这个密码存储系统。

解答:

        下面是一个简单的解答方案,使用哈希函数(例如SHA-256)来存储用户密码的哈希值:

  1. 注册用户

    • 当用户注册时,他们会提供一个密码。网站将用户提供的密码经过哈希函数处理,并将得到的哈希值存储在数据库中,而不是明文密码。
  2. 验证用户登录

    • 当用户尝试登录时,他们会输入密码。网站将输入的密码经过哈希函数处理得到哈希值,并与数据库中存储的哈希值进行比较。
    • 如果两个哈希值匹配,则说明用户输入的密码是正确的。

        相应代码展示:

import hashlib

# 假设数据库中已经存储了用户的哈希密码
user_password_hash = "4a7d1ed414474e4033ac29ccb8653d9b"  # 这是 "password" 的哈希值

# 登录时用户输入的密码
input_password = "password"

# 使用哈希函数(例如SHA-256)处理输入密码
input_password_hash = hashlib.sha256(input_password.encode()).hexdigest()

# 验证密码是否匹配
if input_password_hash == user_password_hash:
    print("密码正确,登录成功!")
else:
    print("密码错误,请重试。")

        在这个例子中,用户的密码 "password" 被哈希处理并存储在数据库中,当用户输入密码尝试登录时,输入的密码也被哈希处理,然后与数据库中存储的哈希值进行比较。如果两个哈希值匹配,则说明用户输入的密码是正确的。

四.哈希冲突的处理

4.1什么是哈希冲突处理

        哈希冲突是指两个不同的输入数据经过哈希函数处理后产生相同的哈希值。在实际应用中,哈希冲突是不可避免的,因为哈希函数的输出空间通常比输入空间小得多,所以一定会出现多个不同的输入映射到同一个哈希值的情况。

处理哈希冲突的方法取决于应用场景和哈希函数的要求。下面是一些常见的处理哈希冲突的方法:

  1. 链地址法(Chaining):在哈希表中,每个哈希值对应一个链表,当发生冲突时,将新数据添加到链表中。这样可以保证哈希表的插入和查找操作的平均时间复杂度为 O(1),但最坏情况下可能会退化为 O(n)。
  2. 开放定址法(Open Addressing):在哈希表中,发生冲突时,使用另一种方法来寻找空闲的位置存储数据,例如线性探测、二次探测、双重散列等。这种方法可以减少内存的使用,并且适用于内存受限的环境。
  3. 重新哈希(Rehashing):当哈希表中的负载因子达到一定阈值时,可以对哈希表进行重新哈希操作,即增加哈希表的大小并重新将所有元素插入到新的哈希表中。这种方法可以减少冲突的概率,但会导致一定的性能损失。
  4. 完美哈希(Perfect Hashing):对于一组静态数据,可以使用完美哈希函数来消除冲突,即保证每个键都映射到唯一的哈希值。这种方法通常需要对数据进行预处理,并且适用于静态数据集。
  5. 哈希函数的改进:有时可以通过改进哈希函数来减少冲突的发生,例如选择更好的哈希函数、增加哈希值的位数、使用更好的散列方法等。

        选择合适的处理哈希冲突的方法取决于应用的需求、数据的特性以及对性能和空间的要求。在设计哈希表或其他哈希数据结构时,需要综合考虑这些因素来选择最合适的方法。

4.2链地址法(拉链法 Separate Chaining)

也叫开散列方法,将取模后相同地址,存储在这个地址所指向的链表中。

拉链法是解决哈希冲突的一种行之有效的方法,某些哈希地址可以被多个关键字值共享,这样可以针对每个哈希地址建立一个单链表。

在拉链(单链表)的哈希表中搜索一个记录是容易的,首先计算哈希地址,然后搜索该地址的单链表

4.3开放地址法

为产生冲突的地址H(key)求得一个地址

所谓开放定址法,也叫闭散列法,是指可存放新表项的空闲地址既向它的同义词表项开放,又向它的非同义词表项开放。其数学递推公式为:
同义词:散列后相同的数值
H=(H(key) + di) % m

i=0,1,2....,k (k≤m -1) ,m表示散列表表长;di为增量序列;i可理解为“第i次发生冲突”

(1)线性探测
①线性探测法一一 di (增量序列)=0,1,2,3,..., m-1;即发生冲突时,每次往后探测相邻的下一个单元是否为空

说明:当遭遇哈希冲突时,会按照规则顺延往下找空挡位置插入元素,这种方式如果哈希冲突比较严重,会造成寻找空挡位置效率变低。哈希表性能变差。这种方式就是要设置合适的哈希表容量。

缺点:线性探测法很容易造成同义词火非同义亏的“聚集(堆积)”现象,严重影响查找效率,为了解决这个问题,引入了平方探测法。

删除实例:

将删除掉的数字用一个Tag标记,不能直接删除,直接删除会形成空值,会影响查找。

注意:采用该种方法,不能直接删除元素(直接删除后会产生null 影响元素查找),要用Tag标记为已经删除,如下图:


添加实例:

4.4 平方探测法

当di (增量序列)= 02,12,-12,22,-22,..., k2,-k2时,称为平方探测法,又称二次探测法其中k<=m/2,:散列表长度m必须是一个可以表示成4j+3的素数


非重点小坑:散列表长度m必须是一个可以表示成4j+3的素数(答案在数论中),才能探测到所有位置


当表长为8时候,并不能探测所有的表中元素。

说明:这种方式相对于线性探测,加大了寻找空挡位置的步长。

4.5再散列法(再哈希法)

除了原始的散列函数H(key之外,多准备几个散列函数,当散列函数冲突时,用下一个散列函数计算一个就地址,直到不冲突为止:

说明:当遭遇哈希冲突后,再运行一个哈希函数,对上一次哈希运算结果再计算一次结果,二次运算后得到的索引位置,是一个空挡位置的几率增大。

五.结语

之后会持续跟进这方面知识内容,以上内容可能不是很完整,大家也可以看看其他文章内容进行对比补充,以上照片来源于:

  • 26
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值