#hash #merkle-tree #blake3 #prime-field #crypto

no-std winter-crypto

Winterfell STARK 证明/验证器的加密库

20 个不稳定版本 (8 个破坏性版本)

0.9.0 2024年5月9日
0.8.3 2024年3月15日
0.8.1 2024年2月21日
0.7.0 2023年10月23日
0.2.0 2021年8月24日

#66 in 密码学

Download history 2735/week @ 2024-04-26 2384/week @ 2024-05-03 2336/week @ 2024-05-10 1599/week @ 2024-05-17 1643/week @ 2024-05-24 2494/week @ 2024-05-31 2243/week @ 2024-06-07 2528/week @ 2024-06-14 2533/week @ 2024-06-21 2722/week @ 2024-06-28 2481/week @ 2024-07-05 3202/week @ 2024-07-12 2653/week @ 2024-07-19 3391/week @ 2024-07-26 2748/week @ 2024-08-02 1984/week @ 2024-08-09

11,302 每月下载量
用于 48 个 crate (8 直接)

MIT 许可证

535KB
9K SLoC

Winter crypto

此 crate 包含用于 STARK 证明生成和验证所需的加密操作模块。

哈希

哈希 模块定义了一组可用于加密操作的哈希函数。目前,支持以下哈希函数

  • SHA3 输出 256 位。
  • BLAKE3 输出 256 位或 192 位。较小的输出版本可用于减少 STARK 证明大小,但这也将证明的安全性级别限制在最多 96 位。
  • 在 64 位字段上的 Rescue Prime,输出 256 位,在 62 位字段上输出 248 位。Rescue 是一个适合算术化的哈希函数,当需要递归证明组合时可以在 STARK 协议中使用。然而,Winterfell STARK 证明器和验证器尚未支持此函数。
  • 与上述相同的 64 位字段上的 Rescue Prime,输出 256 位,但使用新颖的 Jive 压缩模式 以获得更小的状态和更快的 2-to-1 压缩。

Rescue 哈希函数实现

Rescue 哈希函数是根据 Rescue Prime 规范 实现的,但有以下例外

  • 我们将轮数设置为 7,这意味着比规范中使用的 50% 安全边际提高了 40%(50% 边际向上取整为 8 轮)。这样做的主要动机是,将轮数设为小于 2 的幂的数可以简化涉及哈希函数的计算的 AIR 设计。
  • 在散列一系列元素时,我们不会在序列末尾追加Fp(1)后跟Fp(0)个元素作为填充。相反,我们将容量元素之一初始化为要散列的元素数量,并且只使用Fp(0)元素填充序列。这确保了当我们使用merge()函数(例如,构建Merkle树)散列8个域元素来计算2-to-1散列时,以及当我们使用hash_elements()函数将8个域元素作为元素序列散列时,散列函数的输出是相同的。然而,这也意味着我们的Rescue Prime实例不能以流模式使用,因为必须事先知道要散列的元素数量。
  • 对于实例RP64_256,我们还进行了以下修改
    • 我们使用状态的前4个元素(而不是状态的最后一个4个元素)作为容量,其余8个元素作为速率。散列函数的输出来自状态速率部分的第一个四个元素(元素4,5,6和7)。这实际上在XLIX置换之前和之后应用了一个固定的位置换。我们断言这不会影响构造的安全性。
    • 我们不是使用Rescue Prime论文中描述的标准方法,即使用Vandermonde矩阵生成MDS矩阵,而是使用Polygon Zero开发的方法来找到一个系数在频域中是两个小的二进制幂的MDS矩阵。这使我们能够显著减少MDS矩阵乘法的时间。使用不同的MDS矩阵不会影响散列函数的安全性,因为任何MDS矩阵都满足Rescue Prime构造(如论文第4.2节所述)。
  • 使用Jive作为压缩模式的RPJive64_256实例的Rescue Prime实现了与Rp64_256类似的修改,唯一的例外是其填充规则实现了Hirose填充。此外,由于使用了Jive,当我们使用hash_elements()函数将8个域元素作为元素序列散列时,以及当我们使用2-to-1 Jive压缩模式将8个域元素压缩为4(例如,构建Merkle树)时,散列函数的输出并不相同。

用于实例化函数的参数是

  • 对于RP64_256
    • 域:模数为264 - 232 + 1的64位素域。
    • 状态宽度:12个域元素。
    • 容量大小:4个域元素。
    • 摘要大小:4个域元素(可以序列化为32字节)。
    • 找到的数量:7。
    • S-Box度:7。
    • 目标安全级别:128位。
  • 对于RPJive64_256
    • 域:模数为264 - 232 + 1的64位素域。
    • 状态宽度:8个域元素。
    • 容量大小:4个域元素。
    • 摘要大小:4个域元素(可以序列化为32字节)。
    • 找到的数量:7。
    • S-Box度:7。
    • 目标安全级别:128位。
  • 对于RP62_248
    • 域:模数为262 - 111 * 239 + 1的62位素域。
    • 状态宽度:12个域元素。
    • 容量大小:4个域元素。
    • 摘要大小:4个域元素(可以序列化为31字节)。
    • 找到的数量:7。
    • S-Box度:3。
    • 目标安全级别:124位。

散列函数性能

在STARK证明生成期间执行的核心操作之一是构建Merkle树。我们非常关注尽快构建这些树,因此,对于STARK协议,2-to-1散列操作(例如,计算两个32字节值的散列)尤为重要。下表包含计算所有当前实现散列函数2-to-1散列的粗略基准。

CPU BLAKE3_256 SHA3_256 RP64_256 RPJ64_256 RP62_248
苹果M1 Pro 76 ns 227 ns 5.1 us 3.8 us 7.1 us
AMD Ryzen 9 5950X @ 3.4 GHz 62 ns 310 ns 5.2 us 3.9 us 6.9 us
Core i9-9980KH @ 2.4 GHz 66 ns 400 ns - - 6.6 us
Core i5-7300U @ 2.6 GHz 81 ns 540 ns - - 9.5 us
Core i5-4300U @ 1.9 GHz 106 ns 675 ns - - 13.9 us

从表中可以看出,BLAKE3是目前最快的哈希函数,而我们的代数哈希实现比BLAKE3慢70倍,比SHA3慢20倍。

默克尔

默克尔模块包含一个默克尔树实现,该树支持批处理证明生成和验证。批处理证明基于此处描述的章鱼算法(此处)

箱子功能

此箱子可以编译以下功能

  • std - 默认启用并依赖于Rust标准库。
  • concurrent - 意味着std并使某些箱子函数启用多线程执行。
  • no_std不依赖于Rust标准库并使编译到WebAssembly成为可能。

要使用no_std编译,通过--no-default-features标志禁用默认功能。

并发执行

当启用concurrent功能进行编译时,以下操作将在多个线程中执行

  • MerkleTree::new() - 即,将在多个线程中构建默克尔树。

线程数可以通过RAYON_NUM_THREADS环境变量进行配置,通常默认为机器上的逻辑核心数。

许可证

本项目是MIT许可

依赖关系

~3MB
~53K SLoC