SHA-1哈希函数 | AI生成和翻译

Home 2025.03

让我们深入理解给定代码片段的工作原理,特别是这几行:

hash_obj = hashlib.sha1(piece)
hashes.append(hash_obj.hexdigest())
return hashes

用户要求我们不使用库来解释这段代码,因此我将先说明使用 hashlib 库时代码的功能,然后探讨如何在不使用该库的情况下实现相同的功能。


使用 hashlib 理解代码

这段代码计算数据片段的哈希值并将其存储在列表中。以下是逐步解析:

  1. hash_obj = hashlib.sha1(piece)
    • 功能:该行使用 Python 的 hashlib 模块创建一个 SHA-1 哈希对象。SHA-1(安全哈希算法 1)是一种加密哈希函数,接收输入(此处为 piece)并生成一个 160 位(20 字节)的哈希值。
    • 输入piece 是从文件或其他来源读取的数据块,可能是字节数据。
    • 处理过程hashlib.sha1() 函数初始化一个哈希对象,并立即使用 piece 中的数据更新它。可以将其视为将数据输入到开始处理数字的哈希机器中。
  2. hashes.append(hash_obj.hexdigest())
    • 功能hexdigest() 方法获取哈希对象计算出的哈希值,并将其转换为十六进制字符串(使用数字 0-9 和字母 a-f 的人类可读格式)。
    • 输出:对于 SHA-1,该字符串长度为 40 个字符,因为每个 20 字节的哈希值用两个十六进制数字表示(例如,字节值 255 变为 “ff”)。
    • 存储:生成的字符串被追加到名为 hashes 的列表中,该列表可能用于收集多个数据片段的哈希值。
  3. return hashes
    • 功能:在处理完所有片段后(假设此代码位于循环或函数中),返回包含所有十六进制哈希字符串的列表 hashes

总结:对于每个数据 piece,代码使用 hashlib.sha1() 计算其 SHA-1 哈希值,使用 hexdigest() 将哈希值转换为十六进制字符串,并将其存储在 hashes 列表中,最后返回该列表。


不使用库:从零开始计算 SHA-1

用户要求“不使用库”,表明他们希望了解在不依赖 hashlib 的情况下如何实现此功能。从头实现 SHA-1 算法很复杂,但我会清晰地解释过程,并提供一个可在此基础上扩展的简化版本。

什么是 SHA-1?

SHA-1 是一种哈希函数,具有以下特点:

在不使用 hashlib 的情况下,我们需要自己复制此算法。以下是针对给定代码的实现方式:

SHA-1 算法的逐步过程

  1. 准备输入(填充)
    • SHA-1 以 512 位(64 字节)块处理数据。如果 piece 不是恰好 64 字节,则进行填充:
      • 追加一个 1 位(例如,字节 0x80)。
      • 添加足够的 0 位,使长度对 512 取模后为 448 位(56 字节)。
      • 追加 piece 的原始长度(以位为单位)作为 64 位整数。
    • 为简化起见,如果 piece 小于 64 字节,我们可以将其填充为一个块。
  2. 初始化哈希值
    • SHA-1 使用五个 32 位变量(总计 160 位),初始化为特定常量:
      • h0 = 0x67452301
      • h1 = 0xEFCDAB89
      • h2 = 0x98BADCFE
      • h3 = 0x10325476
      • h4 = 0xC3D2E1F0
  3. 处理数据块
    • 将 64 字节块拆分为 16 个 32 位字(每个 4 字节)。
    • 使用以下公式将其扩展为 80 个字:
      w[i] = left_rotate(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1)  # 对于 i = 16 到 79
      

      其中 left_rotate 将位向左循环移位。

    • 在 80 轮循环中,更新临时变量 abcde(初始为 h0h4 的副本):
      • 根据轮数(0-19、20-39 等)使用不同的函数和常量。
      • 例如,对于 0-19 轮:
        f = (b & c) | (~b & d)
        k = 0x5A827999
        temp = (left_rotate(a, 5) + f + e + k + w[i]) & 0xFFFFFFFF
        
      • 移位变量:e = dd = cc = left_rotate(b, 30)b = aa = temp
  4. 更新哈希值
    • 80 轮循环后,将结果添加到初始哈希值中:
      h0 = (h0 + a) & 0xFFFFFFFF
      h1 = (h1 + b) & 0xFFFFFFFF
      # ...依此类推 h2、h3、h4
      
  5. 生成十六进制输出
    • h0h4 连接为 160 位值,并转换为 40 字符的十六进制字符串。

简化的 Python 实现

以下是如何在不使用 hashlib 的情况下重写代码的基本版本:

def left_rotate(value, shift):
    """将 32 位整数左移 'shift' 位。"""
    return ((value << shift) | (value >> (32 - shift))) & 0xFFFFFFFF

def custom_sha1(piece):
    """计算 'piece' 的 SHA-1 哈希值,并返回十六进制字符串。"""
    # 为简化起见,假设 piece 小于 56 字节并填充为一个块
    message = piece + b'\x80' + (b'\x00' * (55 - len(piece))) + (len(piece) * 8).to_bytes(8, 'big')
    
    # 初始化哈希值
    h0, h1, h2, h3, h4 = (
        0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0
    )
    
    # 拆分为 16 个 32 位字
    w = [int.from_bytes(message[i:i+4], 'big') for i in range(0, 64, 4)]
    
    # 扩展为 80 个字
    for i in range(16, 80):
        w.append(left_rotate(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1))
    
    # 初始化工作变量
    a, b, c, d, e = h0, h1, h2, h3, h4
    
    # 80 轮处理
    for i in range(80):
        if 0 <= i < 20:
            f = (b & c) | (~b & d)
            k = 0x5A827999
        elif 20 <= i < 40:
            f = b ^ c ^ d
            k = 0x6ED9EBA1
        elif 40 <= i < 60:
            f = (b & c) | (b & d) | (c & d)
            k = 0x8F1BBCDC
        else:
            f = b ^ c ^ d
            k = 0xCA62C1D6
        
        temp = (left_rotate(a, 5) + f + e + k + w[i]) & 0xFFFFFFFF
        e = d
        d = c
        c = left_rotate(b, 30)
        b = a
        a = temp
    
    # 更新哈希值
    h0 = (h0 + a) & 0xFFFFFFFF
    h1 = (h1 + b) & 0xFFFFFFFF
    h2 = (h2 + c) & 0xFFFFFFFF
    h3 = (h3 + d) & 0xFFFFFFFF
    h4 = (h4 + e) & 0xFFFFFFFF
    
    # 返回 40 字符的十六进制字符串
    return f"{h0:08x}{h1:08x}{h2:08x}{h3:08x}{h4:08x}"

# 重写代码,不使用 hashlib
def compute_hashes(pieces):
    hashes = []
    for piece in pieces:  # 假设 pieces 是字节块列表
        hash_value = custom_sha1(piece)
        hashes.append(hash_value)
    return hashes

# 示例用法
pieces = [b"hello", b"world"]
hashes = compute_hashes(pieces)
print(hashes)

与原代码的对应关系


主要差异与注意事项

本质上,原代码使用 hashlib 作为高效计算 SHA-1 哈希值的快捷方式,而不使用库则需要手动编写整个 SHA-1 算法、处理填充并将结果转换为十六进制格式。逻辑保持不变:处理每个片段,计算其哈希值,存储并返回集合。


Back Donate