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/sha256/table16.html

用于 SHA-256 的 16 比特表芯片(table chip)

这个芯片(chip)实现围绕单张 16 比特查表表(lookup table)构建。它至少需要 个电路行(circuit rows),因此适合用在较大的电路中。

我们的目标是最大约束次数(constraint degree)为 。这将允许我们在一行内处理对进位(carries)以及"小片(small pieces)"约束到 范围内的约束。

轮压缩(Compression round)

共有 轮压缩(compression rounds)。每一轮以 32 比特值 作为输入,并执行以下运算:

其中 必须处理一个满足 的进位(carry)。

The SHA-256 compression function

定义为一张表,它把一个 比特的输入映射到一个用零比特交错(interleaved)的输出。我们不需要为范围检查(range checks)单独建表,因为可以使用

模加法(Modular addition)

为实现模 加法,我们注意到这等价于用域加法(field addition)把操作数相加,然后把结果除最低 32 比特之外的全部比特都掩掉(mask away)。例如,若我们有两个操作数 :

我们把每个操作数(连同结果)分解(decompose)成 16 比特的小块(chunks):

然后用域加法重新表述该约束:

更一般地,输出的任意比特分解(bit-decomposition)都可以使用,而不仅限于分解成 16 比特小块。注意这正确地处理了来自 的进位。

这个约束要求每个小块都被正确地范围检查(否则一次赋值可能溢出该域(overflow the field))。

  • 操作数小块和结果小块可以用 来约束,办法是在表的某个子集中,在"密集(dense)"列里对每个小块查表。这样我们还能免费得到输出的"展开(spread)"形式;特别地,对于右下角那个 的输出(它会成为 ),以及最左边那个 的输出(它会成为 ),都是如此。我们将在下文用这一点来优化

  • 必须被约束到与操作数个数相对应的、允许的进位值的精确范围内。我们用一个 小范围约束(small range constraint)来做这件事。

Maj 函数

可以用 次查表完成: 个小块

  • 如上所述,第一轮之后我们已经拥有展开形式的 ,即 。 类似地, 分别等于上一轮的 , 因此在稳态(steady state)下,我们已经拥有它们的展开形式 。事实上 我们也可以假定在第一轮就拥有它们的展开形式,要么来自固定的 IV,要么来自用 去归约(reduce)上一块前馈(feedforward)的输出。
  • 把这些展开形式在域中相加:;
    • 我们可以把它们当作 比特字相加,也可以分片相加;两者等价。
  • 见证(witness)压缩偶数比特 和压缩奇数比特 ,;
  • 约束 ,其中 函数的输出。

注:我们所说的"偶数(even)"比特指的是权重为 的偶数次幂的比特,即权重为 的比特。类似地,"奇数(odd)"比特指的是权重为 的奇数次幂的比特。

Ch 函数

TODO:借助一张额外的表,可能可以优化到 次查表。

可以用 次查表完成: 个小块

  • 如上所述,第一轮之后我们已经拥有展开形式的 ,即 。 类似地, 分别等于上一轮的 , 因此在稳态下,我们已经拥有它们的展开形式 。事实上 我们也可以假定在第一轮就拥有它们的展开形式,要么来自固定的 IV,要么来自用 去归约上一块前馈的输出。
  • 计算 ,其中
    • 我们可以把它们当作 比特字相加,也可以分片相加;两者等价。
    • 之所以能算出 的展开形式,尽管取反(negation)与 一般并不交换(commute)。它之所以有效,是因为 中的每个展开比特 都从 中减去,所以不会发生借位(borrows)。
  • 见证 ,使得 ,对 同理。
  • 就是 函数的输出。

Σ_0 函数

可以用 次查表完成。

为此,我们首先把 切分成片 ,长度分别为 比特,从低端(little end)开始计数。同时我们得到这些片的展开 形式。这一切都可以在两个 PLONK 行内完成,因为 比特和 比特的片可以用 查表来处理,而 比特的片可以 切分成 比特的子片(subpieces)。后者和剩下的 比特片可以 与这两次查表并行地用多项式约束(polynomial constraints)做范围检查,每行做两个小片 。这些小片的展开形式通过插值(interpolation)求得。

注意,把它切分成片这件事可以与 的归约(reduction)合并,即 后者不需要额外的查表。在最后一轮中,我们在加上前馈之后再归约 (需要处理一个至多为 的进位,这没问题)。

等价于 :

然后,再用 查表,我们把结果作为这些片的某个 线性组合(linear combination)的偶数比特而得到:

也就是说,我们见证压缩偶数比特 和压缩奇数比特 ,并约束 其中 函数的输出。

Σ_1 函数

可以用 次查表完成。

为此,我们首先把 切分成片 ,长度分别为 比特,从低端开始计数。同时我们得到这些片的展开 形式。这一切都可以在两个 PLONK 行内完成,因为 比特和 比特的片可以用 查表来处理, 比特的片可以 切分成 比特和 比特的子片,而 比特的片可以切分成 比特 的子片。这四个小片可以与这两次查表 并行地用多项式约束做范围检查,每行做两个小片。这些 小片的展开形式通过插值求得。

注意,把它切分成片这件事可以与 的归约合并,即 后者不需要额外的查表。在最后一轮中,我们在加上前馈 之后再归约 (需要处理一个至多为 的进位,这没问题)。

等价于

然后,再用 查表,我们以与 相同的方式,把结果作为这些片的某个线性组合的偶数比特而得到:

也就是说,我们见证压缩偶数比特 和压缩奇数比特 ,并约束 其中 函数的输出。

块分解(Block decomposition)

对于已填充消息(padded message)的每一个块 ,要构造 个各 比特的字 ,方法如下:

  • 个通过把 切分成 比特的块来得到
  • 其余 个字用以下公式构造:

注: 字的下标采用从 开始的编号。

注: 是右移位(shift),不是旋转(rotation)。

σ_0 函数

等价于

与上面类似,但片 的长度为 ,从低端 开始计数。把 切分成两个 比特子片。

σ_1 函数

等价于

TODO:这张图与右侧的表达式不符。这里只是为了与 其他图保持一致。

与上面类似,但片 的长度为 ,从低端 开始计数。把 切分成 比特子片。

消息调度(Message scheduling)

我们对 应用 ,对 应用 。为了避免 对 的冗余应用,在 的情形下,我们可以把 的切片合并。把片长度 合并后,得到长度为 的片。

如果我们能用 行完成这个合并的切分(而不是分别为 切分时总共需要的 行),我们就节省了 行。

这些甚至或许能用 行做到;不确定。 ——Daira

被用于计算后续的字时,我们可以把它们的模 归约 合并进它们的切分中,类似于我们对轮函数中的 所做的。

我们仍然需要归约 ,因为它们没有被切分。(从技术上讲我们可以 让它们保持未归约,因为稍后用它们来计算 时它们会被归约——但那会需要处理一个至多为 而不是 的进位,所以不值得为此增加复杂度。)

由此得到的消息调度代价为:

  • 行用于把 约束为 比特
    • 这从技术上讲是可选的,但为了健壮性我们还是这么做,因为输入的其余部分 是免费被约束的。
  • 行用于把 切分成 比特的片
  • 行用于把 切分成 比特的片(对 合并了一次归约)
  • 行用于把 切分成 比特的片(合并了一次 归约)
  • 行用于提取 结果
  • 行用于提取 结果
  • 行用于归约
  • 行。

总体代价(Overall cost)

对每一轮:

  • 行用于
  • 行用于
  • 行用于
  • 行用于
  • 始终是免费的
  • 每轮

这给整个"步骤 3"带来 行,在此之上我们还需加上:

  • 行用于消息调度
  • 行用于"步骤 4"中 次模 归约

总计 行。

表(Tables)

我们只需要一张表 ,它有 行和 列。我们需要一个 标签(tag)列,以便为 选取表的 比特子集。

spread

rowtagtable (16b)spread (32b)
0000000000000000000000000000000000000000000000000
0000000000000000100000000000000000000000000000001
0000000000000001000000000000000000000000000000100
0000000000000001100000000000000000000000000000101
...0......
0000000000111111100000000000000000001010101010101
1000000001000000000000000000000000100000000000000
...1......
1000000111111111100000000000001010101010101010101
...2......
2000001111111111100000000010101010101010101010101
...3......
3000111111111111100000001010101010101010101010101
...4......
4001111111111111100000101010101010101010101010101
...5......
5111111111111111101010101010101010101010101010101

例如,要做一次 比特的 查表,我们用多项式约束把标签 约束到 内。对于最常见的 比特查表的情形,我们不需要 约束标签。注意我们可以用一个重复条目(例如全零)来填充超出 的任何 未用行。

门(Gates)

选择门(Choice gate)

来自先前运算的输入:

  • 即 32 比特字 的 64 比特展开形式,假定已被先前运算所约束
    • 在实践中,把 分解成 16 比特子片之后,我们才会有它们的展开形式
  • 定义为

E ∧ F

s_ch
0{0,1,2,3,4,5}
1{0,1,2,3,4,5}
0{0,1,2,3,4,5}
0{0,1,2,3,4,5}

¬E ∧ G

s_ch_neg
0{0,1,2,3,4,5}
1{0,1,2,3,4,5}
0{0,1,2,3,4,5}
0{0,1,2,3,4,5}

约束:

  • s_ch(选择,choice):
  • s_ch_neg(取反,negation):带一个额外取反检查的 s_ch
  • 查表
  • 之间的置换(permutation)

输出:

多数门(Majority gate)

来自先前运算的输入:

  • 即 32 比特字 的 64 比特展开形式,假定已被先前运算所约束
    • 在实践中,把 分解成 比特子片之后,我们才会有它们的展开形式
s_maj
0{0,1,2,3,4,5}
1{0,1,2,3,4,5}
0{0,1,2,3,4,5}
0{0,1,2,3,4,5}

约束:

  • s_maj(多数,majority):
  • 查表
  • 之间的置换

输出:

Σ_0 门

是一个 32 比特字,被切分成 比特的小块,从低端开始。我们分别把这些小块称为 ,并进一步把 切分成三个 3 比特小块 。我们见证这些小块的展开版本。

s_upp_sigma_0
0{0,1,2,3,4,5}
1{0,1,2,3,4,5}
0{0,1,2,3,4,5}
0{0,1,2,3,4,5}

约束:

  • s_upp_sigma_0( 约束):

  • 查表
  • 做 2 比特范围检查和 2 比特展开检查
  • 做 3 比特范围检查和 3 比特展开检查

(参见辅助门(Helper gates)一节)

输出:

Σ_1 门

是一个 32 比特字,被切分成 比特的小块,从低端开始。我们分别把这些小块称为 ,并进一步把 切分成两个 3 比特小块 ,把 切分成 (2,3) 比特小块 。我们见证这些小块的展开版本。

s_upp_sigma_1
0{0,1,2,3,4,5}
1{0,1,2,3,4,5}
0{0,1,2,3,4,5}
0{0,1,2,3,4,5}

约束:

  • s_upp_sigma_1( 约束):

  • 查表
  • 做 2 比特范围检查和 2 比特展开检查
  • 做 3 比特范围检查和 3 比特展开检查

(参见辅助门(Helper gates)一节)

输出:

σ_0 门

v1

门的 v1 版本接收一个被切分成 比特小块的字(已由消息调度约束)。我们分别把这些小块称为 被进一步切分成两个 2 比特小块 我们见证这些小块的展开版本。我们已经从消息调度得到了

等价于

s_low_sigma_0
0{0,1,2,3,4,5}
1{0,1,2,3,4,5}
0{0,1,2,3,4,5}
0{0,1,2,3,4,5}

约束:

  • s_low_sigma_0( v1 约束):

  • 检查 b 是否被正确地切分成 4 比特片的各子段。
  • 做 2 比特范围检查和 2 比特展开检查
  • 做 3 比特范围检查和 3 比特展开检查

v2

门的 v2 版本接收一个被切分成 比特小块的字(已由消息调度约束)。我们分别把这些小块称为 我们已经从消息调度得到了 。1 比特的 经展开运算后保持不变,可以直接使用。我们进一步把 切分成两个 2 比特小块 我们见证这些小块的展开版本。

等价于

s_low_sigma_0_v2
0{0,1,2,3,4,5}
1{0,1,2,3,4,5}
0{0,1,2,3,4,5}
0{0,1,2,3,4,5}

约束:

  • s_low_sigma_0_v2( v2 约束):

  • 检查 b 是否被正确地切分成 4 比特片的各子段。
  • 做 2 比特范围检查和 2 比特展开检查
  • 做 3 比特范围检查和 3 比特展开检查

σ_1 门

v1

门的 v1 版本接收一个被切分成 比特小块的字(已由消息调度约束)。我们分别把这些小块称为 被进一步切分成 比特小块 我们见证这些小块的展开版本。我们已经从消息调度得到了

等价于

s_low_sigma_1
0{0,1,2,3,4,5}
1{0,1,2,3,4,5}
0{0,1,2,3,4,5}
0{0,1,2,3,4,5}

约束:

  • s_low_sigma_1( v1 约束):

  • 检查 b 是否被正确地切分成 7 比特片的各子段。

  • 做 2 比特范围检查和 2 比特展开检查

  • 做 3 比特范围检查和 3 比特展开检查

v2

门的 v2 版本接收一个被切分成 比特小块的字(已由消息调度约束)。我们分别把这些小块称为 我们已经从消息调度得到了 。1 比特的 经展开运算后保持不变,可以直接使用。我们进一步把 切分成两个 2 比特小块 我们见证这些小块的展开版本。

等价于

s_low_sigma_1_v2
0{0,1,2,3,4,5}
1{0,1,2,3,4,5}
0{0,1,2,3,4,5}
0{0,1,2,3,4,5}

约束:

  • s_low_sigma_1_v2( v2 约束):

  • 检查 b 是否被正确地切分成 4 比特片的各子段。
  • 做 2 比特范围检查和 2 比特展开检查
  • 做 3 比特范围检查和 3 比特展开检查

辅助门(Helper gates)

小范围约束(Small range constraints)

。把这个表达式约束为零就强制 位于 内。

2 比特范围检查

sr2
1a

2 比特展开

ss2
1aa'

插值多项式(interpolation polynomials)为:

  • ()
  • ()
  • ()
  • ()

3 比特范围检查

sr3
1a

3 比特展开

ss3
1aa'

插值多项式为:

  • ()
  • ()
  • ()
  • ()
  • ()
  • ()
  • ()
  • ()

reduce_6 门

6 个元素的模 加法

输入:

检查:

假定输入已被约束为 16 比特。

  • 加法门(sa):
  • 进位门(sc):
sasc
10
11

假定输入已被约束为 16 比特。

  • 加法门(sa):
  • 进位门(sc):
sasc
00
11
00
10

reduce_7 门

7 个元素的模 加法

输入:

检查:

假定输入已被约束为 16 比特。

  • 加法门(sa):
  • 进位门(sc):
sasc
10
11

消息调度区域(Message scheduling region)

对于已填充消息的每一个块 ,要构造 个各 比特的字,方法如下:

  • 个通过把 切分成 比特的块来得到
  • 其余 个字用以下公式构造:
swsd0sd1sd2sd3ss0ss0_v2ss1ss1_v2
010000000{0,1,2,3,4,5}
100000000{0,1,2,3,4,5}
011000000{0,1,2,3,4}
100000000{0,1,2}
000000000{0,1,2,3,4,5}
000001000{0,1,2,3,4,5}
000000000{0,1,2,3,4,5}
000000000{0,1,2,3,4,5}
.....................................................
000000000{0,1,2,3}
0101000000
1000000000
000000000{0,1,2,3,4,5}
000000100{0,1,2,3,4,5}
000000000{0,1,2,3,4,5}
000000000{0,1,2,3,4,5}
000000000{0,1,2,3,4,5}
000000001{0,1,2,3,4,5}
000000000{0,1,2,3,4,5}
000000000{0,1,2,3,4,5}
.....................................................
010010000{0,1,2,3}
000000000{0,1}
000000000{0,1,2,3,4,5}
000000001{0,1,2,3,4,5}
000000000{0,1,2,3,4,5}
000000000{0,1,2,3,4,5}
.....................................................
010000000{0,1,2,3,4,5}
000000000{0,1,2,3,4,5}
010000000{0,1,2,3,4,5}
000000000{0,1,2,3,4,5}

约束:

  • sw:用 构造字
  • sd0: 的分解门
  • sd1: 的分解门(切分成 比特的片)
  • sd2: 的分解门(切分成 比特的片)
  • sd3: 的分解门(切分成 比特的片)

压缩区域(Compression region)

+----------------------------------------------------------+
|                                                          |
|          decompose E,                                    |
|          Σ_1(E)                                          |
|                                                          |
|                  +---------------------------------------+
|                  |                                       |
|                  |        reduce_5() to get H'           |
|                  |                                       |
+----------------------------------------------------------+
|          decompose F, decompose G                        |
|                                                          |
|                        Ch(E,F,G)                         |
|                                                          |
+----------------------------------------------------------+
|                                                          |
|          decompose A,                                    |
|          Σ_0(A)                                          |
|                                                          |
|                                                          |
|                  +---------------------------------------+
|                  |                                       |
|                  |        reduce_7() to get A_new,       |
|                  |              using H'                 |
|                  |                                       |
+------------------+---------------------------------------+
|          decompose B, decompose C                        |
|                                                          |
|          Maj(A,B,C)                                      |
|                                                          |
|                  +---------------------------------------+
|                  |        reduce_6() to get E_new,       |
|                  |              using H'                 |
+------------------+---------------------------------------+

初始轮(Initial round):

s_digestsd_abcdsd_efghss0ss1s_majs_ch_negs_chs_a_news_e_news_h_prime
00100000000{0,1,2}
00000000000{0,1}
00000000000{0,1,2,3,4,5}
00001000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00100000000{0,1,2}
00000000000{0,1}
00100000000{0,1,2}
00000000000{0,1}
00000000000{0,1,2,3,4,5}
00000001001{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000000010{0,1,2,3,4,5}
00000010000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
01000000000{0,1,2}
00000000000{0,1}
00000000000{0,1,2,3,4,5}
00010000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
01000000000{0,1,2}
00000000000{0,1}
01000000000{0,1,2}
00000000000{0,1}
00000000000{0,1,2,3,4,5}
00000100100{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}

稳态(Steady-state):

s_digestsd_abcdsd_efghss0ss1s_majs_ch_negs_chs_a_news_e_news_h_prime
00100000000{0,1,2}
00000000000{0,1}
00000000000{0,1,2,3,4,5}
00001000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000001001{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000000010{0,1,2,3,4,5}
00000010000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
01000000000{0,1,2}
00000000000{0,1}
00000000000{0,1,2,3,4,5}
00010000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000100100{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}
00000000000{0,1,2,3,4,5}

最终摘要(Final digest):

s_digestsd_abcdsd_efghss0ss1s_majs_ch_negs_chs_a_news_e_news_h_prime
10000000000000
00000000000000
10000000000000
00000000000000