Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

译自 halo2 book:https://zcash.github.io/halo2/design/gadgets/sinsemilla.html

Sinsemilla

概述

Sinsemilla 是一种抗碰撞(collision-resistant)的哈希(hash)函数和承诺(commitment)方案,其设计目标是在支持查表(lookups)的代数电路模型(如 PLONK 或 Halo 2)中保持高效。

Sinsemilla 的安全性质与 Pedersen 哈希类似;它并非设计用于需要随机预言机(random oracle)、PRF 或抗原像(preimage-resistant)哈希的场合。该哈希函数唯一声称的安全性质是对定长输入的抗碰撞性。

在电路内部,Sinsemilla 的效率大约比代数哈希 Rescue 和 Poseidon 低 4 倍,但在电路外部却比 Rescue 高约 19 倍。与这两种哈希不同的是,Sinsemilla 的抗碰撞性质可以基于已确立至少 20 年的密码学假设来证明。Sinsemilla 还可用作一个计算上绑定(computationally binding)且完美隐藏(perfectly hiding)的承诺方案。

总体思路是把消息切分成 比特的小片,对每一片,从我们密码学群中的一张含 个基底(bases)的表里选出一个。我们用倍加(double-and-add)算法把所选的基底组合起来。最终其安全性可证明地等同于一个向量 Pedersen 哈希,并且充分利用了 Halo 2 所支持的查表功能。

描述

本节是 Sinsemilla 工作原理的概述:规范性的定义请参阅协议规范中的 §5.4.1.9 Sinsemilla 哈希函数。我们下文使用的不完全点加(incomplete point addition)运算符 ⸭ 也在那里定义。

是一个素数阶 的密码学群。我们用加法记号书写 ,其单位元为 ,并用 表示 作标量乘法。

是一个基于效率考量选取的整数(表的大小将为 )。设 是一个整数,对每个实例化是固定的,使得消息为 比特,其中 。必要时我们用零填充(zero-padding)补到下一个 比特的整数倍。

:选取 作为 个独立的、可验证随机(verifiably random)的生成元,方法是使用一个合适的"哈希进 "(hash into )函数,使得 都不等于

在 Orchard 中,我们将 定义为依赖于一个域分隔符(domain separator)。协议规范用 替代 ,用 替代

:

  • 切分成 组,每组 比特。把每组解释为一个 比特小端(little-endian)整数
  • :
  • 返回

坐标。(这里假定 是短 Weierstrass 形式(short Weierstrass form)的素数阶椭圆曲线,对 Pallas 和 Vesta 而言确实如此。)

把一个倍加 表示为 会稍微高效一些。我们也使用不完全加法:Sinsemilla 安全性论证中证明了,在 为素数阶短 Weierstrass 椭圆曲线的情形下,加法的一个例外情形(exceptional case)将会导致求出一个离散对数(discrete logarithm),而即便对于敌手构造的输入,这也可以假定以可忽略的概率发生。

用作承诺方案

独立于 另选一个生成元

承诺的随机量 上均匀选取。

。(这同样假定 是短 Weierstrass 形式的素数阶椭圆曲线。)

注意,与简单的 Pedersen 承诺不同,这个承诺方案()不是加法同态(additively homomorphic)的。

高效实现

设计的目标是,在给定表大小的前提下,优化算法每一步(每步需要在 中作一次倍乘和一次加法)所能处理的比特数。使用一张大小为 个群元素的单表,我们每次可以处理 比特。

不完全加法

在 Sinsemilla 的每一步中,我们要计算 。设 为中间结果,使得 。 回顾不完全加法公式:

。依次代入每个不完全加法的坐标并整理,我们得到

以及

约束程序

输入:。(这里消息字(message words)的下标从 1 开始,与协议规范一致,但我们让循环从 开始,使得 对应协议规范中的 。)

输出:

  • :

PLONK / Halo 2 约束

消息分解(decomposition)

我们有一条 比特的消息 。(注意消息字的下标从 1 开始,与协议规范一致。)

将累加和(running sum)初始化为 ,并定义 。最终我们将得到

整理后得到原消息每个字的表达式 ,我们可以在表中对它进行查表。我们把 放在同一列的相邻两行,这样就能沿整条消息顺序地施加该约束。

换言之,

对于此处所用的小端分解,累加和初始化为该标量并以 0 结束。而对于变基标量乘法(variable-base scalar multiplication)中所用的大端(big-endian)分解,累加和会从 0 开始,并以恢复出原标量结束。

高效打包(packing)

累加和只适用于单个域元素(field element)内部的消息字。这意味着,如果 ,我们就需要多个互不相交的累加和。更长的消息可以通过把消息字拆分到多个域元素中来构造,然后运行下面这些约束的多个实例。

上面 的表达式在 列中需要 行,这会在相邻列里留下一行空隙,使得 更难累加。为了支持把多个域元素串联起来而不留空隙,我们对 使用一个稍复杂、包含一个选择子(selector)的表达式:

这实际上把每个域元素最后一步的 强制为零,从而让本应作为 的那个单元(cell)可以被用来为下一个域元素重新初始化累加和。

这样安排好之后,不完全加法累加器几乎可以完全消去 ,办法是在当前行和下一行中用 的值进行代换。两个例外是在 Sinsemilla 的起点(那里我们需要约束累加器的初始值为 )和终点(那里我们需要见证(witness) 以供 Sinsemilla 之外使用)。

选择子

我们总共需要四个逻辑选择子,用于:

  • 控制 Sinsemilla 门(gate)和查表。
  • 区分一个累加和中的最后一个消息字与它之前的各个字。
  • 标记 Sinsemilla 的开始。
  • 标记 Sinsemilla 的结束。

我们对 Sinsemilla 门选择子 和 Sinsemilla 起始选择子 使用普通的选择子列。另外两个选择子从单一固定列 按如下方式合成(synthesized):

我们在大多数 Sinsemilla 行上把 设为 ,在每个域元素的最后一步设为 ,但最后一个域元素例外,那里设为 。然后我们可以用 在两种约束之间切换:约束相邻两行上经代换的 ,以及约束 Sinsemilla 末尾处所见证的 :

生成元查表表

Sinsemilla 电路使用了 个预计算的随机生成元。它们被装入一张查表表中:

布局(Layout)

等通过相等约束(equality constraints)拷入。

优化后的 Sinsemilla 门

Halo 2 电路 API 可以自动代换 ,所以我们无需手动去做。

  • :

注意,相对于前面给出的约束程序,最后一个约束的每一项都乘以了 。这是一个小的优化,可以避免除以

通过用 来门控(gating)查表表达式,我们避免了为了让查表论证(lookup argument)通过而用哑值(dummy values)去填充未用单元的需要。优化后的查表值(使用默认下标 )为:

这把查表论证的次数(degree)提高到了